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