[Numpy-svn] r3951 - trunk/numpy/f2py/lib/extgen

numpy-svn@scip... numpy-svn@scip...
Tue Aug 7 04:03:56 CDT 2007


Author: pearu
Date: 2007-08-07 04:03:40 -0500 (Tue, 07 Aug 2007)
New Revision: 3951

Modified:
   trunk/numpy/f2py/lib/extgen/c_type.py
   trunk/numpy/f2py/lib/extgen/pyc_argument.py
   trunk/numpy/f2py/lib/extgen/pyc_function.py
Log:
extgen: added argument dependecies support, reviewed reference counting of input and output arguments.

Modified: trunk/numpy/f2py/lib/extgen/c_type.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/c_type.py	2007-08-06 13:07:03 UTC (rev 3950)
+++ trunk/numpy/f2py/lib/extgen/c_type.py	2007-08-07 09:03:40 UTC (rev 3951)
@@ -34,12 +34,6 @@
     def __str__(self):
         return self.name
 
-    def set_pyarg_decl(self, arg):
-        if arg.input_intent=='return':
-            arg += CDecl(self, '%s = Py_None' % (arg.pycvar))
-        else:
-            arg += CDecl(self, '%s = NULL' % (arg.pycvar))
-        
     def get_pyarg_fmt(self, arg):
         if arg.input_intent=='hide': return None
         return 'O'
@@ -49,13 +43,83 @@
         return '&' + arg.pycvar
     
     def get_pyret_fmt(self, arg):
-        if arg.output_intent=='hide': return None
-        return 'O'
+        if arg.output_intent=='return':
+            # set_converters ensures tha all return values a new references
+            return 'N'
+        return
     
     def get_pyret_obj(self, arg):
-        if arg.output_intent=='hide': return None
-        return arg.pycvar
+        if arg.output_intent=='return':
+            return arg.retpycvar
+        return
 
+    def set_Decl(self, arg):
+        if arg.input_intent!='hide':
+            arg += CDecl(self, '%s = NULL' % (arg.pycvar))
+
+        if arg.output_intent!='hide':
+            arg += CDecl(self, '%s = NULL' % (arg.retpycvar))
+
+    def set_converters(self, arg):
+        """
+        Notes for user:
+          if arg is intent(optional, in, out) and not specified
+          as function argument then function may created but
+          it must then have *new reference* (ie use Py_INCREF
+          unless it is a new reference already).
+        """
+        # this method is called from PyCFunction.update_containers(),
+        # note that self.parent is None put arg.parent is PyCFunction
+        # instance.
+        eval_a = arg.evaluate
+        FromPyObj = arg.container_FromPyObj
+        PyObjFrom = arg.container_PyObjFrom
+        if arg.output_intent=='return':
+            if arg.input_intent in ['optional', 'extra']:
+                FromPyObj += eval_a('''\
+if (!(%(pycvar)s==NULL)) {
+  /* make %(pycvar)r a new reference */
+  %(retpycvar)s = %(pycvar)s;
+  Py_INCREF((PyObject*)%(retpycvar)s);
+}
+''')
+                PyObjFrom += eval_a('''\
+if (%(retpycvar)s==NULL) {
+  /* %(pycvar)r was not specified */
+  if (%(pycvar)s==NULL) {
+    %(retpycvar)s = Py_None;
+    Py_INCREF((PyObject*)%(retpycvar)s);
+  } else {
+    %(retpycvar)s = %(pycvar)s;
+    /* %(pycvar)r must be a new reference or expect a core dump. */
+  }
+} elif (!(%(retpycvar)s == %(pycvar)s)) {
+  /* a new %(retpycvar)r was created, undoing %(pycvar)s new reference */
+  Py_DECREF((PyObject*)%(pycvar)s);
+}
+''')
+            elif arg.input_intent=='hide':
+                PyObjFrom += eval_a('''\
+if (%(retpycvar)s==NULL) {
+  %(retpycvar)s = Py_None;
+  Py_INCREF((PyObject*)%(retpycvar)s);
+} /* else %(retpycvar)r must be a new reference or expect a core dump. */
+''')
+            elif arg.input_intent=='required':
+                 FromPyObj += eval_a('''\
+/* make %(pycvar)r a new reference */
+%(retpycvar)s = %(pycvar)s;
+Py_INCREF((PyObject*)%(retpycvar)s);
+''')
+                 PyObjFrom += eval_a('''\
+if (!(%(retpycvar)s==%(pycvar)s)) {
+  /* a new %(retpycvar)r was created, undoing %(pycvar)r new reference */
+  /* %(retpycvar)r must be a new reference or expect a core dump. */
+  Py_DECREF((PyObject*)%(pycvar)s);
+}
+''')
+        return
+
 class _CatchTypeDef(Component): # for doctest
     template = '%(TypeDef)s'
     default_container_label = '<IGNORE>'
@@ -405,7 +469,6 @@
         numpy_complex192 = ('PyComplex192ArrType_Type', 'PyComplex192ScalarObject*', 'O!'),
         numpy_complex256 = ('PyComplex256ArrType_Type', 'PyComplex256ScalarObject*', 'O!'),
         numeric_array = ('PyArray_Type', 'PyArrayObject*', 'O!'),
-        c_int = (None, 'int', 'i')
         )
     
     def initialize(self, typeobj):
@@ -468,12 +531,6 @@
             if arg.output_title: r = ', ' + arg.output_title
             arg.output_title = tn + r
 
-    def set_pyarg_decl(self, arg):
-        if arg.input_intent=='hide':
-            arg += CDecl(self, '%s = Py_None' % (arg.pycvar))
-        else:
-            arg += CDecl(self, '%s = NULL' % (arg.pycvar))
-
     def get_pyarg_fmt(self, arg):
         if arg.input_intent=='hide': return None
         return self.pyarg_fmt
@@ -490,9 +547,6 @@
 class CInt(CType):
     name = provides = 'int'
     def initialize(self): return self
-    def set_pyarg_decl(self, arg):
-        #arg += CDecl(Component.get('PyObject*'), '%s = NULL' % (arg.pycvar))
-        arg += CDecl(self, '%s = 0' % (arg.cvar))
     def get_pyarg_fmt(self, arg): return 'i'
     def get_pyarg_obj(self, arg): return '&' + arg.cvar
     def get_pyret_fmt(self, arg): return 'i'

Modified: trunk/numpy/f2py/lib/extgen/pyc_argument.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/pyc_argument.py	2007-08-06 13:07:03 UTC (rev 3950)
+++ trunk/numpy/f2py/lib/extgen/pyc_argument.py	2007-08-07 09:03:40 UTC (rev 3951)
@@ -10,7 +10,8 @@
                 input_title = None,
                 output_title = None,
                 input_description = None,
-                output_description = None
+                output_description = None,
+                depends = []
                )
 
     """
@@ -29,21 +30,37 @@
         self.output_title = options.pop('output_title', None)
         self.input_description = options.pop('input_description', None)
         self.output_description = options.pop('output_description', None)
+        self.depends = options.pop('depends', [])
 
         if options: self.warning('%s unused options: %s\n' % (self.__class__.__name__, options))
         
         map(self.add, components)
+
         self.cvar = name
-        self.pycvar = name + '_pyc'
+        self.pycvar = None
+        self.retpycvar = None
 
         if ctype is None:
             ctype = Component.CTypePython(object)
         else:
             ctype = Component.CType(ctype)
         self.ctype = ctype
-        ctype.set_pyarg_decl(self)
+
+        if isinstance(ctype, Component.CTypePython):
+            if self.output_intent == 'return':
+                if self.input_intent=='hide':
+                    self.retpycvar = name
+                else:
+                    self.pycvar = name
+                    self.retpycvar = name + '_return'
+            elif self.input_intent!='hide':
+                self.pycvar = name
+        else:
+            self.pycvar = name + '_pyc'
+            self.retpycvar = name + '_pyc_r'
+
         ctype.set_titles(self)
-        #self.add(ctype)
+        ctype.set_Decl(self)
 
         return self
             

Modified: trunk/numpy/f2py/lib/extgen/pyc_function.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/pyc_function.py	2007-08-06 13:07:03 UTC (rev 3950)
+++ trunk/numpy/f2py/lib/extgen/pyc_function.py	2007-08-07 09:03:40 UTC (rev 3951)
@@ -19,7 +19,7 @@
     >>> f += PyCArgument('a2',input_intent='required')
     >>> f += PyCArgument('c2',input_intent='extra')
     >>> f += PyCArgument('b2',input_intent='optional')
-    >>> m = ExtensionModule('foo', f)
+    >>> m = ExtensionModule('test_PyCFunction', f)
     >>> foo = m.build() #doctest: +ELLIPSIS
     exec_command...
     >>> print foo.hello.__doc__
@@ -175,32 +175,57 @@
     def update_containers(self):
         evaluate = self.evaluate
 
-        # get containers
-        FuncTitle = self.container_FuncTitle
-        FuncDescr = self.container_FuncDescr
-        ReqArgs = self.container_ReqArgs
-        OptArgs = self.container_OptArgs
-        ExtArgs = self.container_ExtArgs
-        OptExtArgs = self.container_OptExtArgs
-        OptPyArgFmt = self.container_OptPyArgFmt
-        ExtPyArgFmt = self.container_ExtPyArgFmt
-        OptExtPyArgFmt = self.container_OptExtPyArgFmt
-        ModuleMethod = self.container_ModuleMethod
-        ModuleFuncDoc = self.container_ModuleFuncDoc
-
         # update ExtensionModule containers:
         t = '{"%(name)s", (PyCFunction)%(pyc_name)s,\n METH_VARARGS | METH_KEYWORDS, %(pyc_name)s_doc}'
-        ModuleMethod.add(evaluate(t), self.name)
+        self.container_ModuleMethod.add(evaluate(t), self.name)
 
         # update local containers:
-        OptExtArgs += OptArgs + ExtArgs
-        OptExtPyArgFmt += OptPyArgFmt + ExtPyArgFmt
-        ModuleFuncDoc += evaluate('%(name)s(%(ReqArgs)s%(OptExtArgs)s) -> %(RetArgs)s')
+        self.container_OptExtArgs += self.container_OptArgs + self.container_ExtArgs
+        self.container_OptExtPyArgFmt += self.container_OptPyArgFmt + self.container_ExtPyArgFmt
+        self.container_ModuleFuncDoc += evaluate('%(name)s(%(ReqArgs)s%(OptExtArgs)s) -> %(RetArgs)s')
         if self.title is not None:
-            FuncTitle += self.title
-            ModuleFuncDoc += '  ' + self.title
+            self.container_FuncTitle += self.title
+            self.container_ModuleFuncDoc += '  ' + self.title
         if self.description is not None:
-            FuncDescr += self.description
+            self.container_FuncDescr += self.description
+
+        # resolve dependencies
+        sorted_arguments = []
+        sorted_names = []
+        comp_map = {}
+        dep_map = {}
+        for (c,l) in self.components:
+            if not isinstance(c, Component.PyCArgument):
+                continue
+            d = [n for n in c.depends if n not in sorted_names]
+            if not d:
+                sorted_arguments.append((c,l))
+                sorted_names.append(c.name)
+            else:
+                comp_map[c.name] = (c,l)
+                dep_map[c.name] = d
+
+        while dep_map:
+            dep_map_copy = dep_map.copy()
+            for name, deps in dep_map.items():
+                d = [n for n in deps if dep_map.has_key(n)]
+                if not d:
+                    sorted_arguments.append(comp_map[name])
+                    del dep_map[name]
+                else:
+                    dep_map[name] = d
+            if dep_map_copy==dep_map:
+                self.warnign('%s: detected cyclic dependencies in %r, incorrect behavior is expected.\n'\
+                             % (self.provides, dep_map))
+                sorted_arguments += dep_map.values()
+                break
+
+        for c, l in sorted_arguments:
+            old_parent = c.parent
+            c.parent = self
+            c.ctype.set_converters(c)
+            c.parent = old_parent
+        
         return
 
     



More information about the Numpy-svn mailing list