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