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