[Numpy-svn] r3962 - trunk/numpy/f2py/lib/extgen
numpy-svn at scipy.org
numpy-svn at scipy.org
Fri Aug 10 09:58:07 EDT 2007
Author: pearu
Date: 2007-08-10 08:57:35 -0500 (Fri, 10 Aug 2007)
New Revision: 3962
Added:
trunk/numpy/f2py/lib/extgen/c_support.py
trunk/numpy/f2py/lib/extgen/py_support.py
trunk/numpy/f2py/lib/extgen/setup_py.py
trunk/numpy/f2py/lib/extgen/utils.py
Modified:
trunk/numpy/f2py/lib/extgen/__init__.py
trunk/numpy/f2py/lib/extgen/base.py
trunk/numpy/f2py/lib/extgen/doc.txt
Log:
extgen: rewrite, clean up, update docs, simple example from Python reference manual.
Modified: trunk/numpy/f2py/lib/extgen/__init__.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/__init__.py 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/__init__.py 2007-08-10 13:57:35 UTC (rev 3962)
@@ -2,19 +2,26 @@
Python Extensions Generator
"""
-__all__ = ['Component', 'ExtensionModule', 'PyCFunction', 'PyCArgument',
- 'CCode']
+__all__ = ['Component']
from base import Component
-from extension_module import ExtensionModule
-from pyc_function import PyCFunction
-from pyc_argument import PyCArgument
-from c_code import CCode
-import c_type
-from c_type import *
-__all__ += c_type.__all__
+for _m in ['utils', 'c_support', 'py_support', 'setup_py']:
+ exec 'from %s import *' % (_m)
+ exec 'import %s as _m' % (_m)
+ __all__.extend(_m.__all__)
-import predefined_components
-import converters
-c_type.register()
+#from pyc_function import PyCFunction
+#from pyc_argument import PyCArgument
+#from c_code import CCode
+
+#import c_type
+#from c_type import *
+#__all__ += c_type.__all__
+#import c_struct
+#from c_struct import *
+#__all__ += c_struct.__all__#
+
+#import predefined_components
+#import converters
+#c_type.register()
Modified: trunk/numpy/f2py/lib/extgen/base.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/base.py 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/base.py 2007-08-10 13:57:35 UTC (rev 3962)
@@ -4,6 +4,7 @@
Defines Component and Container classes.
"""
+import os
import re
import sys
import time
@@ -12,14 +13,19 @@
classnamespace = {}
- def __init__(cls,*args,**kws):
+ def __new__(mcls, *args, **kws):
+ cls = type.__new__(mcls, *args, **kws)
n = cls.__name__
c = ComponentMetaClass.classnamespace.get(n)
if c is None:
ComponentMetaClass.classnamespace[n] = cls
else:
- print 'Ignoring redefinition of %s: %s defined earlier than %s' % (n, c, cls)
- type.__init__(cls, *args, **kws)
+ if not c.__module__=='__main__':
+ sys.stderr.write('ComponentMetaClass: returning %s as %s\n'\
+ % (cls, c))
+ ComponentMetaClass.classnamespace[n] = c
+ cls = c
+ return cls
def __getattr__(cls, name):
try: return ComponentMetaClass.classnamespace[name]
@@ -27,14 +33,14 @@
raise AttributeError("'%s' object has no attribute '%s'"%
(cls.__name__, name))
-class Component(object): # XXX: rename Component to Component
+class Component(object):
__metaclass__ = ComponentMetaClass
container_options = dict()
component_container_map = dict()
default_container_label = None
- default_component_class_name = 'CCode'
+ default_component_class_name = 'Code'
template = ''
def __new__(cls, *args, **kws):
@@ -42,10 +48,24 @@
obj._provides = kws.get('provides', None)
obj.parent = None
obj.containers = {} # holds containers for named string lists
- obj.components = [] # holds pairs (<Component subclass instance>, <container name or None>)
+ obj._components = [] # holds pairs (<Component subclass instance>, <container name or None>)
+ obj._generate_components = {} # temporary copy of components used for finalize and generate methods.
obj = obj.initialize(*args, **kws) # initialize from constructor arguments
return obj
+ @property
+ def components(self):
+ if Component._running_generate:
+ try:
+ return self._generate_components[Component._running_generate_id]
+ except KeyError:
+ pass
+ while self._generate_components: # clean up old cache
+ self._generate_components.popitem()
+ self._generate_components[Component._running_generate_id] = l = list(self._components)
+ return l
+ return self._components
+
def initialize(self, *components, **options):
"""
Set additional attributes, add components to instance, etc.
@@ -54,6 +74,12 @@
# map(self.add, components)
return self
+ def finalize(self):
+ """
+ Set components after all components are added.
+ """
+ return
+
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(c) for (c,l) in self.components]))
@@ -70,6 +96,7 @@
@staticmethod
def warning(message):
+ #raise RuntimeError('extgen:' + message)
print >> sys.stderr, 'extgen:',message
@staticmethod
def info(message):
@@ -78,6 +105,8 @@
def __getattr__(self, attr):
if attr.startswith('container_'): # convenience feature
return self.get_container(attr[10:])
+ if attr.startswith('component_'): # convenience feature
+ return self.get_component(attr[10:])
raise AttributeError('%s instance has no attribute %r' % (self.__class__.__name__, attr))
def __add__(self, other): # convenience method
@@ -116,14 +145,56 @@
break
except KeyError:
pass
+ if container_label is None:
+ container_label = component.__class__.__name__
self.components.append((component, container_label))
+ component.update_parent(self)
return
- def generate(self):
+ def update_parent(self, parent):
+ pass
+
+ def get_path(self, *paths):
+ if not hasattr(self, 'path'):
+ if paths:
+ return os.path.join(*paths)
+ return ''
+ if not self.parent:
+ return os.path.join(*((self.path,) + paths))
+ return os.path.join(*((self.parent.get_path(), self.path)+paths))
+
+ def get_component(self, cls):
+ if isinstance(cls, str):
+ cls = getattr(Component, cls)
+ if isinstance(self, cls):
+ return self
+ if self.parent:
+ return self.parent.get_component(cls)
+ self.warning('could not find %r parent component %s, returning self'\
+ % (self.__class__.__name__, cls.__name__))
+ return self
+
+ _running_generate = False
+ _running_generate_id = 0
+ _generate_dry_run = True
+
+ def generate(self, dry_run=True):
+ old_dry_run = Component._generate_dry_run
+ Component._generate_dry_run = dry_run
+ Component._running_generate_id += 1
+ Component._running_generate = True
+ result = self._generate()
+ Component._running_generate = False
+ Component._generate_dry_run = old_dry_run
+ return result
+
+ def _generate(self):
"""
Generate code idioms (saved in containers) and
return evaluated template strings.
"""
+ self.finalize()
+
# clean up containers
self.containers = {}
for n in dir(self):
@@ -151,7 +222,7 @@
continue
old_parent = component.parent
component.parent = self
- result = component.generate()
+ result = component._generate()
if container_key == '<IGNORE>':
pass
elif container_key is not None:
@@ -167,6 +238,7 @@
container = component.get_container(k)
container.add(r, component.provides)
else:
+
self.warning('%s: no container label specified for component providing %r'\
% (self.__class__.__name__,component.provides))
component.parent = old_parent
@@ -181,7 +253,6 @@
else:
assert isinstance(templates, (tuple, list)),`type(templates)`
result = tuple(map(self.evaluate, templates))
-
return result
def init_containers(self):
@@ -225,7 +296,7 @@
# create local container
self.warning('Created container for %r with name %r, define it in'\
- ' .container_options mapping to get rid of this warning' \
+ ' parent .container_options mapping to get rid of this warning' \
% (self.__class__.__name__, name))
c = self.containers[name] = Container()
return c
@@ -259,7 +330,10 @@
i = template.index(s)
template = template[:i] + str(container) + template[i+len(s):]
container.indent_offset = old_indent
- template = template % d
+ try:
+ template = template % d
+ except KeyError, msg:
+ raise KeyError('%s.container_options needs %s item' % (self.__class__.__name__, msg))
return re.sub(r'.*[<]KILLLINE[>].*(\n|$)','', template)
@@ -330,7 +404,9 @@
use_indent = False,
indent_offset = 0,
use_firstline_indent = False, # implies use_indent
- replace_map = {}
+ replace_map = {},
+ ignore_empty_content = False,
+ skip_prefix_suffix_when_single = False
):
self.list = []
self.label_map = {}
@@ -347,6 +423,8 @@
self.indent_offset = indent_offset
self.use_firstline_indent = use_firstline_indent
self.replace_map = replace_map
+ self.ignore_empty_content = ignore_empty_content
+ self.skip_prefix_suffix_when_single = skip_prefix_suffix_when_single
def __nonzero__(self):
return bool(self.list)
@@ -374,6 +452,8 @@
"""
if content is None:
return
+ if content=='' and self.ignore_empty_content:
+ return
assert isinstance(content, str),`type(content)`
if label is None:
label = time.time()
@@ -406,8 +486,9 @@
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
+ if not (len(self.list)==1 and self.skip_prefix_suffix_when_single):
+ r = self.prefix + r
+ r = r + self.suffix
else:
r = self.default
if not self.skip_prefix:
@@ -429,7 +510,9 @@
use_indent = self.use_indent,
indent_offset = self.indent_offset,
use_firstline_indent = self.use_firstline_indent,
- replace_map = self.replace_map
+ replace_map = self.replace_map,
+ ignore_empty_content = self.ignore_empty_content,
+ skip_prefix_suffix_when_single = self.skip_prefix_suffix_when_single
)
options.update(extra_options)
cpy = Container(**options)
Added: trunk/numpy/f2py/lib/extgen/c_support.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/c_support.py 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/c_support.py 2007-08-10 13:57:35 UTC (rev 3962)
@@ -0,0 +1,293 @@
+
+__all__ = ['CLine', 'Keyword', 'CTypeSpec', 'CDeclarator', 'CDeclaration',
+ 'CArgument', 'CCode', 'CFunction', 'CSource', 'CHeader', 'CStdHeader']
+
+from base import Component
+from utils import Line, Code, FileSource
+
+class CLine(Line):
+ pass
+
+class Keyword(CLine):
+ pass
+
+class CInitExpr(CLine):
+ pass
+
+class CTypeSpec(CLine):
+
+ """
+ >>> i = CTypeSpec('int')
+ >>> print i.generate()
+ int
+ >>> print i.as_ptr().generate()
+ int*
+ """
+ def as_ptr(self): return self.__class__(self.generate()+'*')
+
+
+class CDeclarator(Component):
+
+ """
+
+ >>> CDeclarator('name').generate()
+ 'name'
+ >>> CDeclarator('name','0').generate()
+ 'name = 0'
+ """
+ container_options = dict(
+ Initializer = dict(default='',prefix=' = ', skip_prefix_when_empty=True,
+ ignore_empty_content = True
+ ),
+ ScalarInitializer = dict(default='',prefix=' = ', skip_prefix_when_empty=True,
+ ignore_empty_content = True
+ ),
+ SequenceInitializer = dict(default='',prefix=' = {\n', skip_prefix_when_empty=True,
+ suffix='}', skip_suffix_when_empty=True,
+ ignore_empty_content = True,
+ separator = ',\n', use_indent=True,
+ ),
+ StringInitializer = dict(default='',prefix=' = "', skip_prefix_when_empty=True,
+ suffix='"', skip_suffix_when_empty=True,
+ ignore_empty_content = True,
+ separator='\\n"\n"', replace_map = {'\n':'\\n'},
+ use_firstline_indent = True,
+ ),
+ )
+
+ default_component_class_name = 'CInitExpr'
+
+ component_container_map = dict(
+ CInitExpr = 'Initializer'
+ )
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.name]+[c for (c,l) in self.components])))
+
+ def initialize(self, name, *initvalues, **options):
+ self.name = name
+ self.is_string = options.get('is_string', None)
+ if self.is_string:
+ assert not options.get('is_scalar', None)
+ self.is_scalar = False
+ else:
+ if name.endswith(']'):
+ self.is_scalar = False
+ else:
+ self.is_scalar = options.get('is_scalar', True)
+
+ map(self.add, initvalues)
+ return self
+
+ def update_containers(self):
+ if self.is_scalar:
+ self.container_ScalarInitializer += self.container_Initializer
+ self.template = '%(name)s%(ScalarInitializer)s'
+ elif self.is_string:
+ self.container_StringInitializer += self.container_Initializer
+ self.template = '%(name)s%(StringInitializer)s'
+ elif len(self.containers)>1 or not self.is_scalar:
+ self.container_SequenceInitializer += self.container_Initializer
+ self.template = '%(name)s%(SequenceInitializer)s'
+ else:
+ self.container_ScalarInitializer += self.container_Initializer
+ self.template = '%(name)s%(ScalarInitializer)s'
+
+class CDeclaration(Component):
+
+ """
+ >>> d = CDeclaration('int', 'a')
+ >>> print d.generate()
+ int a
+ >>> d += 'b'
+ >>> print d.generate()
+ int a, b
+ >>> d += CDeclarator('c',1)
+ >>> print d.generate()
+ int a, b, c = 1
+ """
+
+ template = '%(CTypeSpec)s %(CDeclarator)s'
+
+ container_options = dict(
+ CTypeSpec = dict(default='int', separator=' '),
+ CDeclarator = dict(default='<KILLLINE>', separator=', '),
+ )
+
+ component_container_map = dict(
+ CTypeSpec = 'CTypeSpec',
+ CDeclarator = 'CDeclarator',
+ )
+
+ default_component_class_name = 'CDeclarator'
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[c for (c,l) in self.components])))
+
+ def initialize(self, ctype, *declarators, **options):
+ ctype = CTypeSpec(ctype)
+ self.ctype = ctype
+ self.add(ctype)
+ map(self.add, declarators)
+ return self
+
+class CArgument(CDeclaration):
+
+ def initialize(self, name, ctype, **options):
+ return CDeclaration.initialize(ctype, name, **options)
+
+
+class CCode(Code):
+ parent_container_options = dict(default='<KILLLINE>', use_indent=True, ignore_empty_content=True)
+
+class CFunction(Component):
+
+ """
+ >>> f = CFunction('foo')
+ >>> print f.generate()
+ int
+ foo(void) {
+ }
+ >>> f += Keyword('static')
+ >>> f += CArgument('int', 'a')
+ >>> f += 'a = 2;'
+ >>> print f.generate()
+ static
+ int
+ foo(int a) {
+ a = 2;
+ }
+ >>> f += CArgument('float', 'b')
+ >>> f += CDeclaration('float', 'c')
+ >>> f += CDeclaration('float', CDeclarator('d','3.0'))
+ >>> print f.generate()
+ static
+ int
+ foo(int a, float b) {
+ float c;
+ float d = 3.0;
+ a = 2;
+ }
+ """
+
+ template = '''\
+%(CSpecifier)s
+%(CTypeSpec)s
+%(name)s(%(CArgument)s) {
+ %(CDeclaration)s
+ %(CBody)s
+}'''
+
+ container_options = dict(
+ CArgument = dict(separator=', ', default='void'),
+ CDeclaration = dict(default='<KILLLINE>', use_indent=True, ignore_empty_content=True,
+ separator = ';\n', suffix=';', skip_suffix_when_empty=True),
+ CBody = dict(default='<KILLLINE>', use_indent=True, ignore_empty_content=True),
+ CTypeSpec = dict(default='int', separator = ' ', ignore_empty_content=True),
+ CSpecifier = dict(default='<KILLLINE>', separator = ' ', ignore_empty_content = True)
+ )
+
+ component_container_map = dict(
+ CArgument = 'CArgument',
+ CDeclaration = 'CDeclaration',
+ CCode = 'CBody',
+ CTypeSpec = 'CTypeSpec',
+ Keyword = 'CSpecifier',
+ )
+
+ default_component_class_name = 'CCode'
+
+ def initialize(self, name, rctype='int', *components, **options):
+ self.name = name
+ rctype = CTypeSpec(rctype)
+ self.rctype = rctype
+ self.add(rctype)
+ map(self.add, components)
+ if options: self.warning('%s unused options: %s\n' % (self.__class__.__name__, options))
+ return self
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.name, self.rctype]+[c for (c,l) in self.components])))
+
+class CHeader(CLine):
+
+ """
+ >>> h = CHeader('noddy.h')
+ >>> print h.generate()
+ #include "noddy.h"
+
+ """
+ template = '#include "%(line)s"'
+
+class CStdHeader(CHeader):
+ template = '#include <%(line)s>'
+
+class CSource(FileSource):
+
+ """
+ >>> s = CSource('foo.c')
+ >>> print s.generate() #doctest: +ELLIPSIS
+ /* -*- c -*- */
+ /* This file 'foo.c' is generated using ExtGen tool
+ from NumPy version ...
+ ExtGen is developed by Pearu Peterson <pearu.peterson at gmail.com>.
+ For more information see http://www.scipy.org/ExtGen/ .
+ */
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ #ifdef __cplusplus
+ }
+ #endif
+ <BLANKLINE>
+ """
+
+ container_options = dict(
+ CHeader = dict(default='<KILLLINE>', prefix='\n/* CHeader */\n', skip_prefix_when_empty=True),
+ CTypeDef = dict(default='<KILLLINE>', prefix='\n/* CTypeDef */\n', skip_prefix_when_empty=True),
+ CProto = dict(default='<KILLLINE>', prefix='\n/* CProto */\n', skip_prefix_when_empty=True),
+ CDefinition = dict(default='<KILLLINE>', prefix='\n/* CDefinition */\n', skip_prefix_when_empty=True),
+ CDeclaration = dict(default='<KILLLINE>', separator=';\n', suffix=';',
+ prefix='\n/* CDeclaration */\n', skip_prefix_when_empty=True),
+ CMainProgram = dict(default='<KILLLINE>', prefix='\n/* CMainProgram */\n', skip_prefix_when_empty=True),
+ )
+
+ template_c_header = '''\
+/* -*- c -*- */
+/* This file %(path)r is generated using ExtGen tool
+ from NumPy version %(numpy_version)s.
+ ExtGen is developed by Pearu Peterson <pearu.peterson at gmail.com>.
+ For more information see http://www.scipy.org/ExtGen/ .
+*/'''
+
+
+ template = template_c_header + '''
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+%(CHeader)s
+%(CTypeDef)s
+%(CProto)s
+%(CDefinition)s
+%(CDeclaration)s
+%(CMainProgram)s
+#ifdef __cplusplus
+}
+#endif
+'''
+
+ component_container_map = dict(
+ CHeader = 'CHeader',
+ CFunction = 'CDefinition',
+ CDeclaration = 'CDeclaration',
+ )
+
+
+
+
+def _test():
+ import doctest
+ doctest.testmod()
+
+if __name__ == "__main__":
+ _test()
Modified: trunk/numpy/f2py/lib/extgen/doc.txt
===================================================================
--- trunk/numpy/f2py/lib/extgen/doc.txt 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/doc.txt 2007-08-10 13:57:35 UTC (rev 3962)
@@ -15,23 +15,252 @@
ExtGen is a pure Python package that provides a high-level
tool for constructing and building Python extension modules.
-Hello example follows::
+Even an inexperienced user with no background on writing extension
+modules can build extension modules on fly when using ExtGen tool!
+Hello example follows
+
>>> from numpy.f2py.lib.extgen import *
- >>> m = ExtensionModule('foo')
- >>> f = PyCFunction('hello')
- >>> f += 'printf("Hello!\\n");'
- >>> m += f
- >>> print m.generate() # shows a string containing C source to extension module, useful for debugging
- >>> foo = m.build()
- >>> foo.hello()
+ >>> m = PyCModule('foo') # define extension module component
+ >>> f = PyCFunction('hello') # define function component
+ >>> f += 'printf("Hello!\\n");' # put a C statement into function body
+ >>> m += f # add function to module
+ >>> print m.generate() # shows a string containing C source to extension module
+ # useful for debugging
+ >>> foo = m.build() # compile, build, and return extension module object
+ >>> foo.hello() # call function
Hello!
- >>>
-Description of the ExtGen model
-===============================
+Users reference manual
+======================
+Writing a python extension module requires a knowledge of Pyhton C/API
+details and may take lots of effort to get your first extension module
+compile and working, even for a simple problem. See the `Simple Example`__
+in Python reference manual. ExtGen provides a high level tool for
+constructing extension modules by automatically taking care of the
+Pyhton C/API details while providing full control how an extension
+module is created.
+
+__ http://docs.python.org/ext/
+
+Getting started
+---------------
+
+Creating the `Simple Example`__ with the help of ExtGen tool is really simple
+
+ >>> system = PyCFunction('system',
+ PyCArgument('command', 'c_const_char_ptr'),
+ PyCReturn('sts','c_int'))
+ >>> system += 'sts = system(command);'
+ >>> module = PyCModule('spam', system)
+ >>> spam = module.build()
+ >>> spam.system('pwd')
+ /home/pearu/svn/numpy/numpy/f2py/lib
+ 0
+
+__ http://docs.python.org/ext/
+
+ExtGen generated modules have automatically generated documentation
+strings that accept also user input
+
+ >>> a = PyCArgument('command', 'c_const_char_ptr',
+ input_description='a shell command string')
+ >>> r = PyCReturn('sts', 'c_int',
+ output_description='status value returned by shell command')
+ >>> system = PyCFunction('system', title='Execute a shell command.')
+ >>> system += a # add argument component to function
+ >>> system += r # add return value component to function
+ >>> system += 'sts = system(command);' # add C code to functon body
+ >>> module = PyCModule('spam', system) # create module instance with function component
+ >>> spam = module.build()
+ >>> print spam.__doc__
+ This module 'spam' is generated with ExtGen from NumPy version 1.0.4.dev3744.
+ :Functions:
+ system(command) -> sts
+ >>> print spam.system.__doc__
+ system(command) -> sts
+ Execute a shell command.
+ :Parameters:
+ command : a to C const char ptr convertable object
+ a shell command string
+ :Returns:
+ sts : a to C int convertable object
+ status value returned by shell command
+ >>>
+
+To see the source code that ExtGen generates, use `.generate()` method for any component instance
+
+ >>> print system.generate()
+ static
+ char pyc_function_system_doc[] =
+ " system(command) -> sts"
+ "\n\nExecute a shell command."
+ "\n\n:Parameters:\n"
+ " command : a to C const char ptr convertable object\n"
+ " a shell command string"
+ "\n\n:Returns:\n"
+ " sts : a to C int convertable object\n"
+ " status value returned by shell command"
+ ;
+ static
+ PyObject*
+ pyc_function_system(PyObject *pyc_self, PyObject *pyc_args, PyObject *pyc_keywds) {
+ PyObject * volatile pyc_buildvalue = NULL;
+ volatile int capi_success = 1;
+ const char * command = NULL;
+ int sts = 0;
+ static char *capi_kwlist[] = {"command", NULL};
+ if (PyArg_ParseTupleAndKeywords(pyc_args, pyc_keywds,"z",
+ capi_kwlist, &command)) {
+ sts = system(command);
+ capi_success = !PyErr_Occurred();
+ if (capi_success) {
+ pyc_buildvalue = Py_BuildValue("i", sts);
+ }
+ }
+ return pyc_buildvalue;
+ }
+ >>> print module.generate() # prints full extension module source
+ ...
+
+Components
+----------
+
+All components are subclassed of `Component` base class that provides
+the following methods:
+
+- `.generate(self)` --- return a generated component string
+- `.add(self, component, container_label=None)` --- add subcomponent
+ to component instance. The `container_label` argument can be used to tell
+ `ExtGen` where this component should be used, see `Developers reference
+ manual` for more details, otherwise `EgtGen` figures that out by
+ looking at subcomponent class properties.
+- `.__add__(self, other)`, `.__iadd__(self, other)` --- shortcuts
+ for `self.add(other)` call.
+
+ExtGen provides the following Python C/API related components:
+
+- `SetupPy(<build directory>, *components)` --- generates a `setup.py` file
+ that is used to build extension modules to the given build directory.
+ It provides the following methods:
+
+ - `.execute(self, *args)` --- runs `python setup.py` command with given
+ arguments.
+
+ One can add `PyCModule` and `PySource` components to `SetupPy`.
+
+- `PyCModule(<modulename>, *components, title=..., description=...)` ---
+ represents python extension module source. It provides the following
+ methods:
+
+ - `.build(self, build_dir=None, clean_at_exit=None)` --- compilers,
+ builds, and returns extension module object.
+
+ One can add `PyCFunction` components to `PyCModule`.
+
+- `PyCFunction(<funcname>, *components, title=..., description=...)` ---
+ represents python extension module function source.
+
+ One can add `PyCArgument`, `PyCReturn`, `CCode` components to `PyCfunction`.
+ String components are converted `CCode` components by default.
+
+- `PyCArgument(<argname>, ctype=<expected C type>, **components,
+ input_intent='required', input_title=..., input_description=...,
+ output_intent='hide', output_title=..., output_description=...,
+ title=..., description=...,
+ depends=<list of argument dependencies>)` --- represents argument
+ to python extension module function.
+
+ `ctype` is `PyCTypeSpec` component instance or string. In the latter case
+ it is converted to `PyCTypeSpec` component.
+
+- `PyCReturn(<retname>, ctype=<expected C type>, **components)` ---
+ same as `PyCArgument` but with `input_intent='hide'` and `output_intent='return'`
+ options set.
+
+- `PyCTypeSpec(<typeobj>)` --- represents variable type in a
+ python extension module. Over 70 types are supported:
+
+ >>> typenames = PyCTypeSpec.typeinfo_map.keys()
+ >>> typenames.sort()
+ >>> print ', '.join(typenames)
+ buffer, c_Py_UNICODE, c_Py_complex, c_Py_ssize_t, c_char, c_char1,
+ c_const_char_ptr, c_double, c_float, c_int, c_long, c_long_long,
+ c_short, c_unsigned_char, c_unsigned_int, c_unsigned_long,
+ c_unsigned_long_long, c_unsigned_short, cell, cobject, complex, dict,
+ file, float, frozenset, function, generator, instance, int, iter,
+ list, long, method, module, numeric_array, numpy_complex128,
+ numpy_complex160, numpy_complex192, numpy_complex256, numpy_complex32,
+ numpy_complex64, numpy_descr, numpy_float128, numpy_float16,
+ numpy_float32, numpy_float64, numpy_float80, numpy_float96,
+ numpy_int128, numpy_int16, numpy_int32, numpy_int64, numpy_int8,
+ numpy_iter, numpy_multiiter, numpy_ndarray, numpy_ufunc,
+ numpy_uint128, numpy_uint16, numpy_uint32, numpy_uint64, numpy_uint8,
+ object, property, set, slice, str, tuple, type, unicode
+
+ `typeobj` can be python type instance (e.g. `int`) or one of the string values
+ from the list of typenames above.
+
+- `PySource(<filename>, *components)` --- represents pure python module file.
+
+ One can add `Code` components to `PySource`.
+
+ExtGen provides the following C related components:
+
+- `CSource` --- represents C file. Derived from `FileSource`.
+
+ One can add `CCode` components to `CSource`.
+ String input is converted to `CCode` component.
+
+- `CHeader(<header filename>)`, `CStdHeader(<std header filename>)`. Derived from `Line`.
+
+- `CCode(*components)` --- represents any C code block. Derived from `Code`.
+
+- `CFunction(<funcname>, rctype=CTypeSpec('int'), *components)` --- represents
+ a C function.
+
+ One can add `CArgument`, `CDeclaration`, `CCode` components to `CFunction`.
+
+- `CDeclaration(<ctype>, *declarators)` --- represenets `<ctype> <declarators list>`
+ code idiom. `<ctype>` is `CTypeSpec` instance.
+
+ One can add `CDeclarator` components to `CDeclaration`.
+
+- `CArgument(<argument name>, <ctype>)` --- C function argument. Derived from `CDeclaration`.
+
+- `CTypeSpec(<typename>)` --- C type specifier. Derived from `Line`.
+
+- `CDeclarator(<name>, *initvalues, is_string=..., is_scalar=...)` --- represents
+ `<name> [= <initialzer>]` code idiom.
+
+ String input is converted to `CInitExpr` component.
+
+ExtGen provides the following general purpose components:
+
+- `Word(<word>)`
+
+ Nothing can be added to `Word`.
+
+- `Line(*strings)`
+
+ One can add `Line` component to `Line`.
+ String input is converted to `Line` component.
+
+- `Code(*lines)`
+
+ One can add `Line` and `Code` components to `Code`.
+ String input is converted to `Line` component.
+
+- `FileSource(<filename>, *components)`.
+
+ One can add `Line` and `Code` components to `FileSource`.
+ String input is converted to `Code` component.
+
+Developers reference manual
+===========================
+
To extend ExtGen, one needs to understand the infrastructure of
generating extension modules.
@@ -43,7 +272,7 @@
for constructing code sources:
- creating code components and adding them together to a parent
- component. For example, the `ExtensionModule` instance in the
+ component. For example, the `PyCModule` instance in the
hello example becomes a parent component to a `PyCFunction` instance
after executing `m += f`.
@@ -52,7 +281,7 @@
One can iterate the above process as one wishes.
-The method `ExtensionModule.build()` is defined for convenience.
+The method `PyCModule.build()` is defined for convenience.
It compiles the generated sources, builds an extension module,
imports the resulting module to Python, and returns the module object.
@@ -79,6 +308,11 @@
- `.component_containe_map` is used to find `container_label`
corresponding to `component` argument class.
+- `.update_parent(self, parent)` is called after `parent.add(self,..)`.
+
+- `.finalize(self)` is called after finishing adding new components
+ and before `.generate()` method call.
+
- `.generate(self)` returns a source code string. It recursively
processes all subcomponents, creates code containers, and
evaluates code templates.
@@ -129,7 +363,8 @@
- A component class must have a base class `Component`.
- A component class may redefine `.initialize()`,
- `.init_containers()`, `.update_containers()`, `.get_templates()`
+ `.init_containers()`, `.add()`, `update_parent()`,
+ `.update_containers()`, `.get_templates()`
methods, `.provides()` property method and `.container_options`,
`.component_container_map`, `.default_container_label`,
`.default_component_class_name`, `.template` attributes.
@@ -157,43 +392,12 @@
- All classes derived from `Component` are available as
`Component.<subclass name>`.
-Here follows a simplified version of `ExtensionModule.template`::
-
- #include "Python.h"
-
- %(Header)s
- %(TypeDef)s
- %(Extern)s
- %(CCode)s
- %(CAPICode)s
- %(ObjDecl)s
-
- static PyObject* extgen_module;
-
- static PyMethodDef extgen_module_methods[] = {
- %(ModuleMethod)s
- {NULL,NULL,0,NULL}
- };
-
- PyMODINIT_FUNC init%(modulename)s(void) {
- extgen_module = Py_InitModule("%(modulename)s", extgen_module_methods);
- %(ModuleInit)s
- return;
- capi_error:
- if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_RuntimeError, "failed to initialize %(modulename)s module.");
- }
- return;
- }
-
-Here formatting mapping keys `Header`, `TypeDef`, etc are the labels
-of containers which will be used in the templare evaluation.
See `extgen/*.py` files for more examples how to redefine `Component`
class methods and attributes.
Using `Container` class
-=======================
+-----------------------
`Container` class has the following optional arguments:
@@ -209,6 +413,8 @@
- `indent_offset=0`
- `user_defined_str=None`
- `replace_map={}`
+ - `ignore_empty_content=False`
+ - `skip_prefix_suffix_when_single=False`
that are used to enhance the behaviour of `Container.__str__()`
method. By default, `Container.__str__()` returns
@@ -241,67 +447,3 @@
Full control over the `__str__()` method is obtained via
defining `user_defined_str` that should be a callable object taking
list as input and return a string.
-
-
-Component classes
-=================
-
-ExtGen package defines the following extension module component classes:
-
- - `ExtensionModule(<modulename>, *components, numpy=False,
- provides=.., title=.., description=..)` ---
- represents an extension module component. If `numpy` is `True` then
- `NumPy` support will be added to an extension module.
-
- - `PyCFunction(<name>, *components, provides=.., title=.., description=..)` ---
- represents an extension function component.
-
- - `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 component.
-
- - `CType(<name or python type obj>)` --- represents a predefined or intrinsic C type
- with a given name.
-
- - `CTypeAlias(<name>, <ctype>)` --- represents `typedef ctype name;`
- declaration.
-
- - `CTypeFuncAlias(<name>, <return ctype>, <argument ctypes>)` ---
- represents `typedef rctype (*name)(actype1,..)` declaration.
- Use `.add()` method to add more argument types.
-
- - `CTypePtr(<ctype>)` --- represents `typedef ctype* ctype_ptr;`
- declaration.
-
- - `CTypeStruct(<name>, *declarations)` --- represents `typedef struct {
- <declarations> } name;` declaration. Use `.add()` method to add
- more declarations.
-
- - `CDecl(<ctype>, *names)` --- represents `ctype name1, name2, ..;`
- declaration. Use `.add()` method to add more names.
-
- - `CTypePython(<python type object or type name>)`
- --- represents python type object in C, see
- `CTypePython.typeinfo_map.keys()` for supported type names
- (there are over 70 supported types).
-
-
-Predefined components
-=====================
-
-ExtGen defines the following components that can be retrived
-using `Component.get(<provides>)` method:
-
-- `'Python.h'` - include `Pyhton.h` header file.
-
-- `'arrayobject.h'` - include NumPy header files.
-
-- `'import_array'` - code for importing numpy package to extension
- module.
-
Added: trunk/numpy/f2py/lib/extgen/py_support.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/py_support.py 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/py_support.py 2007-08-10 13:57:35 UTC (rev 3962)
@@ -0,0 +1,833 @@
+
+__all__ = ['PySource', 'PyCFunction', 'PyCModule', 'PyCTypeSpec', 'PyCArgument', 'PyCReturn']
+
+import os
+import sys
+from base import Component
+from utils import *
+from c_support import *
+
+class PySource(FileSource):
+
+ template_py_header = '''\
+#!/usr/bin/env python
+# This file %(path)r is generated using ExtGen tool
+# from NumPy version %(numpy_version)s.
+# ExtGen is developed by Pearu Peterson <pearu.peterson at gmail.com>.
+# For more information see http://www.scipy.org/ExtGen/ .'''
+
+ container_options = dict(
+ Content = dict(default='',
+ prefix = template_py_header + '\n',
+ suffix = '\n',
+ use_indent=True)
+ )
+
+ pass
+
+class PyCModule(CSource):
+
+ """
+ >>> m = PyCModule('PyCModule_test', title='This is first line.\\nSecond line.', description='This is a module.\\nYes, it is.')
+ >>> mod = m.build()
+ >>> print mod.__doc__ #doctest: +ELLIPSIS
+ This module 'PyCModule_test' is generated with ExtGen from NumPy version ...
+ <BLANKLINE>
+ This is first line.
+ Second line.
+ <BLANKLINE>
+ This is a module.
+ Yes, it is.
+ """
+
+ template = CSource.template_c_header + '''
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+#include "Python.h"
+%(CHeader)s
+%(CTypeDef)s
+%(CProto)s
+%(CDefinition)s
+%(CAPIDefinition)s
+%(CDeclaration)s
+%(PyCModuleCDeclaration)s
+%(CMainProgram)s
+#ifdef __cplusplus
+}
+#endif
+'''
+
+ container_options = CSource.container_options.copy()
+ container_options.update(CAPIDefinition=container_options['CDefinition'],
+ PyCModuleCDeclaration=dict(default='<KILLLINE>',
+ ignore_empty_content=True),
+ )
+
+ component_container_map = dict(
+ PyCModuleInitFunction = 'CMainProgram',
+ PyCModuleCDeclaration = 'PyCModuleCDeclaration',
+ PyCFunction = 'CAPIDefinition',
+ )
+
+ def initialize(self, pyname, *components, **options):
+ self.pyname = pyname
+ self.title = options.pop('title', None)
+ self.description = options.pop('description', None)
+
+ self = CSource.initialize(self, '%smodule.c' % (pyname), **options)
+
+ self.cdecl = PyCModuleCDeclaration(pyname)
+ self += self.cdecl
+
+ self.main = PyCModuleInitFunction(pyname)
+ self += self.main
+ map(self.add, components)
+ return self
+
+ def update_parent(self, parent):
+ if isinstance(parent, Component.SetupPy):
+ self.update_SetupPy(parent)
+
+ def update_SetupPy(self, parent):
+ parent.setup_py += self.evaluate(' config.add_extension(%(pyname)r, sources = ["%(extmodulesrc)s"])',
+ extmodulesrc = self.path)
+ parent.init_py += 'import %s' % (self.pyname)
+
+ def build(self, build_dir=None, clean_at_exit=None):
+ """ build(build_dir=None, clean_at_exit=None)
+
+ A convenience function to build, import, an return
+ an extension module object.
+ """
+ if build_dir is None:
+ import tempfile
+ import time
+ packagename = 'extgen_' + str(hex(int(time.time()*10000000)))[2:]
+ build_dir = os.path.join(tempfile.gettempdir(), packagename)
+ clean_at_exit = True
+ if clean_at_exit:
+ import atexit
+ import shutil
+ atexit.register(lambda d=build_dir: shutil.rmtree(d))
+ self.info('directory %r will be removed at exit from python.' % (build_dir))
+
+ setup = Component.SetupPy(build_dir)
+ setup += self
+ s,o = setup.execute('build_ext','--inplace')
+ if s:
+ self.info('return status=%s' % (s))
+ self.info(o)
+ raise RuntimeError('failed to build extension module %r' % (self.pyname))
+ sys.path.insert(0, os.path.dirname(build_dir))
+ packagename = os.path.basename(build_dir)
+ try:
+ p = __import__(packagename)
+ #exec 'import %s as p' % (packagename)
+ m = getattr(p, self.pyname)
+ except:
+ self.info(sys.path)
+ del sys.path[0]
+ raise
+ else:
+ del sys.path[0]
+ return m
+
+class PyCModuleCDeclaration(Component):
+
+ template = '''\
+static PyObject* extgen_module;
+static
+PyMethodDef extgen_module_methods[] = {
+ %(PyMethodDef)s
+ {NULL,NULL,0,NULL}
+};
+static
+char extgen_module_doc[] =
+"This module %(pyname)r is generated with ExtGen from NumPy version %(numpy_version)s."
+%(Title)s
+%(Description)s
+%(FunctionSignature)s
+;'''
+ container_options = dict(
+ PyMethodDef = dict(suffix=',', skip_suffix_when_empty=True,separator=',\n',
+ default='<KILLLINE>', use_indent=True, ignore_empty_content=True),
+ FunctionSignature = dict(prefix='"\\n\\n:Functions:\\n"\n" ', skip_prefix_when_empty=True, use_indent=True,
+ ignore_empty_content=True, default='<KILLLINE>',
+ separator = '"\n" ', suffix='"', skip_suffix_when_empty=True,
+ ),
+ Title = dict(default='<KILLLINE>',prefix='"\\n\\n',suffix='"',separator='\\n"\n"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True, replace_map={'\n':'\\n'}),
+ Description = dict(default='<KILLLINE>',prefix='"\\n\\n"\n"',
+ suffix='"',separator='\\n"\n"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True, replace_map={'\n':'\\n'}),
+ )
+
+ default_component_class_name = 'Line'
+
+ def initialize(self, pyname):
+ self.pyname = pyname
+ return self
+
+ def update_parent(self, parent):
+ if isinstance(parent, PyCModule):
+ self.update_PyCModule(parent)
+
+ def update_PyCModule(self, parent):
+ if parent.title:
+ self.add(parent.title, 'Title')
+ if parent.description:
+ self.add(parent.description, 'Description')
+
+
+class PyCModuleInitFunction(CFunction):
+
+ """
+ >>> f = PyCModuleInitFunction('test_PyCModuleInitFunction')
+ >>> print f.generate()
+ PyMODINIT_FUNC
+ inittest_PyCModuleInitFunction(void) {
+ PyObject* extgen_module_dict = NULL;
+ PyObject* extgen_str_obj = NULL;
+ extgen_module = Py_InitModule(\"test_PyCModuleInitFunction\", extgen_module_methods);
+ if ((extgen_module_dict = PyModule_GetDict(extgen_module))==NULL) goto capi_error;
+ if ((extgen_str_obj = PyString_FromString(extgen_module_doc))==NULL) goto capi_error;
+ PyDict_SetItemString(extgen_module_dict, \"__doc__\", extgen_str_obj);
+ Py_DECREF(extgen_str_obj);
+ if ((extgen_str_obj = PyString_FromString(\"restructuredtext\"))==NULL) goto capi_error;
+ PyDict_SetItemString(extgen_module_dict, \"__docformat__\", extgen_str_obj);
+ Py_DECREF(extgen_str_obj);
+ return;
+ capi_error:
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_RuntimeError, \"failed to initialize 'test_PyCModuleInitFunction' module.\");
+ }
+ return;
+ }
+ """
+
+ template = '''\
+%(CSpecifier)s
+%(CTypeSpec)s
+%(name)s(void) {
+ PyObject* extgen_module_dict = NULL;
+ PyObject* extgen_str_obj = NULL;
+ %(CDeclaration)s
+ extgen_module = Py_InitModule("%(pyname)s", extgen_module_methods);
+ if ((extgen_module_dict = PyModule_GetDict(extgen_module))==NULL) goto capi_error;
+ if ((extgen_str_obj = PyString_FromString(extgen_module_doc))==NULL) goto capi_error;
+ PyDict_SetItemString(extgen_module_dict, "__doc__", extgen_str_obj);
+ Py_DECREF(extgen_str_obj);
+ if ((extgen_str_obj = PyString_FromString("restructuredtext"))==NULL) goto capi_error;
+ PyDict_SetItemString(extgen_module_dict, "__docformat__", extgen_str_obj);
+ Py_DECREF(extgen_str_obj);
+ %(CBody)s
+ return;
+capi_error:
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_RuntimeError, "failed to initialize %(pyname)r module.");
+ }
+ return;
+}'''
+
+ def initialize(self, pyname, *components, **options):
+ self.pyname = pyname
+ self.title = options.pop('title', None)
+ self.description = options.pop('description', None)
+ self = CFunction.initialize(self, 'init'+pyname, 'PyMODINIT_FUNC', *components, **options)
+ return self
+
+#helper classes for PyCFunction
+class KWListBase(Word): parent_container_options = dict(separator=', ', suffix=', ', skip_suffix_when_empty=True)
+class ReqKWList(KWListBase): pass
+class OptKWList(KWListBase): pass
+class ExtKWList(KWListBase): pass
+class ArgBase(Word): parent_container_options = dict(separator=', ')
+class ReqArg(ArgBase): pass
+class OptArg(ArgBase): pass
+class ExtArg(ArgBase): pass
+class RetArg(ArgBase):
+ parent_container_options = dict(separator=', ', prefix='(', suffix=')', default = 'None',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ skip_prefix_suffix_when_single=True)
+class OptExtArg(ArgBase):
+ parent_container_options = dict(separator=', ', prefix=' [, ', skip_prefix_when_empty=True,
+ suffix=']', skip_suffix_when_empty=True)
+class ArgDocBase(Word):
+ parent_container_options = dict(default='<KILLLINE>', prefix='"\\n\\nArguments:\\n"\n" ',
+ separator='\\n"\n" ', suffix='"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True, replace_map={'\n':'\\n'})
+class ReqArgDoc(ArgDocBase):
+ parent_container_options = ArgDocBase.parent_container_options.copy()
+ parent_container_options.update(prefix='"\\n\\n:Parameters:\\n"\n" ')
+class OptArgDoc(ArgDocBase):
+ parent_container_options = ArgDocBase.parent_container_options.copy()
+ parent_container_options.update(prefix='"\\n\\n:Optional parameters:\\n"\n" ')
+class ExtArgDoc(ArgDocBase):
+ parent_container_options = ArgDocBase.parent_container_options.copy()
+ parent_container_options.update(prefix='"\\n\\n:Extra parameters:\\n"\n" ')
+class RetArgDoc(ArgDocBase):
+ parent_container_options = ArgDocBase.parent_container_options.copy()
+ parent_container_options.update(prefix='"\\n\\n:Returns:\\n"\n" ',
+ default='"\\n\\n:Returns:\\n None"')
+class ArgFmtBase(Word): parent_container_options = dict(separator='')
+class ReqArgFmt(ArgFmtBase): pass
+class OptArgFmt(ArgFmtBase): pass
+class ExtArgFmt(ArgFmtBase): pass
+class RetArgFmt(ArgFmtBase): pass
+class OptExtArgFmt(ArgFmtBase):
+ parent_container_options = dict(separator='', prefix='|', skip_prefix_when_empty=True)
+class ArgObjBase(Word): parent_container_options = dict(separator=', ', prefix=', ', skip_prefix_when_empty=True)
+class ReqArgObj(ArgObjBase): pass
+class OptArgObj(ArgObjBase): pass
+class ExtArgObj(ArgObjBase): pass
+class RetArgObj(ArgObjBase): pass
+
+class FunctionSignature(Component):
+ template = '%(name)s(%(ReqArg)s%(OptExtArg)s) -> %(RetArg)s'
+ parent_container_options = dict()
+ container_options = dict(
+ ReqArg = ReqArg.parent_container_options,
+ OptArg = OptArg.parent_container_options,
+ ExtArg = ExtArg.parent_container_options,
+ RetArg = RetArg.parent_container_options,
+ OptExtArg = OptExtArg.parent_container_options,
+ )
+ def initialize(self, name, *components, **options):
+ self.name = name
+ map(self.add, components)
+ return self
+ def update_containers(self):
+ self.container_OptExtArg += self.container_OptArg + self.container_ExtArg
+
+class PyCFunction(CFunction):
+
+ """
+ >>> from __init__ import *
+ >>> f = PyCFunction('foo')
+ >>> print f.generate()
+ static
+ char pyc_function_foo_doc[] =
+ \" foo() -> None\"
+ \"\\n\\n:Returns:\\n None\"
+ ;
+ static
+ PyObject*
+ pyc_function_foo(PyObject *pyc_self, PyObject *pyc_args, PyObject *pyc_keywds) {
+ PyObject * volatile pyc_buildvalue = NULL;
+ volatile int capi_success = 1;
+ static char *capi_kwlist[] = {NULL};
+ if (PyArg_ParseTupleAndKeywords(pyc_args, pyc_keywds,"",
+ capi_kwlist)) {
+ capi_success = !PyErr_Occurred();
+ if (capi_success) {
+ pyc_buildvalue = Py_BuildValue("");
+ }
+ }
+ return pyc_buildvalue;
+ }
+ >>> f = PyCFunction('foo', title=' Function title.\\nSecond line.', description=' This is a function.\\n2nd line.')
+ >>> e = PyCModule('PyCFunction_test', f)
+ >>> mod = e.build()
+ >>> print mod.foo.__doc__
+ foo() -> None
+ <BLANKLINE>
+ Function title.
+ Second line.
+ <BLANKLINE>
+ This is a function.
+ 2nd line.
+ <BLANKLINE>
+ :Returns:
+ None
+ """
+
+ template = '''\
+static
+char %(name)s_doc[] =
+" %(FunctionSignature)s"
+%(Title)s
+%(Description)s
+%(ReqArgDoc)s
+%(RetArgDoc)s
+%(OptArgDoc)s
+%(ExtArgDoc)s
+;
+static
+PyObject*
+%(name)s(PyObject *pyc_self, PyObject *pyc_args, PyObject *pyc_keywds) {
+ PyObject * volatile pyc_buildvalue = NULL;
+ volatile int capi_success = 1;
+ %(CDeclaration)s
+ static char *capi_kwlist[] = {%(ReqKWList)s%(OptKWList)s%(ExtKWList)sNULL};
+ if (PyArg_ParseTupleAndKeywords(pyc_args, pyc_keywds,"%(ReqArgFmt)s%(OptExtArgFmt)s",
+ capi_kwlist%(ReqArgObj)s%(OptArgObj)s%(ExtArgObj)s)) {
+ %(FromPyObj)s
+ %(CBody)s
+ capi_success = !PyErr_Occurred();
+ if (capi_success) {
+ %(PyObjFrom)s
+ pyc_buildvalue = Py_BuildValue("%(RetArgFmt)s"%(RetArgObj)s);
+ %(CleanPyObjFrom)s
+ }
+ %(CleanCBody)s
+ %(CleanFromPyObj)s
+ }
+ return pyc_buildvalue;
+}'''
+
+ container_options = CFunction.container_options.copy()
+
+ container_options.update(\
+
+ TMP = dict(),
+
+ ReqArg = ReqArg.parent_container_options,
+ OptArg = OptArg.parent_container_options,
+ ExtArg = ExtArg.parent_container_options,
+ RetArg = RetArg.parent_container_options,
+
+ FunctionSignature = FunctionSignature.parent_container_options,
+
+ OptExtArg = OptExtArg.parent_container_options,
+
+ Title = dict(default='<KILLLINE>',prefix='"\\n\\n',suffix='"',separator='\\n"\n"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True, replace_map={'\n':'\\n'}),
+ Description = dict(default='<KILLLINE>',prefix='"\\n\\n"\n"',
+ suffix='"',separator='\\n"\n"',
+ skip_prefix_when_empty=True, skip_suffix_when_empty=True,
+ use_firstline_indent=True, replace_map={'\n':'\\n'}),
+
+ ReqArgDoc = ReqArgDoc.parent_container_options,
+ OptArgDoc = OptArgDoc.parent_container_options,
+ ExtArgDoc = ExtArgDoc.parent_container_options,
+ RetArgDoc = RetArgDoc.parent_container_options,
+
+ ReqKWList = ReqKWList.parent_container_options,
+ OptKWList = OptKWList.parent_container_options,
+ ExtKWList = ExtKWList.parent_container_options,
+
+ ReqArgFmt = ReqArgFmt.parent_container_options,
+ OptArgFmt = OptArgFmt.parent_container_options,
+ ExtArgFmt = ExtArgFmt.parent_container_options,
+ OptExtArgFmt = OptExtArgFmt.ExtArgFmt.parent_container_options,
+ RetArgFmt = ExtArgFmt.parent_container_options,
+
+ ReqArgObj = ReqArgObj.parent_container_options,
+ OptArgObj = OptArgObj.parent_container_options,
+ ExtArgObj = ExtArgObj.parent_container_options,
+ RetArgObj = RetArgObj.parent_container_options,
+
+ FromPyObj = CCode.parent_container_options,
+ PyObjFrom = CCode.parent_container_options,
+
+ CleanPyObjFrom = dict(default='<KILLLINE>', reverse=True, use_indent=True, ignore_empty_content=True),
+ CleanCBody = dict(default='<KILLLINE>', reverse=True, use_indent=True, ignore_empty_content=True),
+ CleanFromPyObj = dict(default='<KILLLINE>', reverse=True, use_indent=True, ignore_empty_content=True),
+
+ )
+
+ default_component_class_name = 'CCode'
+
+ component_container_map = CFunction.component_container_map.copy()
+ component_container_map.update(
+ PyCArgument = 'TMP',
+ CCode = 'CBody',
+ )
+
+ def initialize(self, pyname, *components, **options):
+ self.pyname = pyname
+ self.title = options.pop('title', None)
+ self.description = options.pop('description', None)
+ self = CFunction.initialize(self, 'pyc_function_'+pyname, 'PyObject*', **options)
+ self.signature = FunctionSignature(pyname)
+ self += self.signature
+ if self.title:
+ self.add(self.title, 'Title')
+ if self.description:
+ self.add(self.description, 'Description')
+ map(self.add, components)
+ return self
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.pyname]+[c for (c,l) in self.components])))
+
+ def update_parent(self, parent):
+ if isinstance(parent, PyCModule):
+ self.update_PyCModule(parent)
+
+ def update_PyCModule(self, parent):
+ t = ' {"%(pyname)s", (PyCFunction)%(name)s, METH_VARARGS | METH_KEYWORDS, %(name)s_doc}'
+ parent.cdecl.add(self.evaluate(t),'PyMethodDef')
+ parent.cdecl.add(self.signature,'FunctionSignature')
+
+ def update_containers(self):
+ self.container_OptExtArg += self.container_OptArg + self.container_ExtArg
+ self.container_OptExtArgFmt += self.container_OptArgFmt + self.container_ExtArgFmt
+
+
+class PyCArgument(Component):
+
+ """
+ >>> from __init__ import *
+ >>> a = PyCArgument('a')
+ >>> print a
+ PyCArgument('a', PyCTypeSpec('object'))
+ >>> print a.generate()
+ a
+ >>> f = PyCFunction('foo')
+ >>> f += a
+ >>> f += PyCArgument('b')
+ >>> m = PyCModule('PyCArgument_test')
+ >>> m += f
+ >>> #print m.generate()
+ >>> mod = m.build()
+ >>> print mod.__doc__ #doctest: +ELLIPSIS
+ This module 'PyCArgument_test' is generated with ExtGen from NumPy version ...
+ <BLANKLINE>
+ :Functions:
+ foo(a, b) -> None
+
+ """
+
+ container_options = dict(
+ TMP = dict()
+ )
+
+ component_container_map = dict(
+ PyCTypeSpec = 'TMP'
+ )
+
+ template = '%(name)s'
+
+ def initialize(self, name, ctype = object, *components, **options):
+ self.input_intent = options.pop('input_intent','required') # 'optional', 'extra', 'hide'
+ self.output_intent = options.pop('output_intent','hide') # 'return'
+ self.input_title = options.pop('input_title', None)
+ 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', [])
+ title = options.pop('title', None)
+ description = options.pop('description', None)
+ if title is not None:
+ if self.input_intent!='hide':
+ if self.input_title is None:
+ self.input_title = title
+ elif self.output_intent!='hide':
+ if self.output_title is None:
+ self.output_title = title
+ if description is not None:
+ if self.input_intent!='hide':
+ if self.input_description is None:
+ self.input_description = description
+ elif self.output_intent!='hide':
+ if self.output_description is None:
+ self.output_description = description
+ if options: self.warning('%s unused options: %s\n' % (self.__class__.__name__, options))
+
+ self.name = name
+ self.ctype = ctype = PyCTypeSpec(ctype)
+ self += ctype
+
+ self.cvar = name
+ self.pycvar = None
+ self.retpycvar = None
+
+ retfmt = ctype.get_pyret_fmt(self)
+ if isinstance(ctype, PyCTypeSpec):
+ if retfmt and retfmt in 'SON':
+ 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
+ self.retpycvar = name
+ else:
+ self.pycvar = name + '_pyc'
+ self.retpycvar = name + '_pyc_r'
+
+ ctype.set_titles(self)
+
+ map(self.add, components)
+ return self
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.name]+[c for (c,l) in self.components])))
+
+ def update_parent(self, parent):
+ if isinstance(parent, PyCFunction):
+ self.update_PyCFunction(parent)
+
+ def update_PyCFunction(self, parent):
+ ctype = self.ctype
+
+ 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)
+ else:
+ input_doc_descr = None
+ if self.output_description is not None:
+ output_doc_descr = ' %s' % (self.output_description)
+ else:
+ output_doc_descr = None
+
+ # add components to parent:
+ parent += ctype.get_decl(self)
+ if self.input_intent=='required':
+ parent += ReqArg(self.name)
+ parent.signature += ReqArg(self.name)
+ parent += ReqKWList('"' + self.name + '"')
+ parent += ReqArgFmt(ctype.get_pyarg_fmt(self))
+ parent += ReqArgObj(ctype.get_pyarg_obj(self))
+ parent += ReqArgDoc(input_doc_title)
+ parent += ReqArgDoc(input_doc_descr)
+ elif self.input_intent=='optional':
+ parent += OptArg(self.name)
+ parent.signature += OptArg(self.name)
+ parent += OptKWList('"' + self.name + '"')
+ parent += OptArgFmt(ctype.get_pyarg_fmt(self))
+ parent += OptArgObj(ctype.get_pyarg_obj(self))
+ parent += OptArgDoc(input_doc_title)
+ parent += OptArgDoc(input_doc_descr)
+ elif self.input_intent=='extra':
+ parent += ExtArg(self.name)
+ parent.signature += ExtArg(self.name)
+ parent += ExtKWList('"' + self.name + '"')
+ parent += ExtArgFmt(ctype.get_pyarg_fmt(self))
+ parent += ExtArgObj(ctype.get_pyarg_obj(self))
+ parent += ExtArgDoc(input_doc_title)
+ parent += ExtArgDoc(input_doc_descr)
+ elif self.input_intent=='hide':
+ pass
+ else:
+ raise NotImplementedError('input_intent=%r' % (self.input_intent))
+
+ if self.output_intent=='return':
+ parent += RetArg(self.name)
+ parent.signature += RetArg(self.name)
+ parent += RetArgFmt(ctype.get_pyret_fmt(self))
+ parent += RetArgObj(ctype.get_pyret_obj(self))
+ parent += RetArgDoc(output_doc_title)
+ parent += RetArgDoc(output_doc_descr)
+ elif self.output_intent=='hide':
+ pass
+ else:
+ raise NotImplementedError('output_intent=%r' % (self.output_intent))
+
+class PyCReturn(PyCArgument):
+
+ def initialize(self, name, ctype = object, *components, **options):
+ return PyCArgument(name, ctype, input_intent='hide', output_intent='return', *components, **options)
+
+class PyCTypeSpec(CTypeSpec):
+
+ """
+ >>> s = PyCTypeSpec(object)
+ >>> print s
+ PyCTypeSpec('object')
+ >>> print s.generate()
+ PyObject*
+ """
+
+ typeinfo_map = dict(
+ int = ('PyInt_Type', 'PyIntObject*', 'O!', 'N', 'NULL'),
+ long = ('PyLong_Type', 'PyLongObject*', 'O!', 'N', 'NULL'),
+ float = ('PyFloat_Type', 'PyFloatObject*', 'O!', 'N', 'NULL'),
+ complex = ('PyComplex_Type', 'PyComplexObject*', 'O!', 'N', 'NULL'),
+ str = ('PyString_Type', 'PyStringObject*', 'S', 'N', 'NULL'),
+ unicode = ('PyUnicode_Type', 'PyUnicodeObject*', 'U', 'N', 'NULL'),
+ buffer = ('PyBuffer_Type', 'PyBufferObject*', 'O!', 'N', 'NULL'),
+ tuple = ('PyTuple_Type', 'PyTupleObject*', 'O!', 'N', 'NULL'),
+ list = ('PyList_Type', 'PyListObject*', 'O!', 'N', 'NULL'),
+ dict = ('PyDict_Type', 'PyDictObject*', 'O!', 'N', 'NULL'),
+ file = ('PyFile_Type', 'PyFileObject*', 'O!', 'N', 'NULL'),
+ instance = ('PyInstance_Type', 'PyObject*', 'O!', 'N', 'NULL'),
+ function = ('PyFunction_Type', 'PyFunctionObject*', 'O!', 'N', 'NULL'),
+ method = ('PyMethod_Type', 'PyObject*', 'O!', 'N', 'NULL'),
+ module = ('PyModule_Type', 'PyObject*', 'O!', 'N', 'NULL'),
+ iter = ('PySeqIter_Type', 'PyObject*', 'O!', 'N', 'NULL'),
+ property = ('PyProperty_Type', 'PyObject*', 'O!', 'N', 'NULL'),
+ slice = ('PySlice_Type', 'PyObject*', 'O!', 'N', 'NULL'),
+ cell = ('PyCell_Type', 'PyCellObject*', 'O!', 'N', 'NULL'),
+ generator = ('PyGen_Type', 'PyGenObject*', 'O!', 'N', 'NULL'),
+ set = ('PySet_Type', 'PySetObject*', 'O!', 'N', 'NULL'),
+ frozenset = ('PyFrozenSet_Type', 'PySetObject*', 'O!', 'N', 'NULL'),
+ cobject = (None, 'PyCObject*', 'O', 'N', 'NULL'),
+ type = ('PyType_Type', 'PyTypeObject*', 'O!', 'N', 'NULL'),
+ object = (None, 'PyObject*', 'O', 'N', 'NULL'),
+ numpy_ndarray = ('PyArray_Type', 'PyArrayObject*', 'O!', 'N', 'NULL'),
+ numpy_descr = ('PyArrayDescr_Type','PyArray_Descr', 'O!', 'N', 'NULL'),
+ numpy_ufunc = ('PyUFunc_Type', 'PyUFuncObject*', 'O!', 'N', 'NULL'),
+ numpy_iter = ('PyArrayIter_Type', 'PyArrayIterObject*', 'O!', 'N', 'NULL'),
+ numpy_multiiter = ('PyArrayMultiIter_Type', 'PyArrayMultiIterObject*', 'O!', 'N', 'NULL'),
+ numpy_int8 = ('PyInt8ArrType_Type', 'PyInt8ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_int16 = ('PyInt16ArrType_Type', 'PyInt16ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_int32 = ('PyInt32ArrType_Type', 'PyInt32ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_int64 = ('PyInt64ArrType_Type', 'PyInt64ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_int128 = ('PyInt128ArrType_Type', 'PyInt128ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_uint8 = ('PyUInt8ArrType_Type', 'PyUInt8ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_uint16 = ('PyUInt16ArrType_Type', 'PyUInt16ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_uint32 = ('PyUInt32ArrType_Type', 'PyUInt32ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_uint64 = ('PyUInt64ArrType_Type', 'PyUInt64ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_uint128 = ('PyUInt128ArrType_Type', 'PyUInt128ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_float16 = ('PyFloat16ArrType_Type', 'PyFloat16ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_float32 = ('PyFloat32ArrType_Type', 'PyFloat32ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_float64 = ('PyFloat64ArrType_Type', 'PyFloat64ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_float80 = ('PyFloat80ArrType_Type', 'PyFloat80ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_float96 = ('PyFloat96ArrType_Type', 'PyFloat96ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_float128 = ('PyFloat128ArrType_Type', 'PyFloat128ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_complex32 = ('PyComplex32ArrType_Type', 'PyComplex32ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_complex64 = ('PyComplex64ArrType_Type', 'PyComplex64ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_complex128 = ('PyComplex128ArrType_Type', 'PyComplex128ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_complex160 = ('PyComplex160ArrType_Type', 'PyComplex160ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_complex192 = ('PyComplex192ArrType_Type', 'PyComplex192ScalarObject*', 'O!', 'N', 'NULL'),
+ numpy_complex256 = ('PyComplex256ArrType_Type', 'PyComplex256ScalarObject*', 'O!', 'N', 'NULL'),
+ numeric_array = ('PyArray_Type', 'PyArrayObject*', 'O!', 'N', 'NULL'),
+ c_char = (None, 'char', 'b', 'b', '0'),
+ c_unsigned_char = (None, 'unsigned char', 'B', 'B', '0'),
+ c_short = (None, 'short int', 'h', 'h', '0'),
+ c_unsigned_short = (None, 'unsigned short int', 'H', 'H', '0'),
+ c_int = (None,'int', 'i', 'i', '0'),
+ c_unsigned_int = (None,'unsigned int', 'I', 'I', '0'),
+ c_long = (None,'long', 'l', 'l', '0'),
+ c_unsigned_long = (None,'unsigned long', 'k', 'k', '0'),
+ c_long_long = (None,'PY_LONG_LONG', 'L', 'L', '0'),
+ c_unsigned_long_long = (None,'unsigned PY_LONG_LONG', 'K', 'K', '0'),
+ c_Py_ssize_t = (None,'Py_ssize_t', 'n', 'n', '0'),
+ c_char1 = (None,'char', 'c', 'c', '"\\0"'),
+ c_float = (None,'float', 'f', 'f', '0.0'),
+ c_double = (None,'double', 'd', 'd', '0.0'),
+ c_Py_complex = (None,'Py_complex', 'D', 'D', '{0.0, 0.0}'),
+ c_const_char_ptr = (None,'const char *', 'z', 'z', 'NULL'),
+ c_Py_UNICODE = (None,'Py_UNICODE*','u','u', 'NULL'),
+ )
+
+ def initialize(self, typeobj):
+ if isinstance(typeobj, self.__class__):
+ return typeobj
+
+ m = self.typeinfo_map
+
+ key = None
+ if isinstance(typeobj, type):
+ if typeobj.__module__=='__builtin__':
+ key = typeobj.__name__
+ if key=='array':
+ key = 'numeric_array'
+ elif typeobj.__module__=='numpy':
+ key = 'numpy_' + typeobj.__name__
+ elif isinstance(typeobj, str):
+ key = typeobj
+ if key.startswith('numpy_'):
+ k = key[6:]
+ named_scalars = ['byte','short','int','long','longlong',
+ 'ubyte','ushort','uint','ulong','ulonglong',
+ 'intp','uintp',
+ 'float_','double',
+ 'longfloat','longdouble',
+ 'complex_',
+ ]
+ if k in named_scalars:
+ import numpy
+ key = 'numpy_' + getattr(numpy, k).__name__
+
+ try: item = m[key]
+ except KeyError:
+ raise NotImplementedError('%s: need %s support' % (self.__class__.__name__, typeobj))
+
+ self.typeobj_name = key
+ self.ctypeobj = item[0]
+ self.line = item[1]
+ self.arg_fmt = item[2]
+ self.ret_fmt = item[3]
+ self.cinit_value = item[4]
+
+ #if key.startswith('numpy_'):
+ # self.add(Component.get('arrayobject.h'), 'Header')
+ # self.add(Component.get('import_array'), 'ModuleInit')
+ if key.startswith('numeric_'):
+ raise NotImplementedError(self.__class__.__name__ + ': Numeric support')
+
+ return self
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(self.typeobj_name)]+[repr(c) for (c,l) in self.components]))
+
+ def get_pyarg_fmt(self, arg):
+ if arg.input_intent=='hide': return None
+ return self.arg_fmt
+
+ def get_pyarg_obj(self, arg):
+ if arg.input_intent=='hide': return None
+ if self.arg_fmt=='O!':
+ return '&%s, &%s' % (self.ctypeobj, arg.pycvar)
+ return '&' + arg.pycvar
+
+ def get_pyret_fmt(self, arg):
+ if arg.output_intent=='hide': return None
+ return self.ret_fmt
+
+ def get_pyret_obj(self, arg):
+ if arg.output_intent=='return':
+ if self.get_pyret_fmt(arg)=='D':
+ return '&' + arg.retpycvar
+ return arg.retpycvar
+ return
+
+ def get_init_value(self, arg):
+ return self.cinit_value
+
+ def set_titles(self, arg):
+ if self.typeobj_name == 'object':
+ tn = 'a python ' + self.typeobj_name
+ else:
+ if self.typeobj_name.startswith('numpy_'):
+ tn = 'a numpy.' + self.typeobj_name[6:] + ' object'
+ elif self.typeobj_name.startswith('c_'):
+ n = self.typeobj_name[2:]
+ if not n.startswith('Py_'):
+ n = ' '.join(n.split('_'))
+ tn = 'a to C ' + n + ' convertable object'
+ else:
+ tn = 'a python ' + self.typeobj_name + ' object'
+ if arg.input_intent!='hide':
+ r = ''
+ if arg.input_title: r = ', ' + arg.input_title
+ arg.input_title = tn + r
+ if arg.output_intent!='hide':
+ r = ''
+ if arg.output_title: r = ', ' + arg.output_title
+ arg.output_title = tn + r
+
+ def get_decl(self, arg):
+ init_value = self.get_init_value(arg)
+ if init_value:
+ init = ' = %s' % (init_value)
+ else:
+ init = ''
+ if arg.pycvar and arg.pycvar==arg.retpycvar:
+ return CDeclaration(self, '%s%s' % (arg.pycvar, init))
+ else:
+ if arg.input_intent!='hide':
+ return CDeclaration(self, '%s%s' % (arg.pycvar, init))
+ if arg.output_intent!='hide':
+ return CDeclaration(self, '%s%s' % (arg.retpycvar, init))
+ return
+
+def _test():
+ import doctest
+ doctest.testmod()
+
+if __name__ == "__main__":
+ _test()
Added: trunk/numpy/f2py/lib/extgen/setup_py.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/setup_py.py 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/setup_py.py 2007-08-10 13:57:35 UTC (rev 3962)
@@ -0,0 +1,103 @@
+
+__all__ = ['SetupPy']
+
+import os
+import sys
+from numpy.distutils.exec_command import exec_command
+from base import Component
+from utils import FileSource
+
+def write_files(container):
+ s = ['creating files and directories:']
+ for filename, i in container.label_map.items():
+ content = container.list[i]
+ d,f = os.path.split(filename)
+ if d and not os.path.isdir(d):
+ s.append(' %s/' % (d))
+ if not Component._generate_dry_run:
+ os.makedirs(d)
+ s.append(' %s' % (filename))
+ if not Component._generate_dry_run:
+ f = file(filename,'w')
+ f.write(content)
+ f.close()
+ return '\n'.join(s)
+
+
+class SetupPy(Component):
+
+ """
+ >>> from __init__ import *
+ >>> s = SetupPy('SetupPy_doctest')
+ >>> s += PyCModule('foo')
+ >>> s,o = s.execute('build_ext', '--inplace')
+ >>> assert s==0,`s`
+ >>> import SetupPy_doctest as mypackage
+ >>> print mypackage.foo.__doc__ #doctest: +ELLIPSIS
+ This module 'foo' is generated with ExtGen from NumPy version...
+
+ """
+ template_setup_py_start = '''\
+def configuration(parent_package='', top_path = ''):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('',parent_package,top_path)'''
+ template_setup_py_end = '''\
+ return config
+if __name__ == "__main__":
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
+'''
+ template = '%(SourceWriter)s'
+
+ container_options = dict(
+ SourceWriter = dict(user_defined_str = write_files),
+ TMP = dict()
+ )
+
+ component_container_map = dict(
+ FileSource = 'SourceWriter',
+ ExtensionModule = 'TMP',
+ )
+
+ def initialize(self, build_dir, *components, **options):
+ self.name = self.path = build_dir
+ if not self.path:
+ self.setup_py = setup_py = Component.PySource('extgen_setup.py')
+ self.init_py = init_py = Component.PySource('extgen__init__.py')
+ else:
+ self.setup_py = setup_py = Component.PySource('setup.py')
+ self.init_py = init_py = Component.PySource('__init__.py')
+
+ setup_py += self.template_setup_py_start
+
+ self += init_py
+ self += setup_py
+
+ map(self.add, components)
+
+ return self
+
+ def finalize(self):
+ self.setup_py += self.template_setup_py_end
+
+ def execute(self, *args):
+ """
+ Run generated setup.py file with given arguments.
+ """
+ if not args:
+ raise ValueError('need setup.py arguments')
+ self.info(self.generate(dry_run=False))
+ cmd = [sys.executable,'setup.py'] + list(args)
+ self.info('entering %r directory' % (self.path))
+ self.info('executing command %r' % (' '.join(cmd)))
+ r = exec_command(cmd, execute_in=self.path, use_tee=False)
+ self.info('leaving %r directory' % (self.path))
+ return r
+
+
+def _test():
+ import doctest
+ doctest.testmod()
+
+if __name__ == "__main__":
+ _test()
Added: trunk/numpy/f2py/lib/extgen/utils.py
===================================================================
--- trunk/numpy/f2py/lib/extgen/utils.py 2007-08-10 08:37:24 UTC (rev 3961)
+++ trunk/numpy/f2py/lib/extgen/utils.py 2007-08-10 13:57:35 UTC (rev 3962)
@@ -0,0 +1,126 @@
+
+__all__ = ['Word', 'Line', 'Code', 'FileSource']
+
+from base import Component
+
+class Word(Component):
+ template = '%(word)s'
+
+ def initialize(self, word):
+ if not word: return None
+ self.word = word
+ return self
+
+ def add(self, component, container_label=None):
+ raise ValueError('%s does not take components' % (self.__class__.__name__))
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.word]+[c for (c,l) in self.components])))
+
+
+class Line(Component):
+
+ """
+ >>> l = Line('hey')
+ >>> l += ' you '
+ >>> l += 2
+ >>> print l
+ Line('hey you 2')
+ >>> print l.generate()
+ hey you 2
+ >>> l += l
+ >>> print l.generate()
+ hey you 2hey you 2
+ """
+
+ template = '%(line)s'
+
+ def initialize(self, *strings):
+ self.line = ''
+ map(self.add, strings)
+ return self
+
+ def add(self, component, container_label=None):
+ if isinstance(component, Line):
+ self.line += component.line
+ elif isinstance(component, str):
+ self.line += component
+ elif component is None:
+ pass
+ else:
+ self.line += str(component)
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.line]+[c for (c,l) in self.components])))
+
+
+class Code(Component):
+
+ """
+ >>> c = Code('start')
+ >>> c += 2
+ >>> c += 'end'
+ >>> c
+ Code(Line('start'), Line('2'), Line('end'))
+ >>> print c.generate()
+ start
+ 2
+ end
+ """
+
+ template = '%(Line)s'
+
+ container_options = dict(
+ Line = dict(default = '<KILLLINE>', ignore_empty_content=True)
+ )
+ component_container_map = dict(
+ Line = 'Line'
+ )
+ default_component_class_name = 'Line'
+
+ def initialize(self, *lines):
+ map(self.add, lines)
+ return self
+
+ def add(self, component, label=None):
+ if isinstance(component, Code):
+ assert label is None,`label`
+ self.components += component.components
+ else:
+ Component.add(self, component, label)
+
+
+class FileSource(Component):
+
+ container_options = dict(
+ Content = dict(default='<KILLLINE>')
+ )
+
+ template = '%(Content)s'
+
+ default_component_class_name = 'Code'
+
+ component_container_map = dict(
+ Line = 'Content',
+ Code = 'Content',
+ )
+
+ def initialize(self, path, *components, **options):
+ self.path = path
+ map(self.add, components)
+ self._provides = options.pop('provides', path)
+ if options: self.warning('%s unused options: %s\n' % (self.__class__.__name__, options))
+ return self
+
+ def finalize(self):
+ self._provides = self.get_path() or self._provides
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,[self.path]+[c for (c,l) in self.components])))
+
+def _test():
+ import doctest
+ doctest.testmod()
+
+if __name__ == "__main__":
+ _test()
More information about the Numpy-svn
mailing list