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