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