Commits

Henning Schröder committed 993ce20

moved files into new source folder

  • Participants
  • Parent commits 1840f44

Comments (0)

Files changed (34)

demo.sh

-#!/bin/sh
-qmake
-make
-./embeddedpyqt

embeddedpyqt.pro

-#-------------------------------------------------
-#
-# Project created by QtCreator 2011-08-03T07:09:48
-#
-#-------------------------------------------------
-
-QT       += core gui
-
-TARGET = embeddedpyqt
-TEMPLATE = app
-
-SOURCES += main.cpp\
-        mainwindow.cpp \
-    test.cpp
-HEADERS  += mainwindow.h \
-    test.h
-FORMS    += mainwindow.ui
-
-
-# -- Generic Python support --------------------------------------
-INCLUDEPATH += -I./embpyqt
-LIBS        += -lpython2.7 -L/usr/lib/
-INCLUDEPATH += /usr/include/python2.7/
-
-# -- Add embpyqt -------------------------------------------------
-SOURCES += \
-    embpyqt/embeddedpyqt.cpp \
-    embpyqt/pythonize.cpp
-HEADERS += \
-    embpyqt/embeddedpyqt.h \
-    embpyqt/pythonize.h

embpyqt/embeddedpyqt.cpp

-#include "embeddedpyqt.h"
-#include "pythonize.h"
-#include <QApplication>
-#include <QVariant>
-#include <QPushButton>
-#include <qdebug.h>
-
-
-EmbeddedPyQt *EmbeddedPyQt::_instance = 0;
-
-
-EmbeddedPyQt::EmbeddedPyQt(QObject *parent) :
-    QObject(parent)
-{
-    EmbeddedPyQt::_instance = this;
-    setObjectName("embeddedPyQt");
-    QApplication::instance()->setProperty("embedded_pyqt",
-                                          qVariantFromValue((QObject*)this));
-    python = new Pythonize();
-    Q_ASSERT(python);
-}
-
-
-void EmbeddedPyQt::init(const QString &filename) {
-    char *cfn = (char*)filename.toLocal8Bit().constData();
-    python->runScript(cfn);
-    //python->appendToSysPath("");
-    //python->runString("import embeddedpyqt");
-}
-
-
-void EmbeddedPyQt::deleteLater() {
-    Q_ASSERT(python);
-    QApplication::instance()->setProperty("embedded_pyqt",
-                                          qVariantFromValue(NULL));
-    delete(python);
-}
-
-
-void EmbeddedPyQt::raiseException(const QString &type, const QString &message) {
-    QApplication::instance()->setProperty("embedded_pyqt_exception_type",
-                                         qVariantFromValue(type));
-    QApplication::instance()->setProperty("embedded_pyqt_exception_msg",
-                                         qVariantFromValue(message));
-    const char *cmsg = message.toLocal8Bit().constData();
-    python->raiseException(cmsg);
-}
-
-
-void EmbeddedPyQt::clearException() {
-    raiseException(NULL, NULL);
-}
-
-void* EmbeddedPyQt::metaObjectByName(const QString &name) {
-    return (void*)classes[name];
-}
-
-QObject* EmbeddedPyQt::objectByName(const QString &name) {
-    return (QObject*)objects[name];
-}
-
-
-QStringList EmbeddedPyQt::availableClasses() {
-    return classes.keys();
-}
-
-
-QStringList EmbeddedPyQt::availableObjects() {
-    return objects.keys();
-}
-
-
-void EmbeddedPyQt::registerMetaObject(const QMetaObject &mo) {
-    classes[mo.className()] = &mo;
-}
-
-
-void EmbeddedPyQt::registerObject(const QObject &obj) {
-    //connect(obj, SIGNAL(destroyed()), unregister_objec);
-    objects[obj.objectName()] = &obj;
-}
-
-
-void EmbeddedPyQt::execute(const QString &command, bool globalContext) {
-    emit executionRequested(command, globalContext);
-}

embpyqt/embeddedpyqt.h

-#ifndef EMBEDDEDPYQT_H
-#define EMBEDDEDPYQT_H
-
-#include <QObject>
-#include <QMetaObject>
-#include <QMap>
-#include <QStringList>
-#include "pythonize.h"
-
-#define RAISE(type, msg) EmbeddedPyQt::instance()->raiseException(type, msg);
-#define REGISTER_CLASS(cls) EmbeddedPyQt::instance()->registerMetaObject(cls::staticMetaObject);
-#define REGISTER_INSTANCE(obj) EmbeddedPyQt::instance()->registerObject(obj);
-
-
-class EmbeddedPyQt : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit EmbeddedPyQt(QObject *parent = 0);
-    void init(const QString &filename);
-    static EmbeddedPyQt *instance();
-signals:
-    void executionRequested(const QString &command, bool globalContext);
-
-public slots:
-    void deleteLater();
-    void raiseException(const QString &type, const QString &message);
-    void clearException();
-    void* metaObjectByName(const QString &name);
-    QObject* objectByName(const QString &name);
-    QStringList availableClasses();
-    QStringList availableObjects();
-    void registerMetaObject(const QMetaObject &mo);
-    void registerObject(const QObject &obj);
-    void execute(const QString &command, bool globalContext);
-
-private:
-    static EmbeddedPyQt *_instance;
-    Pythonize *python;
-    QMap<QString,const QMetaObject*> classes;
-    QMap<QString,const QObject*> objects;
-};
-
-
-#endif // EMBEDDEDPYQT_H

embpyqt/python/embeddedpyqt/__init__.py

-# -*- coding: utf-8 -*-
-import sys
-import os
-import sip
-from PyQt4.QtCore import QMetaObject
-from PyQt4.QtGui import qApp
-
-from embeddedpyqt.miniconsole import Console
-from embeddedpyqt.proxy import class_from_metaobject, wrap_instance
-
-
-global_namespace = {}
-base_namespace = {}
-embpyqt = None
-
-
-def class_by_name(name):
-	ptr = embpyqt.metaObjectByName(name)
-	mo = sip.wrapinstance(int(ptr), QMetaObject)
-	return class_from_metaobject(mo)
-
-
-def execute(command, global_context=False):
-	if global_context:
-		namespace = global_namespace
-	else:
-		namespace = dict(base_namespace)
-	try:
-		exec unicode(command) in namespace
-	except Exception, e:
-		if sys.excepthook != sys.__excepthook__:
-			raise
-		print 
-		print "-"*40
-		print e
-		import traceback
-		traceback.print_exc()
-
-
-def init():
-	global embpyqt
-	embpyqt = wrap_instance(qApp.property("embedded_pyqt").toPyObject())
-	embpyqt.executionRequested.connect(execute)
-		
-	global_namespace.update(
-	  embpyqt=embpyqt,
-	  embpyqt_console=wrap_instance(Console(execute))
-	)
-
-	# add classes to global_namespace
-	for class_name in embpyqt.availableClasses():
-		cls = class_by_name(class_name)
-		global_namespace[str(class_name)] = cls
-
-
-	# add existing instances to global_namespace
-	for obj_name in embpyqt.availableObjects():
-		obj = embpyqt.objectByName(obj_name)
-		global_namespace[str(obj_name)] = obj
-	
-	#base_namespace.update(global_namespace)
-
-		
-	# if the env var DUMP_STUBS is set create a stub file 
-	if os.environ.get("DUMP_STUBS", None):
-		from embeddedpyqt.stubgen import StubCreator
-		stubs = StubCreator()
-		for cls in global_namespace.values():
-			stubs.add_class(cls)
-		target = "/tmp/embpyqtstubs.py"
-		open(target, "w").write(str(stubs))
-		print target, "written"
-
-	# add global_namespace variables to globals
-	for k, v in global_namespace.items():
-		globals()[k] = v
-
-
-init()
-__all__ = global_namespace.keys()

embpyqt/python/embeddedpyqt/miniconsole.py

-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-import sys
-from PyQt4.QtCore import Qt, QRegExp
-from PyQt4.QtGui import (
-   QDialog, QPlainTextEdit, QVBoxLayout, QSplitter, QPushButton, QTextCursor,
-   QSyntaxHighlighter, QTextCharFormat, QColor, QFont)
-
-
-class DefaultColorScheme:
-    syntax_keyword="#808000" # darkYellow
-    syntax_builtin="brown" 
-    syntax_magic="magenta"
-    syntax_self="darkMagenta"
-    syntax_comment="darkGray"
-    syntax_string="darkGreen"
-    syntax_number="darkBlue"
-scheme = DefaultColorScheme
-
-example = """\
-from embeddedpyqt import *
-print 'names in current namespace', dir()
-t = Test()
-print 'members of Test instance', dir(t)
-for i in range(3):
-    print 'Hello, world!', t.calc(i, i)
-embpyqt_console.WindowTitle = 'Done'
-"""
-
-class PythonHighlighter(QSyntaxHighlighter):
-
-    keywords = (
-        "and",       "del",       "for",       "is",        "raise",
-        "assert",    "elif",      "from",      "lambda",    "return",
-        "break",     "else",      "global",    "not",       "try",
-        "class",     "except",    "if",        "or",        "while",
-        "continue",  "exec",      "import",    "pass",      "yield",
-        "def",       "finally",   "in",        "print",     "with"
-        )
-    builtins = ('ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 
-    'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 
-    'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 
-    'LookupError', 'MemoryError', 'NameError', 'None', 
-    'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 
-    'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 
-    'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 
-    'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__debug__', '__doc__', '__import__', '__name__', '__package__', 
-    'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 
-    'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 
-    'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 
-    'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 
-    'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'next', 
-    'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 
-    'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 
-    'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip') 
-    
-
-    def __init__(self, edit):
-        self.textedit = edit
-        document = edit.document()
-        QSyntaxHighlighter.__init__(self, document)
-
-        base_format = QTextCharFormat()
-        base_format.setFont(edit.font())
-        self.base_format = base_format
-        self.document = document
-        
-        self.updateHighlighter(base_format.font())
-
-
-    def highlightBlock(self, text):
-        self.setCurrentBlockState(0)
-        
-        if text.trimmed().isEmpty():
-            self.setFormat(0, len(text), self.empty_format)
-            return
-        
-        self.setFormat(0, len(text), self.base_format)
-        
-        startIndex = 0
-        if self.previousBlockState() != 1:
-            startIndex = self.multiLineStringBegin.indexIn(text)
-        
-        if startIndex > -1:
-            self.highlightRules(text, 0, startIndex)
-        else:
-            self.highlightRules(text, 0, len(text))
-        
-        while startIndex >= 0:
-            endIndex = self.multiLineStringEnd.indexIn(text, 
-                  startIndex + len(self.multiLineStringBegin.pattern()))
-            if endIndex == -1:
-                self.setCurrentBlockState(1)
-                commentLength = text.length() - startIndex
-            else:
-                commentLength = endIndex - startIndex + \
-                                self.multiLineStringEnd.matchedLength()
-                self.highlightRules(text, endIndex, len(text))
-            
-            self.setFormat(startIndex, commentLength, self.multiLineStringFormat)
-            startIndex = self.multiLineStringBegin.indexIn(text, 
-                                           startIndex + commentLength)
-    
-    
-    def highlightRules(self, text, start, finish):
-        for expression, format in self.rules:
-            index = expression.indexIn(text, start)
-            while index >= start and index < finish:
-                length = expression.matchedLength()
-                self.setFormat(index, min(length, finish - index), format)
-                index = expression.indexIn(text, index + length)
-    
-
-    def updateFonts(self, font):    
-        self.base_format.setFont(font)
-        self.empty_format = QTextCharFormat(self.base_format)
-        #self.empty_format.setFontPointSize(font.pointSize()/4.0)
-        
-        self.keywordFormat = QTextCharFormat(self.base_format)
-        self.keywordFormat.setForeground(QColor(scheme.syntax_keyword))
-        self.keywordFormat.setFontWeight(QFont.Bold)
-        self.builtinFormat = QTextCharFormat(self.base_format)
-        self.builtinFormat.setForeground(QColor(scheme.syntax_builtin))
-        self.magicFormat = QTextCharFormat(self.base_format)
-        self.magicFormat.setForeground(QColor(scheme.syntax_magic))
-        #self.qtFormat = QTextCharFormat(self.base_format)
-        #self.qtFormat.setForeground(QColor(scheme.syntax_qt))
-        ##self.qtFormat.setFontWeight(QFont.Bold)
-        self.selfFormat = QTextCharFormat(self.base_format)
-        self.selfFormat.setForeground(QColor(scheme.syntax_self))
-        #self.selfFormat.setFontItalic(True)
-        self.singleLineCommentFormat = QTextCharFormat(self.base_format)
-        self.singleLineCommentFormat.setForeground(QColor(scheme.syntax_comment))
-        self.singleLineCommentFormat.setFontItalic(True)
-        self.multiLineStringFormat = QTextCharFormat(self.base_format)
-        self.multiLineStringFormat.setForeground(QColor(scheme.syntax_string))
-        #self.multiLineStringFormat.setBackground(QBrush(Qt.green))
-        self.quotationFormat1 = QTextCharFormat(self.base_format)
-        self.quotationFormat1.setForeground(QColor(scheme.syntax_string))
-        self.quotationFormat2 = QTextCharFormat(self.base_format)
-        self.quotationFormat2.setForeground(QColor(scheme.syntax_string))
-        self.numFormat = QTextCharFormat(self.base_format)
-        self.numFormat.setForeground(QColor(scheme.syntax_number))
-
-
-    def updateRules(self):
-        self.rules = []
-        self.rules += map(lambda s: (QRegExp(r"\b"+s+r"\b"),
-                          self.keywordFormat), self.keywords)
-        self.rules += map(lambda s: (QRegExp(r"\b"+s+r"\b"),
-                          self.builtinFormat), self.builtins)
-
-        self.rules.append((QRegExp(r"\b__[a-z]+__\b"), self.magicFormat))
-        self.rules.append((QRegExp(r"\bself\b"), self.selfFormat))
-        self.rules.append((QRegExp(r"\b\d+(\.\d*)?\b"), self.numFormat))
-        #self.rules.append((QRegExp(r"\bQ([A-Z][a-z]*)+\b"), self.qtFormat))
-        self.rules.append((QRegExp(r"#[^\n]*"), self.singleLineCommentFormat))
-        self.multiLineStringBegin = QRegExp(r'\"\"\"')
-        self.multiLineStringEnd = QRegExp(r'\"\"\"')
-        self.rules.append((QRegExp(r'\"[^\n]*\"'), self.quotationFormat1))
-        self.rules.append((QRegExp(r"'[^\n]*'"), self.quotationFormat2))
-    
-
-    def updateHighlighter(self, font):    
-        self.updateFonts(font)
-        self.updateRules()
-        self.setDocument(self.document)
-
-
-
-
-class EditorWidget(QPlainTextEdit):
-
-    
-    def __init__(self, parent):
-        super(EditorWidget, self).__init__(parent)
-        self.highlighter = PythonHighlighter(self)
-
-        
-    def keyPressEvent(self, event):
-        key = event.key()
-        if key == Qt.Key_Tab:
-            self.textCursor().insertText(" " * 4)
-            event.accept()
-        elif key in (Qt.Key_Return, Qt.Key_Enter):
-            cursor = self.textCursor()
-            line = unicode(cursor.block().text())
-            indent = (len(line) - len(line.lstrip(" "))) / 4
-            cursor.insertText("\n")
-            if line.endswith(":"):
-                indent += 1
-            elif line.strip().startswith(("return", "pass")):
-                indent = max(indent - 1, 0)
-            cursor.insertText(" " * (indent*4))
-            event.accept()
-        else:
-            return super(EditorWidget, self).keyPressEvent(event)
-
-
-
-class OutputWidget(QPlainTextEdit):
-
-    
-    def __init__(self, parent, autoshow=False):
-        super(OutputWidget, self).__init__(parent)
-        self.autoshow = autoshow
-        self.setReadOnly(True)
-        sys.stdout = self
-        sys.stderr = self
-        self.buf = u""
-        self.startTimer(500)
-
-        
-    def write(self, s):
-        sys.__stdout__.write(s)
-        self.buf += unicode(s)
-
-        
-    def writeline(self, s):
-        self.write(u"%s\n" % s)
-
-        
-    def timerEvent(self, event):
-        self.flush()
-
-        
-    def flush(self):
-        if self.buf:
-            if self.autoshow and not self.window().isVisible():
-                self.window().show()
-            self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
-            self.textCursor().insertText(self.buf)          
-            self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
-            self.ensureCursorVisible()
-            self.buf = ""
-
-
-    
-class Console(QDialog):
-
-
-    def __init__(self, execute_function, example=example, autoshow=False):
-        QDialog.__init__(self)
-        self.execute = execute_function
-        self.vblayout = QVBoxLayout(self)
-        self.splitter = QSplitter(Qt.Vertical, self)
-        self.layout().addWidget(self.splitter)
-        self.edit = EditorWidget(self.splitter)
-        self.edit.setPlainText(example)
-        self.output = OutputWidget(self.splitter, autoshow=autoshow)
-        self.runButton = QPushButton(self, text="&Run")
-        self.runButton.clicked.connect(self.run)
-        self.layout().addWidget(self.runButton)
-        self.edit.setFocus()
-        self.resize(800, 600)
-        
-
-    def run(self):
-        code = unicode(self.edit.toPlainText())
-        self.execute(code)
-    
-        
-
-        
-
-        
-if __name__ == "__main__":
-    import sys
-    from PyQt4.QtGui import QApplication
-    app = QApplication(sys.argv)
-    win = Console()
-    win.show()
-    app.exec_()
-    

embpyqt/python/embeddedpyqt/proxy.py

-# -*- coding: utf-8 -*-
-import sys
-
-from PyQt4.QtCore import QMetaMethod, pyqtSlot, QObject, QVariant, QString, QStringList
-
-
-def wrap_value(value):
-    if isinstance(value, QObject):
-        return wrap_instance(value)
-    elif isinstance(value, QString):
-        return unicode(value)
-    elif isinstance(value, QStringList):
-        return [unicode(v) for v in value]
-    elif isinstance(value, dict):
-        d = {}
-        for k, v in value.items():
-            d[unicode(v)] = wrap_value(v)
-        return d
-    elif isinstance(value, list):
-        return [wrap_value(v) for v in value]
-    else:
-        return value
-
-        
-
-
-
-class QtMethodCall(QObject):
-    
-
-    def __init__(self, obj, methods):
-        QObject.__init__(self)
-        self.obj = obj
-        self.methods = methods
-        
-        
-    def __repr__(self):
-        return "<instance method %r of %r>" % (self.methods.values()[0].name, self.obj)
-
-    
-    def _matching_method_for_signature(self, arg_types):
-        found = None
-        for i, (signature, method) in enumerate(self.methods.items()):
-            found = method
-            break # XXX: add real code here
-        if not found:
-            raise TypeError("No matching methods with given signature found")
-        return found
-
-
-    def __call__(self, *args, **kwargs):
-        if kwargs:
-            raise TypeError("Keyword arguments are not supported currently")
-        new_args = []
-        for a in args:
-            if isinstance(a, PyQtClass):
-                new_args.append(a._qt)
-            else:
-                new_args.append(a)
-        args = new_args
-        arg_types = [type(a) for a in args]
-        method = self._matching_method_for_signature(arg_types)
-        call = getattr(self.obj._qt, method.name)
-        result = call(*args)
-        return wrap_value(result)
-
-
-    @pyqtSlot()
-    def _parameterless_callback(self):
-        return self()
-
-
-
-
-class QtMethod(object):
-
-
-    def __init__(self, meta_method):
-        self._mm = meta_method
-        name, _sep, params = self._mm.signature().partition("(")
-        self.name = name
-        self.signature = params[:-1]
-        self.param_names = self._mm.parameterNames()
-        self.param_types = self._mm.parameterTypes()
-        self.return_type = self._mm.typeName()
-        self.method_type = self._mm.methodType()
-
-    
-    def __repr__(self):
-        return "%s %s(%s)" % (
-              self.return_type or "void", self.name, self.signature)
-
-              
-
-
-class QtMethodSignal(object):
-    
-
-    def __init__(self, obj, signal, signature=None):
-        self.obj = obj
-        self.signal = signal
-        self.signature = signature
-
-        
-    def __repr__(self):
-        return "<Signal %r of %r>" % (self.signal, self.obj)
-
-
-    def connect(self, callback):
-        signal = getattr(self.obj._qt, self.signal.name)
-        if isinstance(callback, QtMethodCall) and not self.signature:
-            # cannot guess empty signature  with __call__(*args,**kwargs)
-            signal.connect(callback._parameterless_callback)
-            return
-    
-        if self.signature:
-            signal[self.signature].connect(callback)
-        else:
-            signal.connect(callback)
-
-
-    def __getitem__(self, *args):
-        return self.__class__(self.obj, self.signal, signature=args)
-
-
-
-
-class QtMethodDispatcher(object):
-    
-
-    def __init__(self, name, methods):
-        self.name = name
-        self.methods = methods
-
-        
-    def __call__(self, *args, **kwargs):
-        raise TypeError("%r is not a static or class method" % self.name)
-
-        
-    def __repr__(self):
-        return "<QtMethod %r>" % self.name
-
-
-    def __get__(self, obj, cls):
-        if obj is None:
-            return self
-        signal = None
-        for method in self.methods.values():
-            if method.method_type == QMetaMethod.Signal:
-                signal = QtMethodSignal(obj, method)
-                break
-        # calls to the same method will be cached inside the object
-        if signal:
-            setattr(obj, self.name, signal)
-            return signal
-        else:
-            call = QtMethodCall(obj, self.methods)
-            setattr(obj, self.name, call)
-            return call
-
-
-
-
-class QtProperty(object):
-
-
-    def __init__(self, meta_property):
-        self._mp = meta_property
-        name = self._mp.name()
-        self.qt_name = name
-        self.name = name[0].upper() + name[1:]
-        self.type = self._mp.typeName()
-
-        
-    def __get__(self, obj, cls):
-        if obj is None:
-            return self
-        if isinstance(obj, PyQtClass):
-            obj = obj._qt
-        value = self._mp.read(obj)
-        return wrap_value(value)
-
-    
-    def __set__(self, obj, value):
-        if obj is None:
-            return
-        if isinstance(obj, PyQtClass):
-            obj = obj._qt
-        if isinstance(value, PyQtClass):
-            value = value._qt
-        self._mp.write(obj, value)
-
-
-
-
-class PyQtClass(object):
-    
-
-    def __init__(self, *args, **kwargs):
-        instance = kwargs.pop("_wrap_instance", None)
-        if not instance:
-            mo = self.__class__.__dict__["_metaobject"]
-            instance = mo.newInstance(*args)
-        elif args:
-            raise TypeError("Could not handle args %r for %s" % (args, self))
-        self._qt = instance
-        if kwargs:
-            for name, value in kwargs.items():
-                self.__set__(self, self.__class__, value)
-
-        
-    def __del__(self):
-        pass #print self, "deleted"
-
-
-    def __repr__(self):
-        mo = self.__class__.__dict__["_metaobject"]
-        return "<%s object %r>" % (mo.className(), unicode(self._qt.objectName()))
-
-    
-    def __iter__(self):
-        for child in self._qt.children():
-            yield wrap_instance(child)
-
-
-    def __getattr__(self, name):
-        # dynamic properties cannot be wrapped with QtProperty descriptors
-        pnames = [unicode(n) for n in self._qt.dynamicPropertyNames()]
-        qname = name[0].lower() + name[1:]
-        if qname in pnames:
-            value = self._qt.property(qname).toPyObject()
-            return wrap_value(value)
-
-        # access child objects as attribute
-        for child in self._qt.children():
-            if child.objectName() == name:
-                return wrap_instance(child)
-        # unknown
-        raise AttributeError("%s has not attribute %r" % (self, name))
-
-
-    def __setitem__(self, name, value):
-        # set dynamic property
-        if isinstance(value, PyQtClass):
-            value = value._qt
-        self._qt.setProperty(name, QVariant(value))
-
-
-def create_proxy_class(meta_object, bases=(PyQtClass,), attrs=None):
-    mo = meta_object
-    properties = {}
-    for pi in range(mo.propertyCount()):
-        meta_property = mo.property(pi)
-        p = QtProperty(meta_property)
-        properties[p.name] = p
-    methods = {}
-    for mi in range(mo.methodCount()):
-        meta_method = mo.method(mi)
-        m = QtMethod(meta_method)
-        methods.setdefault(m.name, {})[m.signature] = m
-    if attrs is None:
-        attrs = {}
-    for k, v in properties.items():
-        attrs[k] = v
-    attrs["_properties"] = properties
-    for k, v in methods.items():
-        attrs[k] = QtMethodDispatcher(k, v)
-    attrs["_methods"] = methods
-    attrs["_metaobject"] = meta_object
-    class_name = mo.className()
-    return type(class_name, bases, attrs)
-
-
-
-# cache classes
-_qt_classes = {}
-
-
-def class_from_metaobject(meta_object):
-    class_name = meta_object.className()
-    cls = _qt_classes.get(class_name, None)
-    if not cls:
-        cls = create_proxy_class(meta_object)
-        _qt_classes[class_name] = cls
-    return cls
-
-
-def wrap_instance(instance):
-    cls = class_from_metaobject(instance.metaObject())
-    return cls(_wrap_instance=instance)
-
-
-
-
-if __name__ == "__main__":
-    from PyQt4.QtCore import QObject
-    from PyQt4.QtGui import QApplication, QPushButton
-    _a = QApplication(sys.argv)
-    a = wrap_instance(_a)
-    
-    def on_click():
-        print "clicked!"
-        ap.quit()
-
-
-    _b = QPushButton(None)
-    b = wrap_instance(_b)
-    b.Text = "Click to close!"
-    b.clicked.connect(on_click)
-    
-    cls = class_from_metaobject(QObject.staticMetaObject)
-    print cls
-    t = cls()
-    t.ObjectName = "foo bar"
-    print t

embpyqt/python/embeddedpyqt/stubgen.py

-# -*- coding: utf-8 -*-
-import keyword
-from PyQt4.QtCore import QMetaMethod, QObject
-from embeddedpyqt.proxy import class_from_metaobject
-
-
-
-
-class CodeGenerator(object):
-	
-	
-	def __init__(self):
-		self.output = []
-		self.level = 0
-
-	
-	def indent(self, count=1):
-		self.level += count
-	
-		
-	def dedent(self, count=1):
-		self.level -= count
-	
-	
-	def begin(self, code=""):
-		if code:
-			self.emit(code)
-		self.indent()
-
-	
-	def end(self):
-		if self.output and self.output[-1] and self.output[-1][-1] == ":":
-			self.emit("pass")
-		self.dedent()
-
-
-	def emit(self, code):
-		indention = "  " * self.level
-		self.output.append(indention + code)
-
-
-	def prepend_header(self, code):
-		if code not in self.output:
-			self.output.insert(0, code)
-
-		
-	def newline(self, count=1):
-		self.output.extend([""]*count)
-
-
-	def __str__(self):
-		return "\n".join(["# coding: utf-8 -*-", "# created stub"] + self.output)
-	
-
-
-class StubCreator(object):
-
-	
-	def __init__(self):
-		self.codegen = CodeGenerator()
-		self.codegen.newline()
-
-	def add_class(self, cls):
-		if isinstance(cls, QObject):
-			pcls = class_from_metaobject(cls.staticMetaObject)
-		else:
-			pcls = cls
-		self.codegen.newline()
-		self.codegen.begin("class %s(object):" % pcls._metaobject.className())
-		self.codegen.newline()
-		qt_types = set()
-		# -- methods --
-		for method_name, methods in pcls._methods.items():
-			if method_name.startswith("_") or method_name in ("deleteLater",):
-				continue # skip private methods
-			for signature, method in methods.items():
-				param_names = map(unicode, method.param_names)
-				param_types = map(unicode, method.param_types)
-				for i, (pn, pt) in enumerate(zip(param_names, param_types)):
-					pt = self.fix_type(pt)
-					if pt.startswith("Q"):
-						qt_types.add(pt)
-					param_types[i] = pt
-					if not pn:
-						pn = "%s_%s" % (pt, i)
-						param_names[i] = pn
-				args = ["self"] + param_names
-				signature = ", ".join(args)
-				if method.method_type == QMetaMethod.Signal:
-					self.codegen.emit("%s = pyqtSignal(%s)" % (method_name, ", ".join(param_types)))
-				else:
-					self.codegen.begin("def %s(%s):" % (self.fix_name(method_name), signature))
-					for pname, ptype in zip(param_names, param_types):
-						self.codegen.emit("assert isinstance(%s, %s)" % (pname, ptype))
-					
-					rtype = unicode(method.return_type)
-					if rtype not in ("void", ""):
-						rtype = self.fix_type(rtype)
-						if rtype.startswith("Q"):
-							qt_types.add(rtype)
-						self.codegen.emit("return %s()" % rtype)
-					self.codegen.end()
-				self.codegen.newline()
-				break
-		# -- properties --
-		for property_name, prop in pcls._properties.items():
-			if property_name in ("destroyed",):
-				continue
-			ptype = self.fix_type(prop.type)
-			if ptype.startswith("Q"):
-				qt_types.add(ptype)
-
-			getter = pcls._methods.get(prop.qt_name, None)
-			setter = pcls._methods.get("set%s" % property_name, None)
-			if getter and setter:
-				self.codegen.emit("%s = property(fget=%s, fset=set%s)" % (property_name, prop.qt_name, property_name))
-			elif getter:
-				self.codegen.emit("%s = property(fget=%s)" % (property_name, prop.qt_name))
-			elif setter:
-				self.codegen.emit("%s = property(fset=set%s)" % (property_name, property_name))
-			else:
-				self.codegen.emit("%s = property()" % property_name)
-
-		self.codegen.newline()
-		self.codegen.begin("def __assert_property_types(self):")
-		self.codegen.emit("# gives source code analyzers hints about assumed type of property")
-		for property_name, prop in pcls._properties.items():
-			if property_name in ("destroyed",):
-				continue
-			ptype = self.fix_type(prop.type)
-			self.codegen.emit("assert isinstance(self.%s, %s)" % (property_name, ptype))
-		self.codegen.end()
-		self.codegen.end()
-		self.codegen.newline()
-		self.codegen.newline()
-		
-		# -- imports ---
-		import PyQt4.QtCore, PyQt4.QtGui
-		qt_modules = (PyQt4.QtCore, PyQt4.QtGui)
-		self.codegen.prepend_header("from PyQt4.QtCore import Qt, pyqtSignal")
-		for qtt in qt_types:
-			for mod in qt_modules:
-				if hasattr(mod, qtt):
-					self.codegen.prepend_header("from %s import %s" % (mod.__name__, qtt))
-					break
-		
-		
-	def fix_name(self, n):
-		if keyword.iskeyword(n):
-			return "%s_" % n
-		else:
-			return n
-
-		
-	def fix_type(self, t):
-		t = t.replace("&", "").replace("*", "").replace("::", ".")
-		if t == "QString":
-			t = "unicode"
-		return t
-
-	
-	def __str__(self):
-		return str(self.codegen)
-
-
-	
-if __name__ == "__main__":
-	from PyQt4.QtGui import QApplication, QPushButton
-	stubs = StubCreator()
-	stubs.add_class(QApplication)
-	stubs.add_class(QPushButton)
-	print stubs

embpyqt/python/initembpyqt.py

-# -*- coding: utf-8 -*-
-import sys, os
-
-path = os.path.dirname(os.path.abspath(__file__))
-if path not in sys.path:
-	sys.path.insert(0, path)
-
-import embeddedpyqt

embpyqt/pythonize.cpp

-/* copyright 2003 Jim Bublitz <jbublitz@nwinternet.com>
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public
-   License as published by the Free Software Foundation; either
-   version 2 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public License
-   along with this library; see the file COPYING.LIB.  If not, write to
-   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.
-*/
-
-#include <stdarg.h>
-#include <string.h>
-
-// this just gets rid of a warning when Python.h redefines it
-#undef _POSIX_C_SOURCE
-
-#include "pythonize.h"
-
-#define debug 0
-
-ObjectRef::ObjectRef (ObjectRef *oi, PyObject *o)
-{
-    prevObject = oi;
-    object     = o;
-}
-
-
-Pythonize::Pythonize ()
-{
-    pythonInit  = 1;
-    objects    = NULL;
-
-    if (debug) printf ("\n\nPythonize constructor -- pid = %i\n", getpid ());
-
-    if (!Py_IsInitialized ())
-    {
-        PyEval_InitThreads ();
-        Py_Initialize ();
-        if (!Py_IsInitialized ())
-        {
-            pythonInit = 0;
-            return;
-        }
-
-        if (debug) printf ("Python interpreter initialized!\n\n");
-
-        // free the lock
-        PyEval_ReleaseLock();
-    }
-}
-
-bool Pythonize::runScript (const char *scriptPath)
-{
-    FILE *f;
-    int res;
-
-    if (debug) printf ("Running script: %s\n", scriptPath);
-
-    if (scriptPath == NULL || strlen (scriptPath) == 0) return false;
-
-    f = fopen (scriptPath, "r");
-    if (f == NULL) return false;
-
-    res = PyRun_SimpleFile (f, scriptPath);
-
-    fclose (f);
-    return res == 0;
-}
-
-
-PyObject * Pythonize::runFunction (PyObject *object, PyObject *args)
-{
-
-    if (!PyCallable_Check (object))
-        return NULL;
-
-    PyObject *res = PyObject_CallObject (object, args ? args : PyTuple_New (0));
-    Py_XINCREF (res);
-
-    return res;
-}
-
-void * Pythonize::runFunctionVoid (PyObject *object, PyObject *args)
-{
-
-    if (!PyCallable_Check (object))
-        return NULL;
-
-    PyObject *pyRes = PyObject_CallObject (object, args ? args : PyTuple_New (0));
-    void *res = PyLong_AsVoidPtr (pyRes);
-
-    return res;
-}
-
-bool Pythonize::runString (const char *str)
-{
-
-    if (str == NULL || strlen (str) == 0) return false;
-
-    int res = PyRun_SimpleString (str);
-
-    return res == 0;
-}
-
-bool Pythonize::appendToSysPath (const char* newPath)
-{
-    if (newPath == NULL || strlen (newPath) == 0) return false;
-
-    char *fmtString = "import sys\nif not '%s' in sys.path:\n\tsys.path.append ('%s')\n"; //print sys.path\n";
-    int length      = strlen (fmtString) + 2*strlen (newPath) + 1;
-    char *line      =  new char [length];
-    if (!line) return false;
-    snprintf (line, length, fmtString, newPath, newPath);
-
-    int res = PyRun_SimpleString (line);
-
-    delete line;
-    return res == 0;
-}
-
-PyObject *Pythonize::importModule (const char *moduleName)
-{
-    if (moduleName == NULL || strlen (moduleName) == 0) return NULL;
-
-    PyObject *module = PyImport_ImportModule (moduleName);
-
-    objects = new ObjectRef (objects, module);
-    if (!objects) return NULL;
-
-    return module;
-}
-
-void Pythonize::raiseException(const char *msg) {
-    PyErr_SetString(PyExc_RuntimeError, msg);
-}
-
-Pythonize::~Pythonize ()
-{
-
-    if (debug) printf ("Pythonize destructor\n");
-    ObjectRef *top;
-
-    while (objects)
-    {
-        top = objects;
-        objects = objects->prevObject;
-        delete top;
-    }
-    if (debug) printf (" --- Objects destroyed\n");
-
-    Py_Finalize();
-
-    if (debug) printf (" --- Py_Finalized\n");
-}
-

embpyqt/pythonize.h

-/* copyright 2003 Jim Bublitz <jbublitz@nwinternet.com>
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public License
-   along with this library; see the file COPYING.LIB.  If not, write to
-   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.
-*/
-
-#ifndef __pythonize_h__
-#define __pythonize_h__
-
-// Pythonize is a general purpose library that wraps the Python
-// interpreter with an interface to a set of common operations
-// used when embedding the interpreter.
-
-#include <Python.h>
-
-struct ObjectRef
-{
-    ObjectRef (ObjectRef *oi, PyObject *o);
-    ~ObjectRef () {
-        Py_XDECREF (object);
-    }
-
-    PyObject        *object;        // pointer to an object we created
-    ObjectRef       *prevObject;    // pointer to next object on the stack
-};
-
-class Pythonize
-{
-public:
-    Pythonize ();
-    ~Pythonize ();
-
-    // adds a path to sys.path
-    bool appendToSysPath (const char* newPath);
-
-    // imports a module into the interpreter
-    // or gets a PyObject for an already loaded module
-    PyObject *importModule (const char *moduleName);
-
-    void raiseException(const char *msg);
-    // returns an object from a loaded module
-    // you must decref the object returned when done with it (new reference returned)
-    PyObject *getNewObjectRef (PyObject *module, char *object) {
-        return PyObject_GetAttrString (module, object);
-    }
-
-    int getPythonInit () {
-        return pythonInit;
-    }
-
-    // decrements the ref count of an object
-    void decref (PyObject *object) {
-        Py_XDECREF (object);
-    }
-
-    // runs a script on the current sys.path
-    bool runScript (const char *scriptPath);
-
-    // executes a string of Python in the interpreter
-    bool runString (const char *str);
-
-    // runs a callable Python object
-    PyObject *runFunction(PyObject *object, PyObject *args);
-    void *runFunctionVoid(PyObject *object, PyObject *args);
-
-private:
-    int pythonInit;         // status of Py_Initialize
-    ObjectRef *objects;     // a stack of PyObjects (used in destructor)
-};
-
-
-#endif

main.cpp

-#include <QtGui/QApplication>
-#include "mainwindow.h"
-
-
-int main(int argc, char *argv[])
-{
-    QApplication a(argc, argv);
-    MainWindow w;
-    w.show();
-    return a.exec();
-}
-

mainwindow.cpp

-#include "mainwindow.h"
-#include "ui_mainwindow.h"
-#include <QObject>
-#include "test.h"
-
-MainWindow::MainWindow(QWidget *parent) :
-    QMainWindow(parent),
-    ui(new Ui::MainWindow)
-{
-    ui->setupUi(this);
-    setObjectName("mainWindow");
-
-    embpyqt = new EmbeddedPyQt();
-    embpyqt->registerMetaObject(Test::staticMetaObject);
-    embpyqt->init("embpyqt/python/initembpyqt.py");
-}
-
-MainWindow::~MainWindow()
-{
-    delete ui;
-}
-
-void MainWindow::on_actionExit_triggered()
-{
-    close();
-}
-
-void MainWindow::on_actionConsole_triggered()
-{
-    embpyqt->execute("embpyqt_console.Visible = True", true);
-}

mainwindow.h

-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include <QMainWindow>
-#include "embpyqt/embeddedpyqt.h"
-
-namespace Ui {
-    class MainWindow;
-}
-
-class MainWindow : public QMainWindow
-{
-    Q_OBJECT
-
-public:
-    explicit MainWindow(QWidget *parent = 0);
-    ~MainWindow();
-    EmbeddedPyQt *embpyqt;
-
-private slots:
-    void on_actionExit_triggered();
-
-    void on_actionConsole_triggered();
-
-private:
-    Ui::MainWindow *ui;
-};
-
-#endif // MAINWINDOW_H

mainwindow.ui

-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>396</width>
-    <height>296</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>MainWindow</string>
-  </property>
-  <widget class="QWidget" name="centralWidget"/>
-  <widget class="QMenuBar" name="menuBar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>396</width>
-     <height>24</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menu_File">
-    <property name="title">
-     <string>&amp;File</string>
-    </property>
-    <addaction name="actionConsole"/>
-    <addaction name="separator"/>
-    <addaction name="actionExit"/>
-   </widget>
-   <addaction name="menu_File"/>
-  </widget>
-  <widget class="QToolBar" name="mainToolBar">
-   <attribute name="toolBarArea">
-    <enum>TopToolBarArea</enum>
-   </attribute>
-   <attribute name="toolBarBreak">
-    <bool>false</bool>
-   </attribute>
-  </widget>
-  <widget class="QStatusBar" name="statusBar"/>
-  <action name="actionExit">
-   <property name="text">
-    <string>&amp;Exit</string>
-   </property>
-   <property name="shortcut">
-    <string>Ctrl+Q</string>
-   </property>
-  </action>
-  <action name="actionConsole">
-   <property name="text">
-    <string>Show scripting &amp;console</string>
-   </property>
-   <property name="shortcut">
-    <string>Ctrl+S</string>
-   </property>
-  </action>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <resources/>
- <connections/>
-</ui>
+#!/bin/sh
+qmake
+make
+./embeddedpyqt

src/embeddedpyqt.pro

+#-------------------------------------------------
+#
+# Project created by QtCreator 2011-08-03T07:09:48
+#
+#-------------------------------------------------
+
+QT       += core gui
+
+TARGET = embeddedpyqt
+TEMPLATE = app
+
+SOURCES += main.cpp\
+        mainwindow.cpp \
+    test.cpp
+HEADERS  += mainwindow.h \
+    test.h
+FORMS    += mainwindow.ui
+
+
+# -- Generic Python support --------------------------------------
+INCLUDEPATH += -I./embpyqt
+LIBS        += -lpython2.7 -L/usr/lib/
+INCLUDEPATH += /usr/include/python2.7/
+
+# -- Add embpyqt -------------------------------------------------
+SOURCES += \
+    embpyqt/embeddedpyqt.cpp \
+    embpyqt/pythonize.cpp
+HEADERS += \
+    embpyqt/embeddedpyqt.h \
+    embpyqt/pythonize.h

src/embpyqt/embeddedpyqt.cpp

+#include "embeddedpyqt.h"
+#include "pythonize.h"
+#include <QApplication>
+#include <QVariant>
+#include <QPushButton>
+#include <qdebug.h>
+
+
+EmbeddedPyQt *EmbeddedPyQt::_instance = 0;
+
+
+EmbeddedPyQt::EmbeddedPyQt(QObject *parent) :
+    QObject(parent)
+{
+    EmbeddedPyQt::_instance = this;
+    setObjectName("embeddedPyQt");
+    QApplication::instance()->setProperty("embedded_pyqt",
+                                          qVariantFromValue((QObject*)this));
+    python = new Pythonize();
+    Q_ASSERT(python);
+}
+
+
+void EmbeddedPyQt::init(const QString &filename) {
+    char *cfn = (char*)filename.toLocal8Bit().constData();
+    python->runScript(cfn);
+    //python->appendToSysPath("");
+    //python->runString("import embeddedpyqt");
+}
+
+
+void EmbeddedPyQt::deleteLater() {
+    Q_ASSERT(python);
+    QApplication::instance()->setProperty("embedded_pyqt",
+                                          qVariantFromValue(NULL));
+    delete(python);
+}
+
+
+void EmbeddedPyQt::raiseException(const QString &type, const QString &message) {
+    QApplication::instance()->setProperty("embedded_pyqt_exception_type",
+                                         qVariantFromValue(type));
+    QApplication::instance()->setProperty("embedded_pyqt_exception_msg",
+                                         qVariantFromValue(message));
+    const char *cmsg = message.toLocal8Bit().constData();
+    python->raiseException(cmsg);
+}
+
+
+void EmbeddedPyQt::clearException() {
+    raiseException(NULL, NULL);
+}
+
+void* EmbeddedPyQt::metaObjectByName(const QString &name) {
+    return (void*)classes[name];
+}
+
+QObject* EmbeddedPyQt::objectByName(const QString &name) {
+    return (QObject*)objects[name];
+}
+
+
+QStringList EmbeddedPyQt::availableClasses() {
+    return classes.keys();
+}
+
+
+QStringList EmbeddedPyQt::availableObjects() {
+    return objects.keys();
+}
+
+
+void EmbeddedPyQt::registerMetaObject(const QMetaObject &mo) {
+    classes[mo.className()] = &mo;
+}
+
+
+void EmbeddedPyQt::registerObject(const QObject &obj) {
+    //connect(obj, SIGNAL(destroyed()), unregister_objec);
+    objects[obj.objectName()] = &obj;
+}
+
+
+void EmbeddedPyQt::execute(const QString &command, bool globalContext) {
+    emit executionRequested(command, globalContext);
+}

src/embpyqt/embeddedpyqt.h

+#ifndef EMBEDDEDPYQT_H
+#define EMBEDDEDPYQT_H
+
+#include <QObject>
+#include <QMetaObject>
+#include <QMap>
+#include <QStringList>
+#include "pythonize.h"
+
+#define RAISE(type, msg) EmbeddedPyQt::instance()->raiseException(type, msg);
+#define REGISTER_CLASS(cls) EmbeddedPyQt::instance()->registerMetaObject(cls::staticMetaObject);
+#define REGISTER_INSTANCE(obj) EmbeddedPyQt::instance()->registerObject(obj);
+
+
+class EmbeddedPyQt : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit EmbeddedPyQt(QObject *parent = 0);
+    void init(const QString &filename);
+    static EmbeddedPyQt *instance();
+signals:
+    void executionRequested(const QString &command, bool globalContext);
+
+public slots:
+    void deleteLater();
+    void raiseException(const QString &type, const QString &message);
+    void clearException();
+    void* metaObjectByName(const QString &name);
+    QObject* objectByName(const QString &name);
+    QStringList availableClasses();
+    QStringList availableObjects();
+    void registerMetaObject(const QMetaObject &mo);
+    void registerObject(const QObject &obj);
+    void execute(const QString &command, bool globalContext);
+
+private:
+    static EmbeddedPyQt *_instance;
+    Pythonize *python;
+    QMap<QString,const QMetaObject*> classes;
+    QMap<QString,const QObject*> objects;
+};
+
+
+#endif // EMBEDDEDPYQT_H

src/embpyqt/python/embeddedpyqt/__init__.py

+# -*- coding: utf-8 -*-
+import sys
+import os
+import sip
+from PyQt4.QtCore import QMetaObject
+from PyQt4.QtGui import qApp
+
+from embeddedpyqt.miniconsole import Console
+from embeddedpyqt.proxy import class_from_metaobject, wrap_instance
+
+
+global_namespace = {}
+base_namespace = {}
+embpyqt = None
+
+
+def class_by_name(name):
+	ptr = embpyqt.metaObjectByName(name)
+	mo = sip.wrapinstance(int(ptr), QMetaObject)
+	return class_from_metaobject(mo)
+
+
+def execute(command, global_context=False):
+	if global_context:
+		namespace = global_namespace
+	else:
+		namespace = dict(base_namespace)
+	try:
+		exec unicode(command) in namespace
+	except Exception, e:
+		if sys.excepthook != sys.__excepthook__:
+			raise
+		print 
+		print "-"*40
+		print e
+		import traceback
+		traceback.print_exc()
+
+
+def init():
+	global embpyqt
+	embpyqt = wrap_instance(qApp.property("embedded_pyqt").toPyObject())
+	embpyqt.executionRequested.connect(execute)
+		
+	global_namespace.update(
+	  embpyqt=embpyqt,
+	  embpyqt_console=wrap_instance(Console(execute))
+	)
+
+	# add classes to global_namespace
+	for class_name in embpyqt.availableClasses():
+		cls = class_by_name(class_name)
+		global_namespace[str(class_name)] = cls
+
+
+	# add existing instances to global_namespace
+	for obj_name in embpyqt.availableObjects():
+		obj = embpyqt.objectByName(obj_name)
+		global_namespace[str(obj_name)] = obj
+	
+	#base_namespace.update(global_namespace)
+
+		
+	# if the env var DUMP_STUBS is set create a stub file 
+	if os.environ.get("DUMP_STUBS", None):
+		from embeddedpyqt.stubgen import StubCreator
+		stubs = StubCreator()
+		for cls in global_namespace.values():
+			stubs.add_class(cls)
+		target = "/tmp/embpyqtstubs.py"
+		open(target, "w").write(str(stubs))
+		print target, "written"
+
+	# add global_namespace variables to globals
+	for k, v in global_namespace.items():
+		globals()[k] = v
+
+
+init()
+__all__ = global_namespace.keys()

src/embpyqt/python/embeddedpyqt/miniconsole.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import sys
+from PyQt4.QtCore import Qt, QRegExp
+from PyQt4.QtGui import (
+   QDialog, QPlainTextEdit, QVBoxLayout, QSplitter, QPushButton, QTextCursor,
+   QSyntaxHighlighter, QTextCharFormat, QColor, QFont)
+
+
+class DefaultColorScheme:
+    syntax_keyword="#808000" # darkYellow
+    syntax_builtin="brown" 
+    syntax_magic="magenta"
+    syntax_self="darkMagenta"
+    syntax_comment="darkGray"
+    syntax_string="darkGreen"
+    syntax_number="darkBlue"
+scheme = DefaultColorScheme
+
+example = """\
+from embeddedpyqt import *
+print 'names in current namespace', dir()
+t = Test()
+print 'members of Test instance', dir(t)
+for i in range(3):
+    print 'Hello, world!', t.calc(i, i)
+embpyqt_console.WindowTitle = 'Done'
+"""
+
+class PythonHighlighter(QSyntaxHighlighter):
+
+    keywords = (
+        "and",       "del",       "for",       "is",        "raise",
+        "assert",    "elif",      "from",      "lambda",    "return",
+        "break",     "else",      "global",    "not",       "try",
+        "class",     "except",    "if",        "or",        "while",
+        "continue",  "exec",      "import",    "pass",      "yield",
+        "def",       "finally",   "in",        "print",     "with"
+        )
+    builtins = ('ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 
+    'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 
+    'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 
+    'LookupError', 'MemoryError', 'NameError', 'None', 
+    'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 
+    'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 
+    'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 
+    'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__debug__', '__doc__', '__import__', '__name__', '__package__', 
+    'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 
+    'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 
+    'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 
+    'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 
+    'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'next', 
+    'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 
+    'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 
+    'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip') 
+    
+
+    def __init__(self, edit):
+        self.textedit = edit
+        document = edit.document()
+        QSyntaxHighlighter.__init__(self, document)
+
+        base_format = QTextCharFormat()
+        base_format.setFont(edit.font())
+        self.base_format = base_format
+        self.document = document
+        
+        self.updateHighlighter(base_format.font())
+
+
+    def highlightBlock(self, text):
+        self.setCurrentBlockState(0)
+        
+        if text.trimmed().isEmpty():
+            self.setFormat(0, len(text), self.empty_format)
+            return
+        
+        self.setFormat(0, len(text), self.base_format)
+        
+        startIndex = 0
+        if self.previousBlockState() != 1:
+            startIndex = self.multiLineStringBegin.indexIn(text)
+        
+        if startIndex > -1:
+            self.highlightRules(text, 0, startIndex)
+        else:
+            self.highlightRules(text, 0, len(text))
+        
+        while startIndex >= 0:
+            endIndex = self.multiLineStringEnd.indexIn(text, 
+                  startIndex + len(self.multiLineStringBegin.pattern()))
+            if endIndex == -1:
+                self.setCurrentBlockState(1)
+                commentLength = text.length() - startIndex
+            else:
+                commentLength = endIndex - startIndex + \
+                                self.multiLineStringEnd.matchedLength()
+                self.highlightRules(text, endIndex, len(text))
+            
+            self.setFormat(startIndex, commentLength, self.multiLineStringFormat)
+            startIndex = self.multiLineStringBegin.indexIn(text, 
+                                           startIndex + commentLength)
+    
+    
+    def highlightRules(self, text, start, finish):
+        for expression, format in self.rules:
+            index = expression.indexIn(text, start)
+            while index >= start and index < finish:
+                length = expression.matchedLength()
+                self.setFormat(index, min(length, finish - index), format)
+                index = expression.indexIn(text, index + length)
+    
+
+    def updateFonts(self, font):    
+        self.base_format.setFont(font)
+        self.empty_format = QTextCharFormat(self.base_format)
+        #self.empty_format.setFontPointSize(font.pointSize()/4.0)
+        
+        self.keywordFormat = QTextCharFormat(self.base_format)
+        self.keywordFormat.setForeground(QColor(scheme.syntax_keyword))
+        self.keywordFormat.setFontWeight(QFont.Bold)
+        self.builtinFormat = QTextCharFormat(self.base_format)
+        self.builtinFormat.setForeground(QColor(scheme.syntax_builtin))
+        self.magicFormat = QTextCharFormat(self.base_format)
+        self.magicFormat.setForeground(QColor(scheme.syntax_magic))
+        #self.qtFormat = QTextCharFormat(self.base_format)
+        #self.qtFormat.setForeground(QColor(scheme.syntax_qt))
+        ##self.qtFormat.setFontWeight(QFont.Bold)
+        self.selfFormat = QTextCharFormat(self.base_format)
+        self.selfFormat.setForeground(QColor(scheme.syntax_self))
+        #self.selfFormat.setFontItalic(True)
+        self.singleLineCommentFormat = QTextCharFormat(self.base_format)
+        self.singleLineCommentFormat.setForeground(QColor(scheme.syntax_comment))
+        self.singleLineCommentFormat.setFontItalic(True)
+        self.multiLineStringFormat = QTextCharFormat(self.base_format)
+        self.multiLineStringFormat.setForeground(QColor(scheme.syntax_string))
+        #self.multiLineStringFormat.setBackground(QBrush(Qt.green))
+        self.quotationFormat1 = QTextCharFormat(self.base_format)
+        self.quotationFormat1.setForeground(QColor(scheme.syntax_string))
+        self.quotationFormat2 = QTextCharFormat(self.base_format)
+        self.quotationFormat2.setForeground(QColor(scheme.syntax_string))
+        self.numFormat = QTextCharFormat(self.base_format)
+        self.numFormat.setForeground(QColor(scheme.syntax_number))
+
+
+    def updateRules(self):
+        self.rules = []
+        self.rules += map(lambda s: (QRegExp(r"\b"+s+r"\b"),
+                          self.keywordFormat), self.keywords)
+        self.rules += map(lambda s: (QRegExp(r"\b"+s+r"\b"),
+                          self.builtinFormat), self.builtins)
+
+        self.rules.append((QRegExp(r"\b__[a-z]+__\b"), self.magicFormat))
+        self.rules.append((QRegExp(r"\bself\b"), self.selfFormat))
+        self.rules.append((QRegExp(r"\b\d+(\.\d*)?\b"), self.numFormat))
+        #self.rules.append((QRegExp(r"\bQ([A-Z][a-z]*)+\b"), self.qtFormat))
+        self.rules.append((QRegExp(r"#[^\n]*"), self.singleLineCommentFormat))
+        self.multiLineStringBegin = QRegExp(r'\"\"\"')
+        self.multiLineStringEnd = QRegExp(r'\"\"\"')
+        self.rules.append((QRegExp(r'\"[^\n]*\"'), self.quotationFormat1))
+        self.rules.append((QRegExp(r"'[^\n]*'"), self.quotationFormat2))
+    
+
+    def updateHighlighter(self, font):    
+        self.updateFonts(font)
+        self.updateRules()
+        self.setDocument(self.document)
+
+
+
+
+class EditorWidget(QPlainTextEdit):
+
+    
+    def __init__(self, parent):
+        super(EditorWidget, self).__init__(parent)
+        self.highlighter = PythonHighlighter(self)
+
+        
+    def keyPressEvent(self, event):
+        key = event.key()
+        if key == Qt.Key_Tab:
+            self.textCursor().insertText(" " * 4)
+            event.accept()
+        elif key in (Qt.Key_Return, Qt.Key_Enter):
+            cursor = self.textCursor()
+            line = unicode(cursor.block().text())
+            indent = (len(line) - len(line.lstrip(" "))) / 4
+            cursor.insertText("\n")
+            if line.endswith(":"):
+                indent += 1
+            elif line.strip().startswith(("return", "pass")):
+                indent = max(indent - 1, 0)
+            cursor.insertText(" " * (indent*4))
+            event.accept()
+        else:
+            return super(EditorWidget, self).keyPressEvent(event)
+
+
+
+class OutputWidget(QPlainTextEdit):
+
+    
+    def __init__(self, parent, autoshow=False):
+        super(OutputWidget, self).__init__(parent)
+        self.autoshow = autoshow
+        self.setReadOnly(True)
+        sys.stdout = self
+        sys.stderr = self
+        self.buf = u""
+        self.startTimer(500)
+
+        
+    def write(self, s):
+        sys.__stdout__.write(s)
+        self.buf += unicode(s)
+
+        
+    def writeline(self, s):
+        self.write(u"%s\n" % s)
+
+        
+    def timerEvent(self, event):
+        self.flush()
+
+        
+    def flush(self):
+        if self.buf:
+            if self.autoshow and not self.window().isVisible():
+                self.window().show()
+            self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
+            self.textCursor().insertText(self.buf)          
+            self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
+            self.ensureCursorVisible()
+            self.buf = ""
+
+
+    
+class Console(QDialog):
+
+
+    def __init__(self, execute_function, example=example, autoshow=False):
+        QDialog.__init__(self)
+        self.execute = execute_function
+        self.vblayout = QVBoxLayout(self)
+        self.splitter = QSplitter(Qt.Vertical, self)
+        self.layout().addWidget(self.splitter)
+        self.edit = EditorWidget(self.splitter)
+        self.edit.setPlainText(example)
+        self.output = OutputWidget(self.splitter, autoshow=autoshow)
+        self.runButton = QPushButton(self, text="&Run")
+        self.runButton.clicked.connect(self.run)
+        self.layout().addWidget(self.runButton)
+        self.edit.setFocus()
+        self.resize(800, 600)
+        
+
+    def run(self):
+        code = unicode(self.edit.toPlainText())
+        self.execute(code)
+    
+        
+
+        
+
+        
+if __name__ == "__main__":
+    import sys
+    from PyQt4.QtGui import QApplication
+    app = QApplication(sys.argv)
+    win = Console()
+    win.show()
+    app.exec_()
+    

src/embpyqt/python/embeddedpyqt/proxy.py

+# -*- coding: utf-8 -*-
+import sys
+
+from PyQt4.QtCore import QMetaMethod, pyqtSlot, QObject, QVariant, QString, QStringList
+
+
+def wrap_value(value):
+    if isinstance(value, QObject):
+        return wrap_instance(value)
+    elif isinstance(value, QString):
+        return unicode(value)
+    elif isinstance(value, QStringList):
+        return [unicode(v) for v in value]
+    elif isinstance(value, dict):
+        d = {}
+        for k, v in value.items():
+            d[unicode(v)] = wrap_value(v)
+        return d
+    elif isinstance(value, list):
+        return [wrap_value(v) for v in value]
+    else:
+        return value
+
+        
+
+
+
+class QtMethodCall(QObject):
+    
+
+    def __init__(self, obj, methods):
+        QObject.__init__(self)
+        self.obj = obj
+        self.methods = methods
+        
+        
+    def __repr__(self):
+        return "<instance method %r of %r>" % (self.methods.values()[0].name, self.obj)
+