xref: /petsc/setup.py (revision fafc128d12f77c4a8b1177adad22fe40a990e020)
1#!/usr/bin/env python
2
3"""
4PETSc for Python
5================
6
7Python bindings for PETSc libraries.
8"""
9
10
11## try:
12##     import setuptools
13## except ImportError:
14##     pass
15
16import sys, os
17
18# --------------------------------------------------------------------
19# Metadata
20# --------------------------------------------------------------------
21
22from conf.metadata import metadata
23
24def name():
25    return 'petsc4py'
26
27def version():
28    import re
29    fh = open(os.path.join('src', '__init__.py'))
30    try: data = fh.read()
31    finally: fh.close()
32    m = re.search(r"__version__\s*=\s*'(.*)'", data)
33    return m.groups()[0]
34
35name     = name()
36version  = version()
37
38url      = 'http://%(name)s.googlecode.com/' % vars()
39download = url + 'files/%(name)s-%(version)s.tar.gz' % vars()
40
41descr    = __doc__.strip().split('\n'); del descr[1:3]
42devstat  = ['Development Status :: 3 - Alpha']
43keywords = ['PETSc', 'MPI']
44
45metadata['name'] = name
46metadata['version'] = version
47metadata['description'] = descr.pop(0)
48metadata['long_description'] = '\n'.join(descr)
49metadata['keywords'] += keywords
50metadata['classifiers'] += devstat
51metadata['url'] = url
52metadata['download_url'] = download
53
54metadata['provides'] = ['petsc4py']
55metadata['requires'] = ['numpy']
56
57# --------------------------------------------------------------------
58# Extension modules
59# --------------------------------------------------------------------
60
61def get_ext_modules(Extension):
62    from os   import walk, path
63    from glob import glob
64    depends = []
65    for pth, dirs, files in walk('src'):
66        depends += glob(path.join(pth, '*.h'))
67    for pth, dirs, files in walk(path.join('src', 'source')):
68        depends += glob(path.join(pth, '*.h'))
69        depends += glob(path.join(pth, '*.c'))
70    try:
71        import numpy
72        numpy_includes = [numpy.get_include()]
73    except ImportError:
74        numpy_includes = []
75    return [Extension('petsc4py.lib.PETSc',
76                      sources=['src/PETSc.c',
77                               'src/source/libpetsc4py.c',
78                               ],
79                      include_dirs=['src/include',
80                                    'src/source',
81                                    ] + numpy_includes,
82                      depends=depends)]
83
84# --------------------------------------------------------------------
85# Setup
86# --------------------------------------------------------------------
87
88from conf.petscconf import setup, Extension
89from conf.petscconf import config, build, build_src, build_ext
90from conf.petscconf import test, sdist
91
92def run_setup():
93    if (('distribute' in sys.modules) or
94        ('setuptools' in sys.modules)):
95        metadata['install_requires'] = ['numpy']
96        if not os.environ.get('PETSC_DIR'):
97            metadata['install_requires'].append('petsc')
98    if 'setuptools' in sys.modules:
99        metadata['zip_safe'] = False
100    setup(packages     = ['petsc4py',
101                          'petsc4py.lib',],
102          package_dir  = {'petsc4py'     : 'src',
103                          'petsc4py.lib' : 'src/lib'},
104          package_data = {'petsc4py'     : ['include/petsc4py/*.h',
105                                            'include/petsc4py/*.i',
106                                            'include/petsc4py/*.pxd',
107                                            'include/petsc4py/*.pxi',
108                                            'include/petsc4py/*.pyx',],
109                          'petsc4py.lib' : ['petsc.cfg'],},
110          ext_modules  = get_ext_modules(Extension),
111          cmdclass     = {'config'     : config,
112                          'build'      : build,
113                          'build_src'  : build_src,
114                          'build_ext'  : build_ext,
115                          'test'       : test,
116                          'sdist'      : sdist,
117                          },
118          **metadata)
119
120def chk_cython(CYTHON_VERSION_REQUIRED):
121    from distutils import log
122    from distutils.version import StrictVersion as Version
123    warn = lambda msg='': sys.stderr.write(msg+'\n')
124    #
125    cython_zip = 'cython.zip'
126    if os.path.isfile(cython_zip):
127        path = os.path.abspath(cython_zip)
128        if sys.path[0] != path:
129            sys.path.insert(0, os.path.abspath(cython_zip))
130            log.info("adding '%s' to sys.path", cython_zip)
131    #
132    try:
133        import Cython
134    except ImportError:
135        warn("*"*80)
136        warn()
137        warn(" You need to generate C source files with Cython!!")
138        warn(" Download and install Cython <http://www.cython.org>")
139        warn()
140        warn("*"*80)
141        return False
142    #
143    try:
144        CYTHON_VERSION = Cython.__version__
145    except AttributeError:
146        from Cython.Compiler.Version import version as CYTHON_VERSION
147    CYTHON_VERSION = CYTHON_VERSION.split('+', 1)[0]
148    for s in ('.alpha', 'alpha'):
149        CYTHON_VERSION = CYTHON_VERSION.replace(s, 'a')
150    for s in ('.beta',  'beta', '.rc', 'rc', '.c', 'c'):
151        CYTHON_VERSION = CYTHON_VERSION.replace(s, 'b')
152    if (CYTHON_VERSION_REQUIRED is not None and
153        Version(CYTHON_VERSION) < Version(CYTHON_VERSION_REQUIRED)):
154        warn("*"*80)
155        warn()
156        warn(" You need to install Cython %s (you have version %s)"
157             % (CYTHON_VERSION_REQUIRED, CYTHON_VERSION))
158        warn(" Download and install Cython <http://www.cython.org>")
159        warn()
160        warn("*"*80)
161        return False
162    #
163    return True
164
165def run_cython(source, depends=(), includes=(),
166               destdir_c=None, destdir_h=None, wdir=None,
167               force=False, VERSION=None):
168    from glob import glob
169    from distutils import log
170    from distutils import dep_util
171    from distutils.errors import DistutilsError
172    target = os.path.splitext(source)[0]+".c"
173    cwd = os.getcwd()
174    try:
175        if wdir: os.chdir(wdir)
176        alldeps = [source]
177        for dep in depends:
178            alldeps += glob(dep)
179        if not (force or dep_util.newer_group(alldeps, target)):
180            log.debug("skipping '%s' -> '%s' (up-to-date)",
181                      source, target)
182            return
183    finally:
184        os.chdir(cwd)
185    if not chk_cython(VERSION):
186        raise DistutilsError("requires Cython>=%s" % VERSION)
187    log.info("cythonizing '%s' -> '%s'", source, target)
188    from conf.cythonize import cythonize
189    err = cythonize(source,
190                    includes=includes,
191                    destdir_c=destdir_c,
192                    destdir_h=destdir_h,
193                    wdir=wdir)
194    if err:
195        raise DistutilsError(
196            "Cython failure: '%s' -> '%s'" % (source, target))
197
198def build_sources(cmd):
199    CYTHON_VERSION_REQUIRED = '0.13'
200    if not (os.path.isdir('.hg')  or
201            os.path.isdir('.git') or
202            cmd.force): return
203    # petsc4py.PETSc
204    source = 'petsc4py.PETSc.pyx'
205    depends = ("include/*/*.pxd",
206               "*/*.pyx",
207               "*/*.pxi",)
208    includes = ['include']
209    destdir_h = os.path.join('include', 'petsc4py')
210    run_cython(source, depends, includes,
211               destdir_c=None, destdir_h=destdir_h, wdir='src',
212               force=cmd.force, VERSION=CYTHON_VERSION_REQUIRED)
213
214build_src.run = build_sources
215
216def run_testsuite(cmd):
217    from distutils.errors import DistutilsError
218    sys.path.insert(0, 'test')
219    try:
220        from runtests import main
221    finally:
222        del sys.path[-1]
223    err = main(cmd.args or [])
224    if err:
225        raise DistutilsError("test")
226
227test.run = run_testsuite
228
229# --------------------------------------------------------------------
230
231def main():
232    run_setup()
233
234if __name__ == '__main__':
235    main()
236
237# --------------------------------------------------------------------
238