[Numpy-svn] r3943 - trunk/numpy/f2py/lib/extgen
numpy-svn at scipy.org
numpy-svn at scipy.org
Sat Aug 4 15:59:08 EDT 2007
Author: pearu
Date: 2007-08-04 14:58:57 -0500 (Sat, 04 Aug 2007)
New Revision: 3943
Added:
trunk/numpy/f2py/lib/extgen/pyc_argument.py
Modified:
trunk/numpy/f2py/lib/extgen/__init__.py
trunk/numpy/f2py/lib/extgen/base.py
trunk/numpy/f2py/lib/extgen/doc.txt
trunk/numpy/f2py/lib/extgen/extension_module.py
trunk/numpy/f2py/lib/extgen/pyc_function.py
Log:
Impl basic argument support and documentation generation.
Modified: trunk/numpy/f2py/lib/extgen/__init__.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/__init__.py 2007-08-03 22:19:13 UTC (rev 3942)
+++ trunk/numpy/f2py/lib/extgen/__init__.py 2007-08-04 19:58:57 UTC (rev 3943)
@@ -2,11 +2,13 @@
Python Extensions Generator
"""
-__all__ = ['ExtensionModule', 'PyCFunction', 'CCode']
+__all__ = ['ExtensionModule', 'PyCFunction', 'PyCArgument',
+ 'CCode']
import base
from extension_module import ExtensionModule
from pyc_function import PyCFunction
+from pyc_argument import PyCArgument
from c_code import CCode
import predefined_components
Modified: trunk/numpy/f2py/lib/extgen/base.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/base.py 2007-08-03 22:19:13 UTC (rev 3942)
+++ trunk/numpy/f2py/lib/extgen/base.py 2007-08-04 19:58:57 UTC (rev 3943)
@@ -63,6 +63,11 @@
def __repr__(self):
return '%s%s' % (self.__class__.__name__, `self._args`)
+ def __getattr__(self, attr):
+ if attr.startswith('container_'):
+ return self.get_container(attr[10:])
+ raise AttributeError('%s instance has no attribute %r' % (self.__class__.__name__, attr))
+
def get_container(self, key):
""" Return named container.
@@ -117,6 +122,11 @@
"""
# clean up containers
self.containers = {}
+ for n in dir(self):
+ if n.startswith('container_') and isinstance(getattr(self, n), Container):
+ delattr(self, n)
+
+ # create containers
for k,kwargs in self.container_options.items():
self.containers[k] = Container(**kwargs)
@@ -201,7 +211,7 @@
r.append('--- %s ---\n%s' % (k,v))
return '\n'.join(r)
- def evaluate(self, template):
+ def evaluate(self, template, **attrs):
"""
Evaluate template using instance attributes and code
idioms from containers.
@@ -213,17 +223,19 @@
v = getattr(self, n)
if isinstance(v, str):
d[n] = v
+ d.update(attrs)
for label, container in self.containers.items():
- if container.use_indent is None:
+ if not container.use_indent:
continue
replace_list = set(re.findall(r'[ ]*%\('+label+r'\)s', template))
for s in replace_list:
- old_indent = container.use_indent
- container.use_indent = len(s) - len(s.lstrip())
+ old_indent = container.indent_offset
+ container.indent_offset = old_indent + len(s) - len(s.lstrip())
i = template.index(s)
template = template[:i] + str(container) + template[i+len(s):]
- container.use_indent = old_indent
- return re.sub(r'[ \t]*[<]KILLLINE[>]\n','', template % d)
+ container.indent_offset = old_indent
+ template = template % d
+ return re.sub(r'.*[<]KILLLINE[>].*\n','', template)
_registered_components_map = {}
@@ -253,31 +265,44 @@
pass
raise KeyError('no registered component provides %r' % (provides))
+ @property
+ def numpy_version(self):
+ import numpy
+ return numpy.__version__
class Container(object):
"""
Container of a list of named strings.
>>> c = Container(separator=', ', prefix='"', suffix='"')
- >>> c.add(1, 'hey')
- >>> c.add(2, 'hoo')
- >>> str(c)
- '"hey, hoo"'
- >>> c.add(1, 'hey')
- >>> c.add(1, 'hey2')
+ >>> c.add('hey',1)
+ >>> c.add('hoo',2)
+ >>> print c
+ "hey, hoo"
+ >>> c.add('hey',1)
+ >>> c.add('hey2',1)
Traceback (most recent call last):
...
ValueError: Container item 1 exists with different value
+
+ >>> c2 = Container()
+ >>> c2.add('bar')
+ >>> c += c2
+ >>> print c
+ "hey, hoo, bar"
"""
__metaclass__ = BaseMetaClass
- def __init__(self, separator='\n', prefix='', suffix='',
+ def __init__(self,
+ separator='\n', prefix='', suffix='',
skip_prefix_when_empty=False,
skip_suffix_when_empty=False,
default = '', reverse=False,
user_defined_str = None,
- use_indent = None,
+ use_indent = False,
+ indent_offset = 0,
+ use_firstline_indent = False, # implies use_indent
):
self.list = []
self.label_map = {}
@@ -290,7 +315,12 @@
self.default = default
self.reverse = reverse
self.user_str = user_defined_str
- self.use_indent = use_indent
+ self.use_indent = use_indent or use_firstline_indent
+ self.indent_offset = indent_offset
+ self.use_firstline_indent = use_firstline_indent
+
+ def __notzero__(self):
+ return bool(self.list)
def has(self, label):
return self.label_map.has_key(label)
@@ -298,14 +328,23 @@
def get(self, label):
return self.list[self.label_map[label]]
- def __iadd__(self, other):
- self.add(other)
+ def __add__(self, other):
+ if isinstance(other, Container):
+ lst = [(i,l) for (l,i) in other.label_map.items()]
+ lst.sort()
+ for i,l in lst:
+ self.add(other.list[i], l)
+ else:
+ self.add(other)
return self
+ __iadd__ = __add__
def add(self, content, label=None):
""" Add content to container using label.
If label is None, an unique label will be generated using time.time().
"""
+ if content is None:
+ return
assert isinstance(content, str),`type(content)`
if label is None:
label = time.time()
@@ -326,6 +365,15 @@
if self.reverse:
l = l[:]
l.reverse()
+ if self.use_firstline_indent:
+ new_l = []
+ for l1 in l:
+ lines = l1.split('\\n')
+ i = len(lines[0]) - len(lines[0].lstrip())
+ indent = i * ' '
+ new_l.append(lines[0])
+ new_l.extend([indent + l2 for l2 in lines[1:]])
+ l = new_l
r = self.separator.join(l)
r = self.prefix + r
r = r + self.suffix
@@ -336,10 +384,31 @@
if not self.skip_suffix:
r = r + self.suffix
if r and self.use_indent:
- indent = self.use_indent * ' '
- r = ''.join([indent + line for line in r.splitlines(True)])
+ lines = r.splitlines(True)
+ indent = self.indent_offset * ' '
+ r = ''.join([indent + line for line in lines])
return r
+ def copy(self, mapping=None, **extra_options):
+ options = dict(separator=self.separator, prefix=self.prefix, suffix=self.suffix,
+ skip_prefix_when_empty=self.skip_prefix,
+ skip_suffix_when_empty=self.skip_suffix,
+ default = self.default, reverse=self.reverse,
+ user_defined_str = self.user_str,
+ use_indent = self.use_indent,
+ indent_offset = self.indent_offset
+ )
+ options.update(extra_options)
+ cpy = Container(**options)
+ if mapping is None:
+ cpy += self
+ else:
+ lst = [(i,l) for (l,i) in self.label_map.items()]
+ lst.sort()
+ for i,l in lst:
+ cpy.add(mapping(other.list[i]), l)
+ return cpy
+
def _test():
import doctest
doctest.testmod()
Modified: trunk/numpy/f2py/lib/extgen/doc.txt
===================================================================
--- trunk/numpy/f2py/lib/extgen/doc.txt 2007-08-03 22:19:13 UTC (rev 3942)
+++ trunk/numpy/f2py/lib/extgen/doc.txt 2007-08-04 19:58:57 UTC (rev 3943)
@@ -18,11 +18,12 @@
Hello example follows::
>>> from numpy.f2py.lib.extgen import *
+ >>> m = ExtensionModule('foo')
>>> f = PyCFunction('hello')
- >>> f.add('printf("Hello!\\n");')
- >>> m = ExtensionModule('foo', f)
+ >>> f += 'printf("Hello!\\n");'
+ >>> m += f
>>> m.generate() # returns a string containing C source to extension module
- >>> foo = m.build
+ >>> foo = m.build()
>>> foo.hello()
Hello!
>>>
@@ -137,6 +138,9 @@
- `skip_suffix_when_empty=False`
- `default=''`
- `reverse=False`
+ - `use_indent=False`
+ - `use_firstline_indent=False`
+ - `indent_offset=0`
- `user_defined_str=None`
that can be used to change the behaviour of `Container.__str__()`
@@ -154,16 +158,24 @@
item is ignored.
-Reference manual
-================
+Component classes
+=================
ExtGen package defines the following extension module component classes:
- - `ExtensionModule(<modulename>, *components, numpy=False, provides=..)` ---
+ - `ExtensionModule(<modulename>, *components, numpy=False,
+ provides=.., title=.., description=..)` ---
represents an extension module,
- - `PyCFunction(<name>, *components, provides=..)` ---
+ - `PyCFunction(<name>, *components, provides=.., title=.., description=..)` ---
represents an extension function.
+ - `PyCArgument(<name>, *components, provides=.., input_intent=..,
+ output_intent=.., input_title=.., input_description=..,
+ output_title=, output_description=..)` --- represents an argument component for
+ `PyCFunction`. Keyword arguments `input_intent` and
+ `output_intent` may have values `'required'`, `'optional'`,
+ `'extra'`, `'hide'` and `'hide'`, `'return'`, respectively.
+
- `CCode(*lines, provides=..)` --- represents any C code block or statement.
Modified: trunk/numpy/f2py/lib/extgen/extension_module.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/extension_module.py 2007-08-03 22:19:13 UTC (rev 3942)
+++ trunk/numpy/f2py/lib/extgen/extension_module.py 2007-08-04 19:58:57 UTC (rev 3943)
@@ -13,28 +13,62 @@
>>> # instead of the following import statement
>>> from __init__ import * #doctest: +ELLIPSIS
Ignoring...
- >>> f = PyCFunction('hello')
- >>> f.add('printf("Hello!\\\\n");')
- >>> f.add('printf("Bye!\\\\n");')
- >>> m = ExtensionModule('foo', f)
- >>> foo = m.build #doctest: +ELLIPSIS
+ >>> f = PyCFunction('hello', title='Say Hello\\nand Bye.')
+ >>> f += 'printf("Hello!\\\\n");'
+ >>> f += 'printf("Bye!\\\\n");'
+ >>> m = ExtensionModule('foo', f, title='Hello module', description='First line.\\nSecond line.')
+ >>> foo = m.build() #doctest: +ELLIPSIS
exec_command...
>>> foo.hello()
>>> # you should now see Hello! printed to stdout stream.
+ We now add a new function to module and rebuild. But we need to change the
+ module name as one cannot reload extension modules in Python.
+
+ >>> m.modulename = 'foo2'
+ >>> m += PyCFunction('hi', 'printf("Hi\\\\n");', title='Say just Hi.')
+ >>> foo = m.build() #doctest: +ELLIPSIS
+ exec_command...
+ >>> print foo.__doc__ #doctest: +ELLIPSIS
+ This module "foo2" is generated with ExtGen from NumPy version ...
+ <BLANKLINE>
+ Hello module
+ <BLANKLINE>
+ Description:
+ First line.
+ Second line.
+ <BLANKLINE>
+ Functions:
+ hello() -> None
+ Say Hello
+ and Bye.
+ hi() -> None
+ Say just Hi.
"""
container_options = dict(\
- Header=dict(default='<KILLLINE>'),
- TypeDef=dict(default='<KILLLINE>'),
- Extern=dict(default='<KILLLINE>'),
- CCode=dict(default='<KILLLINE>'),
- CAPICode=dict(default='<KILLLINE>'),
- ObjDecl=dict(default='<KILLLINE>'),
- ModuleMethod=dict(suffix=',', skip_suffix_when_empty=True,
- default='<KILLLINE>', use_indent=True),
- ModuleInit=dict(default='<KILLLINE>', use_indent=True),
- )
+ Header=dict(default='<KILLLINE>'),
+ TypeDef=dict(default='<KILLLINE>'),
+ Extern=dict(default='<KILLLINE>'),
+ CCode=dict(default='<KILLLINE>'),
+ CAPICode=dict(default='<KILLLINE>'),
+ ObjDecl=dict(default='<KILLLINE>'),
+ ModuleMethod=dict(suffix=',', skip_suffix_when_empty=True,separator=',\n',
+ default='<KILLLINE>', use_indent=True),
+ ModuleInit=dict(default='<KILLLINE>', use_indent=True),
+
+ ModuleTitle = dict(default='<KILLLINE>',prefix='"\\n\\n',suffix='"',separator='\\n"\n" ',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ ModuleDescr = dict(default='<KILLLINE>',prefix='"\\n\\nDescription:\\n"\n" ',
+ suffix='"',separator='\\n"\n" ',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ ModuleFuncDoc = dict(default='<KILLLINE>', prefix='"\\n\\nFunctions:\\n"\n" ',
+ separator='\\n"\n" ', suffix='"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ )
component_container_map = dict(PyCFunction = 'CAPICode')
@@ -63,9 +97,25 @@
{NULL,NULL,0,NULL}
};
+static char %(modulename)s_doc[] =
+"This module \\"%(modulename)s\\" is generated with ExtGen from NumPy version %(numpy_version)s."
+%(ModuleTitle)s
+%(ModuleDescr)s
+%(ModuleFuncDoc)s
+;
+
PyMODINIT_FUNC init%(modulename)s(void) {
+ PyObject* extgen_module_dict = NULL;
+ PyObject* extgen_str_obj = NULL;
+
extgen_module = Py_InitModule("%(modulename)s", extgen_module_methods);
+ if ((extgen_module_dict = PyModule_GetDict(extgen_module))==NULL) goto capi_error;
+ if ((extgen_str_obj = PyString_FromString(%(modulename)s_doc))==NULL) goto capi_error;
+ PyDict_SetItemString(extgen_module_dict, "__doc__", extgen_str_obj);
+ Py_DECREF(extgen_str_obj);
+
%(ModuleInit)s
+
return;
capi_error:
if (!PyErr_Occurred()) {
@@ -88,10 +138,19 @@
if options.get('numpy'):
self.add(Base.get('arrayobject.h'), 'Header')
self.add(Base.get('import_array'), 'ModuleInit')
+
+ self.title = options.get('title')
+ self.description = options.get('description')
+
map(self.add, components)
return
- @property
+ def update_containers(self):
+ if self.title is not None:
+ self.container_ModuleTitle += self.title.replace('\n','\\n')
+ if self.description is not None:
+ self.container_ModuleDescr += self.description.replace('\n','\\n')
+
def build(self):
import os
import sys
@@ -121,11 +180,11 @@
setup_cmd = ' '.join([sys.executable,setupfile]+setup_args)
build_dir = '.'
from numpy.distutils.exec_command import exec_command
- sts = exec_command(setup_cmd)
+ status, output = exec_command(setup_cmd)
#p = subprocess.Popen(setup_cmd, cwd=build_dir, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
#sts = os.waitpid(p.pid, 0)
- if sts[0]:
- raise "Failed to build (status=%s)." % (`sts`)
+ if status:
+ raise "Failed to build (status=%s)." % (`status`)
exec 'import %s as m' % (modulename)
return m
Added: trunk/numpy/f2py/lib/extgen/pyc_argument.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/pyc_argument.py 2007-08-03 22:19:13 UTC (rev 3942)
+++ trunk/numpy/f2py/lib/extgen/pyc_argument.py 2007-08-04 19:58:57 UTC (rev 3943)
@@ -0,0 +1,135 @@
+
+from base import Base
+
+class PyCArgument(Base):
+
+ """
+ PyCArgument(<name>, *components, provides=..,
+ input_intent = 'required' | 'optional' | 'extra' | 'hide',
+ output_intent = 'hide' | 'return',
+ input_title = None,
+ output_title = None,
+ input_description = None,
+ output_description = None
+ )
+
+ """
+
+ template = '%(name)s'
+
+ def initialize(self, name, *components, **options):
+ self.name = name
+ self._provides = options.get('provides',
+ '%s_%s' % (self.__class__.__name__, name))
+ self.input_intent = options.get('input_intent','required') # 'optional', 'extra', 'hide'
+ self.output_intent = options.get('output_intent','hide') # 'return'
+ self.input_title = options.get('input_title', None)
+ self.output_title = options.get('output_title', None)
+ self.input_description = options.get('input_description', None)
+ self.output_description = options.get('output_description', None)
+
+ map(self.add, components)
+
+ def get_ctype(self):
+ # scan components for c types
+ return
+
+ def init_containers(self):
+ ctype = self.get_ctype()
+ if ctype is None:
+ self.cname = self.name
+ else:
+ self.cname = self.provides
+
+ def update_containers(self):
+ evaluate = self.evaluate
+ ctype = self.get_ctype()
+
+ # get containers
+ ReqArgs = self.container_ReqArgs
+ OptArgs = self.container_OptArgs
+ ExtArgs = self.container_ExtArgs
+ RetArgs = self.container_RetArgs
+
+ ReqArgsDoc = self.container_ReqArgsDoc
+ OptArgsDoc = self.container_OptArgsDoc
+ ExtArgsDoc = self.container_ExtArgsDoc
+
+ Decl = self.container_Decl
+
+ ReqKWList = self.container_ReqKWList
+ OptKWList = self.container_OptKWList
+ ExtKWList = self.container_ExtKWList
+
+ ReqPyArgFmt = self.container_ReqPyArgFmt
+ OptPyArgFmt = self.container_OptPyArgFmt
+ ExtPyArgFmt = self.container_ExtPyArgFmt
+
+ ReqPyArgObj = self.container_ReqPyArgObj
+ OptPyArgObj = self.container_OptPyArgObj
+ ExtPyArgObj = self.container_ExtPyArgObj
+
+ RetDoc = self.container_RetDoc
+ RetFmt = self.container_RetFmt
+ RetObj = self.container_RetObj
+
+ # update PyCFunction containers
+ Decl.add('PyObject* %s = NULL;' % (self.cname))
+ if ctype is not None:
+ Decl.add(ctype.declare(self.name))
+
+ if ctype is None:
+ input_doc_title = '%s - %s' % (self.name, self.input_title)
+ output_doc_title = '%s - %s' % (self.name, self.output_title)
+ if self.input_description is not None:
+ input_doc_descr = ' %s' % (self.input_description.replace('\n','\\n'))
+ else:
+ input_doc_descr = None
+ if self.output_description is not None:
+ output_doc_descr = ' %s' % (self.output_description.replace('\n','\\n'))
+ else:
+ output_doc_descr = None
+ iopt = (self.name, '"%s"' % (self.name), 'O', '&%s' % (self.cname), input_doc_title, input_doc_descr)
+ ropt = (self.name, 'N', self.cname, output_doc_title, output_doc_descr)
+ else:
+ raise NotImplementedError('ctype=%r' % (ctype))
+
+ if self.input_intent=='required':
+ ReqArgs.add(iopt[0])
+ ReqKWList.add(iopt[1])
+ ReqPyArgFmt.add(iopt[2])
+ ReqPyArgObj.add(iopt[3])
+ ReqArgsDoc.add(iopt[4])
+ ReqArgsDoc.add(iopt[5])
+ elif self.input_intent=='optional':
+ OptArgs.add(iopt[0])
+ OptKWList.add(iopt[1])
+ OptPyArgFmt.add(iopt[2])
+ OptPyArgObj.add(iopt[3])
+ OptArgsDoc.add(iopt[4])
+ OptArgsDoc.add(iopt[5])
+ elif self.input_intent=='extra':
+ ExtArgs.add(iopt[0])
+ ExtKWList.add(iopt[1])
+ ExtPyArgFmt.add(iopt[2])
+ ExtPyArgObj.add(iopt[3])
+ ExtArgsDoc.add(iopt[4])
+ ExtArgsDoc.add(iopt[5])
+ elif self.input_intent=='hide':
+ ropt = (self.name, 'O', self.cname, output_doc_title, output_doc_descr)
+ else:
+ raise NotImplementedError('input_intent=%r' % (self.input_intent))
+
+ if self.output_intent=='return':
+ RetArgs.add(ropt[0])
+ RetFmt.add(ropt[1])
+ RetObj.add(ropt[2])
+ RetDoc.add(ropt[3])
+ RetDoc.add(ropt[4])
+ elif self.output_intent=='hide':
+ pass
+ else:
+ raise NotImplementedError('output_intent=%r' % (self.output_intent))
+
+ return
+
Modified: trunk/numpy/f2py/lib/extgen/pyc_function.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/pyc_function.py 2007-08-03 22:19:13 UTC (rev 3942)
+++ trunk/numpy/f2py/lib/extgen/pyc_function.py 2007-08-04 19:58:57 UTC (rev 3943)
@@ -4,31 +4,129 @@
class PyCFunction(Base):
"""
- PyCFunction(<name>, *components, provides=..)
-
+ PyCFunction(<name>, *components, provides=..,title=.., description=..)
+
+ >>> from __init__ import * #doctest: +ELLIPSIS
+ Ignoring...
+ >>> f = PyCFunction('hello', title='A function.', description='\\nFirst line.\\n2nd line.')
+ >>> a1_in_doc = '''First line.\\nSecond line.'''
+ >>> a1_out_doc = '''Single line.'''
+ >>> f += PyCArgument('a1',output_intent='return', input_title='a Python object',
+ ... input_description=a1_in_doc, output_description=a1_out_doc)
+ >>> f += PyCArgument('c1',input_intent='extra')
+ >>> f += PyCArgument('b1',input_intent='optional')
+ >>> f += PyCArgument('d2',input_intent='hide', output_intent='return')
+ >>> f += PyCArgument('a2',input_intent='required')
+ >>> f += PyCArgument('c2',input_intent='extra')
+ >>> f += PyCArgument('b2',input_intent='optional')
+ >>> m = ExtensionModule('foo', f)
+ >>> foo = m.build() #doctest: +ELLIPSIS
+ exec_command...
+ >>> print foo.hello.__doc__
+ hello(a1, a2 [, b1, b2, c1, c2]) -> (a1, d2)
+ <BLANKLINE>
+ A function.
+ <BLANKLINE>
+ Required arguments:
+ a1 - a Python object
+ First line.
+ Second line.
+ a2 - None
+ <BLANKLINE>
+ Optional arguments:
+ b1 - None
+ b2 - None
+ <BLANKLINE>
+ Extra optional arguments:
+ c1 - None
+ c2 - None
+ <BLANKLINE>
+ Return values:
+ a1 - None
+ Single line.
+ d2 - None
+ <BLANKLINE>
+ Description:
+ <BLANKLINE>
+ First line.
+ 2nd line.
"""
- container_options = dict(FuncDoc=dict(separator='"\n"', prefix='"', suffix='"'),
- Args = dict(),
- Decl = dict(default='<KILLLINE>', use_indent=True),
- KWList = dict(separator=', ', suffix=', ', skip_suffix_when_empty=True),
- PyArgFormat = dict(separator=''),
- PyArgObj = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True),
- FromPyObj = dict(default='<KILLLINE>', use_indent=True),
- Exec = dict(default='<KILLLINE>', use_indent=True),
- PyObjFrom = dict(default='<KILLLINE>', use_indent=True),
- RetFormat = dict(separator=''),
- RetObj = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True),
- CleanPyObjFrom = dict(default='<KILLLINE>', reverse=True, use_indent=True),
- CleanExec = dict(default='<KILLLINE>', reverse=True, use_indent=True),
- CleanFromPyObj = dict(default='<KILLLINE>', reverse=True, use_indent=True),
- )
+ container_options = dict(\
+ Args = dict(separator=', '),
+ ReqArgs = dict(separator=', '),
+ OptArgs = dict(separator=', '),
+ ExtArgs = dict(separator=', '),
+ RetArgs = dict(separator=', ', prefix='(', suffix=')', default = 'None',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True),
+
+ OptExtArgs = dict(separator=', ', prefix=' [, ', skip_prefix_when_empty=True,
+ suffix=']', skip_suffix_when_empty=True),
+
+ FuncTitle = dict(default='<KILLLINE>',prefix='"\\n\\n',suffix='"',separator='\\n"\n" ',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ FuncDescr = dict(default='<KILLLINE>',prefix='"\\n\\nDescription:\\n"\n" ',
+ suffix='"',separator='\\n"\n" ',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ ReqArgsDoc = dict(default='<KILLLINE>', prefix='"\\n\\nRequired arguments:\\n"\n" ',
+ separator='\\n"\n" ', suffix='"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ OptArgsDoc = dict(default='<KILLLINE>', prefix='"\\n\\nOptional arguments:\\n"\n" ',
+ separator='\\n"\n" ', suffix='"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ ExtArgsDoc = dict(default='<KILLLINE>', prefix='"\\n\\nExtra optional arguments:\\n"\n" ',
+ separator='\\n"\n" ', suffix='"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+ RetDoc = dict(default='"Return value:\\n None\\n"', prefix='"\\n\\nReturn values:\\n"\n" ',
+ separator='\\n"\n" ', suffix='"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True),
+
+ Decl = dict(default='<KILLLINE>', use_indent=True),
+
+ ReqKWList = dict(separator=', ', suffix=', ', skip_suffix_when_empty=True),
+ OptKWList = dict(separator=', ', suffix=', ', skip_suffix_when_empty=True),
+ ExtKWList = dict(separator=', ', suffix=', ', skip_suffix_when_empty=True),
+
+ ReqPyArgFmt = dict(separator=''),
+ OptPyArgFmt = dict(separator=''),
+ ExtPyArgFmt = dict(separator=''),
+
+ ReqPyArgObj = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True),
+ OptPyArgObj = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True),
+ ExtPyArgObj = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True),
+
+ FromPyObj = dict(default='<KILLLINE>', use_indent=True),
+ Exec = dict(default='<KILLLINE>', use_indent=True),
+ PyObjFrom = dict(default='<KILLLINE>', use_indent=True),
+
+ RetFmt = dict(separator=''),
+ RetObj = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True),
+
+ CleanPyObjFrom = dict(default='<KILLLINE>', reverse=True, use_indent=True),
+ CleanExec = dict(default='<KILLLINE>', reverse=True, use_indent=True),
+ CleanFromPyObj = dict(default='<KILLLINE>', reverse=True, use_indent=True),
+ )
+
component_container_map = dict(CCode = 'Exec',
PyCArgument = 'Args')
template = '''
-static char %(pyc_name)s_doc[] = %(FuncDoc)s;
+static char %(pyc_name)s_doc[] =
+" %(name)s(%(ReqArgs)s%(OptExtArgs)s) -> %(RetArgs)s"
+%(FuncTitle)s
+%(ReqArgsDoc)s
+%(OptArgsDoc)s
+%(ExtArgsDoc)s
+%(RetDoc)s
+%(FuncDescr)s
+;
static PyObject*
%(pyc_name)s
@@ -36,14 +134,15 @@
PyObject * volatile pyc_buildvalue = NULL;
volatile int capi_success = 1;
%(Decl)s
- static char *capi_kwlist[] = {%(KWList)sNULL};
- if (PyArg_ParseTupleAndKeywords(pyc_args, pyc_keywds,"%(PyArgFormat)s", capi_kwlist%(PyArgObj)s)) {
+ static char *capi_kwlist[] = {%(ReqKWList)s%(OptKWList)s%(ExtKWList)sNULL};
+ if (PyArg_ParseTupleAndKeywords(pyc_args, pyc_keywds,"%(ReqPyArgFmt)s%(OptPyArgFmt)s%(ExtPyArgFmt)s",
+ capi_kwlist%(ReqPyArgObj)s%(OptPyArgObj)s%(ExtPyArgObj)s)) {
%(FromPyObj)s
%(Exec)s
capi_success = !PyErr_Occurred();
if (capi_success) {
%(PyObjFrom)s
- pyc_buildvalue = Py_BuildValue("%(RetFormat)s"%(RetObj)s);
+ pyc_buildvalue = Py_BuildValue("%(RetFmt)s"%(RetObj)s);
%(CleanPyObjFrom)s
}
%(CleanExec)s
@@ -58,20 +157,44 @@
self.pyc_name = 'pyc_function_'+name
self._provides = options.get('provides',
'%s_%s' % (self.__class__.__name__, name))
+ self.title = options.get('title', None)
+ self.description = options.get('description', None)
map(self.add, components)
def init_containers(self):
- # set header to FuncDoc, for example.
- FuncDoc = self.get_container('FuncDoc')
- FuncDoc.add(self.name)
return
- def update_containers(self, params=None):
- ModuleMethod = self.get_container('ModuleMethod')
+ 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
+ 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(self.evaluate(t), self.name)
+ ModuleMethod.add(evaluate(t), self.name)
+
+ # update local containers:
+ OptExtArgs += OptArgs + ExtArgs
+ ModuleFuncDoc += evaluate('%(name)s(%(ReqArgs)s%(OptExtArgs)s) -> %(RetArgs)s')
+ if self.title is not None:
+ FuncTitle += self.title.replace('\n','\\n')
+ ModuleFuncDoc += ' ' + self.title.replace('\n','\\n')
+ if self.description is not None:
+ FuncDescr += self.description.replace('\n','\\n')
return
-
-
+def _test():
+ import doctest
+ doctest.testmod()
+
+if __name__ == "__main__":
+ _test()
More information about the Numpy-svn
mailing list