##// END OF EJS Templates
Merge pull request #4975 from minrk/t2pp...
Thomas Kluyver -
r15088:d4d34f7f merge
parent child Browse files
Show More
@@ -1,37 +1,38
1 include README.rst
1 include README.rst
2 include COPYING.txt
2 include COPYING.txt
3 include setupbase.py
3 include setupbase.py
4 include setupegg.py
4 include setupegg.py
5
5
6 graft setupext
6 graft setupext
7
7
8 graft scripts
8 graft scripts
9
9
10 # Load main dir but exclude things we don't want in the distro
10 # Load main dir but exclude things we don't want in the distro
11 graft IPython
11 graft IPython
12 prune IPython/html/static/mathjax
12 prune IPython/html/static/mathjax
13
13
14 # Include some specific files and data resources we need
14 # Include some specific files and data resources we need
15 include IPython/.git_commit_info.ini
15 include IPython/.git_commit_info.ini
16 include IPython/qt/console/resources/icon/IPythonConsole.svg
16 include IPython/qt/console/resources/icon/IPythonConsole.svg
17
17
18 # Documentation
18 # Documentation
19 graft docs
19 graft docs
20 exclude docs/\#*
20 exclude docs/\#*
21 exclude docs/man/*.1.gz
21 exclude docs/man/*.1.gz
22
22
23 # Examples
23 # Examples
24 graft examples
24 graft examples
25
25
26 # docs subdirs we want to skip
26 # docs subdirs we want to skip
27 prune docs/build
27 prune docs/build
28 prune docs/gh-pages
28 prune docs/gh-pages
29 prune docs/dist
29 prune docs/dist
30
30
31 # Patterns to exclude from any directory
31 # Patterns to exclude from any directory
32 global-exclude *~
32 global-exclude *~
33 global-exclude *.flc
33 global-exclude *.flc
34 global-exclude *.pyc
34 global-exclude *.pyc
35 global-exclude *.pyo
35 global-exclude *.pyo
36 global-exclude .dircopy.log
36 global-exclude .dircopy.log
37 global-exclude .git
37 global-exclude .git
38 global-exclude .ipynb_checkpoints
@@ -1,337 +1,336
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (c) 2008-2011, IPython Development Team.
10 # Copyright (c) 2008-2011, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # The full license is in the file COPYING.txt, distributed with this software.
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Minimal Python version sanity check
21 # Minimal Python version sanity check
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
23 from __future__ import print_function
24
24
25 import sys
25 import sys
26
26
27 # This check is also made in IPython/__init__, don't forget to update both when
27 # This check is also made in IPython/__init__, don't forget to update both when
28 # changing Python version requirements.
28 # changing Python version requirements.
29 if sys.version_info[:2] < (2,7):
29 if sys.version_info[:2] < (2,7):
30 error = "ERROR: IPython requires Python Version 2.7 or above."
30 error = "ERROR: IPython requires Python Version 2.7 or above."
31 print(error, file=sys.stderr)
31 print(error, file=sys.stderr)
32 sys.exit(1)
32 sys.exit(1)
33
33
34 PY3 = (sys.version_info[0] >= 3)
34 PY3 = (sys.version_info[0] >= 3)
35
35
36 # At least we're on the python version we need, move on.
36 # At least we're on the python version we need, move on.
37
37
38 #-------------------------------------------------------------------------------
38 #-------------------------------------------------------------------------------
39 # Imports
39 # Imports
40 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
41
41
42 # Stdlib imports
42 # Stdlib imports
43 import os
43 import os
44 import shutil
44 import shutil
45
45
46 from glob import glob
46 from glob import glob
47
47
48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
49 # update it when the contents of directories change.
49 # update it when the contents of directories change.
50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
51
51
52 from distutils.core import setup
52 from distutils.core import setup
53
53
54 # Our own imports
54 # Our own imports
55 from setupbase import target_update
55 from setupbase import target_update
56
56
57 from setupbase import (
57 from setupbase import (
58 setup_args,
58 setup_args,
59 find_packages,
59 find_packages,
60 find_package_data,
60 find_package_data,
61 find_entry_points,
61 find_entry_points,
62 build_scripts_entrypt,
62 build_scripts_entrypt,
63 find_data_files,
63 find_data_files,
64 check_for_dependencies,
64 check_for_dependencies,
65 git_prebuild,
65 git_prebuild,
66 check_submodule_status,
66 check_submodule_status,
67 update_submodules,
67 update_submodules,
68 require_submodules,
68 require_submodules,
69 UpdateSubmodules,
69 UpdateSubmodules,
70 get_bdist_wheel,
70 CompileCSS,
71 CompileCSS,
71 JavascriptVersion,
72 JavascriptVersion,
72 install_symlinked,
73 install_symlinked,
73 install_lib_symlink,
74 install_lib_symlink,
74 install_scripts_for_symlink,
75 install_scripts_for_symlink,
75 unsymlink,
76 unsymlink,
76 )
77 )
77 from setupext import setupext
78 from setupext import setupext
78
79
79 isfile = os.path.isfile
80 isfile = os.path.isfile
80 pjoin = os.path.join
81 pjoin = os.path.join
81
82
82 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
83 # Function definitions
84 # Function definitions
84 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
85
86
86 def cleanup():
87 def cleanup():
87 """Clean up the junk left around by the build process"""
88 """Clean up the junk left around by the build process"""
88 if "develop" not in sys.argv and "egg_info" not in sys.argv:
89 if "develop" not in sys.argv and "egg_info" not in sys.argv:
89 try:
90 try:
90 shutil.rmtree('ipython.egg-info')
91 shutil.rmtree('ipython.egg-info')
91 except:
92 except:
92 try:
93 try:
93 os.unlink('ipython.egg-info')
94 os.unlink('ipython.egg-info')
94 except:
95 except:
95 pass
96 pass
96
97
97 #-------------------------------------------------------------------------------
98 #-------------------------------------------------------------------------------
98 # Handle OS specific things
99 # Handle OS specific things
99 #-------------------------------------------------------------------------------
100 #-------------------------------------------------------------------------------
100
101
101 if os.name in ('nt','dos'):
102 if os.name in ('nt','dos'):
102 os_name = 'windows'
103 os_name = 'windows'
103 else:
104 else:
104 os_name = os.name
105 os_name = os.name
105
106
106 # Under Windows, 'sdist' has not been supported. Now that the docs build with
107 # Under Windows, 'sdist' has not been supported. Now that the docs build with
107 # Sphinx it might work, but let's not turn it on until someone confirms that it
108 # Sphinx it might work, but let's not turn it on until someone confirms that it
108 # actually works.
109 # actually works.
109 if os_name == 'windows' and 'sdist' in sys.argv:
110 if os_name == 'windows' and 'sdist' in sys.argv:
110 print('The sdist command is not available under Windows. Exiting.')
111 print('The sdist command is not available under Windows. Exiting.')
111 sys.exit(1)
112 sys.exit(1)
112
113
113 #-------------------------------------------------------------------------------
114 #-------------------------------------------------------------------------------
114 # Make sure we aren't trying to run without submodules
115 # Make sure we aren't trying to run without submodules
115 #-------------------------------------------------------------------------------
116 #-------------------------------------------------------------------------------
116 here = os.path.abspath(os.path.dirname(__file__))
117 here = os.path.abspath(os.path.dirname(__file__))
117
118
118 def require_clean_submodules():
119 def require_clean_submodules():
119 """Check on git submodules before distutils can do anything
120 """Check on git submodules before distutils can do anything
120
121
121 Since distutils cannot be trusted to update the tree
122 Since distutils cannot be trusted to update the tree
122 after everything has been set in motion,
123 after everything has been set in motion,
123 this is not a distutils command.
124 this is not a distutils command.
124 """
125 """
125 # PACKAGERS: Add a return here to skip checks for git submodules
126 # PACKAGERS: Add a return here to skip checks for git submodules
126
127
127 # don't do anything if nothing is actually supposed to happen
128 # don't do anything if nothing is actually supposed to happen
128 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
129 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
129 if do_nothing in sys.argv:
130 if do_nothing in sys.argv:
130 return
131 return
131
132
132 status = check_submodule_status(here)
133 status = check_submodule_status(here)
133
134
134 if status == "missing":
135 if status == "missing":
135 print("checking out submodules for the first time")
136 print("checking out submodules for the first time")
136 update_submodules(here)
137 update_submodules(here)
137 elif status == "unclean":
138 elif status == "unclean":
138 print('\n'.join([
139 print('\n'.join([
139 "Cannot build / install IPython with unclean submodules",
140 "Cannot build / install IPython with unclean submodules",
140 "Please update submodules with",
141 "Please update submodules with",
141 " python setup.py submodule",
142 " python setup.py submodule",
142 "or",
143 "or",
143 " git submodule update",
144 " git submodule update",
144 "or commit any submodule changes you have made."
145 "or commit any submodule changes you have made."
145 ]))
146 ]))
146 sys.exit(1)
147 sys.exit(1)
147
148
148 require_clean_submodules()
149 require_clean_submodules()
149
150
150 #-------------------------------------------------------------------------------
151 #-------------------------------------------------------------------------------
151 # Things related to the IPython documentation
152 # Things related to the IPython documentation
152 #-------------------------------------------------------------------------------
153 #-------------------------------------------------------------------------------
153
154
154 # update the manuals when building a source dist
155 # update the manuals when building a source dist
155 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
156 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
156
157
157 # List of things to be updated. Each entry is a triplet of args for
158 # List of things to be updated. Each entry is a triplet of args for
158 # target_update()
159 # target_update()
159 to_update = [
160 to_update = [
160 # FIXME - Disabled for now: we need to redo an automatic way
161 # FIXME - Disabled for now: we need to redo an automatic way
161 # of generating the magic info inside the rst.
162 # of generating the magic info inside the rst.
162 #('docs/magic.tex',
163 #('docs/magic.tex',
163 #['IPython/Magic.py'],
164 #['IPython/Magic.py'],
164 #"cd doc && ./update_magic.sh" ),
165 #"cd doc && ./update_magic.sh" ),
165
166
166 ('docs/man/ipcluster.1.gz',
167 ('docs/man/ipcluster.1.gz',
167 ['docs/man/ipcluster.1'],
168 ['docs/man/ipcluster.1'],
168 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
169 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
169
170
170 ('docs/man/ipcontroller.1.gz',
171 ('docs/man/ipcontroller.1.gz',
171 ['docs/man/ipcontroller.1'],
172 ['docs/man/ipcontroller.1'],
172 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
173 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
173
174
174 ('docs/man/ipengine.1.gz',
175 ('docs/man/ipengine.1.gz',
175 ['docs/man/ipengine.1'],
176 ['docs/man/ipengine.1'],
176 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
177 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
177
178
178 ('docs/man/ipython.1.gz',
179 ('docs/man/ipython.1.gz',
179 ['docs/man/ipython.1'],
180 ['docs/man/ipython.1'],
180 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
181 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
181
182
182 ]
183 ]
183
184
184
185
185 [ target_update(*t) for t in to_update ]
186 [ target_update(*t) for t in to_update ]
186
187
187 #---------------------------------------------------------------------------
188 #---------------------------------------------------------------------------
188 # Find all the packages, package data, and data_files
189 # Find all the packages, package data, and data_files
189 #---------------------------------------------------------------------------
190 #---------------------------------------------------------------------------
190
191
191 packages = find_packages()
192 packages = find_packages()
192 package_data = find_package_data()
193 package_data = find_package_data()
193 data_files = find_data_files()
194 data_files = find_data_files()
194
195
195 setup_args['packages'] = packages
196 setup_args['packages'] = packages
196 setup_args['package_data'] = package_data
197 setup_args['package_data'] = package_data
197 setup_args['data_files'] = data_files
198 setup_args['data_files'] = data_files
198
199
199 #---------------------------------------------------------------------------
200 #---------------------------------------------------------------------------
200 # custom distutils commands
201 # custom distutils commands
201 #---------------------------------------------------------------------------
202 #---------------------------------------------------------------------------
202 # imports here, so they are after setuptools import if there was one
203 # imports here, so they are after setuptools import if there was one
203 from distutils.command.sdist import sdist
204 from distutils.command.sdist import sdist
204 from distutils.command.upload import upload
205 from distutils.command.upload import upload
205
206
206 class UploadWindowsInstallers(upload):
207 class UploadWindowsInstallers(upload):
207
208
208 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
209 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
209 user_options = upload.user_options + [
210 user_options = upload.user_options + [
210 ('files=', 'f', 'exe file (or glob) to upload')
211 ('files=', 'f', 'exe file (or glob) to upload')
211 ]
212 ]
212 def initialize_options(self):
213 def initialize_options(self):
213 upload.initialize_options(self)
214 upload.initialize_options(self)
214 meta = self.distribution.metadata
215 meta = self.distribution.metadata
215 base = '{name}-{version}'.format(
216 base = '{name}-{version}'.format(
216 name=meta.get_name(),
217 name=meta.get_name(),
217 version=meta.get_version()
218 version=meta.get_version()
218 )
219 )
219 self.files = os.path.join('dist', '%s.*.exe' % base)
220 self.files = os.path.join('dist', '%s.*.exe' % base)
220
221
221 def run(self):
222 def run(self):
222 for dist_file in glob(self.files):
223 for dist_file in glob(self.files):
223 self.upload_file('bdist_wininst', 'any', dist_file)
224 self.upload_file('bdist_wininst', 'any', dist_file)
224
225
225 setup_args['cmdclass'] = {
226 setup_args['cmdclass'] = {
226 'build_py': git_prebuild('IPython'),
227 'build_py': git_prebuild('IPython'),
227 'sdist' : git_prebuild('IPython', sdist),
228 'sdist' : git_prebuild('IPython', sdist),
228 'upload_wininst' : UploadWindowsInstallers,
229 'upload_wininst' : UploadWindowsInstallers,
229 'submodule' : UpdateSubmodules,
230 'submodule' : UpdateSubmodules,
230 'css' : CompileCSS,
231 'css' : CompileCSS,
231 'symlink': install_symlinked,
232 'symlink': install_symlinked,
232 'install_lib_symlink': install_lib_symlink,
233 'install_lib_symlink': install_lib_symlink,
233 'install_scripts_sym': install_scripts_for_symlink,
234 'install_scripts_sym': install_scripts_for_symlink,
234 'unsymlink': unsymlink,
235 'unsymlink': unsymlink,
235 'jsversion' : JavascriptVersion,
236 'jsversion' : JavascriptVersion,
236 }
237 }
237
238
238 #---------------------------------------------------------------------------
239 #---------------------------------------------------------------------------
239 # Handle scripts, dependencies, and setuptools specific things
240 # Handle scripts, dependencies, and setuptools specific things
240 #---------------------------------------------------------------------------
241 #---------------------------------------------------------------------------
241
242
242 # For some commands, use setuptools. Note that we do NOT list install here!
243 # For some commands, use setuptools. Note that we do NOT list install here!
243 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
244 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
244 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
245 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
245 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
246 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
246 'egg_info', 'easy_install', 'upload',
247 'egg_info', 'easy_install', 'upload', 'install_egg_info',
247 ))
248 ))
248 if sys.platform == 'win32':
249 if sys.platform == 'win32':
249 # Depend on setuptools for install on *Windows only*
250 # Depend on setuptools for install on *Windows only*
250 # If we get script-installation working without setuptools,
251 # If we get script-installation working without setuptools,
251 # then we can back off, but until then use it.
252 # then we can back off, but until then use it.
252 # See Issue #369 on GitHub for more
253 # See Issue #369 on GitHub for more
253 needs_setuptools.add('install')
254 needs_setuptools.add('install')
254
255
255 if len(needs_setuptools.intersection(sys.argv)) > 0:
256 if len(needs_setuptools.intersection(sys.argv)) > 0:
256 import setuptools
257 import setuptools
257
258
258 # This dict is used for passing extra arguments that are setuptools
259 # This dict is used for passing extra arguments that are setuptools
259 # specific to setup
260 # specific to setup
260 setuptools_extra_args = {}
261 setuptools_extra_args = {}
261
262
263 # setuptools requirements
264
265 extras_require = dict(
266 parallel = ['pyzmq>=2.1.11'],
267 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
268 zmq = ['pyzmq>=2.1.11'],
269 doc = ['Sphinx>=1.1', 'numpydoc'],
270 test = ['nose>=0.10.1'],
271 notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2'],
272 nbconvert = ['pygments', 'jinja2', 'Sphinx>=0.3']
273 )
274 everything = set()
275 for deps in extras_require.values():
276 everything.update(deps)
277 extras_require['all'] = everything
278 install_requires = []
279 if sys.platform == 'darwin':
280 install_requires.append('readline')
281 elif sys.platform.startswith('win'):
282 # Pyreadline has unicode and Python 3 fixes in 2.0
283 install_requires.append('pyreadline>=2.0')
284
262 if 'setuptools' in sys.modules:
285 if 'setuptools' in sys.modules:
263 # setup.py develop should check for submodules
286 # setup.py develop should check for submodules
264 from setuptools.command.develop import develop
287 from setuptools.command.develop import develop
265 setup_args['cmdclass']['develop'] = require_submodules(develop)
288 setup_args['cmdclass']['develop'] = require_submodules(develop)
289 setup_args['cmdclass']['bdist_wheel'] = get_bdist_wheel()
266
290
267 setuptools_extra_args['zip_safe'] = False
291 setuptools_extra_args['zip_safe'] = False
268 setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()}
292 setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()}
269 setup_args['extras_require'] = dict(
293 setup_args['extras_require'] = extras_require
270 parallel = 'pyzmq>=2.1.11',
294 requires = setup_args['install_requires'] = install_requires
271 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
272 zmq = 'pyzmq>=2.1.11',
273 doc = ['Sphinx>=1.1', 'numpydoc'],
274 test = 'nose>=0.10.1',
275 notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2'],
276 nbconvert = ['pygments', 'jinja2', 'Sphinx>=0.3']
277 )
278 everything = set()
279 for deps in setup_args['extras_require'].values():
280 if not isinstance(deps, list):
281 deps = [deps]
282 for dep in deps:
283 everything.add(dep)
284 setup_args['extras_require']['all'] = everything
285
286 requires = setup_args.setdefault('install_requires', [])
287 setupext.display_status = False
288 if not setupext.check_for_readline():
289 if sys.platform == 'darwin':
290 requires.append('readline')
291 elif sys.platform.startswith('win'):
292 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
293 # Also solves issues with some older versions of pyreadline that
294 # satisfy the unconstrained depdendency.
295 requires.append('pyreadline>=1.7.1')
296 else:
297 pass
298 # do we want to install readline here?
299
295
300 # Script to be run by the windows binary installer after the default setup
296 # Script to be run by the windows binary installer after the default setup
301 # routine, to add shortcuts and similar windows-only things. Windows
297 # routine, to add shortcuts and similar windows-only things. Windows
302 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
298 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
303 # doesn't find them.
299 # doesn't find them.
304 if 'bdist_wininst' in sys.argv:
300 if 'bdist_wininst' in sys.argv:
305 if len(sys.argv) > 2 and \
301 if len(sys.argv) > 2 and \
306 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
302 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
307 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
303 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
308 sys.exit(1)
304 sys.exit(1)
309 setup_args['data_files'].append(
305 setup_args['data_files'].append(
310 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
306 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
311 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
307 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
312 setup_args['options'] = {"bdist_wininst":
308 setup_args['options'] = {"bdist_wininst":
313 {"install_script":
309 {"install_script":
314 "ipython_win_post_install.py"}}
310 "ipython_win_post_install.py"}}
315
311
316 else:
312 else:
317 # If we are running without setuptools, call this function which will
313 # If we are installing without setuptools, call this function which will
318 # check for dependencies an inform the user what is needed. This is
314 # check for dependencies an inform the user what is needed. This is
319 # just to make life easy for users.
315 # just to make life easy for users.
320 check_for_dependencies()
316 for install_cmd in ('install', 'symlink'):
317 if install_cmd in sys.argv:
318 check_for_dependencies()
319 break
321 # scripts has to be a non-empty list, or install_scripts isn't called
320 # scripts has to be a non-empty list, or install_scripts isn't called
322 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
321 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
323
322
324 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
323 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
325
324
326 #---------------------------------------------------------------------------
325 #---------------------------------------------------------------------------
327 # Do the actual setup now
326 # Do the actual setup now
328 #---------------------------------------------------------------------------
327 #---------------------------------------------------------------------------
329
328
330 setup_args.update(setuptools_extra_args)
329 setup_args.update(setuptools_extra_args)
331
330
332 def main():
331 def main():
333 setup(**setup_args)
332 setup(**setup_args)
334 cleanup()
333 cleanup()
335
334
336 if __name__ == '__main__':
335 if __name__ == '__main__':
337 main()
336 main()
@@ -1,601 +1,680
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import errno
23 import errno
24 import os
24 import os
25 import sys
25 import sys
26
26
27 from distutils.command.build_py import build_py
27 from distutils.command.build_py import build_py
28 from distutils.command.build_scripts import build_scripts
28 from distutils.command.build_scripts import build_scripts
29 from distutils.command.install import install
29 from distutils.command.install import install
30 from distutils.command.install_scripts import install_scripts
30 from distutils.command.install_scripts import install_scripts
31 from distutils.cmd import Command
31 from distutils.cmd import Command
32 from glob import glob
32 from glob import glob
33 from subprocess import call
33 from subprocess import call
34
34
35 from setupext import install_data_ext
35 from setupext import install_data_ext
36
36
37 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
38 # Useful globals and utility functions
38 # Useful globals and utility functions
39 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
40
40
41 # A few handy globals
41 # A few handy globals
42 isfile = os.path.isfile
42 isfile = os.path.isfile
43 pjoin = os.path.join
43 pjoin = os.path.join
44 repo_root = os.path.dirname(os.path.abspath(__file__))
44 repo_root = os.path.dirname(os.path.abspath(__file__))
45
45
46 def oscmd(s):
46 def oscmd(s):
47 print(">", s)
47 print(">", s)
48 os.system(s)
48 os.system(s)
49
49
50 # Py3 compatibility hacks, without assuming IPython itself is installed with
50 # Py3 compatibility hacks, without assuming IPython itself is installed with
51 # the full py3compat machinery.
51 # the full py3compat machinery.
52
52
53 try:
53 try:
54 execfile
54 execfile
55 except NameError:
55 except NameError:
56 def execfile(fname, globs, locs=None):
56 def execfile(fname, globs, locs=None):
57 locs = locs or globs
57 locs = locs or globs
58 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
58 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
59
59
60 # A little utility we'll need below, since glob() does NOT allow you to do
60 # A little utility we'll need below, since glob() does NOT allow you to do
61 # exclusion on multiple endings!
61 # exclusion on multiple endings!
62 def file_doesnt_endwith(test,endings):
62 def file_doesnt_endwith(test,endings):
63 """Return true if test is a file and its name does NOT end with any
63 """Return true if test is a file and its name does NOT end with any
64 of the strings listed in endings."""
64 of the strings listed in endings."""
65 if not isfile(test):
65 if not isfile(test):
66 return False
66 return False
67 for e in endings:
67 for e in endings:
68 if test.endswith(e):
68 if test.endswith(e):
69 return False
69 return False
70 return True
70 return True
71
71
72 #---------------------------------------------------------------------------
72 #---------------------------------------------------------------------------
73 # Basic project information
73 # Basic project information
74 #---------------------------------------------------------------------------
74 #---------------------------------------------------------------------------
75
75
76 # release.py contains version, authors, license, url, keywords, etc.
76 # release.py contains version, authors, license, url, keywords, etc.
77 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
77 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
78
78
79 # Create a dict with the basic information
79 # Create a dict with the basic information
80 # This dict is eventually passed to setup after additional keys are added.
80 # This dict is eventually passed to setup after additional keys are added.
81 setup_args = dict(
81 setup_args = dict(
82 name = name,
82 name = name,
83 version = version,
83 version = version,
84 description = description,
84 description = description,
85 long_description = long_description,
85 long_description = long_description,
86 author = author,
86 author = author,
87 author_email = author_email,
87 author_email = author_email,
88 url = url,
88 url = url,
89 download_url = download_url,
89 download_url = download_url,
90 license = license,
90 license = license,
91 platforms = platforms,
91 platforms = platforms,
92 keywords = keywords,
92 keywords = keywords,
93 classifiers = classifiers,
93 classifiers = classifiers,
94 cmdclass = {'install_data': install_data_ext},
94 cmdclass = {'install_data': install_data_ext},
95 )
95 )
96
96
97
97
98 #---------------------------------------------------------------------------
98 #---------------------------------------------------------------------------
99 # Find packages
99 # Find packages
100 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
101
101
102 def find_packages():
102 def find_packages():
103 """
103 """
104 Find all of IPython's packages.
104 Find all of IPython's packages.
105 """
105 """
106 excludes = ['deathrow', 'quarantine']
106 excludes = ['deathrow', 'quarantine']
107 packages = []
107 packages = []
108 for dir,subdirs,files in os.walk('IPython'):
108 for dir,subdirs,files in os.walk('IPython'):
109 package = dir.replace(os.path.sep, '.')
109 package = dir.replace(os.path.sep, '.')
110 if any(package.startswith('IPython.'+exc) for exc in excludes):
110 if any(package.startswith('IPython.'+exc) for exc in excludes):
111 # package is to be excluded (e.g. deathrow)
111 # package is to be excluded (e.g. deathrow)
112 continue
112 continue
113 if '__init__.py' not in files:
113 if '__init__.py' not in files:
114 # not a package
114 # not a package
115 continue
115 continue
116 packages.append(package)
116 packages.append(package)
117 return packages
117 return packages
118
118
119 #---------------------------------------------------------------------------
119 #---------------------------------------------------------------------------
120 # Find package data
120 # Find package data
121 #---------------------------------------------------------------------------
121 #---------------------------------------------------------------------------
122
122
123 def find_package_data():
123 def find_package_data():
124 """
124 """
125 Find IPython's package_data.
125 Find IPython's package_data.
126 """
126 """
127 # This is not enough for these things to appear in an sdist.
127 # This is not enough for these things to appear in an sdist.
128 # We need to muck with the MANIFEST to get this to work
128 # We need to muck with the MANIFEST to get this to work
129
129
130 # exclude static things that we don't ship (e.g. mathjax)
130 # exclude components from the walk,
131 excludes = ['mathjax']
131 # we will build the components separately
132 excludes = ['components']
132
133
133 # add 'static/' prefix to exclusions, and tuplify for use in startswith
134 # add 'static/' prefix to exclusions, and tuplify for use in startswith
134 excludes = tuple([os.path.join('static', ex) for ex in excludes])
135 excludes = tuple([pjoin('static', ex) for ex in excludes])
135
136
136 # walk notebook resources:
137 # walk notebook resources:
137 cwd = os.getcwd()
138 cwd = os.getcwd()
138 os.chdir(os.path.join('IPython', 'html'))
139 os.chdir(os.path.join('IPython', 'html'))
139 static_walk = list(os.walk('static'))
140 static_data = []
140 static_data = []
141 for parent, dirs, files in static_walk:
141 for parent, dirs, files in os.walk('static'):
142 if parent.startswith(excludes):
142 if parent.startswith(excludes):
143 continue
143 continue
144 for f in files:
144 for f in files:
145 static_data.append(os.path.join(parent, f))
145 static_data.append(pjoin(parent, f))
146
146 components = pjoin("static", "components")
147 # select the components we actually need to install
148 # (there are lots of resources we bundle for sdist-reasons that we don't actually use)
149 static_data.extend([
150 pjoin(components, "backbone", "backbone-min.js"),
151 pjoin(components, "bootstrap", "bootstrap", "js", "bootstrap.min.js"),
152 pjoin(components, "font-awesome", "font", "*.*"),
153 pjoin(components, "highlight.js", "build", "highlight.pack.js"),
154 pjoin(components, "jquery", "jquery.min.js"),
155 pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"),
156 pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"),
157 pjoin(components, "marked", "lib", "marked.js"),
158 pjoin(components, "requirejs", "require.js"),
159 pjoin(components, "underscore", "underscore-min.js"),
160 ])
161
162 # Ship all of Codemirror's CSS and JS
163 for parent, dirs, files in os.walk(pjoin(components, 'codemirror')):
164 for f in files:
165 if f.endswith(('.js', '.css')):
166 static_data.append(pjoin(parent, f))
167
147 os.chdir(os.path.join('tests',))
168 os.chdir(os.path.join('tests',))
148 js_tests = glob('casperjs/*.*') + glob('casperjs/*/*')
169 js_tests = glob('casperjs/*.*') + glob('casperjs/*/*')
149
170
150 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
171 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
151 nbconvert_templates = [os.path.join(dirpath, '*.*')
172 nbconvert_templates = [os.path.join(dirpath, '*.*')
152 for dirpath, _, _ in os.walk('templates')]
173 for dirpath, _, _ in os.walk('templates')]
153
174
154 os.chdir(cwd)
175 os.chdir(cwd)
155
176
156 package_data = {
177 package_data = {
157 'IPython.config.profile' : ['README*', '*/*.py'],
178 'IPython.config.profile' : ['README*', '*/*.py'],
158 'IPython.core.tests' : ['*.png', '*.jpg'],
179 'IPython.core.tests' : ['*.png', '*.jpg'],
159 'IPython.lib.tests' : ['*.wav'],
180 'IPython.lib.tests' : ['*.wav'],
160 'IPython.testing' : ['*.txt'],
161 'IPython.testing.plugin' : ['*.txt'],
181 'IPython.testing.plugin' : ['*.txt'],
162 'IPython.html' : ['templates/*'] + static_data,
182 'IPython.html' : ['templates/*'] + static_data,
163 'IPython.html.tests' : js_tests,
183 'IPython.html.tests' : js_tests,
164 'IPython.qt.console' : ['resources/icon/*.svg'],
184 'IPython.qt.console' : ['resources/icon/*.svg'],
165 'IPython.nbconvert' : nbconvert_templates +
185 'IPython.nbconvert' : nbconvert_templates +
166 ['tests/files/*.*', 'exporters/tests/files/*.*'],
186 ['tests/files/*.*', 'exporters/tests/files/*.*'],
167 'IPython.nbconvert.filters' : ['marked.js'],
187 'IPython.nbconvert.filters' : ['marked.js'],
168 'IPython.nbformat' : ['tests/*.ipynb']
188 'IPython.nbformat' : ['tests/*.ipynb']
169 }
189 }
190
191 # verify that package_data makes sense
192 for pkg, data in package_data.items():
193 pkg_root = pjoin(*pkg.split('.'))
194 for d in data:
195 path = pjoin(pkg_root, d)
196 if '*' in path:
197 assert len(glob(path)) > 0, "No files match pattern %s" % path
198 else:
199 assert os.path.exists(path), "Missing package data: %s" % path
200
170 return package_data
201 return package_data
171
202
172
203
173 #---------------------------------------------------------------------------
204 #---------------------------------------------------------------------------
174 # Find data files
205 # Find data files
175 #---------------------------------------------------------------------------
206 #---------------------------------------------------------------------------
176
207
177 def make_dir_struct(tag,base,out_base):
208 def make_dir_struct(tag,base,out_base):
178 """Make the directory structure of all files below a starting dir.
209 """Make the directory structure of all files below a starting dir.
179
210
180 This is just a convenience routine to help build a nested directory
211 This is just a convenience routine to help build a nested directory
181 hierarchy because distutils is too stupid to do this by itself.
212 hierarchy because distutils is too stupid to do this by itself.
182
213
183 XXX - this needs a proper docstring!
214 XXX - this needs a proper docstring!
184 """
215 """
185
216
186 # we'll use these a lot below
217 # we'll use these a lot below
187 lbase = len(base)
218 lbase = len(base)
188 pathsep = os.path.sep
219 pathsep = os.path.sep
189 lpathsep = len(pathsep)
220 lpathsep = len(pathsep)
190
221
191 out = []
222 out = []
192 for (dirpath,dirnames,filenames) in os.walk(base):
223 for (dirpath,dirnames,filenames) in os.walk(base):
193 # we need to strip out the dirpath from the base to map it to the
224 # we need to strip out the dirpath from the base to map it to the
194 # output (installation) path. This requires possibly stripping the
225 # output (installation) path. This requires possibly stripping the
195 # path separator, because otherwise pjoin will not work correctly
226 # path separator, because otherwise pjoin will not work correctly
196 # (pjoin('foo/','/bar') returns '/bar').
227 # (pjoin('foo/','/bar') returns '/bar').
197
228
198 dp_eff = dirpath[lbase:]
229 dp_eff = dirpath[lbase:]
199 if dp_eff.startswith(pathsep):
230 if dp_eff.startswith(pathsep):
200 dp_eff = dp_eff[lpathsep:]
231 dp_eff = dp_eff[lpathsep:]
201 # The output path must be anchored at the out_base marker
232 # The output path must be anchored at the out_base marker
202 out_path = pjoin(out_base,dp_eff)
233 out_path = pjoin(out_base,dp_eff)
203 # Now we can generate the final filenames. Since os.walk only produces
234 # Now we can generate the final filenames. Since os.walk only produces
204 # filenames, we must join back with the dirpath to get full valid file
235 # filenames, we must join back with the dirpath to get full valid file
205 # paths:
236 # paths:
206 pfiles = [pjoin(dirpath,f) for f in filenames]
237 pfiles = [pjoin(dirpath,f) for f in filenames]
207 # Finally, generate the entry we need, which is a pari of (output
238 # Finally, generate the entry we need, which is a pari of (output
208 # path, files) for use as a data_files parameter in install_data.
239 # path, files) for use as a data_files parameter in install_data.
209 out.append((out_path, pfiles))
240 out.append((out_path, pfiles))
210
241
211 return out
242 return out
212
243
213
244
214 def find_data_files():
245 def find_data_files():
215 """
246 """
216 Find IPython's data_files.
247 Find IPython's data_files.
217
248
218 Most of these are docs.
249 Just man pages at this point.
219 """
250 """
220
251
221 docdirbase = pjoin('share', 'doc', 'ipython')
222 manpagebase = pjoin('share', 'man', 'man1')
252 manpagebase = pjoin('share', 'man', 'man1')
223
253
224 # Simple file lists can be made by hand
254 # Simple file lists can be made by hand
225 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
255 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
226 if not manpages:
256 if not manpages:
227 # When running from a source tree, the manpages aren't gzipped
257 # When running from a source tree, the manpages aren't gzipped
228 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
258 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
229
259
230 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
231
232 # For nested structures, use the utility above
233 example_files = make_dir_struct(
234 'data',
235 pjoin('docs','examples'),
236 pjoin(docdirbase,'examples')
237 )
238 manual_files = make_dir_struct(
239 'data',
240 pjoin('docs','html'),
241 pjoin(docdirbase,'manual')
242 )
243
244 # And assemble the entire output list
260 # And assemble the entire output list
245 data_files = [ (manpagebase, manpages),
261 data_files = [ (manpagebase, manpages) ]
246 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
247 ] + manual_files + example_files
248
262
249 return data_files
263 return data_files
250
264
251
265
252 def make_man_update_target(manpage):
266 def make_man_update_target(manpage):
253 """Return a target_update-compliant tuple for the given manpage.
267 """Return a target_update-compliant tuple for the given manpage.
254
268
255 Parameters
269 Parameters
256 ----------
270 ----------
257 manpage : string
271 manpage : string
258 Name of the manpage, must include the section number (trailing number).
272 Name of the manpage, must include the section number (trailing number).
259
273
260 Example
274 Example
261 -------
275 -------
262
276
263 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
277 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
264 ('docs/man/ipython.1.gz',
278 ('docs/man/ipython.1.gz',
265 ['docs/man/ipython.1'],
279 ['docs/man/ipython.1'],
266 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
280 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
267 """
281 """
268 man_dir = pjoin('docs', 'man')
282 man_dir = pjoin('docs', 'man')
269 manpage_gz = manpage + '.gz'
283 manpage_gz = manpage + '.gz'
270 manpath = pjoin(man_dir, manpage)
284 manpath = pjoin(man_dir, manpage)
271 manpath_gz = pjoin(man_dir, manpage_gz)
285 manpath_gz = pjoin(man_dir, manpage_gz)
272 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
286 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
273 locals() )
287 locals() )
274 return (manpath_gz, [manpath], gz_cmd)
288 return (manpath_gz, [manpath], gz_cmd)
275
289
276 # The two functions below are copied from IPython.utils.path, so we don't need
290 # The two functions below are copied from IPython.utils.path, so we don't need
277 # to import IPython during setup, which fails on Python 3.
291 # to import IPython during setup, which fails on Python 3.
278
292
279 def target_outdated(target,deps):
293 def target_outdated(target,deps):
280 """Determine whether a target is out of date.
294 """Determine whether a target is out of date.
281
295
282 target_outdated(target,deps) -> 1/0
296 target_outdated(target,deps) -> 1/0
283
297
284 deps: list of filenames which MUST exist.
298 deps: list of filenames which MUST exist.
285 target: single filename which may or may not exist.
299 target: single filename which may or may not exist.
286
300
287 If target doesn't exist or is older than any file listed in deps, return
301 If target doesn't exist or is older than any file listed in deps, return
288 true, otherwise return false.
302 true, otherwise return false.
289 """
303 """
290 try:
304 try:
291 target_time = os.path.getmtime(target)
305 target_time = os.path.getmtime(target)
292 except os.error:
306 except os.error:
293 return 1
307 return 1
294 for dep in deps:
308 for dep in deps:
295 dep_time = os.path.getmtime(dep)
309 dep_time = os.path.getmtime(dep)
296 if dep_time > target_time:
310 if dep_time > target_time:
297 #print "For target",target,"Dep failed:",dep # dbg
311 #print "For target",target,"Dep failed:",dep # dbg
298 #print "times (dep,tar):",dep_time,target_time # dbg
312 #print "times (dep,tar):",dep_time,target_time # dbg
299 return 1
313 return 1
300 return 0
314 return 0
301
315
302
316
303 def target_update(target,deps,cmd):
317 def target_update(target,deps,cmd):
304 """Update a target with a given command given a list of dependencies.
318 """Update a target with a given command given a list of dependencies.
305
319
306 target_update(target,deps,cmd) -> runs cmd if target is outdated.
320 target_update(target,deps,cmd) -> runs cmd if target is outdated.
307
321
308 This is just a wrapper around target_outdated() which calls the given
322 This is just a wrapper around target_outdated() which calls the given
309 command if target is outdated."""
323 command if target is outdated."""
310
324
311 if target_outdated(target,deps):
325 if target_outdated(target,deps):
312 os.system(cmd)
326 os.system(cmd)
313
327
314 #---------------------------------------------------------------------------
328 #---------------------------------------------------------------------------
315 # Find scripts
329 # Find scripts
316 #---------------------------------------------------------------------------
330 #---------------------------------------------------------------------------
317
331
318 def find_entry_points():
332 def find_entry_points():
319 """Find IPython's scripts.
333 """Find IPython's scripts.
320
334
321 if entry_points is True:
335 if entry_points is True:
322 return setuptools entry_point-style definitions
336 return setuptools entry_point-style definitions
323 else:
337 else:
324 return file paths of plain scripts [default]
338 return file paths of plain scripts [default]
325
339
326 suffix is appended to script names if entry_points is True, so that the
340 suffix is appended to script names if entry_points is True, so that the
327 Python 3 scripts get named "ipython3" etc.
341 Python 3 scripts get named "ipython3" etc.
328 """
342 """
329 ep = [
343 ep = [
330 'ipython%s = IPython:start_ipython',
344 'ipython%s = IPython:start_ipython',
331 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
345 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
332 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
346 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
333 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
347 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
334 'iptest%s = IPython.testing.iptestcontroller:main',
348 'iptest%s = IPython.testing.iptestcontroller:main',
335 ]
349 ]
336 suffix = str(sys.version_info[0])
350 suffix = str(sys.version_info[0])
337 return [e % '' for e in ep] + [e % suffix for e in ep]
351 return [e % '' for e in ep] + [e % suffix for e in ep]
338
352
339 script_src = """#!{executable}
353 script_src = """#!{executable}
340 # This script was automatically generated by setup.py
354 # This script was automatically generated by setup.py
341 if __name__ == '__main__':
355 if __name__ == '__main__':
342 from {mod} import {func}
356 from {mod} import {func}
343 {func}()
357 {func}()
344 """
358 """
345
359
346 class build_scripts_entrypt(build_scripts):
360 class build_scripts_entrypt(build_scripts):
347 def run(self):
361 def run(self):
348 self.mkpath(self.build_dir)
362 self.mkpath(self.build_dir)
349 outfiles = []
363 outfiles = []
350 for script in find_entry_points():
364 for script in find_entry_points():
351 name, entrypt = script.split('=')
365 name, entrypt = script.split('=')
352 name = name.strip()
366 name = name.strip()
353 entrypt = entrypt.strip()
367 entrypt = entrypt.strip()
354 outfile = os.path.join(self.build_dir, name)
368 outfile = os.path.join(self.build_dir, name)
355 outfiles.append(outfile)
369 outfiles.append(outfile)
356 print('Writing script to', outfile)
370 print('Writing script to', outfile)
357
371
358 mod, func = entrypt.split(':')
372 mod, func = entrypt.split(':')
359 with open(outfile, 'w') as f:
373 with open(outfile, 'w') as f:
360 f.write(script_src.format(executable=sys.executable,
374 f.write(script_src.format(executable=sys.executable,
361 mod=mod, func=func))
375 mod=mod, func=func))
362
376
363 return outfiles, outfiles
377 return outfiles, outfiles
364
378
365 class install_lib_symlink(Command):
379 class install_lib_symlink(Command):
366 user_options = [
380 user_options = [
367 ('install-dir=', 'd', "directory to install to"),
381 ('install-dir=', 'd', "directory to install to"),
368 ]
382 ]
369
383
370 def initialize_options(self):
384 def initialize_options(self):
371 self.install_dir = None
385 self.install_dir = None
372
386
373 def finalize_options(self):
387 def finalize_options(self):
374 self.set_undefined_options('symlink',
388 self.set_undefined_options('symlink',
375 ('install_lib', 'install_dir'),
389 ('install_lib', 'install_dir'),
376 )
390 )
377
391
378 def run(self):
392 def run(self):
379 if sys.platform == 'win32':
393 if sys.platform == 'win32':
380 raise Exception("This doesn't work on Windows.")
394 raise Exception("This doesn't work on Windows.")
381 pkg = os.path.join(os.getcwd(), 'IPython')
395 pkg = os.path.join(os.getcwd(), 'IPython')
382 dest = os.path.join(self.install_dir, 'IPython')
396 dest = os.path.join(self.install_dir, 'IPython')
383 if os.path.islink(dest):
397 if os.path.islink(dest):
384 print('removing existing symlink at %s' % dest)
398 print('removing existing symlink at %s' % dest)
385 os.unlink(dest)
399 os.unlink(dest)
386 print('symlinking %s -> %s' % (pkg, dest))
400 print('symlinking %s -> %s' % (pkg, dest))
387 os.symlink(pkg, dest)
401 os.symlink(pkg, dest)
388
402
389 class unsymlink(install):
403 class unsymlink(install):
390 def run(self):
404 def run(self):
391 dest = os.path.join(self.install_lib, 'IPython')
405 dest = os.path.join(self.install_lib, 'IPython')
392 if os.path.islink(dest):
406 if os.path.islink(dest):
393 print('removing symlink at %s' % dest)
407 print('removing symlink at %s' % dest)
394 os.unlink(dest)
408 os.unlink(dest)
395 else:
409 else:
396 print('No symlink exists at %s' % dest)
410 print('No symlink exists at %s' % dest)
397
411
398 class install_symlinked(install):
412 class install_symlinked(install):
399 def run(self):
413 def run(self):
400 if sys.platform == 'win32':
414 if sys.platform == 'win32':
401 raise Exception("This doesn't work on Windows.")
415 raise Exception("This doesn't work on Windows.")
402
416
403 # Run all sub-commands (at least those that need to be run)
417 # Run all sub-commands (at least those that need to be run)
404 for cmd_name in self.get_sub_commands():
418 for cmd_name in self.get_sub_commands():
405 self.run_command(cmd_name)
419 self.run_command(cmd_name)
406
420
407 # 'sub_commands': a list of commands this command might have to run to
421 # 'sub_commands': a list of commands this command might have to run to
408 # get its work done. See cmd.py for more info.
422 # get its work done. See cmd.py for more info.
409 sub_commands = [('install_lib_symlink', lambda self:True),
423 sub_commands = [('install_lib_symlink', lambda self:True),
410 ('install_scripts_sym', lambda self:True),
424 ('install_scripts_sym', lambda self:True),
411 ]
425 ]
412
426
413 class install_scripts_for_symlink(install_scripts):
427 class install_scripts_for_symlink(install_scripts):
414 """Redefined to get options from 'symlink' instead of 'install'.
428 """Redefined to get options from 'symlink' instead of 'install'.
415
429
416 I love distutils almost as much as I love setuptools.
430 I love distutils almost as much as I love setuptools.
417 """
431 """
418 def finalize_options(self):
432 def finalize_options(self):
419 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
433 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
420 self.set_undefined_options('symlink',
434 self.set_undefined_options('symlink',
421 ('install_scripts', 'install_dir'),
435 ('install_scripts', 'install_dir'),
422 ('force', 'force'),
436 ('force', 'force'),
423 ('skip_build', 'skip_build'),
437 ('skip_build', 'skip_build'),
424 )
438 )
425
439
426 #---------------------------------------------------------------------------
440 #---------------------------------------------------------------------------
427 # Verify all dependencies
441 # Verify all dependencies
428 #---------------------------------------------------------------------------
442 #---------------------------------------------------------------------------
429
443
430 def check_for_dependencies():
444 def check_for_dependencies():
431 """Check for IPython's dependencies.
445 """Check for IPython's dependencies.
432
446
433 This function should NOT be called if running under setuptools!
447 This function should NOT be called if running under setuptools!
434 """
448 """
435 from setupext.setupext import (
449 from setupext.setupext import (
436 print_line, print_raw, print_status,
450 print_line, print_raw, print_status,
437 check_for_sphinx, check_for_pygments,
451 check_for_sphinx, check_for_pygments,
438 check_for_nose, check_for_pexpect,
452 check_for_nose, check_for_pexpect,
439 check_for_pyzmq, check_for_readline,
453 check_for_pyzmq, check_for_readline,
440 check_for_jinja2, check_for_tornado
454 check_for_jinja2, check_for_tornado
441 )
455 )
442 print_line()
456 print_line()
443 print_raw("BUILDING IPYTHON")
457 print_raw("BUILDING IPYTHON")
444 print_status('python', sys.version)
458 print_status('python', sys.version)
445 print_status('platform', sys.platform)
459 print_status('platform', sys.platform)
446 if sys.platform == 'win32':
460 if sys.platform == 'win32':
447 print_status('Windows version', sys.getwindowsversion())
461 print_status('Windows version', sys.getwindowsversion())
448
462
449 print_raw("")
463 print_raw("")
450 print_raw("OPTIONAL DEPENDENCIES")
464 print_raw("OPTIONAL DEPENDENCIES")
451
465
452 check_for_sphinx()
466 check_for_sphinx()
453 check_for_pygments()
467 check_for_pygments()
454 check_for_nose()
468 check_for_nose()
455 check_for_pexpect()
469 if os.name == 'posix':
470 check_for_pexpect()
456 check_for_pyzmq()
471 check_for_pyzmq()
457 check_for_tornado()
472 check_for_tornado()
458 check_for_readline()
473 check_for_readline()
459 check_for_jinja2()
474 check_for_jinja2()
460
475
461 #---------------------------------------------------------------------------
476 #---------------------------------------------------------------------------
462 # VCS related
477 # VCS related
463 #---------------------------------------------------------------------------
478 #---------------------------------------------------------------------------
464
479
465 # utils.submodule has checks for submodule status
480 # utils.submodule has checks for submodule status
466 execfile(pjoin('IPython','utils','submodule.py'), globals())
481 execfile(pjoin('IPython','utils','submodule.py'), globals())
467
482
468 class UpdateSubmodules(Command):
483 class UpdateSubmodules(Command):
469 """Update git submodules
484 """Update git submodules
470
485
471 IPython's external javascript dependencies live in a separate repo.
486 IPython's external javascript dependencies live in a separate repo.
472 """
487 """
473 description = "Update git submodules"
488 description = "Update git submodules"
474 user_options = []
489 user_options = []
475
490
476 def initialize_options(self):
491 def initialize_options(self):
477 pass
492 pass
478
493
479 def finalize_options(self):
494 def finalize_options(self):
480 pass
495 pass
481
496
482 def run(self):
497 def run(self):
483 failure = False
498 failure = False
484 try:
499 try:
485 self.spawn('git submodule init'.split())
500 self.spawn('git submodule init'.split())
486 self.spawn('git submodule update --recursive'.split())
501 self.spawn('git submodule update --recursive'.split())
487 except Exception as e:
502 except Exception as e:
488 failure = e
503 failure = e
489 print(e)
504 print(e)
490
505
491 if not check_submodule_status(repo_root) == 'clean':
506 if not check_submodule_status(repo_root) == 'clean':
492 print("submodules could not be checked out")
507 print("submodules could not be checked out")
493 sys.exit(1)
508 sys.exit(1)
494
509
495
510
496 def git_prebuild(pkg_dir, build_cmd=build_py):
511 def git_prebuild(pkg_dir, build_cmd=build_py):
497 """Return extended build or sdist command class for recording commit
512 """Return extended build or sdist command class for recording commit
498
513
499 records git commit in IPython.utils._sysinfo.commit
514 records git commit in IPython.utils._sysinfo.commit
500
515
501 for use in IPython.utils.sysinfo.sys_info() calls after installation.
516 for use in IPython.utils.sysinfo.sys_info() calls after installation.
502
517
503 Also ensures that submodules exist prior to running
518 Also ensures that submodules exist prior to running
504 """
519 """
505
520
506 class MyBuildPy(build_cmd):
521 class MyBuildPy(build_cmd):
507 ''' Subclass to write commit data into installation tree '''
522 ''' Subclass to write commit data into installation tree '''
508 def run(self):
523 def run(self):
509 build_cmd.run(self)
524 build_cmd.run(self)
510 # this one will only fire for build commands
525 # this one will only fire for build commands
511 if hasattr(self, 'build_lib'):
526 if hasattr(self, 'build_lib'):
512 self._record_commit(self.build_lib)
527 self._record_commit(self.build_lib)
513
528
514 def make_release_tree(self, base_dir, files):
529 def make_release_tree(self, base_dir, files):
515 # this one will fire for sdist
530 # this one will fire for sdist
516 build_cmd.make_release_tree(self, base_dir, files)
531 build_cmd.make_release_tree(self, base_dir, files)
517 self._record_commit(base_dir)
532 self._record_commit(base_dir)
518
533
519 def _record_commit(self, base_dir):
534 def _record_commit(self, base_dir):
520 import subprocess
535 import subprocess
521 proc = subprocess.Popen('git rev-parse --short HEAD',
536 proc = subprocess.Popen('git rev-parse --short HEAD',
522 stdout=subprocess.PIPE,
537 stdout=subprocess.PIPE,
523 stderr=subprocess.PIPE,
538 stderr=subprocess.PIPE,
524 shell=True)
539 shell=True)
525 repo_commit, _ = proc.communicate()
540 repo_commit, _ = proc.communicate()
526 repo_commit = repo_commit.strip().decode("ascii")
541 repo_commit = repo_commit.strip().decode("ascii")
527
542
528 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
543 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
529 if os.path.isfile(out_pth) and not repo_commit:
544 if os.path.isfile(out_pth) and not repo_commit:
530 # nothing to write, don't clobber
545 # nothing to write, don't clobber
531 return
546 return
532
547
533 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
548 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
534
549
535 # remove to avoid overwriting original via hard link
550 # remove to avoid overwriting original via hard link
536 try:
551 try:
537 os.remove(out_pth)
552 os.remove(out_pth)
538 except (IOError, OSError):
553 except (IOError, OSError):
539 pass
554 pass
540 with open(out_pth, 'w') as out_file:
555 with open(out_pth, 'w') as out_file:
541 out_file.writelines([
556 out_file.writelines([
542 '# GENERATED BY setup.py\n',
557 '# GENERATED BY setup.py\n',
543 'commit = "%s"\n' % repo_commit,
558 'commit = "%s"\n' % repo_commit,
544 ])
559 ])
545 return require_submodules(MyBuildPy)
560 return require_submodules(MyBuildPy)
546
561
547
562
548 def require_submodules(command):
563 def require_submodules(command):
549 """decorator for instructing a command to check for submodules before running"""
564 """decorator for instructing a command to check for submodules before running"""
550 class DecoratedCommand(command):
565 class DecoratedCommand(command):
551 def run(self):
566 def run(self):
552 if not check_submodule_status(repo_root) == 'clean':
567 if not check_submodule_status(repo_root) == 'clean':
553 print("submodules missing! Run `setup.py submodule` and try again")
568 print("submodules missing! Run `setup.py submodule` and try again")
554 sys.exit(1)
569 sys.exit(1)
555 command.run(self)
570 command.run(self)
556 return DecoratedCommand
571 return DecoratedCommand
557
572
558 #---------------------------------------------------------------------------
573 #---------------------------------------------------------------------------
574 # bdist related
575 #---------------------------------------------------------------------------
576
577 def get_bdist_wheel():
578 """Construct bdist_wheel command for building wheels
579
580 Constructs py2-none-any tag, instead of py2.7-none-any
581 """
582 class RequiresWheel(Command):
583 description = "Dummy command for missing bdist_wheel"
584 user_options = []
585
586 def initialize_options(self):
587 pass
588
589 def finalize_options(self):
590 pass
591
592 def run(self):
593 print("bdist_wheel requires the wheel package")
594 sys.exit(1)
595
596 if 'setuptools' not in sys.modules:
597 return RequiresWheel
598 else:
599 try:
600 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
601 except ImportError:
602 return RequiresWheel
603
604 class bdist_wheel_tag(bdist_wheel):
605
606 def get_tag(self):
607 return ('py%i' % sys.version_info[0], 'none', 'any')
608
609 def add_requirements(self, metadata_path):
610 """transform platform-dependent requirements"""
611 pkg_info = read_pkg_info(metadata_path)
612 # pkg_info is an email.Message object (?!)
613 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
614 # and transform them to conditionals
615 requires = pkg_info.get_all('Requires-Dist')
616 del pkg_info['Requires-Dist']
617 def _remove_startswith(lis, prefix):
618 """like list.remove, but with startswith instead of =="""
619 found = False
620 for idx, item in enumerate(lis):
621 if item.startswith(prefix):
622 found = True
623 break
624 if found:
625 lis.pop(idx)
626
627 for pkg in ("readline", "pyreadline"):
628 _remove_startswith(requires, pkg)
629 requires.append("readline; sys.platform == 'darwin'")
630 requires.append("pyreadline (>=2.0); sys.platform == 'win32'")
631 for r in requires:
632 pkg_info['Requires-Dist'] = r
633 write_pkg_info(metadata_path, pkg_info)
634
635 return bdist_wheel_tag
636
637 #---------------------------------------------------------------------------
559 # Notebook related
638 # Notebook related
560 #---------------------------------------------------------------------------
639 #---------------------------------------------------------------------------
561
640
562 class CompileCSS(Command):
641 class CompileCSS(Command):
563 """Recompile Notebook CSS
642 """Recompile Notebook CSS
564
643
565 Regenerate the compiled CSS from LESS sources.
644 Regenerate the compiled CSS from LESS sources.
566
645
567 Requires various dev dependencies, such as fabric and lessc.
646 Requires various dev dependencies, such as fabric and lessc.
568 """
647 """
569 description = "Recompile Notebook CSS"
648 description = "Recompile Notebook CSS"
570 user_options = []
649 user_options = []
571
650
572 def initialize_options(self):
651 def initialize_options(self):
573 pass
652 pass
574
653
575 def finalize_options(self):
654 def finalize_options(self):
576 pass
655 pass
577
656
578 def run(self):
657 def run(self):
579 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
658 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
580
659
581 class JavascriptVersion(Command):
660 class JavascriptVersion(Command):
582 """write the javascript version to notebook javascript"""
661 """write the javascript version to notebook javascript"""
583 description = "Write IPython version to javascript"
662 description = "Write IPython version to javascript"
584 user_options = []
663 user_options = []
585
664
586 def initialize_options(self):
665 def initialize_options(self):
587 pass
666 pass
588
667
589 def finalize_options(self):
668 def finalize_options(self):
590 pass
669 pass
591
670
592 def run(self):
671 def run(self):
593 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
672 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
594 with open(nsfile) as f:
673 with open(nsfile) as f:
595 lines = f.readlines()
674 lines = f.readlines()
596 with open(nsfile, 'w') as f:
675 with open(nsfile, 'w') as f:
597 for line in lines:
676 for line in lines:
598 if line.startswith("IPython.version"):
677 if line.startswith("IPython.version"):
599 line = 'IPython.version = "{0}";\n'.format(version)
678 line = 'IPython.version = "{0}";\n'.format(version)
600 f.write(line)
679 f.write(line)
601
680
@@ -1,169 +1,169
1 # encoding: utf-8
1 # encoding: utf-8
2 from __future__ import print_function
2 from __future__ import print_function
3
3
4 __docformat__ = "restructuredtext en"
4 __docformat__ = "restructuredtext en"
5
5
6 #-------------------------------------------------------------------------------
6 #-------------------------------------------------------------------------------
7 # Copyright (C) 2008 The IPython Development Team
7 # Copyright (C) 2008 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16
16
17 import sys, os
17 import sys, os
18 from textwrap import fill
18 from textwrap import fill
19
19
20 display_status=True
20 display_status=True
21
21
22 def check_display(f):
22 def check_display(f):
23 """decorator to allow display methods to be muted by mod.display_status"""
23 """decorator to allow display methods to be muted by mod.display_status"""
24 def maybe_display(*args, **kwargs):
24 def maybe_display(*args, **kwargs):
25 if display_status:
25 if display_status:
26 return f(*args, **kwargs)
26 return f(*args, **kwargs)
27 return maybe_display
27 return maybe_display
28
28
29 @check_display
29 @check_display
30 def print_line(char='='):
30 def print_line(char='='):
31 print(char * 76)
31 print(char * 76)
32
32
33 @check_display
33 @check_display
34 def print_status(package, status):
34 def print_status(package, status):
35 initial_indent = "%22s: " % package
35 initial_indent = "%22s: " % package
36 indent = ' ' * 24
36 indent = ' ' * 24
37 print(fill(str(status), width=76,
37 print(fill(str(status), width=76,
38 initial_indent=initial_indent,
38 initial_indent=initial_indent,
39 subsequent_indent=indent))
39 subsequent_indent=indent))
40
40
41 @check_display
41 @check_display
42 def print_message(message):
42 def print_message(message):
43 indent = ' ' * 24 + "* "
43 indent = ' ' * 24 + "* "
44 print(fill(str(message), width=76,
44 print(fill(str(message), width=76,
45 initial_indent=indent,
45 initial_indent=indent,
46 subsequent_indent=indent))
46 subsequent_indent=indent))
47
47
48 @check_display
48 @check_display
49 def print_raw(section):
49 def print_raw(section):
50 print(section)
50 print(section)
51
51
52 #-------------------------------------------------------------------------------
52 #-------------------------------------------------------------------------------
53 # Tests for specific packages
53 # Tests for specific packages
54 #-------------------------------------------------------------------------------
54 #-------------------------------------------------------------------------------
55
55
56 def check_for_ipython():
56 def check_for_ipython():
57 try:
57 try:
58 import IPython
58 import IPython
59 except ImportError:
59 except ImportError:
60 print_status("IPython", "Not found")
60 print_status("IPython", "Not found")
61 return False
61 return False
62 else:
62 else:
63 print_status("IPython", IPython.__version__)
63 print_status("IPython", IPython.__version__)
64 return True
64 return True
65
65
66 def check_for_sphinx():
66 def check_for_sphinx():
67 try:
67 try:
68 import sphinx
68 import sphinx
69 except ImportError:
69 except ImportError:
70 print_status('sphinx', "Not found (required for docs and nbconvert)")
70 print_status('sphinx', "Not found (required for docs and nbconvert)")
71 return False
71 return False
72 else:
72 else:
73 print_status('sphinx', sphinx.__version__)
73 print_status('sphinx', sphinx.__version__)
74 return True
74 return True
75
75
76 def check_for_pygments():
76 def check_for_pygments():
77 try:
77 try:
78 import pygments
78 import pygments
79 except ImportError:
79 except ImportError:
80 print_status('pygments', "Not found (required for docs and nbconvert)")
80 print_status('pygments', "Not found (required for docs and nbconvert)")
81 return False
81 return False
82 else:
82 else:
83 print_status('pygments', pygments.__version__)
83 print_status('pygments', pygments.__version__)
84 return True
84 return True
85
85
86 def check_for_jinja2():
86 def check_for_jinja2():
87 try:
87 try:
88 import jinja2
88 import jinja2
89 except ImportError:
89 except ImportError:
90 print_status('jinja2', "Not found (required for notebook and nbconvert)")
90 print_status('jinja2', "Not found (required for notebook and nbconvert)")
91 return False
91 return False
92 else:
92 else:
93 print_status('jinja2', jinja2.__version__)
93 print_status('jinja2', jinja2.__version__)
94 return True
94 return True
95
95
96 def check_for_nose():
96 def check_for_nose():
97 try:
97 try:
98 import nose
98 import nose
99 except ImportError:
99 except ImportError:
100 print_status('nose', "Not found (required for running the test suite)")
100 print_status('nose', "Not found (required for running the test suite)")
101 return False
101 return False
102 else:
102 else:
103 print_status('nose', nose.__version__)
103 print_status('nose', nose.__version__)
104 return True
104 return True
105
105
106 def check_for_pexpect():
106 def check_for_pexpect():
107 try:
107 try:
108 import pexpect
108 import pexpect
109 except ImportError:
109 except ImportError:
110 print_status("pexpect", "no (required for running standalone doctests)")
110 print_status("pexpect", "no (will use bundled version in IPython.external)")
111 return False
111 return False
112 else:
112 else:
113 print_status("pexpect", pexpect.__version__)
113 print_status("pexpect", pexpect.__version__)
114 return True
114 return True
115
115
116 def check_for_pyzmq():
116 def check_for_pyzmq():
117 try:
117 try:
118 import zmq
118 import zmq
119 except ImportError:
119 except ImportError:
120 print_status('pyzmq', "no (required for qtconsole, notebook, and parallel computing capabilities)")
120 print_status('pyzmq', "no (required for qtconsole, notebook, and parallel computing capabilities)")
121 return False
121 return False
122 else:
122 else:
123 # pyzmq 2.1.10 adds pyzmq_version_info funtion for returning
123 # pyzmq 2.1.10 adds pyzmq_version_info funtion for returning
124 # version as a tuple
124 # version as a tuple
125 if hasattr(zmq, 'pyzmq_version_info') and zmq.pyzmq_version_info() >= (2,1,11):
125 if hasattr(zmq, 'pyzmq_version_info') and zmq.pyzmq_version_info() >= (2,1,11):
126 print_status("pyzmq", zmq.__version__)
126 print_status("pyzmq", zmq.__version__)
127 return True
127 return True
128 else:
128 else:
129 print_status('pyzmq', "no (have %s, but require >= 2.1.11 for"
129 print_status('pyzmq', "no (have %s, but require >= 2.1.11 for"
130 " qtconsole, notebook, and parallel computing capabilities)" % zmq.__version__)
130 " qtconsole, notebook, and parallel computing capabilities)" % zmq.__version__)
131 return False
131 return False
132
132
133 def check_for_tornado():
133 def check_for_tornado():
134 try:
134 try:
135 import tornado
135 import tornado
136 except ImportError:
136 except ImportError:
137 print_status('tornado', "no (required for notebook)")
137 print_status('tornado', "no (required for notebook)")
138 return False
138 return False
139 else:
139 else:
140 if getattr(tornado, 'version_info', (0,)) < (3,1):
140 if getattr(tornado, 'version_info', (0,)) < (3,1):
141 print_status('tornado', "no (have %s, but require >= 3.1.0)" % tornado.version)
141 print_status('tornado', "no (have %s, but require >= 3.1.0)" % tornado.version)
142 return False
142 return False
143 else:
143 else:
144 print_status('tornado', tornado.version)
144 print_status('tornado', tornado.version)
145 return True
145 return True
146
146
147 def check_for_readline():
147 def check_for_readline():
148 from distutils.version import LooseVersion
148 from distutils.version import LooseVersion
149 try:
149 try:
150 import readline
150 import readline
151 except ImportError:
151 except ImportError:
152 try:
152 try:
153 import pyreadline
153 import pyreadline
154 vs = pyreadline.release.version
154 vs = pyreadline.release.version
155 except (ImportError, AttributeError):
155 except (ImportError, AttributeError):
156 print_status('readline', "no (required for good interactive behavior)")
156 print_status('readline', "no (required for good interactive behavior)")
157 return False
157 return False
158 if LooseVersion(vs).version >= [1,7,1]:
158 if LooseVersion(vs).version >= [1,7,1]:
159 print_status('readline', "yes pyreadline-" + vs)
159 print_status('readline', "yes pyreadline-" + vs)
160 return True
160 return True
161 else:
161 else:
162 print_status('readline', "no pyreadline-%s < 1.7.1" % vs)
162 print_status('readline', "no pyreadline-%s < 1.7.1" % vs)
163 return False
163 return False
164 else:
164 else:
165 if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
165 if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
166 print_status('readline', "no (libedit detected)")
166 print_status('readline', "no (libedit detected)")
167 return False
167 return False
168 print_status('readline', "yes")
168 print_status('readline', "yes")
169 return True
169 return True
General Comments 0
You need to be logged in to leave comments. Login now