test fix for Py<=2.5
[cython.git] / setup.py
1 from distutils.core import setup, Extension
2 from distutils.sysconfig import get_python_lib
3 import os, os.path
4 import sys
5
6 if 'sdist' in sys.argv and sys.platform != "win32" and sys.version_info >= (2,4):
7     # Record the current revision in .hgrev
8     import subprocess # os.popen is cleaner but deprecated
9     changset = subprocess.Popen("hg log --rev tip | grep changeset", 
10                                 shell=True,
11                                 stdout=subprocess.PIPE).stdout.read()
12     rev = changset.decode('ISO-8859-1').split(':')[-1].strip()
13     hgrev = open('.hgrev', 'w')
14     hgrev.write(rev)
15     hgrev.close()
16
17 if sys.platform == "darwin":
18     # Don't create resource files on OS X tar.
19     os.environ['COPY_EXTENDED_ATTRIBUTES_DISABLE'] = 'true'
20     os.environ['COPYFILE_DISABLE'] = 'true'
21
22 setup_args = {}
23
24 def add_command_class(name, cls):
25     cmdclasses = setup_args.get('cmdclass', {})
26     cmdclasses[name] = cls
27     setup_args['cmdclass'] = cmdclasses
28
29 if sys.version_info[0] >= 3:
30     import lib2to3.refactor
31     from distutils.command.build_py \
32          import build_py_2to3 as build_py
33     # need to convert sources to Py3 on installation
34     fixers = [ fix for fix in lib2to3.refactor.get_fixers_from_package("lib2to3.fixes")
35                if fix.split('fix_')[-1] not in ('next',)
36                ]
37     build_py.fixer_names = fixers
38     add_command_class("build_py", build_py)
39
40 pxd_include_dirs = [
41     directory for directory, dirs, files in os.walk('Cython/Includes')
42     if '__init__.pyx' in files or '__init__.pxd' in files
43     or directory == 'Cython/Includes' or directory == 'Cython/Includes/Deprecated']
44
45 pxd_include_patterns = [
46     p+'/*.pxd' for p in pxd_include_dirs ] + [
47     p+'/*.pyx' for p in pxd_include_dirs ]
48
49 if sys.version_info < (2,4):
50     install_base_dir = get_python_lib(prefix='')
51     import glob
52     patterns = pxd_include_patterns + [
53         'Cython/Plex/*.pxd',
54         'Cython/Compiler/*.pxd',
55         'Cython/Runtime/*.pyx'
56         ]
57     setup_args['data_files'] = [
58         (os.path.dirname(os.path.join(install_base_dir, pattern)),
59          [ f for f in glob.glob(pattern) ])
60         for pattern in patterns
61         ]
62 else:
63     setup_args['package_data'] = {
64         'Cython.Plex'     : ['*.pxd'],
65         'Cython.Compiler' : ['*.pxd'],
66         'Cython.Runtime'  : ['*.pyx', '*.pxd'],
67         'Cython'          : [ p[7:] for p in pxd_include_patterns ],
68         }
69
70 # This dict is used for passing extra arguments that are setuptools 
71 # specific to setup
72 setuptools_extra_args = {}
73
74 if 'setuptools' in sys.modules:
75     setuptools_extra_args['zip_safe'] = False
76     setuptools_extra_args['entry_points'] = {
77         'console_scripts': [
78             'cython = Cython.Compiler.Main:setuptools_main',
79         ]
80     }
81     scripts = []
82 else:
83     if os.name == "posix":
84         scripts = ["bin/cython"]
85     else:
86         scripts = ["cython.py"]
87
88 def compile_cython_modules(profile=False):
89     source_root = os.path.abspath(os.path.dirname(__file__))
90     compiled_modules = ["Cython.Plex.Scanners",
91                         "Cython.Compiler.Scanning",
92                         "Cython.Compiler.Parsing",
93                         "Cython.Compiler.Visitor",
94                         "Cython.Runtime.refnanny"]
95     extensions = []
96
97     if sys.version_info[0] >= 3:
98         from Cython.Distutils import build_ext as build_ext_orig
99         for module in compiled_modules:
100             source_file = os.path.join(source_root, *module.split('.'))
101             if os.path.exists(source_file + ".py"):
102                 pyx_source_file = source_file + ".py"
103             else:
104                 pyx_source_file = source_file + ".pyx"
105             extensions.append(
106                 Extension(module, sources = [pyx_source_file])
107                 )
108
109         class build_ext(build_ext_orig):
110             def build_extensions(self):
111                 # add path where 2to3 installed the transformed sources
112                 # and make sure Python (re-)imports them from there
113                 already_imported = [ module for module in sys.modules
114                                      if module == 'Cython' or module.startswith('Cython.') ]
115                 for module in already_imported:
116                     del sys.modules[module]
117                 sys.path.insert(0, os.path.join(source_root, self.build_lib))
118
119                 if profile:
120                     from Cython.Compiler.Options import directive_defaults
121                     directive_defaults['profile'] = True
122                     print("Enabled profiling for the Cython binary modules")
123                 build_ext_orig.build_extensions(self)
124
125         setup_args['ext_modules'] = extensions
126         add_command_class("build_ext", build_ext)
127
128     else: # Python 2.x
129         from distutils.command.build_ext import build_ext as build_ext_orig
130         try:
131             class build_ext(build_ext_orig):
132                 def build_extension(self, ext, *args, **kargs):
133                     try:
134                         build_ext_orig.build_extension(self, ext, *args, **kargs)
135                     except StandardError:
136                         print("Compilation of '%s' failed" % ext.sources[0])
137             from Cython.Compiler.Main import compile
138             from Cython import Utils
139             if profile:
140                 from Cython.Compiler.Options import directive_defaults
141                 directive_defaults['profile'] = True
142                 print("Enabled profiling for the Cython binary modules")
143             source_root = os.path.dirname(__file__)
144             for module in compiled_modules:
145                 source_file = os.path.join(source_root, *module.split('.'))
146                 if os.path.exists(source_file + ".py"):
147                     pyx_source_file = source_file + ".py"
148                 else:
149                     pyx_source_file = source_file + ".pyx"
150                 c_source_file = source_file + ".c"
151                 if not os.path.exists(c_source_file) or \
152                    Utils.file_newer_than(pyx_source_file,
153                                          Utils.modification_time(c_source_file)):
154                     print("Compiling module %s ..." % module)
155                     result = compile(pyx_source_file)
156                     c_source_file = result.c_file
157                 if c_source_file:
158                     # Py2 distutils can't handle unicode file paths
159                     if isinstance(c_source_file, unicode):
160                         filename_encoding = sys.getfilesystemencoding()
161                         if filename_encoding is None:
162                             filename_encoding = sys.getdefaultencoding()
163                         c_source_file = c_source_file.encode(filename_encoding)
164                     extensions.append(
165                         Extension(module, sources = [c_source_file])
166                         )
167                 else:
168                     print("Compilation failed")
169             if extensions:
170                 setup_args['ext_modules'] = extensions
171                 add_command_class("build_ext", build_ext)
172         except Exception:
173             print('''
174 ERROR: %s
175
176 Extension module compilation failed, looks like Cython cannot run
177 properly on this system.  To work around this, pass the option
178 "--no-cython-compile".  This will install a pure Python version of
179 Cython without compiling its own sources.
180 ''' % sys.exc_info()[1])
181             raise
182
183 cython_profile = '--cython-profile' in sys.argv
184 if cython_profile:
185     sys.argv.remove('--cython-profile')
186
187 try:
188     sys.argv.remove("--no-cython-compile")
189 except ValueError:
190     compile_cython_modules(cython_profile)
191
192 setup_args.update(setuptools_extra_args)
193
194 from Cython.Compiler.Version import version
195
196 setup(
197   name = 'Cython',
198   version = version,
199   url = 'http://www.cython.org',
200   author = 'Greg Ewing, Robert Bradshaw, Stefan Behnel, Dag Seljebotn, et al.',
201   author_email = 'cython-dev@codespeak.net',
202   description = "The Cython compiler for writing C extensions for the Python language.",
203   long_description = """\
204   The Cython language makes writing C extensions for the Python language as
205   easy as Python itself.  Cython is a source code translator based on the
206   well-known Pyrex_, but supports more cutting edge functionality and
207   optimizations.
208
209   The Cython language is very close to the Python language (and most Python
210   code is also valid Cython code), but Cython additionally supports calling C
211   functions and declaring C types on variables and class attributes. This
212   allows the compiler to generate very efficient C code from Cython code.
213
214   This makes Cython the ideal language for writing glue code for external C
215   libraries, and for fast C modules that speed up the execution of Python
216   code.
217
218   .. _Pyrex: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
219   """,
220   classifiers = [
221     "Development Status :: 5 - Production/Stable",
222     "Intended Audience :: Developers",
223     "License :: OSI Approved :: Apache Software License",
224     "Operating System :: OS Independent",
225     "Programming Language :: Python",
226     "Programming Language :: Python :: 2",
227     "Programming Language :: Python :: 3",
228     "Programming Language :: C",
229     "Programming Language :: Cython",
230     "Topic :: Software Development :: Code Generators",
231     "Topic :: Software Development :: Compilers",
232     "Topic :: Software Development :: Libraries :: Python Modules"
233   ],
234
235   scripts = scripts,
236   packages=[
237     'Cython',
238     'Cython.Compiler',
239     'Cython.Runtime',
240     'Cython.Distutils',
241     'Cython.Plex',
242
243     'Cython.Tests',
244     'Cython.Compiler.Tests',
245     ],
246
247   # pyximport
248   py_modules = ["pyximport/__init__",
249                 "pyximport/pyximport",
250                 "pyximport/pyxbuild",
251
252                 "cython"],
253
254   **setup_args
255   )