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