This repository has been archived by the owner on Mar 19, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 189
/
setup.py
309 lines (262 loc) · 11 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2015, PyStan developers
#
# This file is licensed under Version 3.0 of the GNU General Public
# License. See LICENSE for a text of the license.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# This file is part of PyStan.
#
# PyStan is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# PyStan is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PyStan. If not, see <http://www.gnu.org/licenses/>.
#-----------------------------------------------------------------------------
import ast
import codecs
import os
import platform
import shutil
import subprocess
import sys
LONG_DESCRIPTION = codecs.open('README.rst', encoding='utf-8').read()
NAME = 'pystan'
DESCRIPTION = 'Python interface to Stan, a package for Bayesian inference'
AUTHOR = 'PyStan Developers'
AUTHOR_EMAIL = '[email protected]'
URL = 'https://github.com/stan-dev/pystan'
LICENSE = 'GPLv3'
CLASSIFIERS = [
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Programming Language :: Cython',
'Development Status :: 4 - Beta',
'Environment :: Console',
'Operating System :: OS Independent',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Topic :: Scientific/Engineering',
'Topic :: Scientific/Engineering :: Information Analysis'
]
# VersionFinder from from django-compressor
class VersionFinder(ast.NodeVisitor):
def __init__(self):
self.version = None
def visit_Assign(self, node):
if node.targets[0].id == '__version__':
self.version = node.value.s
def read(*parts):
filename = os.path.join(os.path.dirname(__file__), *parts)
with codecs.open(filename, encoding='utf-8') as fp:
return fp.read()
def find_version(*parts):
finder = VersionFinder()
finder.visit(ast.parse(read(*parts)))
return finder.version
###############################################################################
def build_tbb():
"""Build tbb."""
stan_math_lib = os.path.abspath(os.path.join(os.path.dirname(__file__), 'pystan', 'stan', 'lib', 'stan_math', 'lib'))
make = 'make' if platform.system() != 'Windows' else 'mingw32-make'
cmd = [make]
tbb_root = os.path.join(stan_math_lib, 'tbb_2019_U8').replace("\\", "/")
cmd.extend(['-C', tbb_root])
cmd.append('tbb_build_dir={}'.format(stan_math_lib))
cmd.append('tbb_build_prefix=tbb')
cmd.append('tbb_root={}'.format(tbb_root))
cmd.append('stdver=c++14')
cmd.append('compiler=gcc')
cwd = os.path.abspath(os.path.dirname(__file__))
subprocess.check_call(cmd, cwd=cwd)
tbb_debug = os.path.join(stan_math_lib, "tbb_debug")
tbb_release = os.path.join(stan_math_lib, "tbb_release")
tbb_dir = os.path.join(stan_math_lib, "tbb")
if not os.path.exists(tbb_dir):
os.makedirs(tbb_dir)
if os.path.exists(tbb_debug):
shutil.rmtree(tbb_debug)
shutil.move(os.path.join(tbb_root, 'include'), tbb_dir)
shutil.rmtree(tbb_root)
for name in os.listdir(tbb_release):
srcname = os.path.join(tbb_release, name)
dstname = os.path.join(tbb_dir, name)
shutil.move(srcname, dstname)
if os.path.exists(tbb_release):
shutil.rmtree(tbb_release)
###############################################################################
# Optional setuptools features
# We need to import setuptools early, if we want setuptools features,
# as it monkey-patches the 'setup' function
# For some commands, use setuptools
if len(set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
'bdist_wininst', 'install_egg_info', 'build_sphinx',
'egg_info', 'easy_install', 'upload', 'bdist_wheel',
'--single-version-externally-managed',
)).intersection(sys.argv)) > 0:
import setuptools
extra_setuptools_args = dict(
install_requires=['Cython>=0.22,!=0.25.1', 'numpy >= 1.7'],
zip_safe=False, # the package can run out of an .egg file
include_package_data=True,
)
else:
extra_setuptools_args = dict()
###############################################################################
from distutils.errors import CCompilerError, DistutilsError
from distutils.extension import Extension
stan_include_dirs = ['pystan/stan/src',
'pystan/stan/lib/stan_math/',
'pystan/stan/lib/stan_math/lib/eigen_3.3.3',
'pystan/stan/lib/stan_math/lib/boost_1.72.0',
'pystan/stan/lib/stan_math/lib/sundials_4.1.0/include',
'pystan/stan/lib/stan_math/lib/tbb/include']
stan_macros = [
('BOOST_DISABLE_ASSERTS', None),
('BOOST_NO_DECLTYPE', None),
('BOOST_PHOENIX_NO_VARIADIC_EXPRESSION', None), # needed for stanc
('BOOST_RESULT_OF_USE_TR1', None),
('FUSION_MAX_VECTOR_SIZE', 12), # for parser, stan-dev/pystan#222
]
extra_compile_args = [
'-Os',
'-ftemplate-depth-256',
'-Wno-unused-function',
'-Wno-uninitialized',
'-std=c++1y',
]
if platform.system() == 'Windows':
from Cython.Build.Inline import _get_build_extension
if _get_build_extension().compiler in (None, 'msvc'):
print("Warning: MSVC is not supported")
extra_compile_args = [
'/EHsc',
'-DBOOST_DATE_TIME_NO_LIB',
'/std:c++14',
]
else:
# fix bug in MingW-W64
# use posix threads
extra_compile_args.extend([
"-D_hypot=hypot",
"-pthread",
"-fexceptions",
])
stanc_sources = [
"pystan/stan/src/stan/lang/ast_def.cpp",
"pystan/stan/src/stan/lang/grammars/bare_type_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/block_var_decls_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/expression07_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/expression_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/functions_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/indexes_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/local_var_decls_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/program_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/semantic_actions_def.cpp",
"pystan/stan/src/stan/lang/grammars/statement_2_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/statement_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/term_grammar_inst.cpp",
"pystan/stan/src/stan/lang/grammars/whitespace_grammar_inst.cpp",
]
extensions = [
Extension("pystan._api",
["pystan/_api.pyx"] + stanc_sources,
language='c++',
define_macros=stan_macros,
include_dirs=stan_include_dirs,
extra_compile_args=extra_compile_args),
Extension("pystan._chains",
["pystan/_chains.pyx"],
language='c++',
define_macros=stan_macros,
include_dirs=stan_include_dirs,
extra_compile_args=extra_compile_args),
# _misc.pyx does not use Stan libs
Extension("pystan._misc",
["pystan/_misc.pyx"],
language='c++',
extra_compile_args=extra_compile_args)
]
## package data
package_data_pats = ['*.hpp', '*.pxd', '*.pyx', 'tests/data/*.csv',
'tests/data/*.stan', 'lookuptable/*.txt']
# Build tbb before setup if needed
tbb_dir = os.path.join(os.path.dirname(__file__), 'pystan', 'stan', 'lib', 'stan_math', 'lib', 'tbb')
tbb_dir = os.path.abspath(tbb_dir)
if not os.path.exists(tbb_dir):
build_tbb()
# get every file under pystan/stan/src and pystan/stan/lib
stan_files_all = sum(
[[os.path.join(path.replace('pystan/', ''), fn) for fn in files]
for path, dirs, files in os.walk('pystan/stan/src/')], [])
lib_files_all = sum(
[[os.path.join(path.replace('pystan/', ''), fn) for fn in files]
for path, dirs, files in os.walk('pystan/stan/lib/')], [])
package_data_pats += stan_files_all
package_data_pats += lib_files_all
def setup_package():
metadata = dict(name=NAME,
version=find_version("pystan", "__init__.py"),
maintainer=AUTHOR,
maintainer_email=AUTHOR_EMAIL,
packages=['pystan',
'pystan.tests',
'pystan.experimental',
'pystan.external',
'pystan.external.pymc',
'pystan.external.enum',
'pystan.external.scipy'],
ext_modules=extensions,
package_data={'pystan': package_data_pats},
platforms='any',
description=DESCRIPTION,
license=LICENSE,
url=URL,
long_description=LONG_DESCRIPTION,
long_description_content_type='text/x-rst',
classifiers=CLASSIFIERS,
**extra_setuptools_args)
if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or sys.argv[1]
in ('--help-commands', 'egg_info', '--version', 'clean')):
# For these actions, neither Numpy nor Cython is required.
#
# They are required to succeed when pip is used to install PyStan
# when, for example, Numpy is not yet present.
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
dist = setup(**metadata)
else:
import distutils.core
distutils.core._setup_stop_after = 'commandline'
from distutils.core import setup
try:
from Cython.Build import cythonize
# FIXME: if header only works, no need for numpy.distutils at all
from numpy.distutils.command import install
except ImportError:
raise SystemExit("Cython>=0.22 and NumPy are required.")
metadata['ext_modules'] = cythonize(extensions)
dist = setup(**metadata)
metadata['cmdclass'] = {'install': install.install}
try:
dist.run_commands()
except KeyboardInterrupt:
raise SystemExit("Interrupted")
except (IOError, os.error) as exc:
from distutils.util import grok_environment_error
error = grok_environment_error(exc)
except (DistutilsError, CCompilerError) as msg:
raise SystemExit("error: " + str(msg))
if __name__ == '__main__':
setup_package()