diff options
author | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2010-01-04 09:13:36 +0000 |
---|---|---|
committer | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2010-01-04 09:13:36 +0000 |
commit | 5224c7cf675d6c8b2df9b3f4b43f8cd8d4eb8184 (patch) | |
tree | fc571c8d011bd0b73d932601e0b026f338e5d675 /bindings/python/lang.py | |
parent | 42062ff986a344f3f33a4465e106fede10aeaa6a (diff) | |
download | lasso-5224c7cf675d6c8b2df9b3f4b43f8cd8d4eb8184.tar.gz lasso-5224c7cf675d6c8b2df9b3f4b43f8cd8d4eb8184.tar.xz lasso-5224c7cf675d6c8b2df9b3f4b43f8cd8d4eb8184.zip |
Bindings: make the binding infrastructure understand GObject-introspections annotations
* bindings/bindings.py
* bindings/utils.py:
add convenience function to treat arguments tuple:
(type,name,{annotations}).
introduce new argument options, fix that arguments are 3-tuple of the
form (type,name,annotations), where annotations is a dictionary.
Key of this dictionnary can be:
- optional, wheter the argument is necessary, it means it has a
default value.
- out, means that the pointer is a pointer of pointer, for bindings
that can return exceptions, it will be returned instead of the
integer error code, the only way to access error codes will be
exceptions.
- element-type, contained type of a list or an array,
- key-type, value-type, type of respectively the key and value of a
GHashTable.
- transfer, wheter a the callee(for arguments)/caller(for return
values) owns the values passed, it can be none,container(if the
callee/caller only owns the container not the contained value) or
full.
doc.parameters is now a 3-tuple of (attribute-name,
attribute-description, attribute-annotations) where
attribute-annotations is a string of the form '(option1)(option2
option-arguments) etc.'.
- add predicates for xml, list and time_t values. improve predicates
for cstring and const modifier.
* bindings/overrides.xml:
'out' arguments are not well supported for java, so skip functions
using them.
* bindings/java/lang.py bindings/php5/php_code.py
bindings/php5/wrapper_source.py bindings/python/lang.py:
- update language specifig binding generators for handling new
annotations.
- improve python method declaration, handle optional arguments with
default values, factorize this chode in two methods,
get_python_arg_decl and defval_to_python_value.
* bindings/python/tests/Makefile.am
bindings/python/tests/idwsf1_tests.py
bindings/python/tests/idwsf2_tests.py:
make test work with out of source build dir.
Diffstat (limited to 'bindings/python/lang.py')
-rw-r--r-- | bindings/python/lang.py | 211 |
1 files changed, 123 insertions, 88 deletions
diff --git a/bindings/python/lang.py b/bindings/python/lang.py index 57d67273..ff06b746 100644 --- a/bindings/python/lang.py +++ b/bindings/python/lang.py @@ -23,7 +23,25 @@ import os import sys import re import textwrap -import utils +from utils import * + +def defval_to_python_value(defval): + if defval is None: + return 'None' + if defval.startswith('b:'): + if defval[2:].lower() == 'true': + return 'True' + if defval[2:].lower() == 'false': + return 'False' + if defval.startswith('c:'): + return defval[8:] + raise Exception('Could not convert %s to python value' % defval) + +def get_python_arg_decl(arg): + if is_optional(arg): + return '%s = %s' % (arg_name(arg), defval_to_python_value(arg_default(arg))) + else: + return arg_name(arg) class Binding: def __init__(self, binding_data): @@ -31,14 +49,7 @@ class Binding: self.src_dir = os.path.dirname(__file__) 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 ['guchar*', 'guchar*', 'char*', 'gchar*', - 'GList*', 'GHashTable*', - 'int', 'gint', 'gboolean', 'xmlNode*'] + self.binding_data.enums - else: - return False + return t and is_object((t,'',{})) and t not in self.binding_data.enums def generate(self): fd = open('lasso.py', 'w') @@ -254,17 +265,14 @@ if WSF_SUPPORT: methods = clss.methods[:] # constructor(s) - method_prefix = 'lasso_' + utils.format_as_underscored(klassname) + '_' + method_prefix = 'lasso_' + 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) + py_args.append(get_python_arg_decl(o)) if self.is_pygobject(arg_type): c_args.append('%s._cptr' % arg_name) @@ -284,15 +292,12 @@ if WSF_SUPPORT: 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):]) + constructor_name = 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) + py_args.append(get_python_arg_decl(o)) if self.is_pygobject(arg_type): c_args.append('%s._cptr' % arg_name) @@ -311,7 +316,7 @@ if WSF_SUPPORT: # create properties for members for m in clss.members: - mname = utils.format_as_camelcase(m[1]) + mname = format_as_camelcase(m[1]) options = m[2] print >> fd, ' def get_%s(self):' % mname if self.is_pygobject(m[0]): @@ -372,7 +377,7 @@ if WSF_SUPPORT: else: mname = m.name mname = re.match(r'lasso_.*_get_(\w+)', mname).group(1) - mname = utils.format_underscore_as_camelcase(mname) + mname = format_underscore_as_camelcase(mname) print >> fd, ' def get_%s(self):' % mname function_name = m.name[6:] @@ -413,25 +418,21 @@ if WSF_SUPPORT: function_name = m.name[6:] py_args = [] c_args = [] + outarg = None 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) + if is_out(o): + assert not outarg + outarg = o + outvar = '_%s_out' % arg_name else: - py_args.append(arg_name) - if arg_type in ('char*', 'const char*', 'guchar*', 'const guchar*', 'gchar*', 'const gchar*', 'xmlNode*') or \ + py_args.append(get_python_arg_decl(o)) + + if is_out(o): + c_args.append(outvar) + elif arg_type in ('char*', 'const char*', 'guchar*', 'const guchar*', 'gchar*', 'const gchar*', 'xmlNode*') or \ arg_type in ['int', 'gint', 'gboolean', 'const gboolean'] or \ - arg_type in self.binding_data.enums: + arg_type in self.binding_data.enums or is_time_t_pointer(o): c_args.append(arg_name) else: c_args.append('%s._cptr' % arg_name) @@ -446,32 +447,39 @@ if WSF_SUPPORT: c_args = '' print >> fd, ' def %s(self%s):' % ( - utils.format_underscore_as_camelcase(mname), py_args) + 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'): + + if outarg: + print >> fd, " %s = list((None,))" % outvar + return_type = m.return_type + return_type_qualifier = m.return_type_qualifier + assert is_int(make_arg(return_type),self.binding_data) or not outarg + if 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, ' if rc != 0:' + print >> fd, ' raise Error.raise_on_rc(rc)' + elif return_type in (None, 'void'): + print >> fd, ' _lasso.%s(self._cptr%s)' % ( + function_name, c_args) + elif return_type == 'GList*' and self.is_pygobject(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): + elif self.is_pygobject(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) + if outarg: + print >> fd, ' return %s[0]' % outvar print >> fd, '' print >> fd, '' @@ -573,10 +581,10 @@ if WSF_SUPPORT: name = m.rename if name.startswith('lasso_'): name = name[6:] - pname = utils.format_as_camelcase(name) + pname = format_as_camelcase(name) else: name = m.name[6:] - pname = utils.format_as_camelcase(name) + pname = format_as_camelcase(name) print >> fd, '%s = _lasso.%s' % (pname, name) @@ -627,7 +635,7 @@ register_constants(PyObject *d) def generate_member_wrapper(self, c, fd): klassname = c.name for m in c.members: - mname = utils.format_as_camelcase(m[1]) + mname = format_as_camelcase(m[1]) # getter print >> fd, '''static PyObject* %s_%s_get(G_GNUC_UNUSED PyObject *self, PyObject *args) @@ -715,60 +723,62 @@ register_constants(PyObject *d) print >> fd, '' - def return_value(self, fd, vtype, options): + def return_value(self, fd, vtype, options, return_var_name = 'return_value', return_pyvar_name = 'return_pyvalue'): if vtype == 'gboolean': - print >> fd, ' if (return_value) {' + print >> fd, ' if (%s) {' % return_var_name print >> fd, ' Py_INCREF(Py_True);' - print >> fd, ' return_pyvalue = Py_True;' + print >> fd, ' %s = Py_True;' % return_pyvar_name print >> fd, ' } else {' print >> fd, ' Py_INCREF(Py_False);' - print >> fd, ' return_pyvalue = Py_False;' + print >> fd, ' %s = Py_False;' % return_pyvar_name print >> fd, ' }' elif vtype in ['int', 'gint'] + self.binding_data.enums: - print >> fd, ' return_pyvalue = PyInt_FromLong(return_value);' + print >> fd, ' %s = PyInt_FromLong(%s);' % (return_pyvar_name, return_var_name) elif vtype in ('char*', 'guchar*', 'const guchar*', 'gchar*'): - print >> fd, ' if (return_value) {' - print >> fd, ' return_pyvalue = PyString_FromString(return_value);' - print >> fd, ' g_free(return_value);' + print >> fd, ' if (%s) {' % return_var_name + print >> fd, ' %s = PyString_FromString(%s);' % (return_pyvar_name, return_var_name) + print >> fd, ' g_free(%s);' % return_var_name print >> fd, ' } else {' - print >> fd, ' return_pyvalue = noneRef();' + print >> fd, ' %s = noneRef();' % return_pyvar_name print >> fd, ' }' elif vtype in ('const char*', 'const gchar*'): - print >> fd, ' if (return_value) {' - print >> fd, ' return_pyvalue = PyString_FromString(return_value);' + print >> fd, ' if (%s) {' % return_var_name + print >> fd, ' %s = PyString_FromString(%s);' % (return_pyvar_name, return_var_name) print >> fd, ' } else {' - print >> fd, ' return_pyvalue = noneRef();' + print >> fd, ' %s = noneRef();' % return_pyvar_name 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);' + if not elem_type or self.is_pygobject(elem_type): + print >> fd, ' %s = get_list_of_pygobject(%s);' % (return_pyvar_name, return_var_name) + elif elem_type == 'char*': + print >> fd, ' %s = get_list_of_strings(%s);' % (return_pyvar_name, return_var_name) + elif elem_type.startswith('xmlNode'): + print >> fd, ' %s = get_list_of_xml_nodes(%s);' % (return_pyvar_name, return_var_name) else: - print >> fd, ' return_pyvalue = get_list_of_pygobject(return_value);' + raise Exception('Should not happen: %s %s ' % (repr(options), vtype)) 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);' + print >> fd, ' %s = get_dict_from_hashtable_of_strings(%s);' % (return_pyvar_name, return_var_name) else: - print >> fd, ' return_pyvalue = get_dict_from_hashtable_of_objects(return_value);' + print >> fd, ' %s = get_dict_from_hashtable_of_objects(%s);' % (return_pyvar_name, return_var_name) 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, ' if (%s) {' % return_var_name + print >> fd, ' %s = get_pystring_from_xml_node(%s);' % (return_pyvar_name, return_var_name) print >> fd, ' } else {' - print >> fd, ' return_pyvalue = noneRef();' + print >> fd, ' %s = noneRef();' % return_pyvar_name print >> fd, ' }' else: # return a PyGObjectPtr (wrapper around GObject) print >> fd, '''\ - if (return_value) { - return_pyvalue = PyGObjectPtr_New(G_OBJECT(return_value)); + if (%s) { + %s = PyGObjectPtr_New(G_OBJECT(%s)); } else { - return_pyvalue = noneRef(); + %s = noneRef(); } -''' +''' % (return_var_name, return_pyvar_name, return_var_name, return_pyvar_name) def generate_function_wrapper(self, m, fd): if m.rename: @@ -785,6 +795,9 @@ register_constants(PyObject *d) parse_tuple_args = [] for arg in m.args: arg_type, arg_name, arg_options = arg + arg_def = None + python_cvt_def = None + defval = None if arg_type in ('char*', 'const char*', 'gchar*', 'const gchar*'): arg_type = arg_type.replace('const ', '') if arg_options.get('optional'): @@ -794,7 +807,7 @@ register_constants(PyObject *d) else: parse_tuple_format.append('s') parse_tuple_args.append('&%s' % arg_name) - print >> fd, ' %s %s = NULL;' % (arg[0], arg[1]) + arg_def = ' %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: @@ -807,23 +820,34 @@ register_constants(PyObject *d) defval = defval[2:].upper() else: defval = defval[2:] - print >> fd, ' %s %s = %s;' % (arg[0], arg[1], defval) + arg_def = ' %s %s = %s;' % (arg[0], arg[1], defval) else: - print >> fd, ' %s %s;' % (arg[0], arg[1]) - elif arg_type in ('GList*', 'xmlNode*'): + arg_def = ' %s %s;' % (arg[0], arg[1]) + elif is_xml_node(arg) or is_list(arg) or is_time_t_pointer(arg): 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 + arg_def = ' %s %s = NULL;' % (arg[0], arg[1]) + python_cvt_def = ' 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 + arg_def = ' %s %s = NULL;' % (arg[0], arg[1]) + python_cvt_def = ' PyGObjectPtr *cvt_%s = NULL;' % arg_name + if is_out(arg): + arg_def = ' %s %s = NULL;' % (var_type(arg), arg[1]) + parse_tuple_format.pop() + parse_tuple_format.append('O') + parse_tuple_args.pop() + parse_tuple_args.append('&cvt_%s_out' % arg_name) + python_cvt_def = ' PyObject *cvt_%s_out = NULL;' % arg_name + print >> fd, ' PyObject *out_pyvalue = NULL;' + print >> fd, arg_def + if python_cvt_def: + print >> fd, python_cvt_def if m.return_type: print >> fd, ' %s return_value;' % m.return_type - print >> fd, ' PyObject* return_pyvalue;' + print >> fd, ' PyObject* return_pyvalue = NULL;' print >> fd, '' parse_tuple_args = ', '.join(parse_tuple_args) @@ -834,7 +858,9 @@ register_constants(PyObject *d) ''.join(parse_tuple_format), parse_tuple_args) for f, arg in zip(parse_tuple_format, m.args): - if arg[0] == 'GList*': + if is_out(arg): + continue + if is_list(arg): qualifier = arg[2].get('elem_type') if qualifier == 'char*': print >> fd, ' set_list_of_strings(&%s, cvt_%s);' % (arg[1], arg[1]) @@ -844,8 +870,10 @@ register_constants(PyObject *d) 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*': + elif is_xml_node(arg): print >> fd, ' %s = get_xml_node_from_pystring(cvt_%s);' % (arg[1], arg[1]) + elif is_time_t_pointer(arg): + print >> fd, ' %s = get_time_t(cvt_%s);' % (arg[1], arg[1]) elif f == 'O': print >> fd, ' %s = (%s)cvt_%s->obj;' % (arg[1], arg[0], arg[1]) @@ -853,10 +881,15 @@ register_constants(PyObject *d) 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])) + else: + print >> fd, ' ', + print >> fd, '%s(%s);' % (m.name, ', '.join([ref_name(x) for x in m.args])) for f, arg in zip(parse_tuple_format, m.args): - if arg[0] == 'GList*': + if is_out(arg): + self.return_value(fd, var_type(arg), {'elem_type': element_type(arg)}, return_var_name = arg[1], return_pyvar_name = 'out_pyvalue') + print >> fd, ' PyList_SetItem(cvt_%s_out, 0, out_pyvalue);' % arg[1] + elif arg[0] == 'GList*': qualifier = arg[2].get('elem_type') if qualifier == 'char*': print >> fd, ' free_list(&%s, (GFunc)g_free);' % arg[1] @@ -864,6 +897,8 @@ register_constants(PyObject *d) print >> fd, ' free_list(&%s, (GFunc)xmlFreeNode);' % arg[1] elif qualifier == 'LassoNode': print >> fd, ' free_list(&%s, (GFunc)g_object_unref);' % arg[1] + elif is_time_t_pointer(arg): + print >> fd, ' if (%s) free(%s);' % (arg[1], arg[1]) if not m.return_type: print >> fd, ' return noneRef();' |