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