diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2007-08-04 19:58:57 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2007-08-04 19:58:57 +0000 |
commit | 0a24806b21134798a0bb3a9382c7cb11d35bc46c (patch) | |
tree | d0bdbd580baac5f80679c229e43351ec464efb79 /numpy/f2py | |
parent | 8092698a31f3cc41f5502f736db2c5863988893d (diff) | |
download | numpy-0a24806b21134798a0bb3a9382c7cb11d35bc46c.tar.gz |
Impl basic argument support and documentation generation.
Diffstat (limited to 'numpy/f2py')
-rw-r--r-- | numpy/f2py/lib/extgen/__init__.py | 4 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/base.py | 107 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/doc.txt | 26 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/extension_module.py | 97 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/pyc_argument.py | 135 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/pyc_function.py | 181 |
6 files changed, 475 insertions, 75 deletions
diff --git a/numpy/f2py/lib/extgen/__init__.py b/numpy/f2py/lib/extgen/__init__.py index 30eb25bd9..7e89614cb 100644 --- a/numpy/f2py/lib/extgen/__init__.py +++ b/numpy/f2py/lib/extgen/__init__.py @@ -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 diff --git a/numpy/f2py/lib/extgen/base.py b/numpy/f2py/lib/extgen/base.py index d494156f1..6a340100c 100644 --- a/numpy/f2py/lib/extgen/base.py +++ b/numpy/f2py/lib/extgen/base.py @@ -63,6 +63,11 @@ class Base(object): 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 @@ class Base(object): """ # 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 @@ class Base(object): 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 @@ class Base(object): 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 @@ class Base(object): 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 @@ class Container(object): 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 @@ class Container(object): 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 @@ class Container(object): 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 @@ class Container(object): 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() diff --git a/numpy/f2py/lib/extgen/doc.txt b/numpy/f2py/lib/extgen/doc.txt index 17ffef138..4809abb31 100644 --- a/numpy/f2py/lib/extgen/doc.txt +++ b/numpy/f2py/lib/extgen/doc.txt @@ -18,11 +18,12 @@ tool for constructing and building Python extension modules. 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 @@ Using `Container` class - `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 @@ they are not equal then `ValueError` is raised, otherwise adding an 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. diff --git a/numpy/f2py/lib/extgen/extension_module.py b/numpy/f2py/lib/extgen/extension_module.py index b469bcf18..c48f682fd 100644 --- a/numpy/f2py/lib/extgen/extension_module.py +++ b/numpy/f2py/lib/extgen/extension_module.py @@ -13,28 +13,62 @@ class ExtensionModule(Base): >>> # 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 @@ static PyMethodDef extgen_module_methods[] = { {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 @@ capi_error: 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 @@ if __name__ == '__main__': 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 diff --git a/numpy/f2py/lib/extgen/pyc_argument.py b/numpy/f2py/lib/extgen/pyc_argument.py new file mode 100644 index 000000000..e3ad5dae4 --- /dev/null +++ b/numpy/f2py/lib/extgen/pyc_argument.py @@ -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 + diff --git a/numpy/f2py/lib/extgen/pyc_function.py b/numpy/f2py/lib/extgen/pyc_function.py index 7641dab38..02a2ebb02 100644 --- a/numpy/f2py/lib/extgen/pyc_function.py +++ b/numpy/f2py/lib/extgen/pyc_function.py @@ -4,31 +4,129 @@ from base import Base 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 @@ static PyObject* 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 @@ static PyObject* 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') - t = '{"%(name)s", (PyCFunction)%(pyc_name)s,\n METH_VARARGS | METH_KEYWORDS, %(pyc_name)s_doc}' - ModuleMethod.add(self.evaluate(t), self.name) - return + 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(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() |