[Numpy-svn] r2990 - in trunk/numpy/core: . code_generators
numpy-svn at scipy.org
numpy-svn at scipy.org
Thu Aug 10 17:16:22 EDT 2006
Author: cookedm
Date: 2006-08-10 16:16:20 -0500 (Thu, 10 Aug 2006)
New Revision: 2990
Modified:
trunk/numpy/core/code_generators/genapi.py
trunk/numpy/core/code_generators/generate_array_api.py
trunk/numpy/core/code_generators/generate_ufunc_api.py
trunk/numpy/core/setup.py
Log:
The code generators for the API now create a .txt file (in ReST format)
with the API functions and the documentation comment from the source.
Currently, this is put in the header file directory
(`src.<platform>/numpy/core/include` in the `build` directory).
Also fixed up dependency checking: API changes should force a rebuild
of all the C extensions using the API.
Modified: trunk/numpy/core/code_generators/genapi.py
===================================================================
--- trunk/numpy/core/code_generators/genapi.py 2006-08-10 21:07:31 UTC (rev 2989)
+++ trunk/numpy/core/code_generators/genapi.py 2006-08-10 21:16:20 UTC (rev 2990)
@@ -1,5 +1,6 @@
import sys, os, re
import md5
+import textwrap
API_FILES = ['arraymethods.c',
'arrayobject.c',
@@ -11,6 +12,9 @@
THIS_DIR = os.path.dirname(__file__)
API_FILES = [os.path.join(THIS_DIR, '..', 'src', a) for a in API_FILES]
+def file_in_this_dir(filename):
+ return os.path.join(THIS_DIR, filename)
+
def remove_whitespace(s):
return ''.join(s.split())
@@ -44,6 +48,21 @@
doccomment = ''
return '%s%s %s(%s)' % (doccomment, self.return_type, self.name, argstr)
+ def to_ReST(self):
+ lines = ['::', '', ' ' + self.return_type]
+ argstr = ',\000'.join([self._format_arg(a) for a in self.args])
+ name = ' %s' % (self.name,)
+ s = textwrap.wrap('(%s)' % (argstr,), width=72,
+ initial_indent=name,
+ subsequent_indent=' ' * (len(name)+1),
+ break_long_words=False)
+ for l in s:
+ lines.append(l.replace('\000', ' ').rstrip())
+ lines.append('')
+ if self.doc:
+ lines.append(textwrap.dedent(self.doc))
+ return '\n'.join(lines)
+
def api_hash(self):
m = md5.new()
m.update(remove_whitespace(self.return_type))
@@ -133,32 +152,36 @@
else:
line = line.lstrip(' *')
doclist.append(line)
- elif state == STATE_RETTYPE: #first line of declaration with return type
+ elif state == STATE_RETTYPE:
+ # first line of declaration with return type
m = re.match(r'static\s+(.*)$', line)
if m:
line = m.group(1)
return_type = line
state = STATE_NAME
- elif state == STATE_NAME: # second line, with function name
+ elif state == STATE_NAME:
+ # second line, with function name
m = re.match(r'(\w+)\s*\(', line)
if m:
function_name = m.group(1)
else:
- raise ParseError(filename, lineno+1, 'could not find function name')
+ raise ParseError(filename, lineno+1,
+ 'could not find function name')
function_args.append(line[m.end():])
state = STATE_ARGS
elif state == STATE_ARGS:
- if line.startswith('{'): # finished
+ if line.startswith('{'):
+ # finished
fargs_str = ' '.join(function_args).rstrip(' )')
fargs = split_arguments(fargs_str)
f = Function(function_name, return_type, fargs,
- ' '.join(doclist))
+ '\n'.join(doclist))
functions.append(f)
return_type = None
function_name = None
function_args = []
doclist = []
- state = 0
+ state = SCANNING
else:
function_args.append(line)
except:
@@ -181,7 +204,7 @@
def get_api_functions(tagname, order_file):
if not os.path.exists(order_file):
- order_file = os.path.join(THIS_DIR, order_file)
+ order_file = file_in_this_dir(order_file)
order = read_order(order_file)
functions = []
for f in API_FILES:
@@ -195,7 +218,7 @@
def add_api_list(offset, APIname, api_list,
module_list, extension_list, init_list):
- """Add the API function declerations to the appropiate lists for use in
+ """Add the API function declarations to the appropiate lists for use in
the headers.
"""
for k, func in enumerate(api_list):
@@ -210,6 +233,15 @@
astr = " (void *) %s," % func.name
init_list.append(astr)
+def should_rebuild(targets, source_files):
+ from distutils.dep_util import newer_group
+ for t in targets:
+ if not os.path.exists(t):
+ return True
+ sources = API_FILES + list(source_files) + [__file__]
+ if newer_group(sources, targets[0], missing='newer'):
+ return True
+ return False
def main():
tagname = sys.argv[1]
Modified: trunk/numpy/core/code_generators/generate_array_api.py
===================================================================
--- trunk/numpy/core/code_generators/generate_array_api.py 2006-08-10 21:07:31 UTC (rev 2989)
+++ trunk/numpy/core/code_generators/generate_array_api.py 2006-08-10 21:16:20 UTC (rev 2990)
@@ -1,6 +1,9 @@
import os
import genapi
+OBJECT_API_ORDER = 'array_api_order.txt'
+MULTIARRAY_API_ORDER = 'multiarray_api_order.txt'
+
types = ['Generic','Number','Integer','SignedInteger','UnsignedInteger',
'Inexact',
'Floating', 'ComplexFloating', 'Flexible', 'Character',
@@ -113,11 +116,23 @@
};
"""
-def generate_api(output_dir):
+def generate_api(output_dir, force=False):
+ header_file = os.path.join(output_dir, '__multiarray_api.h')
+ c_file = os.path.join(output_dir,'__multiarray_api.c')
+ doc_file = os.path.join(output_dir, 'multiarray_api.txt')
+
+ targets = (header_file, c_file, doc_file)
+ if (not force
+ and not genapi.should_rebuild(targets,
+ [OBJECT_API_ORDER,
+ MULTIARRAY_API_ORDER,
+ __file__])):
+ return targets
+
objectapi_list = genapi.get_api_functions('OBJECT_API',
- 'array_api_order.txt')
+ OBJECT_API_ORDER)
multiapi_list = genapi.get_api_functions('MULTIARRAY_API',
- 'multiarray_api_order.txt')
+ MULTIARRAY_API_ORDER)
# API fixes for __arrayobject_api.h
fixed = 10
@@ -141,23 +156,48 @@
(types[k], num)
extension_list.append(astr)
- #setup object API
+ # set up object API
genapi.add_api_list(numtypes, 'PyArray_API', objectapi_list,
module_list, extension_list, init_list)
- # setup multiarray module API
+ # set up multiarray module API
genapi.add_api_list(numobject, 'PyArray_API', multiapi_list,
module_list, extension_list, init_list)
# Write to header
- fid = open(os.path.join(output_dir, '__multiarray_api.h'),'w')
+ fid = open(header_file, 'w')
s = h_template % ('\n'.join(module_list), '\n'.join(extension_list))
fid.write(s)
fid.close()
# Write to c-code
- fid = open(os.path.join(output_dir,'__multiarray_api.c'),'w')
+ fid = open(c_file, 'w')
s = c_template % '\n'.join(init_list)
fid.write(s)
fid.close()
+
+ # write to documentation
+ fid = open(doc_file, 'w')
+ fid.write('''
+===========
+Numpy C-API
+===========
+
+Object API
+==========
+''')
+ for func in objectapi_list:
+ fid.write(func.to_ReST())
+ fid.write('\n\n')
+ fid.write('''
+
+Multiarray API
+==============
+''')
+ for func in multiapi_list:
+ fid.write(func.to_ReST())
+ fid.write('\n\n')
+ fid.close()
+
+ return targets
Modified: trunk/numpy/core/code_generators/generate_ufunc_api.py
===================================================================
--- trunk/numpy/core/code_generators/generate_ufunc_api.py 2006-08-10 21:07:31 UTC (rev 2989)
+++ trunk/numpy/core/code_generators/generate_ufunc_api.py 2006-08-10 21:16:20 UTC (rev 2990)
@@ -1,6 +1,8 @@
import os
import genapi
+UFUNC_API_ORDER = 'ufunc_api_order.txt'
+
h_template = r"""
#ifdef _UMATHMODULE
@@ -64,10 +66,19 @@
};
"""
-def generate_api(output_dir):
- ufunc_api_list = genapi.get_api_functions('UFUNC_API',
- 'ufunc_api_order.txt')
+def generate_api(output_dir, force=False):
+ header_file = os.path.join(output_dir, '__ufunc_api.h')
+ c_file = os.path.join(output_dir, '__ufunc_api.c')
+ doc_file = os.path.join(output_dir, 'ufunc_api.txt')
+ targets = (header_file, c_file, doc_file)
+ if (not force
+ and not genapi.should_rebuild(targets,
+ [UFUNC_API_ORDER, __file__])):
+ return targets
+
+ ufunc_api_list = genapi.get_api_functions('UFUNC_API', UFUNC_API_ORDER)
+
# API fixes for __arrayobject_api.h
fixed = 1
@@ -78,18 +89,32 @@
extension_list = []
init_list = []
- #setup object API
+ # set up object API
genapi.add_api_list(fixed, 'PyUFunc_API', ufunc_api_list,
module_list, extension_list, init_list)
# Write to header
- fid = open(os.path.join(output_dir, '__ufunc_api.h'),'w')
+ fid = open(header_file, 'w')
s = h_template % ('\n'.join(module_list), '\n'.join(extension_list))
fid.write(s)
fid.close()
# Write to c-code
- fid = open(os.path.join(output_dir, '__ufunc_api.c'),'w')
+ fid = open(c_file, 'w')
s = c_template % '\n'.join(init_list)
fid.write(s)
fid.close()
+
+ # Write to documentation
+ fid = open(doc_file, 'w')
+ fid.write('''
+=================
+Numpy Ufunc C-API
+=================
+''')
+ for func in ufunc_api_list:
+ fid.write(func.to_ReST())
+ fid.write('\n\n')
+ fid.close()
+
+ return targets
Modified: trunk/numpy/core/setup.py
===================================================================
--- trunk/numpy/core/setup.py 2006-08-10 21:07:31 UTC (rev 2989)
+++ trunk/numpy/core/setup.py 2006-08-10 21:16:20 UTC (rev 2990)
@@ -6,6 +6,19 @@
from glob import glob
from distutils.dep_util import newer,newer_group
+FUNCTIONS_TO_CHECK = [
+ ('expl', 'HAVE_LONGDOUBLE_FUNCS'),
+ ('expf', 'HAVE_FLOAT_FUNCS'),
+ ('log1p', 'HAVE_LOG1P'),
+ ('expm1', 'HAVE_EXPM1'),
+ ('asinh', 'HAVE_INVERSE_HYPERBOLIC'),
+ ('atanhf', 'HAVE_INVERSE_HYPERBOLIC_FLOAT'),
+ ('atanhl', 'HAVE_INVERSE_HYPERBOLIC_LONGDOUBLE'),
+ ('isnan', 'HAVE_ISNAN'),
+ ('isinf', 'HAVE_ISINF'),
+ ('rint', 'HAVE_RINT'),
+ ]
+
def configuration(parent_package='',top_path=None):
from numpy.distutils.misc_util import Configuration,dot_join
from numpy.distutils.system_info import get_info, default_lib_dirs
@@ -50,14 +63,14 @@
# are actually multiple CPUS? -- but
# threaded code can be nice even on a single
# CPU so that long-calculating code doesn't
- # block.
+ # block.
try:
nosmp = os.environ['NPY_NOSMP']
nosmp = 1
except KeyError:
nosmp = 0
if nosmp: moredefs = [('NPY_ALLOW_THREADS', '0')]
- else: moredefs = []
+ else: moredefs = []
#
mathlibs = []
tc = testcode_mathlib()
@@ -70,36 +83,24 @@
mathlibs = libs
break
else:
- raise "math library missing; rerun setup.py after setting the MATHLIB env variable"
+ raise EnvironmentError("math library missing; rerun "
+ "setup.py after setting the "
+ "MATHLIB env variable")
ext.libraries.extend(mathlibs)
moredefs.append(('MATHLIB',','.join(mathlibs)))
- libs = mathlibs
- kws_args = {'libraries':libs,'decl':0,'headers':['math.h']}
- if config_cmd.check_func('expl', **kws_args):
- moredefs.append('HAVE_LONGDOUBLE_FUNCS')
- if config_cmd.check_func('expf', **kws_args):
- moredefs.append('HAVE_FLOAT_FUNCS')
- if config_cmd.check_func('log1p', **kws_args):
- moredefs.append('HAVE_LOG1P')
- if config_cmd.check_func('expm1', **kws_args):
- moredefs.append('HAVE_EXPM1')
- if config_cmd.check_func('asinh', **kws_args):
- moredefs.append('HAVE_INVERSE_HYPERBOLIC')
- if config_cmd.check_func('atanhf', **kws_args):
- moredefs.append('HAVE_INVERSE_HYPERBOLIC_FLOAT')
- if config_cmd.check_func('atanhl', **kws_args):
- moredefs.append('HAVE_INVERSE_HYPERBOLIC_LONGDOUBLE')
- if config_cmd.check_func('isnan', **kws_args):
- moredefs.append('HAVE_ISNAN')
- if config_cmd.check_func('isinf', **kws_args):
- moredefs.append('HAVE_ISINF')
- if config_cmd.check_func('rint', **kws_args):
- moredefs.append('HAVE_RINT')
+ def check_func(func_name):
+ return config_cmd.check_func(func_name,
+ libraries=mathlibs, decl=False,
+ headers=['math.h'])
+ for func_name, defsymbol in FUNCTIONS_TO_CHECK:
+ if check_func(func_name):
+ moredefs.append(defsymbol)
+
if sys.version[:3] < '2.4':
kws_args['headers'].append('stdlib.h')
- if config_cmd.check_func('strtod', **kws_args):
+ if check_func('strtod'):
moredefs.append(('PyOS_ascii_strtod', 'strtod'))
if moredefs:
@@ -132,26 +133,23 @@
config.add_data_files((header_dir,target))
return target
- def generate_api_func(header_file, module_name):
- def generate_api(ext,build_dir):
- target = join(build_dir, header_file)
+ def generate_api_func(module_name):
+ def generate_api(ext, build_dir):
script = join(codegen_dir, module_name + '.py')
- if newer(script, target):
- sys.path.insert(0, codegen_dir)
- try:
- m = __import__(module_name)
- print 'executing',script
- m.generate_api(build_dir)
- finally:
- del sys.path[0]
- config.add_data_files((header_dir,target))
- return target
+ sys.path.insert(0, codegen_dir)
+ try:
+ m = __import__(module_name)
+ print 'executing', script
+ h_file, c_file, doc_file = m.generate_api(build_dir)
+ finally:
+ del sys.path[0]
+ config.add_data_files((header_dir, h_file),
+ (header_dir, doc_file))
+ return (h_file,)
return generate_api
- generate_array_api = generate_api_func('__multiarray_api.h',
- 'generate_array_api')
- generate_ufunc_api = generate_api_func('__ufunc_api.h',
- 'generate_ufunc_api')
+ generate_array_api = generate_api_func('generate_array_api')
+ generate_ufunc_api = generate_api_func('generate_ufunc_api')
def generate_umath_c(ext,build_dir):
target = join(build_dir,'__umath_generated.c')
More information about the Numpy-svn
mailing list