diff options
| author | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2008-08-05 14:52:52 +0000 |
|---|---|---|
| committer | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2008-08-05 14:52:52 +0000 |
| commit | 1fae093527f69de086934f5df750cf374eaa2f48 (patch) | |
| tree | c182d67081132607753c96da70f7ce0995909ff4 /bindings/python | |
| parent | 0930e6046f5c6e30b9d16fef5bb7a543e8750281 (diff) | |
| download | lasso-1fae093527f69de086934f5df750cf374eaa2f48.tar.gz lasso-1fae093527f69de086934f5df750cf374eaa2f48.tar.xz lasso-1fae093527f69de086934f5df750cf374eaa2f48.zip | |
Move all python binding related files inside the python subdirectory
Diffstat (limited to 'bindings/python')
| -rw-r--r-- | bindings/python/Makefile.am | 2 | ||||
| -rw-r--r-- | bindings/python/lang.py | 887 | ||||
| -rw-r--r-- | bindings/python/wrapper_bottom.c | 18 | ||||
| -rw-r--r-- | bindings/python/wrapper_top.c | 502 |
4 files changed, 1408 insertions, 1 deletions
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index 3da0e08a..51709628 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -30,7 +30,7 @@ if WSF_ENABLED EXTRA_ARGS = --enable-id-wsf endif -lasso.py _lasso.c: +lasso.py _lasso.c: lang.py wrapper_top.c wrapper_bottom.c ../bindings.py $(PYTHON) $(top_srcdir)/bindings/bindings.py -l python --src-dir=$(top_srcdir)/lasso/ $(EXTRA_ARGS) clean-local: diff --git a/bindings/python/lang.py b/bindings/python/lang.py new file mode 100644 index 00000000..483e7614 --- /dev/null +++ b/bindings/python/lang.py @@ -0,0 +1,887 @@ +# Lasso - A free implementation of the Liberty Alliance specifications. +# +# Copyright (C) 2004-2007 Entr'ouvert +# http://lasso.entrouvert.org +# +# Authors: See AUTHORS file in top-level directory. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import re +import textwrap +import utils + +class Binding: + def __init__(self, binding_data): + self.binding_data = binding_data + + def is_pygobject(self, t): + if t: + m = re.match(r'(?:const\s*)?(.*)',t) # Remove const modifier + t = m.group(1) + return t not in ['char*', 'gchar*', + 'GList*', 'GHashTable*', + 'int', 'gint', 'gboolean', 'xmlNode*'] + self.binding_data.enums + else: + return False + + def generate(self): + fd = open('lasso.py', 'w') + self.generate_header(fd) + self.generate_exceptions(fd) + self.generate_constants(fd) + for clss in self.binding_data.structs: + self.generate_class(clss, fd) + self.generate_functions(fd) + self.generate_footer(fd) + fd.close() + + fd = open('_lasso.c', 'w') + self.generate_wrapper(fd) + fd.close() + + def generate_header(self, fd): + print >> fd, '''\ +# this file has been generated automatically; do not edit + +import _lasso + +_lasso.init() + +def cptrToPy(cptr): + if cptr is None: + return None + klass = getattr(lasso, cptr.typename) + o = klass.__new__(klass) + o._cptr = cptr + return o + +class frozendict(dict): + \'\'\'Immutable dict\'\'\' + # from Python Cookbook: + # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/414283 + def _blocked_attribute(obj): + raise AttributeError('A frozendict cannot be modified.') + _blocked_attribute = property(_blocked_attribute) + + __delitem__ = __setitem__ = clear = _blocked_attribute + pop = popitem = setdefault = update = _blocked_attribute + + def __new__(cls, *args): + new = dict.__new__(cls) + dict.__init__(new, *args) + return new + + def __init__(self, *args): + pass + + def __hash__(self): + try: + return self._cached_hash + except AttributeError: + h = self._cached_hash = hash(tuple(sorted(self.items()))) + return h + + def __repr__(self): + return 'frozendict(%s)' % dict.__repr__(self) +''' + + def generate_exceptions(self, fd): + done_cats = [] + print >> fd, '''\ +class Error(Exception): + code = None + + @staticmethod + def raise_on_rc(rc): + global exceptions_dict + exception = exceptions_dict.get(rc, Error()) + exception.code = rc + raise exception + + def __str__(self): + return '<lasso.%s(%s): %s>' % (self.__class__.__name__, self.code, _lasso.strError(self.code)) + + def __getitem__(self, i): + # compatibility with SWIG bindings + if i == 0: + return self.code + elif i == 1: + return _lasso.strError(self.code) + else: + raise IndexError() +''' + for exc_cat in self.binding_data.overrides.findall('exception/category'): + cat = exc_cat.attrib.get('name') + done_cats.append(cat) + parent_cat = exc_cat.attrib.get('parent', '') + print >> fd, '''\ +class %sError(%sError): + pass +''' % (cat, parent_cat) + + exceptions_dict = {} + + for c in self.binding_data.constants: + m = re.match(r'LASSO_(\w+)_ERROR_(.*)', c[1]) + if not m: + continue + cat, detail = m.groups() + cat = cat.title().replace('_', '') + detail = (cat + '_' + detail).title().replace('_', '') + if not cat in done_cats: + done_cats.append(cat) + for exc_cat in self.binding_data.overrides.findall('exception/category'): + if exc_cat.attrib.get('name') == cat: + parent_cat = exc_cat.attrib.get('parent') + break + else: + parent_cat = '' + + print >> fd, '''\ +class %sError(%sError): + pass +''' % (cat, parent_cat) + + exceptions_dict[detail] = c[1][6:] + + if (detail, cat) == ('UnsupportedProfile', 'Logout'): + # skip Logout/UnsupportedProfile exception as its name would + # be the same as Profile/UnsupportedProfile; it is not a + # problem skipping it as they both inherit from ProfileError + # and the exception code will correctly be set by raise_on_rc + # afterwards. (actually it is even totally unnecessary to skip + # it here as Profile/UnsupportedProfile is handled after + # Logout/UnsupportedProfile, this is just done in the case the + # ordering would change) + continue + + print >> fd, '''\ +class %sError(%sError): + pass +''' % (detail, cat) + + print >> fd, 'exceptions_dict = {' + for k, v in exceptions_dict.items(): + print >> fd, ' _lasso.%s: %sError,' % (v, k) + print >> fd, '}' + print >> fd, '' + + def generate_footer(self, fd): + print >> fd, ''' + +import lasso + +# backward compatibility with the SWIG binding + +WSF_SUPPORT = WSF_ENABLED + +Profile.isIdentityDirty = property(Profile.hasDirtyIdentity) +Profile.isSessionDirty = property(Profile.hasDirtySession) + +def identity_get_provider_ids(self): + return self.federations.keys() +Identity.providerIds = property(identity_get_provider_ids) + +def server_get_provider_ids(self): + return self.providers.keys() +Server.providerIds = property(server_get_provider_ids) + +def session_get_provider_ids(self): + return self.assertions.keys() +Session.providerIds = property(session_get_provider_ids) + +Samlp2AuthnRequest.nameIDPolicy = Samlp2AuthnRequest.nameIdPolicy +LibAuthnRequest.nameIDPolicy = LibAuthnRequest.nameIdPolicy +Saml2Subject.nameID = Saml2Subject.nameId +MiscTextNode.text_child = MiscTextNode.textChild +NodeList = list +StringList = list +StringDict = dict +registerIdWsf2DstService = registerIdwsf2DstService + +if WSF_SUPPORT: + DiscoDescription_newWithBriefSoapHttpDescription = DiscoDescription.newWithBriefSoapHttpDescription + Discovery.buildRequestMsg = Discovery.buildSoapRequestMsg + InteractionProfileService.buildRequestMsg = InteractionProfileService.buildSoapRequestMsg + InteractionProfileService.buildResponseMsg = InteractionProfileService.buildSoapResponseMsg + DataService.buildRequestMsg = DataService.buildSoapRequestMsg + DiscoModifyResponse.newEntryIds = DiscoModifyResponse.newEntryIDs +''' + + def generate_constants(self, fd): + print >> fd, '### Constants (both enums and defines)' + for c in self.binding_data.constants: + print >> fd, '%s = _lasso.%s' % (c[1][6:], c[1][6:]) + for c in self.binding_data.overrides.findall('constant'): + name = c.attrib.get('name') + if c.attrib.get('value'): + name = name[6:] # dropping LASSO_ + value = c.attrib.get('value') + if value == 'True': + print >> fd, '%s = True' % name + else: + print >> sys.stderr, 'E: unknown value for constant: %r' % value + print >> fd, '' + + def generate_class(self, clss, fd): + klassname = clss.name[5:] # remove Lasso from class name + if clss.parent == 'GObject': + parentname = 'object' + else: + parentname = clss.parent[5:] + + print >> fd, '''class %(klassname)s(%(parentname)s):''' % locals() + if not clss.members and not clss.methods: + print >> fd, ' pass' + print >> fd, '' + return + + methods = clss.methods[:] + # constructor(s) + method_prefix = 'lasso_' + utils.format_as_underscored(klassname) + '_' + for m in self.binding_data.functions: + if m.name == method_prefix + 'new': + c_args = [] + py_args = [] + for o in m.args: + arg_type, arg_name, arg_options = o + if arg_options.get('optional'): + py_args.append('%s = None' % arg_name) + else: + py_args.append(arg_name) + + if self.is_pygobject(arg_type): + c_args.append('%s._cptr' % arg_name) + else: + c_args.append(arg_name) + + c_args = ', '.join(c_args) + py_args = ', ' + ', '.join(py_args) + print >> fd, ' def __init__(self%s):' % py_args + # XXX: could check self._cptr.typename to see if it got the + # right class type + print >> fd, ' self._cptr = _lasso.%s(%s)' % ( + m.name[6:], c_args) + print >> fd, ' if self._cptr is None:' + print >> fd, ' raise Error(\'failed to create object\')' + print >> fd, '' + + for m in self.binding_data.functions: + if m.name.startswith(method_prefix + 'new_'): + constructor_name = utils.format_as_camelcase(m.name[len(method_prefix):]) + c_args = [] + py_args = [] + for o in m.args: + arg_type, arg_name, arg_options = o + if arg_options.get('optional'): + py_args.append('%s = None' % arg_name) + else: + py_args.append(arg_name) + + if self.is_pygobject(arg_type): + c_args.append('%s._cptr' % arg_name) + else: + c_args.append(arg_name) + c_args = ', '.join(c_args) + py_args = ', ' + ', '.join(py_args) + print >> fd, ' @classmethod' + print >> fd, ' def %s(cls%s):' % (constructor_name, py_args) + print >> fd, ' obj = cls.__new__(cls)' + print >> fd, ' obj._cptr = _lasso.%s(%s)' % (m.name[6:], c_args) + print >> fd, ' if obj._cptr is None:' + print >> fd, ' raise RuntimeError(\'lasso failed to create object\')' + print >> fd, ' return obj' + print >> fd, '' + + # create properties for members + for m in clss.members: + mname = utils.format_as_camelcase(m[1]) + options = m[2] + print >> fd, ' def get_%s(self):' % mname + if self.is_pygobject(m[0]): + print >> fd, ' t = _lasso.%s_%s_get(self._cptr)' % ( + klassname, mname) + print >> fd, ' return cptrToPy(t)' + elif m[0] == 'GList*' and options.get('elem_type') not in ('char*', 'xmlNode*'): + print >> fd, ' l = _lasso.%s_%s_get(self._cptr)' % ( + klassname, mname) + print >> fd, ' if not l: return l' + print >> fd, ' return tuple([cptrToPy(x) for x in l])' + elif m[0] == 'GHashTable*': + print >> fd, ' d = _lasso.%s_%s_get(self._cptr)' % ( + klassname, mname) + print >> fd, ' if not d: return d' + if options.get('elem_type') != 'char*': + print >> fd, ' d2 = {}' + print >> fd, ' for k, v in d.items():' + print >> fd, ' d2[k] = cptrToPy(v)' + print >> fd, ' return frozendict(d2)' + else: + print >> fd, ' return frozendict(d)' + else: + print >> fd, ' return _lasso.%s_%s_get(self._cptr)' % ( + klassname, mname) + print >> fd, ' def set_%s(self, value):' % mname + if self.is_pygobject(m[0]): + print >> fd, ' if value is not None:' + print >> fd, ' value = value._cptr' + elif m[0] == 'GList*' and options.get('elem_type') not in ('char*', 'xmlNode*'): + print >> fd, ' if value is not None:' + print >> fd, ' value = tuple([x._cptr for x in value])' + print >> fd, ' _lasso.%s_%s_set(self._cptr, value)' % ( + klassname, mname) + print >> fd, ' %s = property(get_%s, set_%s)' % (mname, mname, mname) + print >> fd, '' + + # first pass on methods, getting accessors + for m in clss.methods: + if not ('_get_' in m.name and len(m.args) == 1): + continue + methods.remove(m) + try: + setter_name = m.name.replace('_get_', '_set_') + setter = [x for x in methods if x.name == setter_name][0] + methods.remove(setter) + except IndexError: + setter = None + if m.rename: + mname = m.rename + if mname.startswith('lasso_'): + mname = mname[6:] + mname = '%s%s' % (mname[0].lower(), mname[1:]) + print >> fd, ' def get_%s(self):' % mname + function_name = m.rename + if function_name.startswith('lasso_'): + function_name = function_name[6:] + else: + mname = m.name + mname = re.match(r'lasso_.*_get_(\w+)', mname).group(1) + mname = utils.format_underscore_as_camelcase(mname) + print >> fd, ' def get_%s(self):' % mname + function_name = m.name[6:] + + if self.is_pygobject(m.return_type): + print >> fd, ' t = _lasso.%s(self._cptr)' % function_name + print >> fd, ' return cptrToPy(t)' + else: + print >> fd, ' return _lasso.%s(self._cptr)' % function_name + + if mname[0] == mname[0].lower() and not m.rename: + # API compatibility with SWIG bindings which didn't have + # accessors for those methods and used totally pythonified + # method name instead, such as getNextProviderId + print >> fd, ' get%s%s = get_%s' % ( + mname[0].upper(), mname[1:], mname) + if setter: + print >> fd, ' def set_%s(self, value):' % mname + print >> fd, ' _lasso.%s(self._cptr, value)' % setter.name[6:] + print >> fd, ' %s = property(get_%s, set_%s)' % (mname, mname, mname) + else: + print >> fd, ' %s = property(get_%s)' % (mname, mname) + print >> fd, '' + + # second pass on methods, real methods + for m in methods: + if m.name.endswith('_new') or m.name.endswith('_new_from_dump') or \ + m.name.endswith('_new_full'): + continue + if not m.name.startswith(method_prefix): + print >> sys.stderr, 'W:', m.name, 'vs', method_prefix + continue + + if m.rename: + mname = m.rename[len(method_prefix):] + function_name = m.rename[6:] + else: + mname = m.name[len(method_prefix):] + function_name = m.name[6:] + py_args = [] + c_args = [] + for o in m.args[1:]: + arg_type, arg_name, arg_options = o + if arg_options.get('optional'): + if arg_options.get('default'): + defval = arg_options.get('default') + if defval.startswith('c:'): # constant + py_args.append('%s = %s' % (arg_name, defval[8:])) + elif defval.startswith('b:'): # boolean + py_args.append('%s = %s' % (arg_name, defval[2:])) + else: + print >> sys.stderr, "E: don't know what to do with %s" % defval + sys.exit(1) + else: + py_args.append('%s = None' % arg_name) + else: + py_args.append(arg_name) + if arg_type in ('char*', 'const char*', 'gchar*', 'const gchar*', 'xmlNode*') or \ + arg_type in ['int', 'gint', 'gboolean', 'const gboolean'] or \ + arg_type in self.binding_data.enums: + c_args.append(arg_name) + else: + c_args.append('%s._cptr' % arg_name) + + if py_args: + py_args = ', ' + ', '.join(py_args) + else: + py_args = '' + if c_args: + c_args = ', ' + ', '.join(c_args) + else: + c_args = '' + + print >> fd, ' def %s(self%s):' % ( + utils.format_underscore_as_camelcase(mname), py_args) + if m.docstring: + print >> fd, " '''" + print >> fd, self.format_docstring(m, mname, 8) + print >> fd, " '''" + if m.return_type in (None, 'void'): + print >> fd, ' _lasso.%s(self._cptr%s)' % ( + function_name, c_args) + elif m.return_type in ('gint', 'int'): + print >> fd, ' rc = _lasso.%s(self._cptr%s)' % ( + function_name, c_args) + print >> fd, ' if rc == 0:' + print >> fd, ' return' + print >> fd, ' raise Error.raise_on_rc(rc)' + elif m.return_type == 'GList*' and self.is_pygobject(m.return_type_qualifier): + print >> fd, ' value = _lasso.%s(self._cptr%s)' % ( + function_name, c_args) + print >> fd, ' if value is not None:' + print >> fd, ' value = tuple([cptrToPy(x) for x in value])' + print >> fd, ' return value' + elif self.is_pygobject(m.return_type): + print >> fd, ' return cptrToPy(_lasso.%s(self._cptr%s))' % ( + function_name, c_args) + else: + print >> fd, ' return _lasso.%s(self._cptr%s)' % ( + function_name, c_args) + print >> fd, '' + + print >> fd, '' + + def format_docstring(self, func, method_name, indent): + if func.args: + first_arg_name = func.args[0][1] + else: + first_arg_name = None + + def format_inlines_sub(s): + type = s.group(1)[0] + var = s.group(1)[1:] + if type == '#': # struct + if var.startswith('Lasso'): + return 'L{%s}' % var[5:] + elif type == '%': # %TRUE, %FALSE + if var == 'TRUE': + return 'True' + if var == 'FALSE': + return 'False' + print >> sys.stderr, 'W: unknown docstring thingie: %s' % s.group(1) + elif type == '@': + if var == first_arg_name: + var = 'self' + return 'C{%s}' % var + return s.group(1) + + regex = re.compile(r'([\#%@]\w+)', re.DOTALL) + + def format_inline(s): + s = regex.sub(format_inlines_sub, s) + return s.replace('NULL', 'None') + + docstring = func.docstring + s = [] + + if docstring.description: + for paragraph in docstring.description.split('\n\n'): + if '<itemizedlist>' in paragraph: + before, after = paragraph.split('<itemizedlist>' ,1) + if before: + s.append('\n'.join(textwrap.wrap( + format_inline(before), 70))) + + # remove tags + after = after.replace('<itemizedlist>', '') + after = after.replace('</itemizedlist>', '') + + for listitem in after.split('<listitem><para>'): + listitem = listitem.replace('</para></listitem>', '').strip() + s.append('\n'.join(textwrap.wrap( + format_inline(listitem), 70, + initial_indent = ' - ', + subsequent_indent = ' '))) + s.append('\n\n') + + else: + s.append('\n'.join(textwrap.wrap( + format_inline(paragraph), 70))) + s.append('\n\n') + + for param in docstring.parameters: + s.append('\n'.join(textwrap.wrap( + format_inline(param[1]), 70, + initial_indent = '@param %s: ' % param[0], + subsequent_indent = 4*' '))) + s.append('\n') + if docstring.return_value: + rv = docstring.return_value + exceptions_instead = ['0 on success; or a negative value otherwise.', + '0 on success; a negative value if an error occured.', + '0 on success; another value if an error occured.'] + if not rv in exceptions_instead: + owner_info = ['This xmlnode must be freed by caller.', + 'The string must be freed by the caller.', + 'It must be freed by the caller.', + 'This string must be freed by the caller.'] + for o_i in owner_info: + rv = rv.replace(o_i, '') + s.append('\n'.join(textwrap.wrap( + format_inline(rv), 70, + initial_indent = '@return: ', + subsequent_indent = 4*' '))) + s.append('\n') + + + s[-1] = s[-1].rstrip() # remove trailing newline from last line + + return '\n'.join([(indent*' ')+x for x in ''.join(s).splitlines()]) + + + def generate_functions(self, fd): + for m in self.binding_data.functions: + if m.name.endswith('_new') or '_new_' in m.name: + continue + if m.rename: + pname = m.rename + name = m.rename + if name.startswith('lasso_'): + name = name[6:] + pname = utils.format_as_camelcase(name) + else: + name = m.name[6:] + pname = utils.format_as_camelcase(name) + print >> fd, '%s = _lasso.%s' % (pname, name) + + + def generate_wrapper(self, fd): + print >> fd, open('wrapper_top.c').read() + for h in self.binding_data.headers: + print >> fd, '#include <%s>' % h + print >> fd, '' + + self.generate_constants_wrapper(fd) + + self.wrapper_list = [] + for m in self.binding_data.functions: + self.generate_function_wrapper(m, fd) + for c in self.binding_data.structs: + self.generate_member_wrapper(c, fd) + for m in c.methods: + self.generate_function_wrapper(m, fd) + self.generate_wrapper_list(fd) + print >> fd, open('wrapper_bottom.c').read() + + def generate_constants_wrapper(self, fd): + print >> fd, '''static void +register_constants(PyObject *d) +{ + PyObject *obj; +''' + for c in self.binding_data.constants: + if c[0] == 'i': + print >> fd, ' obj = PyInt_FromLong(%s);' % c[1] + elif c[0] == 's': + print >> fd, ' obj = PyString_FromString(%s);' % c[1] + elif c[0] == 'b': + print >> fd, '''\ +#ifdef %s + obj = Py_True; +#else + obj = Py_False; +#endif''' % c[1] + else: + print >> sys.stderr, 'E: unknown constant type: %r' % c[0] + print >> fd, ' PyDict_SetItemString(d, "%s", obj);' % c[1][6:] + print >> fd, ' Py_DECREF(obj);' + print >> fd, '}' + print >> fd, '' + + + def generate_member_wrapper(self, c, fd): + klassname = c.name + for m in c.members: + mname = utils.format_as_camelcase(m[1]) + # getter + print >> fd, '''static PyObject* +%s_%s_get(PyObject *self, PyObject *args) +{''' % (klassname[5:], mname) + self.wrapper_list.append('%s_%s_get' % (klassname[5:], mname)) + + ftype = m[0] + if ftype in ('char*', 'const char*', 'gchar*', 'const gchar*'): + ftype = 'char*' + print >> fd, ' %s return_value;' % ftype + print >> fd, ' PyObject* return_pyvalue;' + print >> fd, ' PyGObjectPtr* cvt_this;' + print >> fd, ' %s* this;' % klassname + print >> fd, '' + print >> fd, ' if (! PyArg_ParseTuple(args, "O", &cvt_this)) return NULL;' + print >> fd, ' this = (%s*)cvt_this->obj;' % klassname + + if self.is_pygobject(ftype): + print >> fd, ' return_value = this->%s;' % m[1]; + elif ftype in ('char*',): + print >> fd, ' return_value = g_strdup(this->%s);' % m[1] + else: + print >> fd, ' return_value = this->%s;' % m[1]; + + self.return_value(fd, ftype, m[2]) + + print >> fd, ' return return_pyvalue;' + print >> fd, '}' + print >> fd, '' + + # setter + print >> fd, '''static PyObject* +%s_%s_set(PyObject *self, PyObject *args) +{''' % (klassname[5:], mname) + self.wrapper_list.append('%s_%s_set' % (klassname[5:], mname)) + + print >> fd, ' PyGObjectPtr* cvt_this;' + print >> fd, ' %s* this;' % klassname + arg_type = m[0] + # Determine type class + if m[0] in ('char*', 'const char*', 'gchar*', 'const gchar*'): + arg_type = arg_type.replace('const ', '') + parse_format = 'z' + parse_arg = '&value' + print >> fd, ' %s value;' % arg_type + elif arg_type in ['int', 'gint', 'gboolean', 'const gboolean'] + self.binding_data.enums: + parse_format = 'i' + parse_arg = '&value' + print >> fd, ' %s value;' % arg_type + elif arg_type in ('GList*','GHashTable*', 'xmlNode*'): + parse_format = 'O' + print >> fd, ' PyObject *cvt_value;' + parse_arg = '&cvt_value' + else: + parse_format = 'O' + print >> fd, ' PyGObjectPtr *cvt_value;' + parse_arg = '&cvt_value' + # Get GObject + print >> fd, ' if (! PyArg_ParseTuple(args, "O%s", &cvt_this, %s)) return NULL;' % ( + parse_format, parse_arg) + print >> fd, ' this = (%s*)cvt_this->obj;' % klassname + # Change value + if parse_format == 'i': + print >> fd, ' this->%s = value;' % m[1] + elif parse_format in ('s', 'z'): + print >> fd, ' if (this->%s) g_free(this->%s);' % (m[1], m[1]) + print >> fd, ' this->%s = g_strdup(value);' % m[1] + elif parse_format == 'O' and arg_type == 'GList*': + elem_type = m[2].get('elem_type') + if elem_type == 'char*': + print >> fd, ' set_list_of_strings(&this->%s, cvt_value);' % m[1] + elif elem_type == 'xmlNode*': + print >> fd, ' set_list_of_xml_nodes(&this->%s, cvt_value);' % m[1] + else: + print >> fd, ' set_list_of_pygobject(&this->%s, cvt_value);' % m[1] + elif parse_format == 'O' and arg_type == 'GHashTable*': + print >> fd, ' set_hashtable_of_pygobject(this->%s, cvt_value);' % m[1] + elif parse_format == 'O' and arg_type == 'xmlNode*': + print >> fd, ' if (this->%s) xmlFreeNode(this->%s);' % (m[1], m[1]) + print >> fd, ' this->%s = get_xml_node_from_pystring(cvt_value);' % m[1] + elif parse_format == 'O': + print >> fd, ' set_object_field((GObject**)&this->%s, cvt_value);' % m[1] + print >> fd, ' return noneRef();' + print >> fd, '}' + print >> fd, '' + + + def return_value(self, fd, vtype, options): + if vtype == 'gboolean': + print >> fd, ' if (return_value) {' + print >> fd, ' Py_INCREF(Py_True);' + print >> fd, ' return_pyvalue = Py_True;' + print >> fd, ' } else {' + print >> fd, ' Py_INCREF(Py_False);' + print >> fd, ' return_pyvalue = Py_False;' + print >> fd, ' }' + elif vtype in ['int', 'gint'] + self.binding_data.enums: + print >> fd, ' return_pyvalue = PyInt_FromLong(return_value);' + elif vtype in ('char*', 'gchar*'): + print >> fd, ' if (return_value) {' + print >> fd, ' return_pyvalue = PyString_FromString(return_value);' + print >> fd, ' g_free(return_value);' + print >> fd, ' } else {' + print >> fd, ' return_pyvalue = noneRef();' + print >> fd, ' }' + elif vtype in ('const char*', 'const gchar*'): + print >> fd, ' if (return_value) {' + print >> fd, ' return_pyvalue = PyString_FromString(return_value);' + print >> fd, ' } else {' + print >> fd, ' return_pyvalue = noneRef();' + print >> fd, ' }' + elif vtype in ('const GList*', 'GList*',): + elem_type = options.get('elem_type') + if elem_type == 'char*': + print >> fd, ' return_pyvalue = get_list_of_strings(return_value);' + elif elem_type == 'xmlNode*': + print >> fd, ' return_pyvalue = get_list_of_xml_nodes(return_value);' + else: + print >> fd, ' return_pyvalue = get_list_of_pygobject(return_value);' + elif vtype in ('GHashTable*',): + elem_type = options.get('elem_type') + if elem_type == 'char*': + print >> fd, ' return_pyvalue = get_dict_from_hashtable_of_strings(return_value);' + else: + print >> fd, ' return_pyvalue = get_dict_from_hashtable_of_objects(return_value);' + elif vtype == 'xmlNode*': + # convert xmlNode* to strings + print >> fd, ' if (return_value) {' + print >> fd, ' return_pyvalue = get_pystring_from_xml_node(return_value);' + print >> fd, ' } else {' + print >> fd, ' return_pyvalue = noneRef();' + print >> fd, ' }' + else: + # return a PyGObjectPtr (wrapper around GObject) + print >> fd, '''\ + if (return_value) { + return_pyvalue = PyGObjectPtr_New(G_OBJECT(return_value)); + } else { + return_pyvalue = noneRef(); + } +''' + + def generate_function_wrapper(self, m, fd): + if m.rename: + name = m.rename + if name.startswith('lasso_'): + name = name[6:] + else: + name = m.name[6:] + self.wrapper_list.append(name) + print >> fd, '''static PyObject* +%s(PyObject *self, PyObject *args) +{''' % name + parse_tuple_format = [] + parse_tuple_args = [] + for arg in m.args: + arg_type, arg_name, arg_options = arg + if arg_type in ('char*', 'const char*', 'gchar*', 'const gchar*'): + arg_type = arg_type.replace('const ', '') + if arg_options.get('optional'): + if not '|' in parse_tuple_format: + parse_tuple_format.append('|') + parse_tuple_format.append('z') + else: + parse_tuple_format.append('s') + parse_tuple_args.append('&%s' % arg_name) + print >> fd, ' %s %s = NULL;' % (arg[0], arg[1]) + elif arg_type in ['int', 'gint', 'gboolean', 'const gboolean'] + self.binding_data.enums: + if arg_options.get('optional'): + if not '|' in parse_tuple_format: + parse_tuple_format.append('|') + parse_tuple_format.append('i') + parse_tuple_args.append('&%s' % arg_name) + if arg_options.get('default'): + defval = arg_options.get('default') + if defval.startswith('b:'): + defval = defval[2:].upper() + else: + defval = defval[2:] + print >> fd, ' %s %s = %s;' % (arg[0], arg[1], defval) + else: + print >> fd, ' %s %s;' % (arg[0], arg[1]) + elif arg_type in ('GList*', 'xmlNode*'): + parse_tuple_format.append('O') + parse_tuple_args.append('&cvt_%s' % arg_name) + print >> fd, ' %s %s = NULL;' % (arg[0], arg[1]) + print >> fd, ' PyObject *cvt_%s = NULL;' % arg_name + else: + parse_tuple_format.append('O') + parse_tuple_args.append('&cvt_%s' % arg_name) + print >> fd, ' %s %s = NULL;' % (arg[0], arg[1]) + print >> fd, ' PyGObjectPtr *cvt_%s = NULL;' % arg_name + + if m.return_type: + print >> fd, ' %s return_value;' % m.return_type + print >> fd, ' PyObject* return_pyvalue;' + print >> fd, '' + + parse_tuple_args = ', '.join(parse_tuple_args) + if parse_tuple_args: + parse_tuple_args = ', ' + parse_tuple_args + + print >> fd, ' if (! PyArg_ParseTuple(args, "%s"%s)) return NULL;' % ( + ''.join(parse_tuple_format), parse_tuple_args) + + for f, arg in zip(parse_tuple_format, m.args): + if arg[0] == 'GList*': + qualifier = arg[2].get('elem_type') + if qualifier == 'char*': + print >> fd, ' set_list_of_strings(&%s, cvt_%s);' % (arg[1], arg[1]) + elif qualifier == 'xmlNode*': + print >> fd, ' set_list_of_xml_nodes(&%s, cvt_%s);' % (arg[1], arg[1]) + elif qualifier == 'LassoNode': + print >> fd, ' set_list_of_pygobject(&%s, cvt_%s);' % (arg[1], arg[1]) + else: + print >> sys.stderr, 'E: unqualified GList argument in', name + elif arg[0] == 'xmlNode*': + print >> fd, ' %s = get_xml_node_from_pystring(cvt_%s);' % (arg[1], arg[1]) + elif f == 'O': + print >> fd, ' %s = (%s)cvt_%s->obj;' % (arg[1], arg[0], arg[1]) + + if m.return_type: + print >> fd, ' return_value =', + if 'new' in m.name: + print >> fd, '(%s)' % m.return_type, + print >> fd, '%s(%s);' % (m.name, ', '.join([x[1] for x in m.args])) + + for f, arg in zip(parse_tuple_format, m.args): + if arg[0] == 'GList*': + qualifier = arg[2].get('elem_type') + if qualifier == 'char*': + print >> fd, ' free_list(&%s, (GFunc)g_free);' % arg[1] + elif qualifier == 'xmlNode*': + print >> fd, ' free_list(&%s, (GFunc)xmlFreeNode);' % arg[1] + elif qualifier == 'LassoNode': + print >> fd, ' free_list(&%s, (GFunc)g_object_unref);' % arg[1] + + if not m.return_type: + print >> fd, ' return noneRef();' + else: + # Constructor so decrease refcount (it was incremented by PyGObjectPtr_New called + # in self.return_value + self.return_value(fd, m.return_type, {'elem_type': m.return_type_qualifier}) + if m.return_owner and self.is_pygobject(m.return_type): + print >> fd, ' if (return_value) g_object_unref(return_value);' + print >> fd, ' return return_pyvalue;' + print >> fd, '}' + print >> fd, '' + + def generate_wrapper_list(self, fd): + print >> fd, ''' +static PyMethodDef lasso_methods[] = {''' + for m in self.wrapper_list: + print >> fd, ' {"%s", %s, METH_VARARGS, NULL},' % (m, m) + print >> fd, ' {NULL, NULL, 0, NULL}' + print >> fd, '};' + print >> fd, '' + diff --git a/bindings/python/wrapper_bottom.c b/bindings/python/wrapper_bottom.c new file mode 100644 index 00000000..51de44b0 --- /dev/null +++ b/bindings/python/wrapper_bottom.c @@ -0,0 +1,18 @@ +PyMODINIT_FUNC +init_lasso(void) +{ + PyObject *m, *d; + + if (PyType_Ready(&PyGObjectPtrType) < 0) + return; + + m = Py_InitModule3("_lasso", lasso_methods, "_lasso wrapper module"); + d = PyModule_GetDict(m); + register_constants(d); + + lasso_wrapper_key = g_quark_from_static_string("PyLasso::wrapper"); + + Py_INCREF(&PyGObjectPtrType); + PyModule_AddObject(m, "PyGObjectPtr", (PyObject *)&PyGObjectPtrType); +} + diff --git a/bindings/python/wrapper_top.c b/bindings/python/wrapper_top.c new file mode 100644 index 00000000..11d83efd --- /dev/null +++ b/bindings/python/wrapper_top.c @@ -0,0 +1,502 @@ +#include <Python.h> +#include <structmember.h> +#include <lasso/lasso.h> +#include <config.h> +#include "../ghashtable.h" + +GQuark lasso_wrapper_key; + +PyMODINIT_FUNC init_lasso(void); +static PyObject* get_pystring_from_xml_node(xmlNode *xmlnode); +static xmlNode* get_xml_node_from_pystring(PyObject *string); +static PyObject* get_dict_from_hashtable_of_objects(GHashTable *value); +static PyObject* PyGObjectPtr_New(GObject *obj); +static void set_hashtable_of_pygobject(GHashTable *a_hash, PyObject *dict); +static void set_list_of_strings(GList **a_list, PyObject *seq); +static void set_list_of_xml_nodes(GList **a_list, PyObject *seq); +static void set_list_of_pygobject(GList **a_list, PyObject *seq); +static PyObject *get_list_of_strings(const GList *a_list); +static PyObject *get_list_of_xml_nodes(const GList *a_list); +static PyObject *get_list_of_pygobject(const GList *a_list); +static gboolean valid_seq(PyObject *seq); +static void free_list(GList **a_list, GFunc free_help); + +typedef struct { + PyObject_HEAD + GObject *obj; + PyObject *typename; +} PyGObjectPtr; +static PyTypeObject PyGObjectPtrType; + +/* utility functions */ +static PyObject * +noneRef() { + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* +get_dict_from_hashtable_of_objects(GHashTable *value) +{ + GList *keys; + PyObject *dict,*proxy; + GObject *item_value; + PyObject *item; + + dict = PyDict_New(); + + keys = g_hash_table_get_keys(value); + for (; keys; keys = g_list_next(keys)) { + item_value = g_hash_table_lookup(value, keys->data); + if (item_value) { + item = PyGObjectPtr_New(G_OBJECT(item_value)); + PyDict_SetItemString(dict, (char*)keys->data, item); + Py_DECREF(item); + } else { + PyErr_Warn(PyExc_RuntimeWarning, "hashtable contains a null value"); + } + } + g_list_free(keys); + + proxy = PyDictProxy_New(dict); + Py_DECREF(dict); + return proxy; +} + +static PyObject* +get_pystring_from_xml_node(xmlNode *xmlnode) +{ + xmlOutputBufferPtr buf; + PyObject *pystring = NULL; + + if (xmlnode == NULL) { + return NULL; + } + + buf = xmlAllocOutputBuffer(NULL); + if (buf == NULL) { + pystring = NULL; + } else { + xmlNodeDumpOutput(buf, NULL, xmlnode, 0, 1, NULL); + xmlOutputBufferFlush(buf); + if (buf->conv == NULL) { + pystring = PyString_FromString((char*)buf->buffer->content); + } else { + pystring = PyString_FromString((char*)buf->conv->content); + } + xmlOutputBufferClose(buf); + } + + return pystring; +} + +static gboolean +valid_seq(PyObject *seq) { + if (! seq || ( seq != Py_None && ! PyTuple_Check(seq))) { + PyErr_SetString(PyExc_TypeError, "value should be tuple"); + return 0; + } + return 1; +} + +static void +free_list(GList **a_list, GFunc free_help) { + if (*a_list) { + g_list_foreach(*a_list, free_help, NULL); + g_list_free(*a_list); + } +} + +/** Remove all elements from a_hash and replace them with + * the key-values pairs from the python dict. + * Increase reference of new values before removeing + * values from the hash, so if there are somme common + * values with RefCoun = 1 they won't be deallocated. + * */ +static void +set_hashtable_of_pygobject(GHashTable *a_hash, PyObject *dict) { + PyObject *key, *value; + int i; + + if (! a_hash) { + PyErr_SetString(PyExc_TypeError, "hashtable does not exist"); + return; + } + if (dict != Py_None && ! PyDict_Check(dict)) { + PyErr_SetString(PyExc_TypeError, "value should be a frozen dict"); + return; + } + i = 0; + // Increase ref count of common object between old and new + // value of the hashtable + while (PyDict_Next(dict, &i, &key, &value)) { + if (! PyString_Check(key) || ! PyObject_TypeCheck(value, &PyGObjectPtrType)) + { + PyErr_SetString(PyExc_TypeError, + "value should be a dict," + "with string keys" + "and GObjectPtr values"); + goto failure; + } + g_object_ref(((PyGObjectPtr*)value)->obj); + } + g_hash_table_remove_all (a_hash); + while (PyDict_Next(dict, &i, &key, &value)) { + char *ckey = g_strdup(PyString_AsString(key)); + g_hash_table_replace (a_hash, ckey, ((PyGObjectPtr*)value)->obj); + } + return; +failure: + i = 0; + while (PyDict_Next(dict, &i, &key, &value)) { + if (! PyString_Check(key) || ! PyObject_TypeCheck(value, &PyGObjectPtrType)) + break; + g_object_unref((PyGObjectPtr*)value); + } +} + +/** Set the GList* pointer, pointed by a_list, to a pointer on a new GList + * created by converting the python seq into a GList of char*. + */ +static void +set_list_of_strings(GList **a_list, PyObject *seq) { + GList *list = NULL; + int l = 0,i; + + g_return_if_fail(valid_seq(seq)); + if (seq != Py_None) { + l = PySequence_Length(seq); + } + for (i=0; i<l; i++) { + PyObject *pystr = PySequence_Fast_GET_ITEM(seq, i); + if (! PyString_Check(pystr)) { + PyErr_SetString(PyExc_TypeError, + "value should be a tuple of strings"); + goto failure; + } + list = g_list_append(list, g_strdup(PyString_AsString(pystr))); + } + free_list(a_list, (GFunc)g_free); + *a_list = list; + return; +failure: + free_list(&list, (GFunc)g_free); +} + +/** Set the GList* pointer, pointed by a_list, to a pointer on a new GList + * created by converting the python seq into a GList of xmlNode*. + */ +static void +set_list_of_xml_nodes(GList **a_list, PyObject *seq) { + GList *list = NULL; + int l = 0,i; + + g_return_if_fail(valid_seq(seq)); + if (seq != Py_None) { + l = PySequence_Length(seq); + } + for (i=0; i<l; i++) { + PyObject *item = PySequence_Fast_GET_ITEM(seq, i); + xmlNode *item_node; + if (! PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "value should be a tuple of strings"); + goto failure; + } + item_node = get_xml_node_from_pystring(item); + list = g_list_append(list, item_node); + } + free_list(a_list, (GFunc)xmlFreeNode); + *a_list = list; + return; +failure: + free_list(&list, (GFunc)xmlFreeNode); +} + +/** Set the GList* pointer, pointed by a_list, to a pointer on a new GList + * created by converting the python seq into a GList of GObject*. + */ +static void +set_list_of_pygobject(GList **a_list, PyObject *seq) { + GList *list = NULL; + int l = 0,i; + + g_return_if_fail(valid_seq(seq)); + if (seq != Py_None) { + l = PySequence_Length(seq); + } + for (i=0; i<l; i++) { + PyObject *item = PySequence_Fast_GET_ITEM(seq, i); + GObject *gobject; + if (! PyObject_TypeCheck(item, &PyGObjectPtrType)) { + PyErr_SetString(PyExc_TypeError, + "value should be a tuple of PyGobject"); + goto failure; + } + gobject = g_object_ref(((PyGObjectPtr*)item)->obj); + list = g_list_append(list, gobject); + } + free_list(a_list, (GFunc)g_object_unref); + *a_list = list; + return; +failure: + free_list(&list, (GFunc)g_object_unref); +} + +static xmlNode* +get_xml_node_from_pystring(PyObject *string) { + xmlDoc *doc; + xmlNode *node; + + doc = xmlReadDoc((xmlChar*)PyString_AsString(string), NULL, NULL, XML_PARSE_NONET); + node = xmlDocGetRootElement(doc); + if (node != NULL) { + node = xmlCopyNode(node, 1); + } + xmlFreeDoc(doc); + + return node; +} +/** Return a tuple containing the string contained in a_list */ +static PyObject * +get_list_of_strings(const GList *a_list) { + PyObject *a_tuple = NULL; + int i = 0; + + if (! a_list) { + return noneRef(); + } + /* Cast because g_list_length does not take const but is a const function */ + a_tuple = PyTuple_New(g_list_length((GList*)a_list)); + if (! a_tuple) + goto failure; + while (a_list) { + if (a_list->data) { + PyObject *str = PyString_FromString((const char*)a_list->data); + if (!str) { + goto failure; + } + PyTuple_SetItem(a_tuple, i, str); + i++; + } else { + PyErr_Warn(PyExc_RuntimeWarning, + "list contains a NULL value"); + } + a_list = a_list->next; + } + if (_PyTuple_Resize(&a_tuple, i)) + goto failure; + return a_tuple; +failure: + PyErr_SetString(PyExc_TypeError, "Allocation problem in get_list_of_strings"); + Py_XDECREF(a_tuple); + return noneRef(); +} + +static PyObject * +get_list_of_xml_nodes(const GList *a_list) { + PyObject *a_tuple = NULL; + int i = 0; + + if (! a_list) { + return noneRef(); + } + /* Cast because g_list_length does not take const but is a const function */ + a_tuple = PyTuple_New(g_list_length((GList*)a_list)); + if (! a_tuple) + goto failure; + while (a_list) { + if (a_list->data) { + PyObject *str = get_pystring_from_xml_node((xmlNode*)a_list->data); + if (str) { + PyTuple_SetItem(a_tuple, i, str); + i++; + } else { + PyErr_Warn(PyExc_RuntimeWarning, + "could not convert an xmlNode to a string"); + } + } else { + PyErr_Warn(PyExc_RuntimeWarning, + "list contains a NULL value"); + } + a_list = a_list->next; + } + if (_PyTuple_Resize(&a_tuple, i)) + goto failure; + return a_tuple; +failure: + PyErr_SetString(PyExc_TypeError, "Allocation problem in get_list_of_strings"); + Py_XDECREF(a_tuple); + return noneRef(); +} + +static PyObject * +get_list_of_pygobject(const GList *a_list) { + PyObject *a_tuple = NULL; + int i = 0; + + if (! a_list) { + return noneRef(); + } + /* Cast because g_list_length does not take const but is a const function */ + a_tuple = PyTuple_New(g_list_length((GList*)a_list)); + if (! a_tuple) + goto failure; + while (a_list) { + if (a_list->data) { + PyObject *pygobject; + pygobject = PyGObjectPtr_New((GObject*)a_list->data); + if (pygobject) { + PyTuple_SetItem(a_tuple, i, pygobject); + i++; + } else { + PyErr_Warn(PyExc_RuntimeWarning, + "could not convert a GObject to a PyGobject"); + } + } else { + PyErr_Warn(PyExc_RuntimeWarning, + "list contains a NULL value"); + } + a_list = a_list->next; + } + if (_PyTuple_Resize(&a_tuple, i)) + goto failure; + return a_tuple; +failure: + PyErr_SetString(PyExc_TypeError, "Allocation problem in get_list_of_strings"); + Py_XDECREF(a_tuple); + return noneRef(); +} + +/* wrapper around GObject */ + + + +static void +PyGObjectPtr_dealloc(PyGObjectPtr *self) +{ +#ifdef LASSO_DEBUG + fprintf(stderr, "dealloc (%p ptr to %p (type:%s, rc:%d))\n", + self, self->obj, + G_OBJECT_TYPE_NAME(self->obj), + self->obj->ref_count); +#endif + g_object_set_qdata_full(self->obj, lasso_wrapper_key, NULL, NULL); + g_object_unref(self->obj); + Py_XDECREF(self->typename); + self->ob_type->tp_free((PyObject*)self); +} + +static int +startswith(const char *string, const char *prefix) +{ + return strncmp(string, prefix, strlen(prefix)) == 0; +} + +static PyObject* +PyGObjectPtr_New(GObject *obj) +{ + PyGObjectPtr *self; + + if (obj == NULL) { + return noneRef(); + } + + self = (PyGObjectPtr*)g_object_get_qdata(obj, lasso_wrapper_key); + if (self != NULL) { + Py_INCREF(self); + } else { + const char *typename; + + self = (PyGObjectPtr*)PyObject_NEW(PyGObjectPtr, &PyGObjectPtrType); + g_object_set_qdata_full(obj, lasso_wrapper_key, self, NULL); + self->obj = g_object_ref(obj); + typename = G_OBJECT_TYPE_NAME(obj); + /* XXX: Fixme !!!!! */ + if (startswith(typename, "LassoDgme")) { + self->typename = PyString_FromString(typename+9); + } else if (startswith(typename, "Lasso")) { + self->typename = PyString_FromString(typename+5); + } else { + self->typename = PyString_FromString(typename); + } + } + return (PyObject*)self; +} + +static PyObject * +PyGObjectPtr_repr(PyGObjectPtr *obj) +{ + return PyString_FromFormat("<PyGObjectPtr to %p (type: %s, refcount: %d)>", + obj->obj, + G_OBJECT_TYPE_NAME(obj->obj), + obj->obj->ref_count); +} + +static PyMemberDef PyGObjectPtr_members[] = { + {"typename", T_OBJECT, offsetof(PyGObjectPtr, typename), 0, "typename"}, + {NULL} +}; + +static PyObject* +PyGObjectPtr_get_refcount(PyGObjectPtr *self, void *closure) +{ + PyObject *refcount; + + refcount = PyInt_FromLong(self->obj->ref_count); + Py_INCREF(refcount); + return refcount; +} + +static PyGetSetDef PyGObjectPtr_getseters[] = { + {"refcount", (getter)PyGObjectPtr_get_refcount, NULL, + "reference count of intern GObject*", NULL}, + {NULL} /* Sentinel */ +}; + + +static PyTypeObject PyGObjectPtrType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_lasso.PyGObjectPtr", /* tp_name */ + sizeof(PyGObjectPtr), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PyGObjectPtr_dealloc, /* tp_dealloc */ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)PyGObjectPtr_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "PyGObjectPtr objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + PyGObjectPtr_members, /* tp_members */ + PyGObjectPtr_getseters, /* tp_getset */ +}; + +static void +set_object_field(GObject **a_gobject_ptr, PyGObjectPtr *a_pygobject) { + if (*a_gobject_ptr) { + g_object_unref(*a_gobject_ptr); + } + if ((PyObject*)a_pygobject == Py_None) { + *a_gobject_ptr = NULL; + } else { + *a_gobject_ptr = g_object_ref(a_pygobject->obj); + } +} |
