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/lang.py | |
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/lang.py')
-rw-r--r-- | bindings/python/lang.py | 887 |
1 files changed, 887 insertions, 0 deletions
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, '' + |