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