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