forked from enthought/mayavi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.py
384 lines (328 loc) · 13 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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#!/usr/bin/env python
#
# Copyright (c) 2008-2022 by Enthought, Inc.
# All rights reserved.
from setuptools import Command, Extension, setup, find_packages
from setuptools.command.build_py import build_py
from setuptools.command.develop import develop
from setuptools.command.install import install
import os
import time
import subprocess
import shutil
import re
import sys
from os.path import (abspath, basename, dirname, exists, getmtime, isdir,
join, split)
from pathlib import Path
from tvtk._setup import can_compile_extensions, gen_tvtk_classes_zip # noqa
MY_DIR = os.path.dirname(__file__)
MODE = 'normal'
if len(sys.argv) >= 2 and \
('--help' in sys.argv[1:] or
sys.argv[1] in ('--help-commands', 'egg_info', '--version',
'clean', 'sdist')):
MODE = 'info'
info = {}
fname = join('mayavi', '__init__.py')
exec(compile(open(fname).read(), fname, 'exec'), info)
DEFAULT_HTML_TARGET_DIR = join('docs', 'build')
DEFAULT_INPUT_DIR = join('docs', 'source',)
class GenDocs(Command):
description = (
"This command generates generated part of the documentation "
"when needed. It's run automatically before a build_docs, and that's "
"the only time it needs to be run."
)
user_options = [
('None', None, 'this command has no options'),
]
def latest_modified(self, the_path, filetypes='', ignore_dirs=''):
"""Traverse a path looking for the most recently modified file.
Parameters
----------
the_path : string
Contains path to be traversed or filename to be inspected.
filetypes : string
Regular expression pattern of files to examine. If specified, other
files are ignored. Otherwise, all files are examined.
ignore_dirs : string
Regular expression pattern of directories to be ignored. If ignore
specified, all directories are walked.
Returns
-------
latest_time : float
Modification time of latest_path.
latest_path : string
Most recently modified file.
"""
file_re = re.compile(filetypes)
dir_re = re.compile(ignore_dirs)
if not exists(the_path):
return 0, the_path
if isdir(the_path):
latest_time = 0
latest_path = the_path
for root, dirs, files in os.walk(the_path):
if ignore_dirs != '':
# This needs to iterate over a copy of the list. Otherwise,
# as things get removed from the original list, the indices
# become invalid.
for dir in dirs[:]:
if dir_re.search(dir):
dirs.remove(dir)
for file in files:
if filetypes != '':
if not file_re.search(file):
continue
current_file_time = getmtime(join(root, file))
if current_file_time > latest_time:
latest_time = current_file_time
latest_path = join(root, file)
return latest_time, latest_path
else:
return getmtime(the_path), the_path
def mlab_reference(self):
"""If mayavi is installed, run the mlab_reference generator."""
# XXX: This is really a hack: the script is not made to be used
# for different projects, but it ended up being. This part is
# mayavi-specific.
mlab_ref_dir = join(DEFAULT_INPUT_DIR, 'mayavi', 'auto')
source_path = 'mayavi'
sources = r'(\.py)|(\.rst)$'
excluded_dirs = r'^\.'
target_path = mlab_ref_dir
target_time = self.latest_modified(target_path,
ignore_dirs=excluded_dirs)[0]
if (self.latest_modified(source_path, filetypes=sources,
ignore_dirs=excluded_dirs)[0] > target_time
or self.latest_modified('mlab_reference.py')[0] > target_time
or not exists(join('docs', 'source', 'mayavi', 'auto',
'mlab_reference.rst'))):
try:
from mayavi import mlab
from mayavi.tools import auto_doc
print("Generating the mlab reference documentation")
os.system('python mlab_reference.py')
except Exception:
pass
def example_files(self):
"""Generate the documentation files for the examples."""
mlab_ref_dir = join(DEFAULT_INPUT_DIR, 'mayavi', 'auto')
source_path = join('examples', 'mayavi')
sources = '(\.py)|(\.rst)$'
excluded_dirs = '^\.'
target_path = mlab_ref_dir
target_time = self.latest_modified(target_path,
ignore_dirs=excluded_dirs)[0]
script_file_name = join('docs', 'source', 'render_examples.py')
if (self.latest_modified(source_path, filetypes=sources,
ignore_dirs=excluded_dirs)[0] > target_time
or self.latest_modified(script_file_name)[0] > target_time
or not exists(join('docs', 'source', 'mayavi', 'auto',
'examples.rst'))
):
try:
from mayavi import mlab
from mayavi.tools import auto_doc
print("Generating the example list")
subprocess.call('python %s' %
basename(script_file_name), shell=True,
cwd=dirname(script_file_name))
except:
pass
def run(self):
self.mlab_reference()
self.example_files()
def initialize_options(self):
pass
def finalize_options(self):
pass
class BuildDocs(Command):
description = \
"This command generates the documentation by running Sphinx. " \
"It then zips the docs into an html.zip file."
user_options = [
('None', None, 'this command has no options'),
]
def make_docs(self):
if os.name == 'nt':
print("Please impelemnt sphinx building on windows here.")
else:
subprocess.call(['make', 'html'], cwd='docs')
def run(self):
self.make_docs()
def initialize_options(self):
pass
def finalize_options(self):
pass
# Functions to generate the docs
def list_doc_projects():
""" List the different source directories under DEFAULT_INPUT_DIR
for which we have docs.
"""
source_dir = join(abspath(MY_DIR), DEFAULT_INPUT_DIR)
source_list = os.listdir(source_dir)
# Check to make sure we're using non-hidden directories.
source_dirs = [listing for listing in source_list
if isdir(join(source_dir, listing))
and not listing.startswith('.')]
return source_dirs
def list_docs_data_files(project):
""" List the files to add to a project by inspecting the
documentation directory. This works only if called after the
build step, as the files have to be built.
returns a list of (install_dir, [data_files, ]) tuples.
"""
project_target_dir = join(DEFAULT_HTML_TARGET_DIR, project, 'html')
return_list = []
for root, dirs, files in os.walk(project_target_dir, topdown=True):
# Modify inplace the list of directories to walk
dirs[:] = [d for d in dirs if not d.startswith('.')]
if len(files) == 0:
continue
install_dir = root.replace(project_target_dir, join(project, 'html'))
return_list.append((install_dir, [join(root, f) for f in files]))
return return_list
def _tvtk_built_recently(zipfile, delay):
"""Returns True if the TVTK classes in zipfile was built in the last
delay seconds.
"""
if not os.path.exists(zipfile):
return False
ctime = os.stat(zipfile).st_ctime
tdiff = time.time() - ctime
return tdiff < delay
# Our custom distutils hooks
def build_tvtk_classes_zip():
zipfile = os.path.join(MY_DIR, 'tvtk', 'tvtk_classes.zip')
if _tvtk_built_recently(zipfile, delay=120):
print("Already built tvtk_classes.zip")
return
else:
print("Building tvtk_classes.zip")
gen_tvtk_classes_zip()
class MyBuildPy(build_py):
"""A build hook to generate the documentation."""
def run(self):
build_tvtk_classes_zip()
super().run()
class MyDevelop(develop):
"""A hook to build the TVTK ZIP file on develop."""
def run(self):
build_tvtk_classes_zip()
super().run()
###########################################################################
# Similar to package_data, but installed before build
build_package_data = {'mayavi.images': ['docs/source/mayavi/_static/m2_about.jpg']}
# Install our data files at build time. This is iffy,
# but we need to do this before distutils kicks in.
for package, files in build_package_data.items():
target_path = package.replace('.', os.sep)
for filename in files:
shutil.copy(filename, target_path)
try:
import numpy as np
except Exception:
HAS_NUMPY = False
else:
HAS_NUMPY = True
if not HAS_NUMPY and MODE != 'info':
msg = '''
Numpy is required to build Mayavi correctly, please install it first.
'''
print('*'*80)
print(msg)
print('*'*80)
raise RuntimeError(msg)
###########################################################################
# The actual setup call
if __name__ == '__main__':
ext_modules = list()
packages = find_packages(exclude=["docs", "examples"])
packages += [ # otherwise we get warnings. Maybe these should be excluded?
"mayavi.core.images",
"mayavi.core.ui.images",
"mayavi.images",
"mayavi.preferences.images",
"mayavi.tests.csv_files",
"mayavi.tests.data",
"mayavi.tools.static.x3d",
"tvtk.pipeline.images",
"tvtk.pyface.images",
"tvtk.src",
"tvtk.tools.images",
]
if can_compile_extensions():
import numpy as np
ext_modules.append(
Extension(
"tvtk.array_ext",
sources=[join("tvtk", "src", "array_ext.c")],
depends=[join("tvtk", "src", "array_ext.pyx")],
include_dirs=[np.get_include()],
)
)
setup(
name='mayavi',
version=info['__version__'],
author="Prabhu Ramachandran, et al.",
author_email="[email protected]",
maintainer='ETS Developers',
python_requires='>=3.8',
maintainer_email='[email protected]',
url='http://docs.enthought.com/mayavi/mayavi/',
classifiers=[c.strip() for c in """\
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
Intended Audience :: Science/Research
License :: OSI Approved :: BSD License
Operating System :: MacOS
Operating System :: Microsoft :: Windows
Operating System :: OS Independent
Operating System :: POSIX
Operating System :: Unix
Programming Language :: C
Programming Language :: Python
Topic :: Scientific/Engineering
Topic :: Software Development
Topic :: Software Development :: Libraries
""".splitlines() if len(c.split()) > 0],
cmdclass={
'build_py': MyBuildPy,
'develop': MyDevelop,
'gen_docs': GenDocs,
'build_docs': BuildDocs,
},
description='3D scientific data visualization library and application',
download_url=('https://www.github.com/enthought/mayavi'),
entry_points={
'gui_scripts': [
'mayavi2 = mayavi.scripts.mayavi2:main',
'tvtk_doc = tvtk.tools.tvtk_doc:main'
],
'envisage.plugins': [
'tvtk.scene = tvtk.plugins.scene.scene_plugin:ScenePlugin',
'tvtk.scene_ui = tvtk.plugins.scene.ui.scene_ui_plugin:SceneUIPlugin',
'tvtk.browser = tvtk.plugins.browser.browser_plugin:BrowserPlugin',
'mayavi = mayavi.plugins.mayavi_plugin:MayaviPlugin',
'mayavi_ui = mayavi.plugins.mayavi_ui_plugin:MayaviUIPlugin'
],
'tvtk.toolkits': [
'qt4 = tvtk.pyface.ui.qt4.init:toolkit_object',
'qt = tvtk.pyface.ui.qt4.init:toolkit_object',
'wx = tvtk.pyface.ui.wx.init:toolkit_object',
'null = tvtk.pyface.ui.null.init:toolkit_object',
]
},
extras_require=info['__extras_require__'],
packages=packages,
include_package_data=True,
package_data={"tvtk": ["tvtk_classes.zip"]},
ext_modules=ext_modules,
install_requires=info['__requires__'],
license="BSD",
long_description=Path('README.rst').read_text(encoding='utf-8'),
platforms=["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"],
zip_safe=False,
)