summaryrefslogtreecommitdiffstats
path: root/codegen/codegen.py
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/codegen.py')
-rw-r--r--codegen/codegen.py1712
1 files changed, 1712 insertions, 0 deletions
diff --git a/codegen/codegen.py b/codegen/codegen.py
new file mode 100644
index 0000000..fa4417a
--- /dev/null
+++ b/codegen/codegen.py
@@ -0,0 +1,1712 @@
+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 + string.count(str, '\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'
+ ' PyObject_HEAD_INIT(NULL)\n'
+ ' 0, /* ob_size */\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'
+ ' (cmpfunc)%(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.c_name,
+ 'errorreturn': '-1' }
+ def get_initial_method_substdict(self, method):
+ substdict = { 'name': '%s.%s' % (self.objinfo.c_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'] = substdict['name'].split('.')[1]
+ 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(&params[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'] = substdict['name'].split('.')[1]
+ 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 <Python.h>\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 in self.overrides.get_imports():
+ 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 in imports:
+ 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 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))