summaryrefslogtreecommitdiff
path: root/numpy/f2py
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2007-08-07 09:03:40 +0000
committerPearu Peterson <pearu.peterson@gmail.com>2007-08-07 09:03:40 +0000
commit45176eddd776226c970b37632205541a1cd37a2c (patch)
tree0775fdfb5f06af2a05063c01b39baa5c315a5c53 /numpy/f2py
parent9bee05389a14f3bbf8f59a10b2398c8a4a7232ca (diff)
downloadnumpy-45176eddd776226c970b37632205541a1cd37a2c.tar.gz
extgen: added argument dependecies support, reviewed reference counting of input and output arguments.
Diffstat (limited to 'numpy/f2py')
-rw-r--r--numpy/f2py/lib/extgen/c_type.py94
-rw-r--r--numpy/f2py/lib/extgen/pyc_argument.py25
-rw-r--r--numpy/f2py/lib/extgen/pyc_function.py67
3 files changed, 141 insertions, 45 deletions
diff --git a/numpy/f2py/lib/extgen/c_type.py b/numpy/f2py/lib/extgen/c_type.py
index 8b985f8bb..18fb4d9f8 100644
--- a/numpy/f2py/lib/extgen/c_type.py
+++ b/numpy/f2py/lib/extgen/c_type.py
@@ -34,12 +34,6 @@ class CTypeBase(Component):
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,12 +43,82 @@ class CTypeBase(Component):
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'
@@ -405,7 +469,6 @@ class CTypePython(CTypeBase):
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 @@ class CTypePython(CTypeBase):
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 CTypePython(CTypeBase):
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'
diff --git a/numpy/f2py/lib/extgen/pyc_argument.py b/numpy/f2py/lib/extgen/pyc_argument.py
index c8667f2d8..75dd34922 100644
--- a/numpy/f2py/lib/extgen/pyc_argument.py
+++ b/numpy/f2py/lib/extgen/pyc_argument.py
@@ -10,7 +10,8 @@ class PyCArgument(Component):
input_title = None,
output_title = None,
input_description = None,
- output_description = None
+ output_description = None,
+ depends = []
)
"""
@@ -29,21 +30,37 @@ class PyCArgument(Component):
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
diff --git a/numpy/f2py/lib/extgen/pyc_function.py b/numpy/f2py/lib/extgen/pyc_function.py
index 1cdbaeb1a..0e2376db9 100644
--- a/numpy/f2py/lib/extgen/pyc_function.py
+++ b/numpy/f2py/lib/extgen/pyc_function.py
@@ -19,7 +19,7 @@ class PyCFunction(Component):
>>> 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 @@ static PyObject*
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