##// END OF EJS Templates
Patch stdout in interactive shell...
Gergely Nagy -
Show More
@@ -1,537 +1,538 b''
1 1 """IPython terminal interface using prompt_toolkit"""
2 2
3 3 import os
4 4 import sys
5 5 import warnings
6 6 from warnings import warn
7 7
8 8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 9 from IPython.utils import io
10 10 from IPython.utils.py3compat import input, cast_unicode_py2
11 11 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 12 from IPython.utils.process import abbrev_cwd
13 13 from traitlets import (
14 14 Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union,
15 15 Any,
16 16 )
17 17
18 18 from prompt_toolkit.document import Document
19 19 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
20 20 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
21 21 from prompt_toolkit.history import InMemoryHistory
22 22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
23 23 from prompt_toolkit.interface import CommandLineInterface
24 24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 25 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 26 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
27 27
28 28 from pygments.styles import get_style_by_name, get_all_styles
29 29 from pygments.style import Style
30 30 from pygments.token import Token
31 31
32 32 from .debugger import TerminalPdb, Pdb
33 33 from .magics import TerminalMagics
34 34 from .pt_inputhooks import get_inputhook_name_and_func
35 35 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
36 36 from .ptutils import IPythonPTCompleter, IPythonPTLexer
37 37 from .shortcuts import register_ipython_shortcuts
38 38
39 39 DISPLAY_BANNER_DEPRECATED = object()
40 40
41 41
42 42 class _NoStyle(Style): pass
43 43
44 44
45 45
46 46 _style_overrides_light_bg = {
47 47 Token.Prompt: '#0000ff',
48 48 Token.PromptNum: '#0000ee bold',
49 49 Token.OutPrompt: '#cc0000',
50 50 Token.OutPromptNum: '#bb0000 bold',
51 51 }
52 52
53 53 _style_overrides_linux = {
54 54 Token.Prompt: '#00cc00',
55 55 Token.PromptNum: '#00bb00 bold',
56 56 Token.OutPrompt: '#cc0000',
57 57 Token.OutPromptNum: '#bb0000 bold',
58 58 }
59 59
60 60
61 61
62 62 def get_default_editor():
63 63 try:
64 64 return os.environ['EDITOR']
65 65 except KeyError:
66 66 pass
67 67 except UnicodeError:
68 68 warn("$EDITOR environment variable is not pure ASCII. Using platform "
69 69 "default editor.")
70 70
71 71 if os.name == 'posix':
72 72 return 'vi' # the only one guaranteed to be there!
73 73 else:
74 74 return 'notepad' # same in Windows!
75 75
76 76 # conservatively check for tty
77 77 # overridden streams can result in things like:
78 78 # - sys.stdin = None
79 79 # - no isatty method
80 80 for _name in ('stdin', 'stdout', 'stderr'):
81 81 _stream = getattr(sys, _name)
82 82 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
83 83 _is_tty = False
84 84 break
85 85 else:
86 86 _is_tty = True
87 87
88 88
89 89 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
90 90
91 91 class TerminalInteractiveShell(InteractiveShell):
92 92 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
93 93 'to reserve for the completion menu'
94 94 ).tag(config=True)
95 95
96 96 def _space_for_menu_changed(self, old, new):
97 97 self._update_layout()
98 98
99 99 pt_cli = None
100 100 debugger_history = None
101 101 _pt_app = None
102 102
103 103 simple_prompt = Bool(_use_simple_prompt,
104 104 help="""Use `raw_input` for the REPL, without completion and prompt colors.
105 105
106 106 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
107 107 IPython own testing machinery, and emacs inferior-shell integration through elpy.
108 108
109 109 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
110 110 environment variable is set, or the current terminal is not a tty."""
111 111 ).tag(config=True)
112 112
113 113 @property
114 114 def debugger_cls(self):
115 115 return Pdb if self.simple_prompt else TerminalPdb
116 116
117 117 confirm_exit = Bool(True,
118 118 help="""
119 119 Set to confirm when you try to exit IPython with an EOF (Control-D
120 120 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
121 121 you can force a direct exit without any confirmation.""",
122 122 ).tag(config=True)
123 123
124 124 editing_mode = Unicode('emacs',
125 125 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
126 126 ).tag(config=True)
127 127
128 128 mouse_support = Bool(False,
129 129 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
130 130 ).tag(config=True)
131 131
132 132 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
133 133 help="""The name or class of a Pygments style to use for syntax
134 134 highlighting: \n %s""" % ', '.join(get_all_styles())
135 135 ).tag(config=True)
136 136
137 137
138 138 @observe('highlighting_style')
139 139 @observe('colors')
140 140 def _highlighting_style_changed(self, change):
141 141 self.refresh_style()
142 142
143 143 def refresh_style(self):
144 144 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
145 145
146 146
147 147 highlighting_style_overrides = Dict(
148 148 help="Override highlighting format for specific tokens"
149 149 ).tag(config=True)
150 150
151 151 true_color = Bool(False,
152 152 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
153 153 "If your terminal supports true color, the following command "
154 154 "should print 'TRUECOLOR' in orange: "
155 155 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
156 156 ).tag(config=True)
157 157
158 158 editor = Unicode(get_default_editor(),
159 159 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
160 160 ).tag(config=True)
161 161
162 162 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
163 163
164 164 prompts = Instance(Prompts)
165 165
166 166 @default('prompts')
167 167 def _prompts_default(self):
168 168 return self.prompts_class(self)
169 169
170 170 @observe('prompts')
171 171 def _(self, change):
172 172 self._update_layout()
173 173
174 174 @default('displayhook_class')
175 175 def _displayhook_class_default(self):
176 176 return RichPromptDisplayHook
177 177
178 178 term_title = Bool(True,
179 179 help="Automatically set the terminal title"
180 180 ).tag(config=True)
181 181
182 182 term_title_format = Unicode("IPython: {cwd}",
183 183 help="Customize the terminal title format. This is a python format string. " +
184 184 "Available substitutions are: {cwd}."
185 185 ).tag(config=True)
186 186
187 187 display_completions = Enum(('column', 'multicolumn','readlinelike'),
188 188 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
189 189 "'readlinelike'. These options are for `prompt_toolkit`, see "
190 190 "`prompt_toolkit` documentation for more information."
191 191 ),
192 192 default_value='multicolumn').tag(config=True)
193 193
194 194 highlight_matching_brackets = Bool(True,
195 195 help="Highlight matching brackets.",
196 196 ).tag(config=True)
197 197
198 198 extra_open_editor_shortcuts = Bool(False,
199 199 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
200 200 "This is in addition to the F2 binding, which is always enabled."
201 201 ).tag(config=True)
202 202
203 203 handle_return = Any(None,
204 204 help="Provide an alternative handler to be called when the user presses "
205 205 "Return. This is an advanced option intended for debugging, which "
206 206 "may be changed or removed in later releases."
207 207 ).tag(config=True)
208 208
209 209 @observe('term_title')
210 210 def init_term_title(self, change=None):
211 211 # Enable or disable the terminal title.
212 212 if self.term_title:
213 213 toggle_set_term_title(True)
214 214 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
215 215 else:
216 216 toggle_set_term_title(False)
217 217
218 218 def init_display_formatter(self):
219 219 super(TerminalInteractiveShell, self).init_display_formatter()
220 220 # terminal only supports plain text
221 221 self.display_formatter.active_types = ['text/plain']
222 222 # disable `_ipython_display_`
223 223 self.display_formatter.ipython_display_formatter.enabled = False
224 224
225 225 def init_prompt_toolkit_cli(self):
226 226 if self.simple_prompt:
227 227 # Fall back to plain non-interactive output for tests.
228 228 # This is very limited, and only accepts a single line.
229 229 def prompt():
230 230 isp = self.input_splitter
231 231 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
232 232 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
233 233 while isp.push_accepts_more():
234 234 line = cast_unicode_py2(input(prompt_text))
235 235 isp.push(line)
236 236 prompt_text = prompt_continuation
237 237 return isp.source_reset()
238 238 self.prompt_for_code = prompt
239 239 return
240 240
241 241 # Set up keyboard shortcuts
242 242 kbmanager = KeyBindingManager.for_prompt(
243 243 enable_open_in_editor=self.extra_open_editor_shortcuts,
244 244 )
245 245 register_ipython_shortcuts(kbmanager.registry, self)
246 246
247 247 # Pre-populate history from IPython's history database
248 248 history = InMemoryHistory()
249 249 last_cell = u""
250 250 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
251 251 include_latest=True):
252 252 # Ignore blank lines and consecutive duplicates
253 253 cell = cell.rstrip()
254 254 if cell and (cell != last_cell):
255 255 history.append(cell)
256 256 last_cell = cell
257 257
258 258 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
259 259 self.style = DynamicStyle(lambda: self._style)
260 260
261 261 editing_mode = getattr(EditingMode, self.editing_mode.upper())
262 262
263 263 def patch_stdout(**kwargs):
264 264 return self.pt_cli.patch_stdout_context(**kwargs)
265 265
266 266 self._pt_app = create_prompt_application(
267 267 editing_mode=editing_mode,
268 268 key_bindings_registry=kbmanager.registry,
269 269 history=history,
270 270 completer=IPythonPTCompleter(shell=self,
271 271 patch_stdout=patch_stdout),
272 272 enable_history_search=True,
273 273 style=self.style,
274 274 mouse_support=self.mouse_support,
275 275 **self._layout_options()
276 276 )
277 277 self._eventloop = create_eventloop(self.inputhook)
278 278 self.pt_cli = CommandLineInterface(
279 279 self._pt_app, eventloop=self._eventloop,
280 280 output=create_output(true_color=self.true_color))
281 281
282 282 def _make_style_from_name_or_cls(self, name_or_cls):
283 283 """
284 284 Small wrapper that make an IPython compatible style from a style name
285 285
286 286 We need that to add style for prompt ... etc.
287 287 """
288 288 style_overrides = {}
289 289 if name_or_cls == 'legacy':
290 290 legacy = self.colors.lower()
291 291 if legacy == 'linux':
292 292 style_cls = get_style_by_name('monokai')
293 293 style_overrides = _style_overrides_linux
294 294 elif legacy == 'lightbg':
295 295 style_overrides = _style_overrides_light_bg
296 296 style_cls = get_style_by_name('pastie')
297 297 elif legacy == 'neutral':
298 298 # The default theme needs to be visible on both a dark background
299 299 # and a light background, because we can't tell what the terminal
300 300 # looks like. These tweaks to the default theme help with that.
301 301 style_cls = get_style_by_name('default')
302 302 style_overrides.update({
303 303 Token.Number: '#007700',
304 304 Token.Operator: 'noinherit',
305 305 Token.String: '#BB6622',
306 306 Token.Name.Function: '#2080D0',
307 307 Token.Name.Class: 'bold #2080D0',
308 308 Token.Name.Namespace: 'bold #2080D0',
309 309 Token.Prompt: '#009900',
310 310 Token.PromptNum: '#00ff00 bold',
311 311 Token.OutPrompt: '#990000',
312 312 Token.OutPromptNum: '#ff0000 bold',
313 313 })
314 314
315 315 # Hack: Due to limited color support on the Windows console
316 316 # the prompt colors will be wrong without this
317 317 if os.name == 'nt':
318 318 style_overrides.update({
319 319 Token.Prompt: '#ansidarkgreen',
320 320 Token.PromptNum: '#ansigreen bold',
321 321 Token.OutPrompt: '#ansidarkred',
322 322 Token.OutPromptNum: '#ansired bold',
323 323 })
324 324 elif legacy =='nocolor':
325 325 style_cls=_NoStyle
326 326 style_overrides = {}
327 327 else :
328 328 raise ValueError('Got unknown colors: ', legacy)
329 329 else :
330 330 if isinstance(name_or_cls, str):
331 331 style_cls = get_style_by_name(name_or_cls)
332 332 else:
333 333 style_cls = name_or_cls
334 334 style_overrides = {
335 335 Token.Prompt: '#009900',
336 336 Token.PromptNum: '#00ff00 bold',
337 337 Token.OutPrompt: '#990000',
338 338 Token.OutPromptNum: '#ff0000 bold',
339 339 }
340 340 style_overrides.update(self.highlighting_style_overrides)
341 341 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
342 342 style_dict=style_overrides)
343 343
344 344 return style
345 345
346 346 def _layout_options(self):
347 347 """
348 348 Return the current layout option for the current Terminal InteractiveShell
349 349 """
350 350 return {
351 351 'lexer':IPythonPTLexer(),
352 352 'reserve_space_for_menu':self.space_for_menu,
353 353 'get_prompt_tokens':self.prompts.in_prompt_tokens,
354 354 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
355 355 'multiline':True,
356 356 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
357 357
358 358 # Highlight matching brackets, but only when this setting is
359 359 # enabled, and only when the DEFAULT_BUFFER has the focus.
360 360 'extra_input_processors': [ConditionalProcessor(
361 361 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
362 362 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
363 363 Condition(lambda cli: self.highlight_matching_brackets))],
364 364 }
365 365
366 366 def _update_layout(self):
367 367 """
368 368 Ask for a re computation of the application layout, if for example ,
369 369 some configuration options have changed.
370 370 """
371 371 if self._pt_app:
372 372 self._pt_app.layout = create_prompt_layout(**self._layout_options())
373 373
374 374 def prompt_for_code(self):
375 document = self.pt_cli.run(
376 pre_run=self.pre_prompt, reset_current_buffer=True)
375 with self.pt_cli.patch_stdout_context(raw=True):
376 document = self.pt_cli.run(
377 pre_run=self.pre_prompt, reset_current_buffer=True)
377 378 return document.text
378 379
379 380 def enable_win_unicode_console(self):
380 381 if sys.version_info >= (3, 6):
381 382 # Since PEP 528, Python uses the unicode APIs for the Windows
382 383 # console by default, so WUC shouldn't be needed.
383 384 return
384 385
385 386 import win_unicode_console
386 387 win_unicode_console.enable()
387 388
388 389 def init_io(self):
389 390 if sys.platform not in {'win32', 'cli'}:
390 391 return
391 392
392 393 self.enable_win_unicode_console()
393 394
394 395 import colorama
395 396 colorama.init()
396 397
397 398 # For some reason we make these wrappers around stdout/stderr.
398 399 # For now, we need to reset them so all output gets coloured.
399 400 # https://github.com/ipython/ipython/issues/8669
400 401 # io.std* are deprecated, but don't show our own deprecation warnings
401 402 # during initialization of the deprecated API.
402 403 with warnings.catch_warnings():
403 404 warnings.simplefilter('ignore', DeprecationWarning)
404 405 io.stdout = io.IOStream(sys.stdout)
405 406 io.stderr = io.IOStream(sys.stderr)
406 407
407 408 def init_magics(self):
408 409 super(TerminalInteractiveShell, self).init_magics()
409 410 self.register_magics(TerminalMagics)
410 411
411 412 def init_alias(self):
412 413 # The parent class defines aliases that can be safely used with any
413 414 # frontend.
414 415 super(TerminalInteractiveShell, self).init_alias()
415 416
416 417 # Now define aliases that only make sense on the terminal, because they
417 418 # need direct access to the console in a way that we can't emulate in
418 419 # GUI or web frontend
419 420 if os.name == 'posix':
420 421 for cmd in ['clear', 'more', 'less', 'man']:
421 422 self.alias_manager.soft_define_alias(cmd, cmd)
422 423
423 424
424 425 def __init__(self, *args, **kwargs):
425 426 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
426 427 self.init_prompt_toolkit_cli()
427 428 self.init_term_title()
428 429 self.keep_running = True
429 430
430 431 self.debugger_history = InMemoryHistory()
431 432
432 433 def ask_exit(self):
433 434 self.keep_running = False
434 435
435 436 rl_next_input = None
436 437
437 438 def pre_prompt(self):
438 439 if self.rl_next_input:
439 440 # We can't set the buffer here, because it will be reset just after
440 441 # this. Adding a callable to pre_run_callables does what we need
441 442 # after the buffer is reset.
442 443 s = self.rl_next_input
443 444 def set_doc():
444 445 self.pt_cli.application.buffer.document = Document(s)
445 446 if hasattr(self.pt_cli, 'pre_run_callables'):
446 447 self.pt_cli.pre_run_callables.append(set_doc)
447 448 else:
448 449 # Older version of prompt_toolkit; it's OK to set the document
449 450 # directly here.
450 451 set_doc()
451 452 self.rl_next_input = None
452 453
453 454 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
454 455
455 456 if display_banner is not DISPLAY_BANNER_DEPRECATED:
456 457 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
457 458
458 459 self.keep_running = True
459 460 while self.keep_running:
460 461 print(self.separate_in, end='')
461 462
462 463 try:
463 464 code = self.prompt_for_code()
464 465 except EOFError:
465 466 if (not self.confirm_exit) \
466 467 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
467 468 self.ask_exit()
468 469
469 470 else:
470 471 if code:
471 472 self.run_cell(code, store_history=True)
472 473
473 474 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
474 475 # An extra layer of protection in case someone mashing Ctrl-C breaks
475 476 # out of our internal code.
476 477 if display_banner is not DISPLAY_BANNER_DEPRECATED:
477 478 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
478 479 while True:
479 480 try:
480 481 self.interact()
481 482 break
482 483 except KeyboardInterrupt as e:
483 484 print("\n%s escaped interact()\n" % type(e).__name__)
484 485 finally:
485 486 # An interrupt during the eventloop will mess up the
486 487 # internal state of the prompt_toolkit library.
487 488 # Stopping the eventloop fixes this, see
488 489 # https://github.com/ipython/ipython/pull/9867
489 490 if hasattr(self, '_eventloop'):
490 491 self._eventloop.stop()
491 492
492 493 _inputhook = None
493 494 def inputhook(self, context):
494 495 if self._inputhook is not None:
495 496 self._inputhook(context)
496 497
497 498 active_eventloop = None
498 499 def enable_gui(self, gui=None):
499 500 if gui:
500 501 self.active_eventloop, self._inputhook =\
501 502 get_inputhook_name_and_func(gui)
502 503 else:
503 504 self.active_eventloop = self._inputhook = None
504 505
505 506 # Run !system commands directly, not through pipes, so terminal programs
506 507 # work correctly.
507 508 system = InteractiveShell.system_raw
508 509
509 510 def auto_rewrite_input(self, cmd):
510 511 """Overridden from the parent class to use fancy rewriting prompt"""
511 512 if not self.show_rewritten_input:
512 513 return
513 514
514 515 tokens = self.prompts.rewrite_prompt_tokens()
515 516 if self.pt_cli:
516 517 self.pt_cli.print_tokens(tokens)
517 518 print(cmd)
518 519 else:
519 520 prompt = ''.join(s for t, s in tokens)
520 521 print(prompt, cmd, sep='')
521 522
522 523 _prompts_before = None
523 524 def switch_doctest_mode(self, mode):
524 525 """Switch prompts to classic for %doctest_mode"""
525 526 if mode:
526 527 self._prompts_before = self.prompts
527 528 self.prompts = ClassicPrompts(self)
528 529 elif self._prompts_before:
529 530 self.prompts = self._prompts_before
530 531 self._prompts_before = None
531 532 self._update_layout()
532 533
533 534
534 535 InteractiveShellABC.register(TerminalInteractiveShell)
535 536
536 537 if __name__ == '__main__':
537 538 TerminalInteractiveShell.instance().interact()
@@ -1,265 +1,265 b''
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 from __future__ import print_function
21 21
22 22 import os
23 23 import sys
24 24
25 25 # **Python version check**
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 if sys.version_info < (3, 3):
30 30 pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.'
31 31 try:
32 32 import pip
33 33 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
34 34 if pip_version < (9, 0, 1) :
35 35 pip_message = 'Your pip version is out of date, please install pip >= 9.0.1. '\
36 36 'pip {} detected.'.format(pip.__version__)
37 37 else:
38 38 # pip is new enough - it must be something else
39 39 pip_message = ''
40 40 except Exception:
41 41 pass
42 42
43 43
44 44 error = """
45 45 IPython 6.0+ does not support Python 2.6, 2.7, 3.0, 3.1, or 3.2.
46 46 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
47 47 Beginning with IPython 6.0, Python 3.3 and above is required.
48 48
49 49 See IPython `README.rst` file for more information:
50 50
51 51 https://github.com/ipython/ipython/blob/master/README.rst
52 52
53 53 Python {py} detected.
54 54 {pip}
55 55 """.format(py=sys.version_info, pip=pip_message )
56 56
57 57 print(error, file=sys.stderr)
58 58 sys.exit(1)
59 59
60 60 # At least we're on the python version we need, move on.
61 61
62 62 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
63 63 # update it when the contents of directories change.
64 64 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
65 65
66 66 from distutils.core import setup
67 67
68 68 # Our own imports
69 69 from setupbase import target_update
70 70
71 71 from setupbase import (
72 72 setup_args,
73 73 find_packages,
74 74 find_package_data,
75 75 check_package_data_first,
76 76 find_entry_points,
77 77 build_scripts_entrypt,
78 78 find_data_files,
79 79 git_prebuild,
80 80 install_symlinked,
81 81 install_lib_symlink,
82 82 install_scripts_for_symlink,
83 83 unsymlink,
84 84 )
85 85
86 86 isfile = os.path.isfile
87 87 pjoin = os.path.join
88 88
89 89 #-------------------------------------------------------------------------------
90 90 # Handle OS specific things
91 91 #-------------------------------------------------------------------------------
92 92
93 93 if os.name in ('nt','dos'):
94 94 os_name = 'windows'
95 95 else:
96 96 os_name = os.name
97 97
98 98 # Under Windows, 'sdist' has not been supported. Now that the docs build with
99 99 # Sphinx it might work, but let's not turn it on until someone confirms that it
100 100 # actually works.
101 101 if os_name == 'windows' and 'sdist' in sys.argv:
102 102 print('The sdist command is not available under Windows. Exiting.')
103 103 sys.exit(1)
104 104
105 105
106 106 #-------------------------------------------------------------------------------
107 107 # Things related to the IPython documentation
108 108 #-------------------------------------------------------------------------------
109 109
110 110 # update the manuals when building a source dist
111 111 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
112 112
113 113 # List of things to be updated. Each entry is a triplet of args for
114 114 # target_update()
115 115 to_update = [
116 116 ('docs/man/ipython.1.gz',
117 117 ['docs/man/ipython.1'],
118 118 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
119 119 ]
120 120
121 121
122 122 [ target_update(*t) for t in to_update ]
123 123
124 124 #---------------------------------------------------------------------------
125 125 # Find all the packages, package data, and data_files
126 126 #---------------------------------------------------------------------------
127 127
128 128 packages = find_packages()
129 129 package_data = find_package_data()
130 130
131 131 data_files = find_data_files()
132 132
133 133 setup_args['packages'] = packages
134 134 setup_args['package_data'] = package_data
135 135 setup_args['data_files'] = data_files
136 136
137 137 #---------------------------------------------------------------------------
138 138 # custom distutils commands
139 139 #---------------------------------------------------------------------------
140 140 # imports here, so they are after setuptools import if there was one
141 141 from distutils.command.sdist import sdist
142 142
143 143 setup_args['cmdclass'] = {
144 144 'build_py': \
145 145 check_package_data_first(git_prebuild('IPython')),
146 146 'sdist' : git_prebuild('IPython', sdist),
147 147 'symlink': install_symlinked,
148 148 'install_lib_symlink': install_lib_symlink,
149 149 'install_scripts_sym': install_scripts_for_symlink,
150 150 'unsymlink': unsymlink,
151 151 }
152 152
153 153
154 154 #---------------------------------------------------------------------------
155 155 # Handle scripts, dependencies, and setuptools specific things
156 156 #---------------------------------------------------------------------------
157 157
158 158 # For some commands, use setuptools. Note that we do NOT list install here!
159 159 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
160 160 needs_setuptools = {'develop', 'release', 'bdist_egg', 'bdist_rpm',
161 161 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
162 162 'egg_info', 'easy_install', 'upload', 'install_egg_info',
163 163 }
164 164
165 165 if len(needs_setuptools.intersection(sys.argv)) > 0:
166 166 import setuptools
167 167
168 168 # This dict is used for passing extra arguments that are setuptools
169 169 # specific to setup
170 170 setuptools_extra_args = {}
171 171
172 172 # setuptools requirements
173 173
174 174 extras_require = dict(
175 175 parallel = ['ipyparallel'],
176 176 qtconsole = ['qtconsole'],
177 177 doc = ['Sphinx>=1.3'],
178 178 test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel'],
179 179 terminal = [],
180 180 kernel = ['ipykernel'],
181 181 nbformat = ['nbformat'],
182 182 notebook = ['notebook', 'ipywidgets'],
183 183 nbconvert = ['nbconvert'],
184 184 )
185 185
186 186 install_requires = [
187 187 'setuptools>=18.5',
188 188 'jedi>=0.10',
189 189 'decorator',
190 190 'pickleshare',
191 191 'simplegeneric>0.8',
192 192 'traitlets>=4.2',
193 'prompt_toolkit>=1.0.4,<2.0.0',
193 'prompt_toolkit>=1.0.15,<2.0.0',
194 194 'pygments',
195 195 ]
196 196
197 197 # Platform-specific dependencies:
198 198 # This is the correct way to specify these,
199 199 # but requires pip >= 6. pip < 6 ignores these.
200 200
201 201 extras_require.update({
202 202 'test:python_version >= "3.4"': ['numpy'],
203 203 ':python_version == "3.3"': ['pathlib2'],
204 204 ':python_version <= "3.4"': ['typing'],
205 205 ':sys_platform != "win32"': ['pexpect'],
206 206 ':sys_platform == "darwin"': ['appnope'],
207 207 ':sys_platform == "win32"': ['colorama'],
208 208 ':sys_platform == "win32" and python_version < "3.6"': ['win_unicode_console>=0.5'],
209 209 })
210 210 # FIXME: re-specify above platform dependencies for pip < 6
211 211 # These would result in non-portable bdists.
212 212 if not any(arg.startswith('bdist') for arg in sys.argv):
213 213 if sys.platform == 'darwin':
214 214 install_requires.extend(['appnope'])
215 215
216 216 if not sys.platform.startswith('win'):
217 217 install_requires.append('pexpect')
218 218
219 219 # workaround pypa/setuptools#147, where setuptools misspells
220 220 # platform_python_implementation as python_implementation
221 221 if 'setuptools' in sys.modules:
222 222 for key in list(extras_require):
223 223 if 'platform_python_implementation' in key:
224 224 new_key = key.replace('platform_python_implementation', 'python_implementation')
225 225 extras_require[new_key] = extras_require.pop(key)
226 226
227 227 everything = set()
228 228 for key, deps in extras_require.items():
229 229 if ':' not in key:
230 230 everything.update(deps)
231 231 extras_require['all'] = everything
232 232
233 233 if 'setuptools' in sys.modules:
234 234 setuptools_extra_args['python_requires'] = '>=3.3'
235 235 setuptools_extra_args['zip_safe'] = False
236 236 setuptools_extra_args['entry_points'] = {
237 237 'console_scripts': find_entry_points(),
238 238 'pygments.lexers': [
239 239 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
240 240 'ipython = IPython.lib.lexers:IPythonLexer',
241 241 'ipython3 = IPython.lib.lexers:IPython3Lexer',
242 242 ],
243 243 }
244 244 setup_args['extras_require'] = extras_require
245 245 setup_args['install_requires'] = install_requires
246 246
247 247 else:
248 248 # scripts has to be a non-empty list, or install_scripts isn't called
249 249 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
250 250
251 251 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
252 252
253 253 #---------------------------------------------------------------------------
254 254 # Do the actual setup now
255 255 #---------------------------------------------------------------------------
256 256
257 257 setup_args.update(setuptools_extra_args)
258 258
259 259
260 260
261 261 def main():
262 262 setup(**setup_args)
263 263
264 264 if __name__ == '__main__':
265 265 main()
General Comments 0
You need to be logged in to leave comments. Login now