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