forked from enthought/mayavi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.py
499 lines (405 loc) · 16.8 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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
#!/usr/bin/env python
#
# Copyright (c) 2008-2015 by Enthought, Inc.
# All rights reserved.
"""
The Mayavi scientific data 3-dimensional visualizer.
The Mayavi *project* includes two related *packages* for 3-dimensional
visualization:
- **Mayavi2**: A tool for easy and interactive visualization of data.
- **TVTK**: A Traits-based wrapper for the Visualization Toolkit, a popular
open-source visualization library.
These libraries operate at different levels of abstraction. TVTK manipulates
visualization objects, while Mayavi2 lets you operate on your data, and then
see the results. Most users either use the Mayavi user interface or program
to its scripting interface; you probably don't need to interact with TVTK
unless you want to create a new Mayavi module.
Mayavi2
-------
Mayavi2 seeks to provide easy and interactive visualization of 3-D data.
It offers:
- An (optional) rich user interface with dialogs to interact with all data
and objects in the visualization.
- A simple and clean scripting interface in Python, including one-liners,
or an object-oriented programming interface.
- The power of the VTK toolkit, harnessed through these interfaces, without
forcing you to learn it.
Additionally Mayavi2 is a reusable tool that can be embedded in your
applications in different ways or combined with the Envisage
application-building framework to assemble domain-specific tools.
TVTK
----
TVTK wraps VTK objects to provide a convenient, Pythonic API, while supporting
Traits attributes and NumPy/SciPy arrays. TVTK is implemented mostly in pure
Python, except for a small extension module.
Developers typically use TVTK to write Mayavi modules, and then use Mayavi to
interact with visualizations or create applications.
Prerequisites
-------------
You must have the following libraries installed before installing the Mayavi
project:
* `Numpy <http://pypi.python.org/pypi/numpy/1.1.1>`_ version 1.1.1 or later
* `VTK <http://www.vtk.org/>`_ version 5.0 or later
* One of the following GUI toolkit packages:
- `Qt <http://www.qt.io>`_ version 4.8 with either PyQt 4.11.4 or PySide 1.2.2
- `wxPython <http://www.wxpython.org/>`_ version 2.8 or later
* `configobj <http://pypi.python.org/pypi/configobj>`_
"""
# NOTE: Setuptools must be imported BEFORE numpy.distutils or else
# numpy.distutils does the Wrong(TM) thing.
import setuptools
from setuptools import Command
import numpy
import os
import subprocess
import shutil
import re
import sys
import traceback
from os.path import (abspath, basename, dirname, exists, getmtime, isdir,
join, split, splitext)
from numpy.distutils.command import build, install_data
from distutils.command import clean
from distutils import log
from setuptools.command import develop, install_scripts
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=''):
"""Traverses 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.
Description
-----------
"""
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 = '(\.py)|(\.rst)$'
excluded_dirs = '^\.'
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:
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(dirname(__file__)),
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
# Our custom distutils hooks
def build_tvtk_classes_zip():
MY_DIR = os.path.dirname(__file__)
sys.path.insert(0, MY_DIR)
import tvtk
tvtk_dir = 'tvtk'
sys.path.insert(0, tvtk_dir)
from setup import gen_tvtk_classes_zip
gen_tvtk_classes_zip()
sys.path.remove(tvtk_dir)
sys.path.remove(MY_DIR)
class MyBuild(build.build):
""" A build hook to generate the documentation.
We sub-class numpy.distutils' build command because we're relying on
numpy.distutils' setup method to build python extensions.
"""
def run(self):
build_tvtk_classes_zip()
build.build.run(self)
self.run_command('gen_docs')
try:
self.run_command('build_docs')
except:
log.warn("Couldn't build documentation:\n%s" %
traceback.format_exception(*sys.exc_info()))
class MyDevelop(develop.develop):
""" A hook to have the docs rebuilt during develop.
Subclassing setuptools' command because numpy.distutils doesn't
have an implementation.
"""
def run(self):
self.run_command('gen_docs')
try:
self.run_command('build_docs')
except:
log.warn("Could not build documentation:\n%s" %
traceback.format_exception(*sys.exc_info()))
# Make sure that the 'build_src' command will
# always be inplace when we do a 'develop'.
self.reinitialize_command('build_src', inplace=1)
# tvtk_classes.zip always need to be created on 'develop'.
build_tvtk_classes_zip()
develop.develop.run(self)
class MyInstallData(install_data.install_data):
""" An install hook to copy the generated documentation.
We subclass numpy.distutils' command because we're relying on
numpy.distutils' setup method to build python extensions.
"""
def run(self):
install_data_command = self.get_finalized_command('install_data')
for project in list_doc_projects():
install_data_command.data_files.extend(
list_docs_data_files(project))
# make sure tvtk_classes.zip always get created before putting it
# in the install data.
build_tvtk_classes_zip()
tvtk_dir = 'tvtk'
install_data_command.data_files.append(
(tvtk_dir, [join(tvtk_dir, 'tvtk_classes.zip')]))
install_data.install_data.run(self)
class MyClean(clean.clean):
"""Reimplements to remove the extension module array_ext to guarantee a
fresh rebuild every time. The module hanging around could introduce
problems when doing develop for a different vtk version."""
def run(self):
MY_DIR = os.path.dirname(__file__)
ext_file = os.path.join(
MY_DIR,
"tvtk",
"array_ext" + (".pyd" if sys.platform == "win32" else ".so")
)
if os.path.exists(ext_file):
print("Removing in-place array extensions {}".format(ext_file))
os.unlink(ext_file)
clean.clean.run(self)
# Configure our extensions to Python
def configuration(parent_package=None, top_path=None):
from numpy.distutils.misc_util import Configuration
config = Configuration(None, parent_package, top_path)
config.set_options(
ignore_setup_xxx_py=True,
assume_default_configuration=True,
delegate_options_to_subpackages=True,
quiet=True,
)
config.add_subpackage('tvtk')
config.add_data_dir('mayavi/core/lut')
config.add_data_dir('mayavi/tests/data')
config.add_data_dir('mayavi/tests/csv_files')
# Image files.
for pkgdir in ('mayavi', 'tvtk'):
for root, dirs, files in os.walk(pkgdir):
if split(root)[-1] == 'images':
config.add_data_dir(root)
# *.ini files.
config.add_data_dir('tvtk/plugins/scene')
config.add_data_dir('mayavi/preferences')
return config
###########################################################################
# Similar to package_data, but installed before build
build_package_data = {'mayavi.images': ['docs/source/mayavi/m2_about.jpg']}
# Instal our data files at build time. This is iffy,
# but we need to do this before distutils kick in.
for package, files in build_package_data.items():
target_path = package.replace('.', os.sep)
for filename in files:
shutil.copy(filename, target_path)
###########################################################################
# Build the full set of packages by appending any found by setuptools'
# find_packages to those discovered by numpy.distutils.
config = configuration().todict()
packages = setuptools.find_packages(exclude=config['packages'] +
['docs', 'examples'])
config['packages'] += packages
# The actual setup call
DOCLINES = __doc__.split("\n")
numpy.distutils.core.setup(
name = 'mayavi',
version = info['__version__'],
author = "Prabhu Ramachandran, et. al.",
author_email = "[email protected]",
maintainer = 'ETS Developers',
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 = {
# Work around a numpy distutils bug by forcing the use of the
# setuptools' sdist command.
'sdist': setuptools.command.sdist.sdist,
'build': MyBuild,
'clean': MyClean,
'develop': MyDevelop,
'install_data': MyInstallData,
'gen_docs': GenDocs,
'build_docs': BuildDocs,
},
description = DOCLINES[1],
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'
],
},
extras_require = info['__extras_require__'],
include_package_data = True,
install_requires = info['__requires__'],
license = "BSD",
long_description = '\n'.join(DOCLINES[3:]),
platforms = ["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"],
zip_safe = False,
**config
)