#! /usr/bin/env python import getopt import keyword import os import string import sys import argtypes import definitions import defsparser import override import reversewrapper import warnings class Coverage(object): def __init__(self, name): self.name = name self.wrapped = 0 self.not_wrapped = 0 def declare_wrapped(self): self.wrapped += 1 def declare_not_wrapped(self): self.not_wrapped += 1 def printstats(self): total = self.wrapped + self.not_wrapped fd = sys.stderr if total: fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" % (self.name, float(self.wrapped*100)/total, self.wrapped, total)) else: fd.write("***INFO*** There are no declared %s.\n" % self.name) functions_coverage = Coverage("global functions") methods_coverage = Coverage("methods") vproxies_coverage = Coverage("virtual proxies") vaccessors_coverage = Coverage("virtual accessors") iproxies_coverage = Coverage("interface proxies") def exc_info(): warnings.warn("deprecated", DeprecationWarning, stacklevel=2) #traceback.print_exc() etype, value, tb = sys.exc_info() ret = "" try: sval = str(value) if etype == argtypes.ArgTypeError: ret = "No ArgType for %s" % (sval,) else: ret = sval finally: del etype, value, tb return ret def fixname(name): if keyword.iskeyword(name): return name + '_' return name class FileOutput: '''Simple wrapper for file object, that makes writing #line statements easier.''' # " def __init__(self, fp, filename=None): self.fp = fp self.lineno = 1 if filename: self.filename = filename else: self.filename = self.fp.name # handle writing to the file, and keep track of the line number ... def write(self, str): self.fp.write(str) self.lineno = self.lineno + str.count('\n') def writelines(self, sequence): for line in sequence: self.write(line) def close(self): self.fp.close() def flush(self): self.fp.flush() def setline(self, linenum, filename): '''writes out a #line statement, for use by the C preprocessor.''' # " self.write('#line %d "%s"\n' % (linenum, filename)) def resetline(self): '''resets line numbering to the original file''' self.setline(self.lineno + 1, self.filename) class Wrapper: type_tmpl = ( 'PyTypeObject G_GNUC_INTERNAL Py%(typename)s_Type = {\n' ' PyVarObject_HEAD_INIT(NULL, 0)\n' ' "%(classname)s", /* tp_name */\n' ' sizeof(%(tp_basicsize)s), /* tp_basicsize */\n' ' 0, /* tp_itemsize */\n' ' /* methods */\n' ' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n' ' (printfunc)0, /* tp_print */\n' ' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n' ' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n' ' NULL, //%(tp_compare)s, /* tp_compare */\n' ' (reprfunc)%(tp_repr)s, /* tp_repr */\n' ' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n' ' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n' ' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n' ' (hashfunc)%(tp_hash)s, /* tp_hash */\n' ' (ternaryfunc)%(tp_call)s, /* tp_call */\n' ' (reprfunc)%(tp_str)s, /* tp_str */\n' ' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n' ' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n' ' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n' ' %(tp_flags)s, /* tp_flags */\n' ' %(tp_doc)s, /* Documentation string */\n' ' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n' ' (inquiry)%(tp_clear)s, /* tp_clear */\n' ' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n' ' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n' ' (getiterfunc)%(tp_iter)s, /* tp_iter */\n' ' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n' ' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n' ' (struct PyMemberDef*)0, /* tp_members */\n' ' (struct PyGetSetDef*)%(tp_getset)s, /* tp_getset */\n' ' NULL, /* tp_base */\n' ' NULL, /* tp_dict */\n' ' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n' ' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n' ' %(tp_dictoffset)s, /* tp_dictoffset */\n' ' (initproc)%(tp_init)s, /* tp_init */\n' ' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n' ' (newfunc)%(tp_new)s, /* tp_new */\n' ' (freefunc)%(tp_free)s, /* tp_free */\n' ' (inquiry)%(tp_is_gc)s /* tp_is_gc */\n' '};\n\n' ) slots_list = [ 'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro', 'tp_compare', 'tp_repr', 'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash', 'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter', 'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init', 'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc', 'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc' ] getter_tmpl = ( 'static PyObject *\n' '%(funcname)s(PyObject *self, void *closure)\n' '{\n' '%(varlist)s' ' ret = %(field)s;\n' '%(codeafter)s\n' '}\n\n' ) parse_tmpl = ( ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,' '"%(typecodes)s:%(name)s"%(parselist)s))\n' ' return %(errorreturn)s;\n' ) deprecated_tmpl = ( ' if (PyErr_Warn(PyExc_DeprecationWarning, ' '"%(deprecationmsg)s") < 0)\n' ' return %(errorreturn)s;\n' ) methdef_tmpl = ( ' { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n' ' %(docstring)s },\n' ) noconstructor = ( 'static int\n' 'pygobject_no_constructor(PyObject *self, PyObject *args, ' 'PyObject *kwargs)\n' '{\n' ' gchar buf[512];\n' '\n' ' g_snprintf(buf, sizeof(buf), "%s is an abstract widget", ' 'self->ob_type->tp_name);\n' ' PyErr_SetString(PyExc_NotImplementedError, buf);\n' ' return -1;\n' '}\n\n' ) function_tmpl = ( 'static PyObject *\n' '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' %(begin_allow_threads)s\n' ' %(setreturn)s%(cname)s(%(arglist)s);\n' ' %(end_allow_threads)s\n' '%(codeafter)s\n' '}\n\n' ) virtual_accessor_tmpl = ( 'static PyObject *\n' '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' '{\n' ' gpointer klass;\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' klass = g_type_class_ref(pyg_type_from_object(cls));\n' ' if (%(class_cast_macro)s(klass)->%(virtual)s)\n' ' %(setreturn)s%(class_cast_macro)s(klass)->' '%(virtual)s(%(arglist)s);\n' ' else {\n' ' PyErr_SetString(PyExc_NotImplementedError, ' '"virtual method %(name)s not implemented");\n' ' g_type_class_unref(klass);\n' ' return NULL;\n' ' }\n' ' g_type_class_unref(klass);\n' '%(codeafter)s\n' '}\n\n' ) # template for method calls constructor_tmpl = None method_tmpl = None def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): self.parser = parser self.objinfo = objinfo self.overrides = overrides self.fp = fp def get_lower_name(self): return string.lower(string.replace(self.objinfo.typecode, '_TYPE_', '_', 1)) def get_field_accessor(self, fieldname): raise NotImplementedError def get_initial_class_substdict(self): return {} def get_initial_constructor_substdict(self, constructor): return { 'name': '%s.__init__' % self.objinfo.py_name, 'errorreturn': '-1' } def get_initial_method_substdict(self, method): substdict = { 'name': '%s.%s' % (self.objinfo.py_name, method.name) } if method.unblock_threads: substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' substdict['end_allow_threads'] = 'pyg_end_allow_threads;' else: substdict['begin_allow_threads'] = '' substdict['end_allow_threads'] = '' return substdict def write_class(self): if self.overrides.is_type_ignored(self.objinfo.c_name): return self.fp.write('\n/* ----------- %s ----------- */\n\n' % self.objinfo.c_name) substdict = self.get_initial_class_substdict() if not substdict.has_key('tp_flags'): substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE' substdict['typename'] = self.objinfo.c_name if self.overrides.modulename: substdict['classname'] = '%s.%s' % (self.overrides.modulename, self.objinfo.name) else: substdict['classname'] = self.objinfo.name substdict['tp_doc'] = self.objinfo.docstring # Maybe this could be done in a nicer way, but I'll leave it as it is # for now: -- Johan if not self.overrides.slot_is_overriden('%s.tp_init' % self.objinfo.c_name): substdict['tp_init'] = self.write_constructor() substdict['tp_methods'] = self.write_methods() substdict['tp_getset'] = self.write_getsets() # handle slots ... for slot in self.slots_list: slotname = '%s.%s' % (self.objinfo.c_name, slot) slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot) if slot[:6] == 'tp_as_': slotfunc = '&' + slotfunc if self.overrides.slot_is_overriden(slotname): data = self.overrides.slot_override(slotname) self.write_function(slotname, data) substdict[slot] = slotfunc else: if not substdict.has_key(slot): substdict[slot] = '0' self.fp.write(self.type_tmpl % substdict) self.write_virtuals() def write_function_wrapper(self, function_obj, template, handle_return=0, is_method=0, kwargs_needed=0, substdict=None): '''This function is the guts of all functions that generate wrappers for functions, methods and constructors.''' if not substdict: substdict = {} info = argtypes.WrapperInfo() substdict.setdefault('errorreturn', 'NULL') # for methods, we want the leading comma if is_method: info.arglist.append('') if function_obj.varargs: raise argtypes.ArgTypeNotFoundError("varargs functions not supported") for param in function_obj.params: if param.pdflt != None and '|' not in info.parsestr: info.add_parselist('|', [], []) handler = argtypes.matcher.get(param.ptype) handler.write_param(param.ptype, param.pname, param.pdflt, param.pnull, info) substdict['setreturn'] = '' if handle_return: if function_obj.ret not in ('none', None): substdict['setreturn'] = 'ret = ' handler = argtypes.matcher.get(function_obj.ret) handler.write_return(function_obj.ret, function_obj.caller_owns_return, info) if function_obj.deprecated != None: deprecated = self.deprecated_tmpl % { 'deprecationmsg': function_obj.deprecated, 'errorreturn': substdict['errorreturn'] } else: deprecated = '' # if name isn't set, set it to function_obj.name substdict.setdefault('name', function_obj.name) if function_obj.unblock_threads: substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' substdict['end_allow_threads'] = 'pyg_end_allow_threads;' else: substdict['begin_allow_threads'] = '' substdict['end_allow_threads'] = '' if self.objinfo: substdict['typename'] = self.objinfo.c_name substdict.setdefault('cname', function_obj.c_name) substdict['varlist'] = info.get_varlist() substdict['typecodes'] = info.parsestr substdict['parselist'] = info.get_parselist() substdict['arglist'] = info.get_arglist() substdict['codebefore'] = deprecated + ( string.replace(info.get_codebefore(), 'return NULL', 'return ' + substdict['errorreturn']) ) substdict['codeafter'] = ( string.replace(info.get_codeafter(), 'return NULL', 'return ' + substdict['errorreturn'])) if info.parsestr or kwargs_needed: substdict['parseargs'] = self.parse_tmpl % substdict substdict['extraparams'] = ', PyObject *args, PyObject *kwargs' flags = 'METH_VARARGS|METH_KEYWORDS' # prepend the keyword list to the variable list substdict['varlist'] = info.get_kwlist() + substdict['varlist'] else: substdict['parseargs'] = '' substdict['extraparams'] = '' flags = 'METH_NOARGS' return template % substdict, flags def write_constructor(self): initfunc = '0' constructor = self.parser.find_constructor(self.objinfo,self.overrides) if not constructor: return self.write_default_constructor() funcname = constructor.c_name try: if self.overrides.is_overriden(funcname): data = self.overrides.override(funcname) self.write_function(funcname, data) self.objinfo.has_new_constructor_api = ( self.objinfo.typecode in self.overrides.newstyle_constructors) else: # ok, a hack to determine if we should use # new-style constructores :P property_based = getattr(self, 'write_property_based_constructor', None) if property_based: if (len(constructor.params) == 0 or isinstance(constructor.params[0], definitions.Property)): # write_property_based_constructor is only # implemented in GObjectWrapper return self.write_property_based_constructor( constructor) else: sys.stderr.write( "Warning: generating old-style constructor for:" + constructor.c_name + '\n') # write constructor from template ... code = self.write_function_wrapper(constructor, self.constructor_tmpl, handle_return=0, is_method=0, kwargs_needed=1, substdict=self.get_initial_constructor_substdict( constructor))[0] self.fp.write(code) initfunc = '_wrap_' + funcname except argtypes.ArgTypeError, ex: sys.stderr.write('Could not write constructor for %s: %s\n' % (self.objinfo.c_name, str(ex))) initfunc = self.write_noconstructor() return initfunc def write_noconstructor(self): # this is a hack ... if not hasattr(self.overrides, 'no_constructor_written'): self.fp.write(self.noconstructor) self.overrides.no_constructor_written = 1 initfunc = 'pygobject_no_constructor' return initfunc def write_default_constructor(self): return self.write_noconstructor() def get_methflags(self, funcname): if self.overrides.wants_kwargs(funcname): flags = 'METH_VARARGS|METH_KEYWORDS' elif self.overrides.wants_noargs(funcname): flags = 'METH_NOARGS' elif self.overrides.wants_onearg(funcname): flags = 'METH_O' else: flags = 'METH_VARARGS' if self.overrides.is_staticmethod(funcname): flags += '|METH_STATIC' elif self.overrides.is_classmethod(funcname): flags += '|METH_CLASS' return flags def write_function(self, funcname, data): lineno, filename = self.overrides.getstartline(funcname) self.fp.setline(lineno, filename) self.fp.write(data) self.fp.resetline() self.fp.write('\n\n') def _get_class_virtual_substdict(self, meth, cname, parent): substdict = self.get_initial_method_substdict(meth) substdict['virtual'] = meth.name substdict['cname'] = cname substdict['class_cast_macro'] = parent.typecode.replace( '_TYPE_', '_', 1) + "_CLASS" substdict['typecode'] = self.objinfo.typecode substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1) return substdict def write_methods(self): methods = [] klass = self.objinfo.c_name # First, get methods from the defs files for meth in self.parser.find_methods(self.objinfo): method_name = meth.c_name if self.overrides.is_ignored(method_name): continue try: if self.overrides.is_overriden(method_name): if not self.overrides.is_already_included(method_name): data = self.overrides.override(method_name) self.write_function(method_name, data) methflags = self.get_methflags(method_name) else: # write constructor from template ... code, methflags = self.write_function_wrapper(meth, self.method_tmpl, handle_return=1, is_method=1, substdict=self.get_initial_method_substdict(meth)) self.fp.write(code) methods.append(self.methdef_tmpl % { 'name': fixname(meth.name), 'cname': '_wrap_' + method_name, 'flags': methflags, 'docstring': meth.docstring }) methods_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: methods_coverage.declare_not_wrapped() sys.stderr.write('Could not write method %s.%s: %s\n' % (klass, meth.name, str(ex))) # Now try to see if there are any defined in the override for method_name in self.overrides.get_defines_for(klass): c_name = override.class2cname(klass, method_name) if self.overrides.is_already_included(method_name): continue try: data = self.overrides.define(klass, method_name) self.write_function(method_name, data) methflags = self.get_methflags(method_name) methods.append(self.methdef_tmpl % { 'name': method_name, 'cname': '_wrap_' + c_name, 'flags': methflags, 'docstring': 'NULL' }) methods_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: methods_coverage.declare_not_wrapped() sys.stderr.write('Could not write method %s.%s: %s\n' % (klass, method_name, str(ex))) # Add GObject virtual method accessors, for chaining to parent # virtuals from subclasses methods += self.write_virtual_accessors() if methods: methoddefs = '_Py%s_methods' % self.objinfo.c_name # write the PyMethodDef structure methods.append(' { NULL, NULL, 0, NULL }\n') self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs) self.fp.write(string.join(methods, '')) self.fp.write('};\n\n') else: methoddefs = 'NULL' return methoddefs def write_virtual_accessors(self): klass = self.objinfo.c_name methods = [] for meth in self.parser.find_virtuals(self.objinfo): method_name = self.objinfo.c_name + "__do_" + meth.name if self.overrides.is_ignored(method_name): continue try: if self.overrides.is_overriden(method_name): if not self.overrides.is_already_included(method_name): data = self.overrides.override(method_name) self.write_function(method_name, data) methflags = self.get_methflags(method_name) else: # temporarily add a 'self' parameter as first argument meth.params.insert(0, definitions.Parameter( ptype=(self.objinfo.c_name + '*'), pname='self', pdflt=None, pnull=None)) try: # write method from template ... code, methflags = self.write_function_wrapper( meth, self.virtual_accessor_tmpl, handle_return=True, is_method=False, substdict=self._get_class_virtual_substdict( meth, method_name, self.objinfo)) self.fp.write(code) finally: del meth.params[0] methods.append(self.methdef_tmpl % { 'name': "do_" + fixname(meth.name), 'cname': '_wrap_' + method_name, 'flags': methflags + '|METH_CLASS', 'docstring': 'NULL'}) vaccessors_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: vaccessors_coverage.declare_not_wrapped() sys.stderr.write( 'Could not write virtual accessor method %s.%s: %s\n' % (klass, meth.name, str(ex))) return methods def write_virtuals(self): ''' Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for GObject virtuals ''' klass = self.objinfo.c_name virtuals = [] for meth in self.parser.find_virtuals(self.objinfo): method_name = self.objinfo.c_name + "__proxy_do_" + meth.name if self.overrides.is_ignored(method_name): continue try: if self.overrides.is_overriden(method_name): if not self.overrides.is_already_included(method_name): data = self.overrides.override(method_name) self.write_function(method_name, data) else: # write virtual proxy ... ret, props = argtypes.matcher.get_reverse_ret(meth.ret) wrapper = reversewrapper.ReverseWrapper( '_wrap_' + method_name, is_static=True) wrapper.set_return_type(ret(wrapper, **props)) wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( wrapper, "self", method_name="do_" + meth.name, c_type=(klass + ' *'))) for param in meth.params: handler, props = argtypes.matcher.get_reverse( param.ptype) props["direction"] = param.pdir wrapper.add_parameter(handler(wrapper, param.pname, **props)) buf = reversewrapper.MemoryCodeSink() wrapper.generate(buf) self.fp.write(buf.flush()) virtuals.append((fixname(meth.name), '_wrap_' + method_name)) vproxies_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: vproxies_coverage.declare_not_wrapped() virtuals.append((fixname(meth.name), None)) sys.stderr.write('Could not write virtual proxy %s.%s: %s\n' % (klass, meth.name, str(ex))) if virtuals: # Write a 'pygtk class init' function for this object, # except when the object type is explicitly ignored (like # GtkPlug and GtkSocket on win32). if self.overrides.is_ignored(self.objinfo.typecode): return class_cast_macro = self.objinfo.typecode.replace( '_TYPE_', '_', 1) + "_CLASS" cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1) funcname = "__%s_class_init" % klass self.objinfo.class_init_func = funcname have_implemented_virtuals = not not [True for name, cname in virtuals if cname is not None] self.fp.write( ('\nstatic int\n' '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n' '{\n') % vars()) if have_implemented_virtuals: self.fp.write(' PyObject *o;\n') self.fp.write( ' %(klass)sClass *klass = ' '%(class_cast_macro)s(gclass);\n' ' PyObject *gsignals = ' 'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n' % vars()) for name, cname in virtuals: do_name = 'do_' + name if cname is None: self.fp.write('\n /* overriding %(do_name)s ' 'is currently not supported */\n' % vars()) else: self.fp.write(''' o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s"); if (o == NULL) PyErr_Clear(); else { if (!PyObject_TypeCheck(o, &PyCFunction_Type) && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s"))) klass->%(name)s = %(cname)s; Py_DECREF(o); } ''' % vars()) self.fp.write(' return 0;\n}\n') def write_getsets(self): lower_name = self.get_lower_name() getsets_name = lower_name + '_getsets' getterprefix = '_wrap_' + lower_name + '__get_' setterprefix = '_wrap_' + lower_name + '__set_' # no overrides for the whole function. If no fields, # don't write a func if not self.objinfo.fields: return '0' getsets = [] for ftype, cfname in self.objinfo.fields: fname = cfname.replace('.', '_') gettername = '0' settername = '0' attrname = self.objinfo.c_name + '.' + fname if self.overrides.attr_is_overriden(attrname): code = self.overrides.attr_override(attrname) self.write_function(attrname, code) if string.find(code, getterprefix + fname) >= 0: gettername = getterprefix + fname if string.find(code, setterprefix + fname) >= 0: settername = setterprefix + fname if gettername == '0': try: funcname = getterprefix + fname info = argtypes.WrapperInfo() handler = argtypes.matcher.get(ftype) # for attributes, we don't own the "return value" handler.write_return(ftype, 0, info) self.fp.write(self.getter_tmpl % { 'funcname': funcname, 'varlist': info.varlist, 'field': self.get_field_accessor(cfname), 'codeafter': info.get_codeafter() }) gettername = funcname except argtypes.ArgTypeError, ex: sys.stderr.write( "Could not write getter for %s.%s: %s\n" % (self.objinfo.c_name, fname, str(ex))) if gettername != '0' or settername != '0': getsets.append(' { "%s", (getter)%s, (setter)%s },\n' % (fixname(fname), gettername, settername)) if not getsets: return '0' self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name) for getset in getsets: self.fp.write(getset) self.fp.write(' { NULL, (getter)0, (setter)0 },\n') self.fp.write('};\n\n') return getsets_name def _write_get_symbol_names(self, writer, functions): self.fp.write("""static PyObject * _wrap__get_symbol_names(PyObject *self) { PyObject *pylist = PyList_New(0); """) for obj, bases in writer.get_classes(): self.fp.write(' PyList_Append(pylist, ' 'PyString_FromString("%s"));\n' % (obj.name)) for name, cname, flags, docstring in functions: self.fp.write(' PyList_Append(pylist, ' 'PyString_FromString("%s"));\n' % (name)) for enum in writer.get_enums(): self.fp.write(' PyList_Append(pylist, ' 'PyString_FromString("%s"));\n' % (enum.name)) for nick, value in enum.values: name = value[len(self.overrides.modulename)+1:] self.fp.write(' PyList_Append(pylist, ' 'PyString_FromString("%s"));\n' % (name)) self.fp.write(" return pylist;\n}\n\n"); def _write_get_symbol(self, writer, functions): self.fp.write("""static PyObject * _wrap__get_symbol(PyObject *self, PyObject *args) { PyObject *d; char *name; static PyObject *modulename = NULL; static PyObject *module = NULL; static char *strip_prefix = "%s"; if (!PyArg_ParseTuple(args, "Os", &d, &name)) return NULL; if (!modulename) modulename = PyString_FromString("%s"); if (!module) module = PyDict_GetItemString(d, "__module__"); """ % (self.overrides.modulename.upper() + '_', self.overrides.modulename)) first = True # Classes / GObjects for obj, bases in writer.get_classes(): if first: self.fp.write(' if (!strcmp(name, "%s")) {\n' % obj.name) first = False else: self.fp.write(' } else if (!strcmp(name, "%s")) {\n' % obj.name) self.fp.write( ' return (PyObject*)pygobject_lookup_class(%s);\n' % obj.typecode) self.fp.write(' }\n') # Functions for name, cname, flags, docstring in functions: self.fp.write(' else if (!strcmp(name, "%s")) {\n' % name) self.fp.write(' static PyMethodDef ml = { ' '"%s", (PyCFunction)%s, %s, "%s"};\n' % ( name, cname, flags, docstring)) self.fp.write(' return PyCFunction_NewEx(&ml, NULL, modulename);\n') self.fp.write(' }\n') # Enums def write_enum(enum, returnobj=False): if returnobj: ret = 'return ' else: ret = '' if enum.deftype == 'enum': self.fp.write( ' %spyg_enum_add(module, "%s", strip_prefix, %s);\n' % (ret, enum.name, enum.typecode)) else: self.fp.write( ' %spyg_flags_add(module, "%s", strip_prefix, %s);\n' % (ret, enum.name, enum.typecode)) strip_len = len(self.overrides.modulename)+1 # GTK_ for enum in writer.get_enums(): # XXX: Implement without typecodes self.fp.write(' else if (!strcmp(name, "%s")) {\n' % enum.name) write_enum(enum, returnobj=True) self.fp.write(' }\n') for nick, value in enum.values: value = value[strip_len:] self.fp.write(' else if (!strcmp(name, "%s")) {\n' % value) write_enum(enum) self.fp.write(' return PyObject_GetAttrString(module, "%s");\n' % value) self.fp.write(' }\n') self.fp.write(' return Py_None;\n}\n\n'); def _write_function_bodies(self): functions = [] # First, get methods from the defs files for func in self.parser.find_functions(): funcname = func.c_name if self.overrides.is_ignored(funcname): continue try: if self.overrides.is_overriden(funcname): data = self.overrides.override(funcname) self.write_function(funcname, data) methflags = self.get_methflags(funcname) else: # write constructor from template ... code, methflags = self.write_function_wrapper(func, self.function_tmpl, handle_return=1, is_method=0) self.fp.write(code) functions.append((func.name, '_wrap_' + funcname, methflags, func.docstring)) functions_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: functions_coverage.declare_not_wrapped() sys.stderr.write('Could not write function %s: %s\n' % (func.name, str(ex))) # Now try to see if there are any defined in the override for funcname in self.overrides.get_functions(): try: data = self.overrides.function(funcname) self.write_function(funcname, data) methflags = self.get_methflags(funcname) functions.append((funcname, '_wrap_' + funcname, methflags, 'NULL')) functions_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: functions_coverage.declare_not_wrapped() sys.stderr.write('Could not write function %s: %s\n' % (funcname, str(ex))) return functions def write_functions(self, writer, prefix): self.fp.write('\n/* ----------- functions ----------- */\n\n') functions = [] func_infos = self._write_function_bodies() # If we have a dynamic namespace, write symbol and attribute getter if self.overrides.dynamicnamespace: self._write_get_symbol_names(writer, func_infos) self._write_get_symbol(writer, func_infos) for obj, bases in writer.get_classes(): self.fp.write("""static PyTypeObject * %s_register_type(const gchar *name, PyObject *unused) { PyObject *m = PyImport_ImportModule("gtk"); PyObject *d = PyModule_GetDict(m); """ % obj.c_name) writer.write_class(obj, bases, indent=1) self.fp.write( ' return (%s)PyDict_GetItemString(d, "%s");\n' % ( 'PyTypeObject*', obj.name)) self.fp.write("}\n") functions.append(' { "_get_symbol_names", ' '(PyCFunction)_wrap__get_symbol_names, ' 'METH_NOARGS, NULL },\n') functions.append(' { "_get_symbol", ' '(PyCFunction)_wrap__get_symbol, ' 'METH_VARARGS, NULL },\n') else: for name, cname, flags, docstring in func_infos: functions.append(self.methdef_tmpl % dict(name=name, cname=cname, flags=flags, docstring=docstring)) # write the PyMethodDef structure functions.append(' { NULL, NULL, 0, NULL }\n') self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n') self.fp.write(string.join(functions, '')) self.fp.write('};\n\n') class GObjectWrapper(Wrapper): constructor_tmpl = ( 'static int\n' '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' self->obj = (GObject *)%(cname)s(%(arglist)s);\n' '%(codeafter)s\n' ' if (!self->obj) {\n' ' PyErr_SetString(PyExc_RuntimeError, ' '"could not create %(typename)s object");\n' ' return -1;\n' ' }\n' '%(aftercreate)s' ' pygobject_register_wrapper((PyObject *)self);\n' ' return 0;\n' '}\n\n' ) method_tmpl = ( 'static PyObject *\n' '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' %(begin_allow_threads)s\n' ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' ' %(end_allow_threads)s\n' '%(codeafter)s\n' '}\n\n' ) def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): Wrapper.__init__(self, parser, objinfo, overrides, fp) if self.objinfo: self.castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) def get_initial_class_substdict(self): return { 'tp_basicsize' : 'PyGObject', 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)', 'tp_dictoffset' : 'offsetof(PyGObject, inst_dict)' } def get_field_accessor(self, fieldname): castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) return '%s(pygobject_get(self))->%s' % (castmacro, fieldname) def get_initial_constructor_substdict(self, constructor): substdict = Wrapper.get_initial_constructor_substdict(self, constructor) if not constructor.caller_owns_return: substdict['aftercreate'] = " g_object_ref(self->obj);\n" else: substdict['aftercreate'] = '' return substdict def get_initial_method_substdict(self, method): substdict = Wrapper.get_initial_method_substdict(self, method) substdict['cast'] = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) return substdict def write_default_constructor(self): try: parent = self.parser.find_object(self.objinfo.parent) except ValueError: parent = None if parent is not None: ## just like the constructor is inheritted, we should # inherit the new API compatibility flag self.objinfo.has_new_constructor_api = ( parent.has_new_constructor_api) elif self.objinfo.parent == 'GObject': self.objinfo.has_new_constructor_api = True return '0' def write_property_based_constructor(self, constructor): self.objinfo.has_new_constructor_api = True out = self.fp print >> out, "static int" print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \ ' PyObject *kwargs)\n{' % constructor.c_name if constructor.params: s = " GType obj_type = pyg_type_from_object((PyObject *) self);" print >> out, s def py_str_list_to_c(arg): if arg: return "{" + ", ".join( map(lambda s: '"' + s + '"', arg)) + ", NULL }" else: return "{ NULL }" classname = '%s.%s' % (self.overrides.modulename, self.objinfo.name) if constructor.params: mandatory_arguments = [param for param in constructor.params if not param.optional] optional_arguments = [param for param in constructor.params if param.optional] arg_names = py_str_list_to_c( [param.argname for param in mandatory_arguments + optional_arguments]) prop_names = py_str_list_to_c( [param.pname for param in mandatory_arguments + optional_arguments]) print >> out, " GParameter params[%i];" % \ len(constructor.params) print >> out, " PyObject *parsed_args[%i] = {NULL, };" % \ len(constructor.params) print >> out, " char *arg_names[] = %s;" % arg_names print >> out, " char *prop_names[] = %s;" % prop_names print >> out, " guint nparams, i;" print >> out if constructor.deprecated is not None: out.write( ' if (PyErr_Warn(PyExc_DeprecationWarning, ' '"%s") < 0)\n' % constructor.deprecated) print >> out, ' return -1;' print >> out out.write(" if (!PyArg_ParseTupleAndKeywords(args, kwargs, ") template = '"' if mandatory_arguments: template += "O"*len(mandatory_arguments) if optional_arguments: template += "|" + "O"*len(optional_arguments) template += ':%s.__init__"' % classname print >> out, template, ", arg_names", for i in range(len(constructor.params)): print >> out, ", &parsed_args[%i]" % i, out.write( "))\n" " return -1;\n" "\n" " memset(params, 0, sizeof(GParameter)*%i);\n" " if (!pyg_parse_constructor_args(obj_type, arg_names,\n" " prop_names, params, \n" " &nparams, parsed_args))\n" " return -1;\n" " pygobject_constructv(self, nparams, params);\n" " for (i = 0; i < nparams; ++i)\n" " g_value_unset(¶ms[i].value);\n" % len(constructor.params)) else: out.write( " static char* kwlist[] = { NULL };\n" "\n") if constructor.deprecated is not None: out.write( ' if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n' ' return -1;\n' '\n' % constructor.deprecated) out.write( ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n' ' ":%s.__init__",\n' ' kwlist))\n' ' return -1;\n' '\n' ' pygobject_constructv(self, 0, NULL);\n' % classname) out.write( ' if (!self->obj) {\n' ' PyErr_SetString(\n' ' PyExc_RuntimeError, \n' ' "could not create %s object");\n' ' return -1;\n' ' }\n' % classname) if not constructor.caller_owns_return: print >> out, " g_object_ref(self->obj);\n" out.write( ' return 0;\n' '}\n\n') return "_wrap_%s" % constructor.c_name class GInterfaceWrapper(GObjectWrapper): virtual_accessor_tmpl = ( 'static PyObject *\n' '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' '{\n' ' %(vtable)s *iface;\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' iface = g_type_interface_peek(' 'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n' ' if (iface->%(virtual)s)\n' ' %(setreturn)siface->%(virtual)s(%(arglist)s);\n' ' else {\n' ' PyErr_SetString(PyExc_NotImplementedError, ' '"interface method %(name)s not implemented");\n' ' return NULL;\n' ' }\n' '%(codeafter)s\n' '}\n\n' ) def get_initial_class_substdict(self): return { 'tp_basicsize' : 'PyObject', 'tp_weaklistoffset' : '0', 'tp_dictoffset' : '0'} def write_constructor(self): # interfaces have no constructors ... return '0' def write_getsets(self): # interfaces have no fields ... return '0' def _get_class_virtual_substdict(self, meth, cname, parent): substdict = self.get_initial_method_substdict(meth) substdict['virtual'] = meth.name substdict['cname'] = cname substdict['typecode'] = self.objinfo.typecode substdict['vtable'] = self.objinfo.vtable return substdict def write_virtuals(self): ## Now write reverse method wrappers, which let python code ## implement interface methods. # First, get methods from the defs files klass = self.objinfo.c_name proxies = [] for meth in self.parser.find_virtuals(self.objinfo): method_name = self.objinfo.c_name + "__proxy_do_" + meth.name if self.overrides.is_ignored(method_name): continue try: if self.overrides.is_overriden(method_name): if not self.overrides.is_already_included(method_name): data = self.overrides.override(method_name) self.write_function(method_name, data) else: # write proxy ... ret, props = argtypes.matcher.get_reverse_ret(meth.ret) wrapper = reversewrapper.ReverseWrapper( '_wrap_' + method_name, is_static=True) wrapper.set_return_type(ret(wrapper, **props)) wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( wrapper, "self", method_name="do_" + meth.name, c_type=(klass + ' *'))) for param in meth.params: handler, props = argtypes.matcher.get_reverse( param.ptype) props["direction"] = param.pdir wrapper.add_parameter( handler(wrapper, param.pname, **props)) buf = reversewrapper.MemoryCodeSink() wrapper.generate(buf) self.fp.write(buf.flush()) proxies.append((fixname(meth.name), '_wrap_' + method_name)) iproxies_coverage.declare_wrapped() except argtypes.ArgTypeError, ex: iproxies_coverage.declare_not_wrapped() proxies.append((fixname(meth.name), None)) sys.stderr.write('Could not write interface proxy %s.%s: %s\n' % (klass, meth.name, str(ex))) if not proxies or not [cname for name, cname in proxies if cname]: return ## Write an interface init function for this object funcname = "__%s__interface_init" % klass vtable = self.objinfo.vtable self.fp.write( '\nstatic void\n' '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n' '{\n' ' %(vtable)s *parent_iface = ' 'g_type_interface_peek_parent(iface);\n' ' PyObject *py_method;\n' '\n' % vars()) for name, cname in proxies: do_name = 'do_' + name if cname is None: continue self.fp.write(( ' py_method = pytype? PyObject_GetAttrString(' '(PyObject *) pytype, "%(do_name)s") : NULL;\n' ' if (py_method && !PyObject_TypeCheck(py_method, ' '&PyCFunction_Type)) {\n' ' iface->%(name)s = %(cname)s;\n' ' } else {\n' ' PyErr_Clear();\n' ' if (parent_iface) {\n' ' iface->%(name)s = parent_iface->%(name)s;\n' ' }\n' ' Py_XDECREF(py_method);\n' ' }\n' ) % vars()) self.fp.write('}\n\n') interface_info = "__%s__iinfo" % klass self.fp.write(''' static const GInterfaceInfo %s = { (GInterfaceInitFunc) %s, NULL, NULL }; ''' % (interface_info, funcname)) self.objinfo.interface_info = interface_info class GBoxedWrapper(Wrapper): constructor_tmpl = ( 'static int\n' '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' self->gtype = %(typecode)s;\n' ' self->free_on_dealloc = FALSE;\n' ' self->boxed = %(cname)s(%(arglist)s);\n' '%(codeafter)s\n' ' if (!self->boxed) {\n' ' PyErr_SetString(PyExc_RuntimeError, ' '"could not create %(typename)s object");\n' ' return -1;\n' ' }\n' ' self->free_on_dealloc = TRUE;\n' ' return 0;\n' '}\n\n' ) method_tmpl = ( 'static PyObject *\n' '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' %(begin_allow_threads)s\n' ' %(setreturn)s%(cname)s(pyg_boxed_get(self, ' '%(typename)s)%(arglist)s);\n' ' %(end_allow_threads)s\n' '%(codeafter)s\n' '}\n\n' ) def get_initial_class_substdict(self): return { 'tp_basicsize' : 'PyGBoxed', 'tp_weaklistoffset' : '0', 'tp_dictoffset' : '0' } def get_field_accessor(self, fieldname): return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname) def get_initial_constructor_substdict(self, constructor): substdict = Wrapper.get_initial_constructor_substdict( self, constructor) substdict['typecode'] = self.objinfo.typecode return substdict class GPointerWrapper(GBoxedWrapper): constructor_tmpl = ( 'static int\n' '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' self->gtype = %(typecode)s;\n' ' self->pointer = %(cname)s(%(arglist)s);\n' '%(codeafter)s\n' ' if (!self->pointer) {\n' ' PyErr_SetString(PyExc_RuntimeError, ' '"could not create %(typename)s object");\n' ' return -1;\n' ' }\n' ' return 0;\n' '}\n\n' ) method_tmpl = ( 'static PyObject *\n' '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' '{\n' '%(varlist)s' '%(parseargs)s' '%(codebefore)s' ' %(setreturn)s%(cname)s(pyg_pointer_get(self, ' '%(typename)s)%(arglist)s);\n' '%(codeafter)s\n' '}\n\n' ) def get_initial_class_substdict(self): return { 'tp_basicsize' : 'PyGPointer', 'tp_weaklistoffset' : '0', 'tp_dictoffset' : '0' } def get_field_accessor(self, fieldname): return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name, fieldname) def get_initial_constructor_substdict(self, constructor): substdict = Wrapper.get_initial_constructor_substdict( self, constructor) substdict['typecode'] = self.objinfo.typecode return substdict class SourceWriter: def __init__(self, parser, overrides, prefix, fp=FileOutput(sys.stdout)): self.parser = parser self.overrides = overrides self.prefix = prefix self.fp = fp def write(self, py_ssize_t_clean=False): argtypes.py_ssize_t_clean = py_ssize_t_clean self.write_headers(py_ssize_t_clean) self.write_imports() self.write_type_declarations() self.write_body() self.write_classes() wrapper = Wrapper(self.parser, None, self.overrides, self.fp) wrapper.write_functions(self, self.prefix) if not self.overrides.dynamicnamespace: self.write_enums() self.write_extension_init() self.write_registers() argtypes.py_ssize_t_clean = False def write_headers(self, py_ssize_t_clean): self.fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */') self.fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n') if py_ssize_t_clean: self.fp.write('#define PY_SSIZE_T_CLEAN\n') self.fp.write('#include \n\n\n') if py_ssize_t_clean: self.fp.write(''' #if PY_VERSION_HEX < 0x02050000 typedef int Py_ssize_t; #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN typedef inquiry lenfunc; typedef intargfunc ssizeargfunc; typedef intobjargproc ssizeobjargproc; #endif ''') self.fp.write(self.overrides.get_headers()) self.fp.resetline() self.fp.write('\n\n') def write_imports(self): self.fp.write('/* ---------- types from other modules ---------- */\n') for module, pyname, cname, importing_for in self.overrides.get_imports(): if importing_for is None or is_registered_object(importing_for): self.fp.write('static PyTypeObject *_%s;\n' % cname) self.fp.write('#define %s (*_%s)\n' % (cname, cname)) self.fp.write('\n\n') def write_type_declarations(self): #todo use 'static' if used only in one file self.fp.write('/* ---------- forward type declarations ---------- */\n') for obj in self.parser.boxes: if not self.overrides.is_type_ignored(obj.c_name): self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n') for obj in self.parser.objects: if not self.overrides.is_type_ignored(obj.c_name): self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n') for interface in self.parser.interfaces: if not self.overrides.is_type_ignored(interface.c_name): self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + interface.c_name + '_Type;\n') self.fp.write('\n') def write_body(self): self.fp.write(self.overrides.get_body()) self.fp.resetline() self.fp.write('\n\n') def _sort_parent_children(self, objects): objects = list(objects) modified = True while modified: modified = False parent_index = None child_index = None for i, obj in enumerate(objects): if obj.parent == 'GObject': continue if obj.parent not in [info.c_name for info in objects[:i]]: for j, info in enumerate(objects[i+1:]): if info.c_name == obj.parent: parent_index = i + 1 + j child_index = i break else: continue break if child_index is not None and parent_index is not None: if child_index != parent_index: objects.insert(child_index, objects.pop(parent_index)) modified = True return objects def write_classes(self): ## Sort the objects, so that we generate code for the parent types ## before their children. objects = self._sort_parent_children(self.parser.objects) for klass, items in ((GBoxedWrapper, self.parser.boxes), (GPointerWrapper, self.parser.pointers), (GObjectWrapper, objects), (GInterfaceWrapper, self.parser.interfaces)): for item in items: instance = klass(self.parser, item, self.overrides, self.fp) instance.write_class() self.fp.write('\n') def get_enums(self): enums = [] for enum in self.parser.enums: if self.overrides.is_type_ignored(enum.c_name): continue enums.append(enum) return enums def write_enums(self): if not self.parser.enums: return self.fp.write('\n/* ----------- enums and flags ----------- */\n\n') self.fp.write( 'void\n' + self.prefix + '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n') self.fp.write( '#ifdef VERSION\n' ' PyModule_AddStringConstant(module, "__version__", VERSION);\n' '#endif\n') for enum in self.get_enums(): if enum.typecode is None: for nick, value in enum.values: self.fp.write( ' PyModule_AddIntConstant(module, ' '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n' % (value, value)) else: if enum.deftype == 'enum': self.fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n' % (enum.name, enum.typecode)) else: self.fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n' % (enum.name, enum.typecode)) self.fp.write('\n') self.fp.write(' if (PyErr_Occurred())\n') self.fp.write(' PyErr_Print();\n') self.fp.write('}\n\n') def write_object_imports(self, retval=''): imports = self.overrides.get_imports()[:] if not imports: return bymod = {} for module, pyname, cname, importing_for in imports: if importing_for is None or is_registered_object(importing_for): bymod.setdefault(module, []).append((pyname, cname)) self.fp.write(' PyObject *module;\n\n') for module in bymod: self.fp.write( ' if ((module = PyImport_ImportModule("%s")) != NULL) {\n' % module) #self.fp.write( # ' PyObject *moddict = PyModule_GetDict(module);\n\n') for pyname, cname in bymod[module]: #self.fp.write( # ' _%s = (PyTypeObject *)PyDict_GetItemString(' # 'moddict, "%s");\n' % (cname, pyname)) self.fp.write( ' _%s = (PyTypeObject *)PyObject_GetAttrString(' 'module, "%s");\n' % (cname, pyname)) self.fp.write(' if (_%s == NULL) {\n' % cname) self.fp.write(' PyErr_SetString(PyExc_ImportError,\n') self.fp.write(' "cannot import name %s from %s");\n' % (pyname, module)) self.fp.write(' return %s;\n' % retval) self.fp.write(' }\n') self.fp.write(' } else {\n') self.fp.write(' PyErr_SetString(PyExc_ImportError,\n') self.fp.write(' "could not import %s");\n' % module) self.fp.write(' return %s;\n' % retval) self.fp.write(' }\n') self.fp.write('\n') def write_extension_init(self): self.fp.write('/* initialise stuff extension classes */\n') self.fp.write('void\n' + self.prefix + '_register_classes(PyObject *d)\n{\n') self.write_object_imports() self.fp.write(self.overrides.get_init() + '\n') self.fp.resetline() def get_classes(self): objects = self.parser.objects[:] pos = 0 while pos < len(objects): parent = objects[pos].parent for i in range(pos+1, len(objects)): if objects[i].c_name == parent: objects.insert(i+1, objects[pos]) del objects[pos] break else: pos = pos + 1 retval = [] for obj in objects: if self.overrides.is_type_ignored(obj.c_name): continue bases = [] if obj.parent != None: bases.append(obj.parent) bases = bases + obj.implements retval.append((obj, bases)) return retval def write_registers(self): for boxed in self.parser.boxes: if not self.overrides.is_type_ignored(boxed.c_name): self.fp.write(' pyg_register_boxed(d, "' + boxed.name + '", ' + boxed.typecode + ', &Py' + boxed.c_name + '_Type);\n') for pointer in self.parser.pointers: if not self.overrides.is_type_ignored(pointer.c_name): self.fp.write(' pyg_register_pointer(d, "' + pointer.name + '", ' + pointer.typecode + ', &Py' + pointer.c_name + '_Type);\n') for interface in self.parser.interfaces: if not self.overrides.is_type_ignored(interface.c_name): self.fp.write(' pyg_register_interface(d, "' + interface.name + '", '+ interface.typecode + ', &Py' + interface.c_name + '_Type);\n') if interface.interface_info is not None: self.fp.write(' pyg_register_interface_info(%s, &%s);\n' % (interface.typecode, interface.interface_info)) if not self.overrides.dynamicnamespace: for obj, bases in self.get_classes(): self.write_class(obj, bases) else: for obj, bases in self.get_classes(): self.fp.write( ' pyg_type_register_custom_callback("%s", ' '(PyGTypeRegistrationFunction)%s_register_type, d);\n' % (obj.c_name, obj.c_name)) self.fp.write('}\n') def _can_direct_ref(self, base): if not self.overrides.dynamicnamespace: return True if base == 'GObject': return True obj = get_object_by_name(base) if obj.module.lower() != self.overrides.modulename: return True return False def write_class(self, obj, bases, indent=1): indent_str = ' ' * (indent * 4) if bases: bases_str = 'Py_BuildValue("(%s)"' % (len(bases) * 'O') for base in bases: if self._can_direct_ref(base): bases_str += ', &Py%s_Type' % base else: baseobj = get_object_by_name(base) bases_str += ', PyObject_GetAttrString(m, "%s")' % baseobj.name bases_str += ')' else: bases_str = 'NULL' self.fp.write( '%(indent)spygobject_register_class(d, "%(c_name)s", %(typecode)s, &Py%(c_name)s_Type, %(bases)s);\n' % dict(indent=indent_str, c_name=obj.c_name, typecode=obj.typecode, bases=bases_str)) if obj.has_new_constructor_api: self.fp.write( indent_str + 'pyg_set_object_has_new_constructor(%s);\n' % obj.typecode) else: print >> sys.stderr, ( "Warning: Constructor for %s needs to be updated to new API\n" " See http://live.gnome.org/PyGTK_2fWhatsNew28" "#update-constructors") % obj.c_name if obj.class_init_func is not None: self.fp.write( indent_str + 'pyg_register_class_init(%s, %s);\n' % (obj.typecode, obj.class_init_func)) _objects = {} def is_registered_object(c_name): return c_name in _objects def get_object_by_name(c_name): global _objects return _objects[c_name] def register_types(parser): global _objects for boxed in parser.boxes: argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode) _objects[boxed.c_name] = boxed for pointer in parser.pointers: argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode) for obj in parser.objects: argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode) _objects[obj.c_name] = obj for iface in parser.interfaces: argtypes.matcher.register_object(iface.c_name, None, iface.typecode) _objects[iface.c_name] = iface for enum in parser.enums: if enum.deftype == 'flags': argtypes.matcher.register_flag(enum.c_name, enum.typecode) else: argtypes.matcher.register_enum(enum.c_name, enum.typecode) usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile' def main(argv): o = override.Overrides() prefix = 'pygtk' outfilename = None errorfilename = None opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:I:", ["override=", "prefix=", "register=", "outfilename=", "load-types=", "errorfilename=", "py_ssize_t-clean"]) defines = {} # -Dkey[=val] options py_ssize_t_clean = False for opt, arg in opts: if opt in ('-o', '--override'): o = override.Overrides(arg) elif opt in ('-p', '--prefix'): prefix = arg elif opt in ('-r', '--register'): # Warning: user has to make sure all -D options appear before -r p = defsparser.DefsParser(arg, defines) p.startParsing() register_types(p) del p elif opt == '--outfilename': outfilename = arg elif opt == '--errorfilename': errorfilename = arg elif opt in ('-t', '--load-types'): globals = {} execfile(arg, globals) elif opt == '-D': nameval = arg.split('=') try: defines[nameval[0]] = nameval[1] except IndexError: defines[nameval[0]] = None elif opt == '-I': defsparser.include_path.insert(0, arg) elif opt == '--py_ssize_t-clean': py_ssize_t_clean = True if len(args) < 1: print >> sys.stderr, usage return 1 if errorfilename: sys.stderr = open(errorfilename, "w") p = defsparser.DefsParser(args[0], defines) if not outfilename: outfilename = os.path.splitext(args[0])[0] + '.c' p.startParsing() register_types(p) sw = SourceWriter(p, o, prefix, FileOutput(sys.stdout, outfilename)) sw.write(py_ssize_t_clean) functions_coverage.printstats() methods_coverage.printstats() vproxies_coverage.printstats() vaccessors_coverage.printstats() iproxies_coverage.printstats() if __name__ == '__main__': sys.exit(main(sys.argv))