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