##// END OF EJS Templates
merge separate input/expected notebooks for execute preprocessor
MinRK -
Show More
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/Clear Output.ipynb to IPython/nbconvert/preprocessors/tests/files/Clear Output.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/Factorials.ipynb to IPython/nbconvert/preprocessors/tests/files/Factorials.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/HelloWorld.ipynb to IPython/nbconvert/preprocessors/tests/files/HelloWorld.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/Inline Image.ipynb to IPython/nbconvert/preprocessors/tests/files/Inline Image.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/SVG.ipynb to IPython/nbconvert/preprocessors/tests/files/SVG.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/Skip Exceptions.ipynb to IPython/nbconvert/preprocessors/tests/files/Skip Exceptions.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/expected/Unicode.ipynb to IPython/nbconvert/preprocessors/tests/files/Unicode.ipynb
1 NO CONTENT: file renamed from IPython/nbconvert/preprocessors/tests/input/python.png to IPython/nbconvert/preprocessors/tests/files/python.png
@@ -1,86 +1,82 b''
1 1 """
2 2 Module with tests for the execute preprocessor.
3 3 """
4 4
5 5 # Copyright (c) IPython Development Team.
6 6 # Distributed under the terms of the Modified BSD License.
7 7
8 8 import copy
9 import glob
9 10 import os
10 11 import re
11 12
12 13 from IPython.nbformat import current as nbformat
13 14
14 15 from .base import PreprocessorTestsBase
15 16 from ..execute import ExecutePreprocessor
16 17
17 18 from IPython.nbconvert.filters import strip_ansi
18 19
19
20 20 addr_pat = re.compile(r'0x[0-9a-f]{7,9}')
21 21
22 22 class TestExecute(PreprocessorTestsBase):
23 23 """Contains test functions for execute.py"""
24 24
25 25 @staticmethod
26 26 def normalize_output(output):
27 27 """
28 28 Normalizes outputs for comparison.
29 29 """
30 30 output = dict(output)
31 31 if 'metadata' in output:
32 32 del output['metadata']
33 33 if 'text' in output:
34 34 output['text'] = re.sub(addr_pat, '<HEXADDR>', output['text'])
35 35 if 'svg' in output:
36 36 del output['text']
37 37 if 'traceback' in output:
38 38 tb = []
39 39 for line in output['traceback']:
40 40 tb.append(strip_ansi(line))
41 41 output['traceback'] = tb
42 42
43 43 return output
44 44
45 45
46 46 def assert_notebooks_equal(self, expected, actual):
47 47 expected_cells = expected['worksheets'][0]['cells']
48 48 actual_cells = actual['worksheets'][0]['cells']
49 49 assert len(expected_cells) == len(actual_cells)
50 50
51 51 for expected_cell, actual_cell in zip(expected_cells, actual_cells):
52 52 expected_outputs = expected_cell.get('outputs', [])
53 53 actual_outputs = actual_cell.get('outputs', [])
54 54 normalized_expected_outputs = list(map(self.normalize_output, expected_outputs))
55 55 normalized_actual_outputs = list(map(self.normalize_output, actual_outputs))
56 56 assert normalized_expected_outputs == normalized_actual_outputs
57 57
58 58
59 59 def build_preprocessor(self):
60 60 """Make an instance of a preprocessor"""
61 61 preprocessor = ExecutePreprocessor()
62 62 preprocessor.enabled = True
63 63 return preprocessor
64 64
65 65
66 66 def test_constructor(self):
67 67 """Can a ExecutePreprocessor be constructed?"""
68 68 self.build_preprocessor()
69 69
70 70
71 71 def test_run_notebooks(self):
72 72 """Runs a series of test notebooks and compares them to their actual output"""
73 73 current_dir = os.path.dirname(__file__)
74 input_files = os.listdir(os.path.join(current_dir, 'input'))
74 input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb'))
75 75 for filename in input_files:
76 if not filename.endswith(".ipynb"):
77 continue
78 with open(os.path.join(current_dir, 'input', filename)) as f:
76 with open(os.path.join(current_dir, 'files', filename)) as f:
79 77 input_nb = nbformat.read(f, 'ipynb')
80 with open(os.path.join(current_dir, 'expected', filename)) as f:
81 expected_nb = nbformat.read(f, 'ipynb')
82 78 res = self.build_resources()
83 79 preprocessor = self.build_preprocessor()
84 output_nb, _ = preprocessor(input_nb, res)
85 self.assert_notebooks_equal(output_nb, expected_nb)
80 output_nb, _ = preprocessor(copy.deepcopy(input_nb), res)
81 self.assert_notebooks_equal(output_nb, input_nb)
86 82
@@ -1,701 +1,700 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 'preprocessors/tests/input/*.*',
192 'preprocessors/tests/expected/*.*',
191 'preprocessors/tests/files/*.*',
193 192 ],
194 193 'IPython.nbconvert.filters' : ['marked.js'],
195 194 'IPython.nbformat' : ['tests/*.ipynb','v3/v3.withref.json']
196 195 }
197 196
198 197 return package_data
199 198
200 199
201 200 def check_package_data(package_data):
202 201 """verify that package_data globs make sense"""
203 202 print("checking package data")
204 203 for pkg, data in package_data.items():
205 204 pkg_root = pjoin(*pkg.split('.'))
206 205 for d in data:
207 206 path = pjoin(pkg_root, d)
208 207 if '*' in path:
209 208 assert len(glob(path)) > 0, "No files match pattern %s" % path
210 209 else:
211 210 assert os.path.exists(path), "Missing package data: %s" % path
212 211
213 212
214 213 def check_package_data_first(command):
215 214 """decorator for checking package_data before running a given command
216 215
217 216 Probably only needs to wrap build_py
218 217 """
219 218 class DecoratedCommand(command):
220 219 def run(self):
221 220 check_package_data(self.package_data)
222 221 command.run(self)
223 222 return DecoratedCommand
224 223
225 224
226 225 #---------------------------------------------------------------------------
227 226 # Find data files
228 227 #---------------------------------------------------------------------------
229 228
230 229 def make_dir_struct(tag,base,out_base):
231 230 """Make the directory structure of all files below a starting dir.
232 231
233 232 This is just a convenience routine to help build a nested directory
234 233 hierarchy because distutils is too stupid to do this by itself.
235 234
236 235 XXX - this needs a proper docstring!
237 236 """
238 237
239 238 # we'll use these a lot below
240 239 lbase = len(base)
241 240 pathsep = os.path.sep
242 241 lpathsep = len(pathsep)
243 242
244 243 out = []
245 244 for (dirpath,dirnames,filenames) in os.walk(base):
246 245 # we need to strip out the dirpath from the base to map it to the
247 246 # output (installation) path. This requires possibly stripping the
248 247 # path separator, because otherwise pjoin will not work correctly
249 248 # (pjoin('foo/','/bar') returns '/bar').
250 249
251 250 dp_eff = dirpath[lbase:]
252 251 if dp_eff.startswith(pathsep):
253 252 dp_eff = dp_eff[lpathsep:]
254 253 # The output path must be anchored at the out_base marker
255 254 out_path = pjoin(out_base,dp_eff)
256 255 # Now we can generate the final filenames. Since os.walk only produces
257 256 # filenames, we must join back with the dirpath to get full valid file
258 257 # paths:
259 258 pfiles = [pjoin(dirpath,f) for f in filenames]
260 259 # Finally, generate the entry we need, which is a pari of (output
261 260 # path, files) for use as a data_files parameter in install_data.
262 261 out.append((out_path, pfiles))
263 262
264 263 return out
265 264
266 265
267 266 def find_data_files():
268 267 """
269 268 Find IPython's data_files.
270 269
271 270 Just man pages at this point.
272 271 """
273 272
274 273 manpagebase = pjoin('share', 'man', 'man1')
275 274
276 275 # Simple file lists can be made by hand
277 276 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
278 277 if not manpages:
279 278 # When running from a source tree, the manpages aren't gzipped
280 279 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
281 280
282 281 # And assemble the entire output list
283 282 data_files = [ (manpagebase, manpages) ]
284 283
285 284 return data_files
286 285
287 286
288 287 def make_man_update_target(manpage):
289 288 """Return a target_update-compliant tuple for the given manpage.
290 289
291 290 Parameters
292 291 ----------
293 292 manpage : string
294 293 Name of the manpage, must include the section number (trailing number).
295 294
296 295 Example
297 296 -------
298 297
299 298 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
300 299 ('docs/man/ipython.1.gz',
301 300 ['docs/man/ipython.1'],
302 301 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
303 302 """
304 303 man_dir = pjoin('docs', 'man')
305 304 manpage_gz = manpage + '.gz'
306 305 manpath = pjoin(man_dir, manpage)
307 306 manpath_gz = pjoin(man_dir, manpage_gz)
308 307 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
309 308 locals() )
310 309 return (manpath_gz, [manpath], gz_cmd)
311 310
312 311 # The two functions below are copied from IPython.utils.path, so we don't need
313 312 # to import IPython during setup, which fails on Python 3.
314 313
315 314 def target_outdated(target,deps):
316 315 """Determine whether a target is out of date.
317 316
318 317 target_outdated(target,deps) -> 1/0
319 318
320 319 deps: list of filenames which MUST exist.
321 320 target: single filename which may or may not exist.
322 321
323 322 If target doesn't exist or is older than any file listed in deps, return
324 323 true, otherwise return false.
325 324 """
326 325 try:
327 326 target_time = os.path.getmtime(target)
328 327 except os.error:
329 328 return 1
330 329 for dep in deps:
331 330 dep_time = os.path.getmtime(dep)
332 331 if dep_time > target_time:
333 332 #print "For target",target,"Dep failed:",dep # dbg
334 333 #print "times (dep,tar):",dep_time,target_time # dbg
335 334 return 1
336 335 return 0
337 336
338 337
339 338 def target_update(target,deps,cmd):
340 339 """Update a target with a given command given a list of dependencies.
341 340
342 341 target_update(target,deps,cmd) -> runs cmd if target is outdated.
343 342
344 343 This is just a wrapper around target_outdated() which calls the given
345 344 command if target is outdated."""
346 345
347 346 if target_outdated(target,deps):
348 347 os.system(cmd)
349 348
350 349 #---------------------------------------------------------------------------
351 350 # Find scripts
352 351 #---------------------------------------------------------------------------
353 352
354 353 def find_entry_points():
355 354 """Find IPython's scripts.
356 355
357 356 if entry_points is True:
358 357 return setuptools entry_point-style definitions
359 358 else:
360 359 return file paths of plain scripts [default]
361 360
362 361 suffix is appended to script names if entry_points is True, so that the
363 362 Python 3 scripts get named "ipython3" etc.
364 363 """
365 364 ep = [
366 365 'ipython%s = IPython:start_ipython',
367 366 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
368 367 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
369 368 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
370 369 'iptest%s = IPython.testing.iptestcontroller:main',
371 370 ]
372 371 suffix = str(sys.version_info[0])
373 372 return [e % '' for e in ep] + [e % suffix for e in ep]
374 373
375 374 script_src = """#!{executable}
376 375 # This script was automatically generated by setup.py
377 376 if __name__ == '__main__':
378 377 from {mod} import {func}
379 378 {func}()
380 379 """
381 380
382 381 class build_scripts_entrypt(build_scripts):
383 382 def run(self):
384 383 self.mkpath(self.build_dir)
385 384 outfiles = []
386 385 for script in find_entry_points():
387 386 name, entrypt = script.split('=')
388 387 name = name.strip()
389 388 entrypt = entrypt.strip()
390 389 outfile = os.path.join(self.build_dir, name)
391 390 outfiles.append(outfile)
392 391 print('Writing script to', outfile)
393 392
394 393 mod, func = entrypt.split(':')
395 394 with open(outfile, 'w') as f:
396 395 f.write(script_src.format(executable=sys.executable,
397 396 mod=mod, func=func))
398 397
399 398 return outfiles, outfiles
400 399
401 400 class install_lib_symlink(Command):
402 401 user_options = [
403 402 ('install-dir=', 'd', "directory to install to"),
404 403 ]
405 404
406 405 def initialize_options(self):
407 406 self.install_dir = None
408 407
409 408 def finalize_options(self):
410 409 self.set_undefined_options('symlink',
411 410 ('install_lib', 'install_dir'),
412 411 )
413 412
414 413 def run(self):
415 414 if sys.platform == 'win32':
416 415 raise Exception("This doesn't work on Windows.")
417 416 pkg = os.path.join(os.getcwd(), 'IPython')
418 417 dest = os.path.join(self.install_dir, 'IPython')
419 418 if os.path.islink(dest):
420 419 print('removing existing symlink at %s' % dest)
421 420 os.unlink(dest)
422 421 print('symlinking %s -> %s' % (pkg, dest))
423 422 os.symlink(pkg, dest)
424 423
425 424 class unsymlink(install):
426 425 def run(self):
427 426 dest = os.path.join(self.install_lib, 'IPython')
428 427 if os.path.islink(dest):
429 428 print('removing symlink at %s' % dest)
430 429 os.unlink(dest)
431 430 else:
432 431 print('No symlink exists at %s' % dest)
433 432
434 433 class install_symlinked(install):
435 434 def run(self):
436 435 if sys.platform == 'win32':
437 436 raise Exception("This doesn't work on Windows.")
438 437
439 438 # Run all sub-commands (at least those that need to be run)
440 439 for cmd_name in self.get_sub_commands():
441 440 self.run_command(cmd_name)
442 441
443 442 # 'sub_commands': a list of commands this command might have to run to
444 443 # get its work done. See cmd.py for more info.
445 444 sub_commands = [('install_lib_symlink', lambda self:True),
446 445 ('install_scripts_sym', lambda self:True),
447 446 ]
448 447
449 448 class install_scripts_for_symlink(install_scripts):
450 449 """Redefined to get options from 'symlink' instead of 'install'.
451 450
452 451 I love distutils almost as much as I love setuptools.
453 452 """
454 453 def finalize_options(self):
455 454 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
456 455 self.set_undefined_options('symlink',
457 456 ('install_scripts', 'install_dir'),
458 457 ('force', 'force'),
459 458 ('skip_build', 'skip_build'),
460 459 )
461 460
462 461 #---------------------------------------------------------------------------
463 462 # Verify all dependencies
464 463 #---------------------------------------------------------------------------
465 464
466 465 def check_for_dependencies():
467 466 """Check for IPython's dependencies.
468 467
469 468 This function should NOT be called if running under setuptools!
470 469 """
471 470 from setupext.setupext import (
472 471 print_line, print_raw, print_status,
473 472 check_for_sphinx, check_for_pygments,
474 473 check_for_nose, check_for_pexpect,
475 474 check_for_pyzmq, check_for_readline,
476 475 check_for_jinja2, check_for_tornado
477 476 )
478 477 print_line()
479 478 print_raw("BUILDING IPYTHON")
480 479 print_status('python', sys.version)
481 480 print_status('platform', sys.platform)
482 481 if sys.platform == 'win32':
483 482 print_status('Windows version', sys.getwindowsversion())
484 483
485 484 print_raw("")
486 485 print_raw("OPTIONAL DEPENDENCIES")
487 486
488 487 check_for_sphinx()
489 488 check_for_pygments()
490 489 check_for_nose()
491 490 if os.name == 'posix':
492 491 check_for_pexpect()
493 492 check_for_pyzmq()
494 493 check_for_tornado()
495 494 check_for_readline()
496 495 check_for_jinja2()
497 496
498 497 #---------------------------------------------------------------------------
499 498 # VCS related
500 499 #---------------------------------------------------------------------------
501 500
502 501 # utils.submodule has checks for submodule status
503 502 execfile(pjoin('IPython','utils','submodule.py'), globals())
504 503
505 504 class UpdateSubmodules(Command):
506 505 """Update git submodules
507 506
508 507 IPython's external javascript dependencies live in a separate repo.
509 508 """
510 509 description = "Update git submodules"
511 510 user_options = []
512 511
513 512 def initialize_options(self):
514 513 pass
515 514
516 515 def finalize_options(self):
517 516 pass
518 517
519 518 def run(self):
520 519 failure = False
521 520 try:
522 521 self.spawn('git submodule init'.split())
523 522 self.spawn('git submodule update --recursive'.split())
524 523 except Exception as e:
525 524 failure = e
526 525 print(e)
527 526
528 527 if not check_submodule_status(repo_root) == 'clean':
529 528 print("submodules could not be checked out")
530 529 sys.exit(1)
531 530
532 531
533 532 def git_prebuild(pkg_dir, build_cmd=build_py):
534 533 """Return extended build or sdist command class for recording commit
535 534
536 535 records git commit in IPython.utils._sysinfo.commit
537 536
538 537 for use in IPython.utils.sysinfo.sys_info() calls after installation.
539 538
540 539 Also ensures that submodules exist prior to running
541 540 """
542 541
543 542 class MyBuildPy(build_cmd):
544 543 ''' Subclass to write commit data into installation tree '''
545 544 def run(self):
546 545 build_cmd.run(self)
547 546 # this one will only fire for build commands
548 547 if hasattr(self, 'build_lib'):
549 548 self._record_commit(self.build_lib)
550 549
551 550 def make_release_tree(self, base_dir, files):
552 551 # this one will fire for sdist
553 552 build_cmd.make_release_tree(self, base_dir, files)
554 553 self._record_commit(base_dir)
555 554
556 555 def _record_commit(self, base_dir):
557 556 import subprocess
558 557 proc = subprocess.Popen('git rev-parse --short HEAD',
559 558 stdout=subprocess.PIPE,
560 559 stderr=subprocess.PIPE,
561 560 shell=True)
562 561 repo_commit, _ = proc.communicate()
563 562 repo_commit = repo_commit.strip().decode("ascii")
564 563
565 564 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
566 565 if os.path.isfile(out_pth) and not repo_commit:
567 566 # nothing to write, don't clobber
568 567 return
569 568
570 569 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
571 570
572 571 # remove to avoid overwriting original via hard link
573 572 try:
574 573 os.remove(out_pth)
575 574 except (IOError, OSError):
576 575 pass
577 576 with open(out_pth, 'w') as out_file:
578 577 out_file.writelines([
579 578 '# GENERATED BY setup.py\n',
580 579 'commit = "%s"\n' % repo_commit,
581 580 ])
582 581 return require_submodules(MyBuildPy)
583 582
584 583
585 584 def require_submodules(command):
586 585 """decorator for instructing a command to check for submodules before running"""
587 586 class DecoratedCommand(command):
588 587 def run(self):
589 588 if not check_submodule_status(repo_root) == 'clean':
590 589 print("submodules missing! Run `setup.py submodule` and try again")
591 590 sys.exit(1)
592 591 command.run(self)
593 592 return DecoratedCommand
594 593
595 594 #---------------------------------------------------------------------------
596 595 # bdist related
597 596 #---------------------------------------------------------------------------
598 597
599 598 def get_bdist_wheel():
600 599 """Construct bdist_wheel command for building wheels
601 600
602 601 Constructs py2-none-any tag, instead of py2.7-none-any
603 602 """
604 603 class RequiresWheel(Command):
605 604 description = "Dummy command for missing bdist_wheel"
606 605 user_options = []
607 606
608 607 def initialize_options(self):
609 608 pass
610 609
611 610 def finalize_options(self):
612 611 pass
613 612
614 613 def run(self):
615 614 print("bdist_wheel requires the wheel package")
616 615 sys.exit(1)
617 616
618 617 if 'setuptools' not in sys.modules:
619 618 return RequiresWheel
620 619 else:
621 620 try:
622 621 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
623 622 except ImportError:
624 623 return RequiresWheel
625 624
626 625 class bdist_wheel_tag(bdist_wheel):
627 626
628 627 def add_requirements(self, metadata_path):
629 628 """transform platform-dependent requirements"""
630 629 pkg_info = read_pkg_info(metadata_path)
631 630 # pkg_info is an email.Message object (?!)
632 631 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
633 632 # and transform them to conditionals
634 633 requires = pkg_info.get_all('Requires-Dist')
635 634 del pkg_info['Requires-Dist']
636 635 def _remove_startswith(lis, prefix):
637 636 """like list.remove, but with startswith instead of =="""
638 637 found = False
639 638 for idx, item in enumerate(lis):
640 639 if item.startswith(prefix):
641 640 found = True
642 641 break
643 642 if found:
644 643 lis.pop(idx)
645 644
646 645 for pkg in ("gnureadline", "pyreadline", "mock"):
647 646 _remove_startswith(requires, pkg)
648 647 requires.append("gnureadline; sys.platform == 'darwin' and platform.python_implementation == 'CPython'")
649 648 requires.append("pyreadline (>=2.0); extra == 'terminal' and sys.platform == 'win32' and platform.python_implementation == 'CPython'")
650 649 requires.append("pyreadline (>=2.0); extra == 'all' and sys.platform == 'win32' and platform.python_implementation == 'CPython'")
651 650 requires.append("mock; extra == 'test' and python_version < '3.3'")
652 651 for r in requires:
653 652 pkg_info['Requires-Dist'] = r
654 653 write_pkg_info(metadata_path, pkg_info)
655 654
656 655 return bdist_wheel_tag
657 656
658 657 #---------------------------------------------------------------------------
659 658 # Notebook related
660 659 #---------------------------------------------------------------------------
661 660
662 661 class CompileCSS(Command):
663 662 """Recompile Notebook CSS
664 663
665 664 Regenerate the compiled CSS from LESS sources.
666 665
667 666 Requires various dev dependencies, such as fabric and lessc.
668 667 """
669 668 description = "Recompile Notebook CSS"
670 669 user_options = []
671 670
672 671 def initialize_options(self):
673 672 pass
674 673
675 674 def finalize_options(self):
676 675 pass
677 676
678 677 def run(self):
679 678 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
680 679
681 680 class JavascriptVersion(Command):
682 681 """write the javascript version to notebook javascript"""
683 682 description = "Write IPython version to javascript"
684 683 user_options = []
685 684
686 685 def initialize_options(self):
687 686 pass
688 687
689 688 def finalize_options(self):
690 689 pass
691 690
692 691 def run(self):
693 692 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
694 693 with open(nsfile) as f:
695 694 lines = f.readlines()
696 695 with open(nsfile, 'w') as f:
697 696 for line in lines:
698 697 if line.startswith("IPython.version"):
699 698 line = 'IPython.version = "{0}";\n'.format(version)
700 699 f.write(line)
701 700
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now