##// END OF EJS Templates
Merge pull request #8301 from minrk/rm-qtconsole...
Min RK -
r21231:79730a28 merge
parent child Browse files
Show More
@@ -1,38 +1,38
1 1 # http://travis-ci.org/#!/ipython/ipython
2 2 language: python
3 3 python:
4 4 - 3.4
5 5 - 2.7
6 6 sudo: false
7 7 env:
8 8 global:
9 9 - PATH=$TRAVIS_BUILD_DIR/pandoc:$PATH
10 10 matrix:
11 11 - GROUP=
12 12 - GROUP=js/base
13 13 - GROUP=js/notebook
14 14 - GROUP=js/services
15 15 - GROUP=js/tree
16 16 - GROUP=js/widgets
17 17 before_install:
18 18 - 'if [[ $GROUP != js* ]]; then wget https://7de4dfdec62155b49b44-d726a73613a1989d29b147f20996e7c1.ssl.cf2.rackcdn.com/pandoc-1.12.3-linux-debian-x86_64.zip && unzip pandoc-1.12.3-linux-debian-x86_64.zip; fi'
19 19 - 'if [[ $GROUP == js* ]]; then wget https://7de4dfdec62155b49b44-d726a73613a1989d29b147f20996e7c1.ssl.cf2.rackcdn.com/mathjax.zip; fi'
20 20 - 'if [[ $GROUP == js* ]]; then npm install -g casperjs; fi'
21 21 - git clone --quiet --depth 1 https://github.com/minrk/travis-wheels travis-wheels
22 22 - 'if [[ $GROUP != js* ]]; then COVERAGE="--coverage xml"; fi'
23 23 install:
24 - pip install -f travis-wheels/wheelhouse -r requirements.txt -e file://$PWD#egg=ipython[all] coveralls
24 - pip install -f travis-wheels/wheelhouse -r requirements.txt -e file://$PWD#egg=ipython[test,notebook] coveralls
25 25 before_script:
26 26 - 'if [[ $GROUP == js* ]]; then python -m IPython.external.mathjax mathjax.zip; fi'
27 27 script:
28 28 - cd /tmp && iptest $GROUP $COVERAGE && cd -
29 29
30 30 matrix:
31 31 include:
32 32 - python: 3.3
33 33 env: GROUP=
34 34
35 35 after_success:
36 36 - cp /tmp/ipy_coverage.xml ./
37 37 - cp /tmp/.coverage ./
38 38 - coveralls
@@ -1,494 +1,490
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 """
16 16
17 17 # Copyright (c) IPython Development Team.
18 18 # Distributed under the terms of the Modified BSD License.
19 19
20 20 from __future__ import print_function
21 21
22 22 import glob
23 23 from io import BytesIO
24 24 import os
25 25 import os.path as path
26 26 import sys
27 27 from threading import Thread, Lock, Event
28 28 import warnings
29 29
30 30 import nose.plugins.builtin
31 31 from nose.plugins.xunit import Xunit
32 32 from nose import SkipTest
33 33 from nose.core import TestProgram
34 34 from nose.plugins import Plugin
35 35 from nose.util import safe_str
36 36
37 37 from IPython.utils.process import is_cmd_found
38 38 from IPython.utils.py3compat import bytes_to_str
39 39 from IPython.utils.importstring import import_item
40 40 from IPython.testing.plugin.ipdoctest import IPythonDoctest
41 41 from IPython.external.decorators import KnownFailure, knownfailureif
42 42
43 43 pjoin = path.join
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Warnings control
47 47 #-----------------------------------------------------------------------------
48 48
49 49 # Twisted generates annoying warnings with Python 2.6, as will do other code
50 50 # that imports 'sets' as of today
51 51 warnings.filterwarnings('ignore', 'the sets module is deprecated',
52 52 DeprecationWarning )
53 53
54 54 # This one also comes from Twisted
55 55 warnings.filterwarnings('ignore', 'the sha module is deprecated',
56 56 DeprecationWarning)
57 57
58 58 # Wx on Fedora11 spits these out
59 59 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
60 60 UserWarning)
61 61
62 62 # ------------------------------------------------------------------------------
63 63 # Monkeypatch Xunit to count known failures as skipped.
64 64 # ------------------------------------------------------------------------------
65 65 def monkeypatch_xunit():
66 66 try:
67 67 knownfailureif(True)(lambda: None)()
68 68 except Exception as e:
69 69 KnownFailureTest = type(e)
70 70
71 71 def addError(self, test, err, capt=None):
72 72 if issubclass(err[0], KnownFailureTest):
73 73 err = (SkipTest,) + err[1:]
74 74 return self.orig_addError(test, err, capt)
75 75
76 76 Xunit.orig_addError = Xunit.addError
77 77 Xunit.addError = addError
78 78
79 79 #-----------------------------------------------------------------------------
80 80 # Check which dependencies are installed and greater than minimum version.
81 81 #-----------------------------------------------------------------------------
82 82 def extract_version(mod):
83 83 return mod.__version__
84 84
85 85 def test_for(item, min_version=None, callback=extract_version):
86 86 """Test to see if item is importable, and optionally check against a minimum
87 87 version.
88 88
89 89 If min_version is given, the default behavior is to check against the
90 90 `__version__` attribute of the item, but specifying `callback` allows you to
91 91 extract the value you are interested in. e.g::
92 92
93 93 In [1]: import sys
94 94
95 95 In [2]: from IPython.testing.iptest import test_for
96 96
97 97 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
98 98 Out[3]: True
99 99
100 100 """
101 101 try:
102 102 check = import_item(item)
103 103 except (ImportError, RuntimeError):
104 104 # GTK reports Runtime error if it can't be initialized even if it's
105 105 # importable.
106 106 return False
107 107 else:
108 108 if min_version:
109 109 if callback:
110 110 # extra processing step to get version to compare
111 111 check = callback(check)
112 112
113 113 return check >= min_version
114 114 else:
115 115 return True
116 116
117 117 # Global dict where we can store information on what we have and what we don't
118 118 # have available at test run time
119 119 have = {}
120 120
121 121 have['curses'] = test_for('_curses')
122 122 have['matplotlib'] = test_for('matplotlib')
123 123 have['numpy'] = test_for('numpy')
124 124 have['pexpect'] = test_for('pexpect')
125 125 have['pymongo'] = test_for('pymongo')
126 126 have['pygments'] = test_for('pygments')
127 have['qt'] = test_for('IPython.external.qt')
128 127 have['sqlite3'] = test_for('sqlite3')
129 128 have['tornado'] = test_for('tornado.version_info', (4,0), callback=None)
130 129 have['jinja2'] = test_for('jinja2')
131 130 have['mistune'] = test_for('mistune')
132 131 have['requests'] = test_for('requests')
133 132 have['sphinx'] = test_for('sphinx')
134 133 have['jsonschema'] = test_for('jsonschema')
135 134 have['terminado'] = test_for('terminado')
136 135 have['casperjs'] = is_cmd_found('casperjs')
137 136 have['phantomjs'] = is_cmd_found('phantomjs')
138 137 have['slimerjs'] = is_cmd_found('slimerjs')
139 138
140 139 min_zmq = (13,)
141 140
142 141 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
143 142
144 143 #-----------------------------------------------------------------------------
145 144 # Test suite definitions
146 145 #-----------------------------------------------------------------------------
147 146
148 147 test_group_names = ['core',
149 148 'extensions', 'lib', 'terminal', 'testing', 'utils',
150 'qt', 'html', 'nbconvert'
149 'html', 'nbconvert'
151 150 ]
152 151
153 152 class TestSection(object):
154 153 def __init__(self, name, includes):
155 154 self.name = name
156 155 self.includes = includes
157 156 self.excludes = []
158 157 self.dependencies = []
159 158 self.enabled = True
160 159
161 160 def exclude(self, module):
162 161 if not module.startswith('IPython'):
163 162 module = self.includes[0] + "." + module
164 163 self.excludes.append(module.replace('.', os.sep))
165 164
166 165 def requires(self, *packages):
167 166 self.dependencies.extend(packages)
168 167
169 168 @property
170 169 def will_run(self):
171 170 return self.enabled and all(have[p] for p in self.dependencies)
172 171
173 172 shims = {
174 173 'html': 'jupyter_notebook',
175 174 }
176 175
177 176 # Name -> (include, exclude, dependencies_met)
178 177 test_sections = {n:TestSection(n, [shims.get(n, 'IPython.%s' % n)]) for n in test_group_names}
179 178
180 179
181 180 # Exclusions and dependencies
182 181 # ---------------------------
183 182
184 183 # core:
185 184 sec = test_sections['core']
186 185 if not have['sqlite3']:
187 186 sec.exclude('tests.test_history')
188 187 sec.exclude('history')
189 188 if not have['matplotlib']:
190 189 sec.exclude('pylabtools'),
191 190 sec.exclude('tests.test_pylabtools')
192 191
193 192 # lib:
194 193 sec = test_sections['lib']
195 194 if not have['zmq']:
196 195 sec.exclude('kernel')
197 196 # We do this unconditionally, so that the test suite doesn't import
198 197 # gtk, changing the default encoding and masking some unicode bugs.
199 198 sec.exclude('inputhookgtk')
200 199 # We also do this unconditionally, because wx can interfere with Unix signals.
201 200 # There are currently no tests for it anyway.
202 201 sec.exclude('inputhookwx')
203 202 # Testing inputhook will need a lot of thought, to figure out
204 203 # how to have tests that don't lock up with the gui event
205 204 # loops in the picture
206 205 sec.exclude('inputhook')
207 206
208 207 # testing:
209 208 sec = test_sections['testing']
210 209 # These have to be skipped on win32 because they use echo, rm, cd, etc.
211 210 # See ticket https://github.com/ipython/ipython/issues/87
212 211 if sys.platform == 'win32':
213 212 sec.exclude('plugin.test_exampleip')
214 213 sec.exclude('plugin.dtexample')
215 214
216 215 # don't run jupyter_console tests found via shim
217 216 test_sections['terminal'].exclude('console')
218 217
219 218 # extensions:
220 219 sec = test_sections['extensions']
221 220 # This is deprecated in favour of rpy2
222 221 sec.exclude('rmagic')
223 222 # autoreload does some strange stuff, so move it to its own test section
224 223 sec.exclude('autoreload')
225 224 sec.exclude('tests.test_autoreload')
226 225 test_sections['autoreload'] = TestSection('autoreload',
227 226 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
228 227 test_group_names.append('autoreload')
229 228
230 # qt:
231 test_sections['qt'].requires('zmq', 'qt', 'pygments')
232
233 229 # html:
234 230 sec = test_sections['html']
235 231 sec.requires('zmq', 'tornado', 'requests', 'sqlite3', 'jsonschema')
236 232 # The notebook 'static' directory contains JS, css and other
237 233 # files for web serving. Occasionally projects may put a .py
238 234 # file in there (MathJax ships a conf.py), so we might as
239 235 # well play it safe and skip the whole thing.
240 236 sec.exclude('static')
241 237 sec.exclude('tasks')
242 238 if not have['jinja2']:
243 239 sec.exclude('notebookapp')
244 240 if not have['pygments'] or not have['jinja2']:
245 241 sec.exclude('nbconvert')
246 242 if not have['terminado']:
247 243 sec.exclude('terminal')
248 244
249 245 # nbconvert:
250 246 sec = test_sections['nbconvert']
251 247 sec.requires('pygments', 'jinja2', 'jsonschema', 'mistune')
252 248 # Exclude nbconvert directories containing config files used to test.
253 249 # Executing the config files with iptest would cause an exception.
254 250 sec.exclude('tests.files')
255 251 sec.exclude('exporters.tests.files')
256 252 if not have['tornado']:
257 253 sec.exclude('nbconvert.post_processors.serve')
258 254 sec.exclude('nbconvert.post_processors.tests.test_serve')
259 255
260 256
261 257 #-----------------------------------------------------------------------------
262 258 # Functions and classes
263 259 #-----------------------------------------------------------------------------
264 260
265 261 def check_exclusions_exist():
266 262 from IPython.utils.path import get_ipython_package_dir
267 263 from IPython.utils.warn import warn
268 264 parent = os.path.dirname(get_ipython_package_dir())
269 265 for sec in test_sections:
270 266 for pattern in sec.exclusions:
271 267 fullpath = pjoin(parent, pattern)
272 268 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
273 269 warn("Excluding nonexistent file: %r" % pattern)
274 270
275 271
276 272 class ExclusionPlugin(Plugin):
277 273 """A nose plugin to effect our exclusions of files and directories.
278 274 """
279 275 name = 'exclusions'
280 276 score = 3000 # Should come before any other plugins
281 277
282 278 def __init__(self, exclude_patterns=None):
283 279 """
284 280 Parameters
285 281 ----------
286 282
287 283 exclude_patterns : sequence of strings, optional
288 284 Filenames containing these patterns (as raw strings, not as regular
289 285 expressions) are excluded from the tests.
290 286 """
291 287 self.exclude_patterns = exclude_patterns or []
292 288 super(ExclusionPlugin, self).__init__()
293 289
294 290 def options(self, parser, env=os.environ):
295 291 Plugin.options(self, parser, env)
296 292
297 293 def configure(self, options, config):
298 294 Plugin.configure(self, options, config)
299 295 # Override nose trying to disable plugin.
300 296 self.enabled = True
301 297
302 298 def wantFile(self, filename):
303 299 """Return whether the given filename should be scanned for tests.
304 300 """
305 301 if any(pat in filename for pat in self.exclude_patterns):
306 302 return False
307 303 return None
308 304
309 305 def wantDirectory(self, directory):
310 306 """Return whether the given directory should be scanned for tests.
311 307 """
312 308 if any(pat in directory for pat in self.exclude_patterns):
313 309 return False
314 310 return None
315 311
316 312
317 313 class StreamCapturer(Thread):
318 314 daemon = True # Don't hang if main thread crashes
319 315 started = False
320 316 def __init__(self, echo=False):
321 317 super(StreamCapturer, self).__init__()
322 318 self.echo = echo
323 319 self.streams = []
324 320 self.buffer = BytesIO()
325 321 self.readfd, self.writefd = os.pipe()
326 322 self.buffer_lock = Lock()
327 323 self.stop = Event()
328 324
329 325 def run(self):
330 326 self.started = True
331 327
332 328 while not self.stop.is_set():
333 329 chunk = os.read(self.readfd, 1024)
334 330
335 331 with self.buffer_lock:
336 332 self.buffer.write(chunk)
337 333 if self.echo:
338 334 sys.stdout.write(bytes_to_str(chunk))
339 335
340 336 os.close(self.readfd)
341 337 os.close(self.writefd)
342 338
343 339 def reset_buffer(self):
344 340 with self.buffer_lock:
345 341 self.buffer.truncate(0)
346 342 self.buffer.seek(0)
347 343
348 344 def get_buffer(self):
349 345 with self.buffer_lock:
350 346 return self.buffer.getvalue()
351 347
352 348 def ensure_started(self):
353 349 if not self.started:
354 350 self.start()
355 351
356 352 def halt(self):
357 353 """Safely stop the thread."""
358 354 if not self.started:
359 355 return
360 356
361 357 self.stop.set()
362 358 os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
363 359 self.join()
364 360
365 361 class SubprocessStreamCapturePlugin(Plugin):
366 362 name='subprocstreams'
367 363 def __init__(self):
368 364 Plugin.__init__(self)
369 365 self.stream_capturer = StreamCapturer()
370 366 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
371 367 # This is ugly, but distant parts of the test machinery need to be able
372 368 # to redirect streams, so we make the object globally accessible.
373 369 nose.iptest_stdstreams_fileno = self.get_write_fileno
374 370
375 371 def get_write_fileno(self):
376 372 if self.destination == 'capture':
377 373 self.stream_capturer.ensure_started()
378 374 return self.stream_capturer.writefd
379 375 elif self.destination == 'discard':
380 376 return os.open(os.devnull, os.O_WRONLY)
381 377 else:
382 378 return sys.__stdout__.fileno()
383 379
384 380 def configure(self, options, config):
385 381 Plugin.configure(self, options, config)
386 382 # Override nose trying to disable plugin.
387 383 if self.destination == 'capture':
388 384 self.enabled = True
389 385
390 386 def startTest(self, test):
391 387 # Reset log capture
392 388 self.stream_capturer.reset_buffer()
393 389
394 390 def formatFailure(self, test, err):
395 391 # Show output
396 392 ec, ev, tb = err
397 393 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
398 394 if captured.strip():
399 395 ev = safe_str(ev)
400 396 out = [ev, '>> begin captured subprocess output <<',
401 397 captured,
402 398 '>> end captured subprocess output <<']
403 399 return ec, '\n'.join(out), tb
404 400
405 401 return err
406 402
407 403 formatError = formatFailure
408 404
409 405 def finalize(self, result):
410 406 self.stream_capturer.halt()
411 407
412 408
413 409 def run_iptest():
414 410 """Run the IPython test suite using nose.
415 411
416 412 This function is called when this script is **not** called with the form
417 413 `iptest all`. It simply calls nose with appropriate command line flags
418 414 and accepts all of the standard nose arguments.
419 415 """
420 416 # Apply our monkeypatch to Xunit
421 417 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
422 418 monkeypatch_xunit()
423 419
424 420 warnings.filterwarnings('ignore',
425 421 'This will be removed soon. Use IPython.testing.util instead')
426 422
427 423 arg1 = sys.argv[1]
428 424 if arg1 in test_sections:
429 425 section = test_sections[arg1]
430 426 sys.argv[1:2] = section.includes
431 427 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
432 428 section = test_sections[arg1[8:]]
433 429 sys.argv[1:2] = section.includes
434 430 else:
435 431 section = TestSection(arg1, includes=[arg1])
436 432
437 433
438 434 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
439 435 # We add --exe because of setuptools' imbecility (it
440 436 # blindly does chmod +x on ALL files). Nose does the
441 437 # right thing and it tries to avoid executables,
442 438 # setuptools unfortunately forces our hand here. This
443 439 # has been discussed on the distutils list and the
444 440 # setuptools devs refuse to fix this problem!
445 441 '--exe',
446 442 ]
447 443 if '-a' not in argv and '-A' not in argv:
448 444 argv = argv + ['-a', '!crash']
449 445
450 446 if nose.__version__ >= '0.11':
451 447 # I don't fully understand why we need this one, but depending on what
452 448 # directory the test suite is run from, if we don't give it, 0 tests
453 449 # get run. Specifically, if the test suite is run from the source dir
454 450 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
455 451 # even if the same call done in this directory works fine). It appears
456 452 # that if the requested package is in the current dir, nose bails early
457 453 # by default. Since it's otherwise harmless, leave it in by default
458 454 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
459 455 argv.append('--traverse-namespace')
460 456
461 457 plugins = [ ExclusionPlugin(section.excludes), KnownFailure(),
462 458 SubprocessStreamCapturePlugin() ]
463 459
464 460 # we still have some vestigial doctests in core
465 461 if (section.name.startswith(('core', 'IPython.core'))):
466 462 plugins.append(IPythonDoctest())
467 463 argv.extend([
468 464 '--with-ipdoctest',
469 465 '--ipdoctest-tests',
470 466 '--ipdoctest-extension=txt',
471 467 ])
472 468
473 469
474 470 # Use working directory set by parent process (see iptestcontroller)
475 471 if 'IPTEST_WORKING_DIR' in os.environ:
476 472 os.chdir(os.environ['IPTEST_WORKING_DIR'])
477 473
478 474 # We need a global ipython running in this process, but the special
479 475 # in-process group spawns its own IPython kernels, so for *that* group we
480 476 # must avoid also opening the global one (otherwise there's a conflict of
481 477 # singletons). Ultimately the solution to this problem is to refactor our
482 478 # assumptions about what needs to be a singleton and what doesn't (app
483 479 # objects should, individual shells shouldn't). But for now, this
484 480 # workaround allows the test suite for the inprocess module to complete.
485 481 if 'kernel.inprocess' not in section.name:
486 482 from IPython.testing import globalipapp
487 483 globalipapp.start_ipython()
488 484
489 485 # Now nose can run
490 486 TestProgram(argv=argv, addplugins=plugins)
491 487
492 488 if __name__ == '__main__':
493 489 run_iptest()
494 490
@@ -1,38 +1,36
1 1 include README.rst
2 2 include COPYING.rst
3 3 include setupbase.py
4 4 include setupegg.py
5 5
6 6 graft setupext
7 7
8 8 graft scripts
9 9
10 10 # Load main dir but exclude things we don't want in the distro
11 11 graft IPython
12 prune IPython/html/static/mathjax
13 12
14 13 # Include some specific files and data resources we need
15 14 include IPython/.git_commit_info.ini
16 include IPython/qt/console/resources/icon/IPythonConsole.svg
17 15
18 16 # Documentation
19 17 graft docs
20 18 exclude docs/\#*
21 19 exclude docs/man/*.1.gz
22 20
23 21 # Examples
24 22 graft examples
25 23
26 24 # docs subdirs we want to skip
27 25 prune docs/build
28 26 prune docs/gh-pages
29 27 prune docs/dist
30 28
31 29 # Patterns to exclude from any directory
32 30 global-exclude *~
33 31 global-exclude *.flc
34 32 global-exclude *.pyc
35 33 global-exclude *.pyo
36 34 global-exclude .dircopy.log
37 35 global-exclude .git
38 36 global-exclude .ipynb_checkpoints
@@ -1,10 +1,9
1 1 -e git+https://github.com/ipython/ipython_genutils.git#egg=ipython_genutils
2 2 -e git+https://github.com/ipython/traitlets.git#egg=traitlets
3 3 # Below here aren't actually needed by IPython.
4 4 # Only while the split is partial
5 5 # and the IPython repo is still running Jupyter tests
6 6 -e git+https://github.com/jupyter/jupyter_core.git#egg=jupyter_core
7 7 -e git+https://github.com/jupyter/jupyter_nbformat.git#egg=jupyter_nbformat
8 8 -e git+https://github.com/jupyter/jupyter_client.git#egg=jupyter_client
9 9 -e git+https://github.com/ipython/ipython_kernel.git#egg=ipython_kernel
10 -e git+https://github.com/ipython/ipython_parallel.git#egg=ipython_parallel
@@ -1,140 +1,138
1 1 #!python
2 2 """Distutils post installation script for Windows.
3 3
4 4 http://docs.python.org/2/distutils/builtdist.html#the-postinstallation-script
5 5
6 6 """
7 7
8 8 from __future__ import print_function
9 9
10 10 import os
11 11 import sys
12 12 import shutil
13 13
14 14 try:
15 15 import setuptools
16 16 have_setuptools = True
17 17 except ImportError:
18 18 have_setuptools = False
19 19
20 20
21 21 pjoin = os.path.join
22 22
23 23 # suffix for start menu folder names
24 24 pyver = "(Py%i.%i %i bit)" % (sys.version_info[0], sys.version_info[1],
25 25 (32, 64)[sys.maxsize > 2**32])
26 26
27 27
28 28 def mkshortcut(target, description, linkdir, arguments="", iconpath='',
29 29 workdir="%HOMEDRIVE%%HOMEPATH%", iconindex=0):
30 30 """Make a shortcut if it doesn't exist and register its creation."""
31 31 filename = pjoin(linkdir, description + '.lnk')
32 32 description = "%s %s" % (description, pyver)
33 33 create_shortcut(target, description, filename, arguments, workdir,
34 34 iconpath, iconindex)
35 35 file_created(filename)
36 36
37 37
38 38 def arguments(scriptsdir, script, scriptargs=''):
39 39 """Return command line arguments to be passed to the python executable."""
40 40 cmdbase = suffix(pjoin(scriptsdir, script))
41 41 if have_setuptools:
42 42 cmdbase += '-script.py'
43 43 return '"%s" %s' % (cmdbase, scriptargs)
44 44
45 45
46 46 def suffix(s):
47 47 """Add '3' suffix to programs for Python 3."""
48 48 if sys.version_info[0] == 3:
49 49 s = s + '3'
50 50 return s
51 51
52 52
53 53 def install():
54 54 """Routine to be run by the win32 installer with the -install switch."""
55 55 # Get some system constants
56 56 python = pjoin(sys.prefix, 'python.exe')
57 57 pythonw = pjoin(sys.prefix, 'pythonw.exe')
58 58
59 59 if not have_setuptools:
60 60 # This currently doesn't work without setuptools,
61 61 # so don't bother making broken links
62 62 print("Setuptools is required to"
63 63 " create Start Menu items.", file=sys.stderr)
64 64 print("Re-run this installer after installing"
65 65 " Setuptools to get Start Menu items.", file=sys.stderr)
66 66 return
67 67
68 68 # Lookup path to common startmenu ...
69 69 ip_start_menu = pjoin(get_special_folder_path('CSIDL_COMMON_PROGRAMS'),
70 70 'IPython %s' % pyver)
71 71
72 72 # Create IPython entry ...
73 73 if not os.path.isdir(ip_start_menu):
74 74 os.mkdir(ip_start_menu)
75 75 directory_created(ip_start_menu)
76 76
77 77 # Create .py and .bat files to make things available from
78 78 # the Windows command line. Thanks to the Twisted project
79 79 # for this logic!
80 80 programs = [
81 81 'ipython',
82 82 'iptest',
83 83 ]
84 84 programs = [suffix(p) for p in programs]
85 85 scripts = pjoin(sys.prefix, 'scripts')
86 86 if not have_setuptools:
87 87 # only create .bat files if we don't have setuptools
88 88 for program in programs:
89 89 raw = pjoin(scripts, program)
90 90 bat = raw + '.bat'
91 91 py = raw + '.py'
92 92 # Create .py versions of the scripts
93 93 shutil.copy(raw, py)
94 94 # Create .bat files for each of the scripts
95 95 bat_file = file(bat, 'w')
96 96 bat_file.write("@%s %s %%*" % (python, py))
97 97 bat_file.close()
98 98
99 99 # Create Start Menu shortcuts
100 100 iconpath = pjoin(scripts, 'ipython.ico')
101 101 mkshortcut(python, 'IPython', ip_start_menu,
102 102 arguments(scripts, 'ipython'), iconpath)
103 103 mkshortcut(python, 'IPython (pylab mode)', ip_start_menu,
104 104 arguments(scripts, 'ipython', '--pylab'), iconpath)
105 mkshortcut(pythonw, 'IPython Qt Console', ip_start_menu,
106 arguments(scripts, 'ipython', 'qtconsole'), iconpath)
107 105
108 106 iconpath = pjoin(scripts, 'ipython_nb.ico')
109 107 mkshortcut(python, 'IPython Notebook', ip_start_menu,
110 108 arguments(scripts, 'ipython', 'notebook'), iconpath)
111 109
112 110 mkshortcut(pythonw, 'IPython Documentation', ip_start_menu,
113 111 '-m webbrowser -t "http://ipython.org/documentation.html',
114 112 iconpath='url.dll')
115 113
116 114 # Disable pysh Start item until the profile restores functionality
117 115 # Most of this code is in IPython/deathrow, and needs to be updated
118 116 # to 0.11 APIs
119 117 #mkshortcut(python, 'IPython%s (command prompt mode)', ip_start_menu,
120 118 # arguments(scripts, 'ipython', 'profile=pysh --init'))
121 119
122 120
123 121 def remove():
124 122 """Routine to be run by the win32 installer with the -remove switch."""
125 123 pass
126 124
127 125
128 126 # main()
129 127 if len(sys.argv) > 1:
130 128 if sys.argv[1] == '-install':
131 129 try:
132 130 install()
133 131 except OSError:
134 132 print("Failed to create Start Menu items, try running the"
135 133 " installer as administrator.", file=sys.stderr)
136 134 elif sys.argv[1] == '-remove':
137 135 remove()
138 136 else:
139 137 print("Script was called with option %s" % sys.argv[1],
140 138 file=sys.stderr)
@@ -1,342 +1,344
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 5 Under Posix environments it works like a typical setup.py script.
6 6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (c) 2008-2011, IPython Development Team.
11 11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.rst, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Minimal Python version sanity check
22 22 #-----------------------------------------------------------------------------
23 23 from __future__ import print_function
24 24
25 25 import sys
26 26
27 27 # This check is also made in IPython/__init__, don't forget to update both when
28 28 # changing Python version requirements.
29 29 v = sys.version_info
30 30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
31 31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
32 32 print(error, file=sys.stderr)
33 33 sys.exit(1)
34 34
35 35 PY3 = (sys.version_info[0] >= 3)
36 36
37 37 # At least we're on the python version we need, move on.
38 38
39 39 #-------------------------------------------------------------------------------
40 40 # Imports
41 41 #-------------------------------------------------------------------------------
42 42
43 43 # Stdlib imports
44 44 import os
45 45 import shutil
46 46
47 47 from glob import glob
48 48
49 49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 50 # update it when the contents of directories change.
51 51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52 52
53 53 from distutils.core import setup
54 54
55 55 # Our own imports
56 56 from setupbase import target_update
57 57
58 58 from setupbase import (
59 59 setup_args,
60 60 find_packages,
61 61 find_package_data,
62 62 check_package_data_first,
63 63 find_entry_points,
64 64 build_scripts_entrypt,
65 65 find_data_files,
66 66 check_for_readline,
67 67 git_prebuild,
68 68 check_submodule_status,
69 69 update_submodules,
70 70 require_submodules,
71 71 UpdateSubmodules,
72 72 get_bdist_wheel,
73 73 CompileCSS,
74 74 JavascriptVersion,
75 75 css_js_prerelease,
76 76 install_symlinked,
77 77 install_lib_symlink,
78 78 install_scripts_for_symlink,
79 79 unsymlink,
80 80 )
81 81
82 82 isfile = os.path.isfile
83 83 pjoin = os.path.join
84 84
85 85 #-------------------------------------------------------------------------------
86 86 # Handle OS specific things
87 87 #-------------------------------------------------------------------------------
88 88
89 89 if os.name in ('nt','dos'):
90 90 os_name = 'windows'
91 91 else:
92 92 os_name = os.name
93 93
94 94 # Under Windows, 'sdist' has not been supported. Now that the docs build with
95 95 # Sphinx it might work, but let's not turn it on until someone confirms that it
96 96 # actually works.
97 97 if os_name == 'windows' and 'sdist' in sys.argv:
98 98 print('The sdist command is not available under Windows. Exiting.')
99 99 sys.exit(1)
100 100
101 101 #-------------------------------------------------------------------------------
102 102 # Make sure we aren't trying to run without submodules
103 103 #-------------------------------------------------------------------------------
104 104 here = os.path.abspath(os.path.dirname(__file__))
105 105
106 106 def require_clean_submodules():
107 107 """Check on git submodules before distutils can do anything
108 108
109 109 Since distutils cannot be trusted to update the tree
110 110 after everything has been set in motion,
111 111 this is not a distutils command.
112 112 """
113 113 # PACKAGERS: Add a return here to skip checks for git submodules
114 114
115 115 # don't do anything if nothing is actually supposed to happen
116 116 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
117 117 if do_nothing in sys.argv:
118 118 return
119 119
120 120 status = check_submodule_status(here)
121 121
122 122 if status == "missing":
123 123 print("checking out submodules for the first time")
124 124 update_submodules(here)
125 125 elif status == "unclean":
126 126 print('\n'.join([
127 127 "Cannot build / install IPython with unclean submodules",
128 128 "Please update submodules with",
129 129 " python setup.py submodule",
130 130 "or",
131 131 " git submodule update",
132 132 "or commit any submodule changes you have made."
133 133 ]))
134 134 sys.exit(1)
135 135
136 136 require_clean_submodules()
137 137
138 138 #-------------------------------------------------------------------------------
139 139 # Things related to the IPython documentation
140 140 #-------------------------------------------------------------------------------
141 141
142 142 # update the manuals when building a source dist
143 143 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
144 144
145 145 # List of things to be updated. Each entry is a triplet of args for
146 146 # target_update()
147 147 to_update = [
148 148 ('docs/man/ipython.1.gz',
149 149 ['docs/man/ipython.1'],
150 150 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
151 151 ]
152 152
153 153
154 154 [ target_update(*t) for t in to_update ]
155 155
156 156 #---------------------------------------------------------------------------
157 157 # Find all the packages, package data, and data_files
158 158 #---------------------------------------------------------------------------
159 159
160 160 packages = find_packages()
161 161 package_data = find_package_data()
162 162
163 163 data_files = find_data_files()
164 164
165 165 setup_args['packages'] = packages
166 166 setup_args['package_data'] = package_data
167 167 setup_args['data_files'] = data_files
168 168
169 169 #---------------------------------------------------------------------------
170 170 # custom distutils commands
171 171 #---------------------------------------------------------------------------
172 172 # imports here, so they are after setuptools import if there was one
173 173 from distutils.command.sdist import sdist
174 174 from distutils.command.upload import upload
175 175
176 176 class UploadWindowsInstallers(upload):
177 177
178 178 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
179 179 user_options = upload.user_options + [
180 180 ('files=', 'f', 'exe file (or glob) to upload')
181 181 ]
182 182 def initialize_options(self):
183 183 upload.initialize_options(self)
184 184 meta = self.distribution.metadata
185 185 base = '{name}-{version}'.format(
186 186 name=meta.get_name(),
187 187 version=meta.get_version()
188 188 )
189 189 self.files = os.path.join('dist', '%s.*.exe' % base)
190 190
191 191 def run(self):
192 192 for dist_file in glob(self.files):
193 193 self.upload_file('bdist_wininst', 'any', dist_file)
194 194
195 195 setup_args['cmdclass'] = {
196 196 'build_py': css_js_prerelease(
197 197 check_package_data_first(git_prebuild('IPython'))),
198 198 'sdist' : css_js_prerelease(git_prebuild('IPython', sdist)),
199 199 'upload_wininst' : UploadWindowsInstallers,
200 200 'submodule' : UpdateSubmodules,
201 201 'css' : CompileCSS,
202 202 'symlink': install_symlinked,
203 203 'install_lib_symlink': install_lib_symlink,
204 204 'install_scripts_sym': install_scripts_for_symlink,
205 205 'unsymlink': unsymlink,
206 206 'jsversion' : JavascriptVersion,
207 207 }
208 208
209 209 ### Temporarily disable install while it's broken during the big split
210 210 from textwrap import dedent
211 211 from distutils.command.install import install
212 212
213 213 class DisabledInstall(install):
214 214 def run(self):
215 215 msg = dedent("""
216 216 While we are in the midst of The Big Split,
217 217 IPython cannot be installed from master.
218 218 You can use `pip install -e .` for an editable install,
219 219 which still works.
220 220 """)
221 221 print(msg, file=sys.stderr)
222 222 raise SystemExit(1)
223 223
224 224 setup_args['cmdclass']['install'] = DisabledInstall
225 225
226 226
227 227 #---------------------------------------------------------------------------
228 228 # Handle scripts, dependencies, and setuptools specific things
229 229 #---------------------------------------------------------------------------
230 230
231 231 # For some commands, use setuptools. Note that we do NOT list install here!
232 232 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
233 233 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
234 234 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
235 235 'egg_info', 'easy_install', 'upload', 'install_egg_info',
236 236 ))
237 237
238 238 if len(needs_setuptools.intersection(sys.argv)) > 0:
239 239 import setuptools
240 240
241 241 # This dict is used for passing extra arguments that are setuptools
242 242 # specific to setup
243 243 setuptools_extra_args = {}
244 244
245 245 # setuptools requirements
246 246
247 247 pyzmq = 'pyzmq>=13'
248 248
249 249 extras_require = dict(
250 250 parallel = ['ipython_parallel'],
251 qtconsole = [pyzmq, 'pygments'],
251 qtconsole = ['jupyter_qtconsole'],
252 252 doc = ['Sphinx>=1.1', 'numpydoc'],
253 253 test = ['nose>=0.10.1', 'requests'],
254 254 terminal = [],
255 kernel = ['ipython_kernel'],
255 256 nbformat = ['jupyter_nbformat'],
256 257 notebook = ['tornado>=4.0', pyzmq, 'jinja2', 'pygments', 'mistune>=0.5'],
257 258 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
258 259 )
259 260
260 261 if not sys.platform.startswith('win'):
261 262 extras_require['notebook'].append('terminado>=0.3.3')
262 263
263 264 if sys.version_info < (3, 3):
264 265 extras_require['test'].append('mock')
265 266
266 extras_require['notebook'].extend(extras_require['nbformat'])
267 267 extras_require['nbconvert'].extend(extras_require['nbformat'])
268 extras_require['notebook'].extend(extras_require['kernel'])
269 extras_require['notebook'].extend(extras_require['nbconvert'])
268 270
269 271 install_requires = [
270 272 'decorator',
271 273 'pickleshare',
272 274 'simplegeneric>0.8',
273 275 'traitlets',
274 276 ]
275 277
276 278 # add platform-specific dependencies
277 279 if sys.platform == 'darwin':
278 280 install_requires.append('appnope')
279 281 if 'bdist_wheel' in sys.argv[1:] or not check_for_readline():
280 282 install_requires.append('gnureadline')
281 283
282 284 if sys.platform.startswith('win'):
283 285 extras_require['terminal'].append('pyreadline>=2.0')
284 286 else:
285 287 install_requires.append('pexpect')
286 288
287 289 everything = set()
288 290 for deps in extras_require.values():
289 291 everything.update(deps)
290 292 extras_require['all'] = everything
291 293
292 294 if 'setuptools' in sys.modules:
293 295 # setup.py develop should check for submodules
294 296 from setuptools.command.develop import develop
295 297 setup_args['cmdclass']['develop'] = require_submodules(develop)
296 298 setup_args['cmdclass']['bdist_wheel'] = css_js_prerelease(get_bdist_wheel())
297 299
298 300 setuptools_extra_args['zip_safe'] = False
299 301 setuptools_extra_args['entry_points'] = {
300 302 'console_scripts': find_entry_points(),
301 303 'pygments.lexers': [
302 304 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
303 305 'ipython = IPython.lib.lexers:IPythonLexer',
304 306 'ipython3 = IPython.lib.lexers:IPython3Lexer',
305 307 ],
306 308 }
307 309 setup_args['extras_require'] = extras_require
308 310 requires = setup_args['install_requires'] = install_requires
309 311
310 312 # Script to be run by the windows binary installer after the default setup
311 313 # routine, to add shortcuts and similar windows-only things. Windows
312 314 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
313 315 # doesn't find them.
314 316 if 'bdist_wininst' in sys.argv:
315 317 if len(sys.argv) > 2 and \
316 318 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
317 319 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
318 320 sys.exit(1)
319 321 setup_args['data_files'].append(
320 322 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
321 323 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
322 324 setup_args['options'] = {"bdist_wininst":
323 325 {"install_script":
324 326 "ipython_win_post_install.py"}}
325 327
326 328 else:
327 329 # scripts has to be a non-empty list, or install_scripts isn't called
328 330 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
329 331
330 332 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
331 333
332 334 #---------------------------------------------------------------------------
333 335 # Do the actual setup now
334 336 #---------------------------------------------------------------------------
335 337
336 338 setup_args.update(setuptools_extra_args)
337 339
338 340 def main():
339 341 setup(**setup_args)
340 342
341 343 if __name__ == '__main__':
342 344 main()
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
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
This diff has been collapsed as it changes many lines, (2167 lines changed) Show them Hide them
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (811 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (594 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (928 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (569 lines changed) Show them Hide them
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
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