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