##// END OF EJS Templates
Merge pull request #9437 from jonathanslenders/prompt-toolkit-1.0.0...
Thomas Kluyver -
r22300:734450ac merge
parent child Browse files
Show More
@@ -1,455 +1,457 b''
1 """IPython terminal interface using prompt_toolkit in place of readline"""
1 """IPython terminal interface using prompt_toolkit in place of readline"""
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 signal
6 import signal
7 import unicodedata
7 import unicodedata
8 from warnings import warn
8 from warnings import warn
9 from wcwidth import wcwidth
9 from wcwidth import wcwidth
10
10
11 from IPython.core.error import TryNext
11 from IPython.core.error import TryNext
12 from IPython.core.interactiveshell import InteractiveShell
12 from IPython.core.interactiveshell import InteractiveShell
13 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
13 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
14 from IPython.utils.terminal import toggle_set_term_title, set_term_title
14 from IPython.utils.terminal import toggle_set_term_title, set_term_title
15 from IPython.utils.process import abbrev_cwd
15 from IPython.utils.process import abbrev_cwd
16 from traitlets import Bool, CBool, Unicode, Dict, Integer
16 from traitlets import Bool, CBool, Unicode, Dict, Integer
17
17
18 from prompt_toolkit.completion import Completer, Completion
18 from prompt_toolkit.completion import Completer, Completion
19 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
19 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
20 from prompt_toolkit.filters import HasFocus, HasSelection, Condition
20 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode
21 from prompt_toolkit.history import InMemoryHistory
21 from prompt_toolkit.history import InMemoryHistory
22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
23 from prompt_toolkit.interface import CommandLineInterface
23 from prompt_toolkit.interface import CommandLineInterface
24 from prompt_toolkit.key_binding.manager import KeyBindingManager
24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 from prompt_toolkit.key_binding.vi_state import InputMode
26 from prompt_toolkit.key_binding.bindings.vi import ViStateFilter
27 from prompt_toolkit.keys import Keys
25 from prompt_toolkit.keys import Keys
28 from prompt_toolkit.layout.lexers import Lexer
26 from prompt_toolkit.layout.lexers import Lexer
29 from prompt_toolkit.layout.lexers import PygmentsLexer
27 from prompt_toolkit.layout.lexers import PygmentsLexer
30 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
28 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
31
29
32 from pygments.styles import get_style_by_name, get_all_styles
30 from pygments.styles import get_style_by_name, get_all_styles
33 from pygments.lexers import Python3Lexer, BashLexer, PythonLexer
31 from pygments.lexers import Python3Lexer, BashLexer, PythonLexer
34 from pygments.token import Token
32 from pygments.token import Token
35
33
36 from .pt_inputhooks import get_inputhook_func
34 from .pt_inputhooks import get_inputhook_func
37 from .interactiveshell import get_default_editor, TerminalMagics
35 from .interactiveshell import get_default_editor, TerminalMagics
38
36
39
37
40 class IPythonPTCompleter(Completer):
38 class IPythonPTCompleter(Completer):
41 """Adaptor to provide IPython completions to prompt_toolkit"""
39 """Adaptor to provide IPython completions to prompt_toolkit"""
42 def __init__(self, ipy_completer):
40 def __init__(self, ipy_completer):
43 self.ipy_completer = ipy_completer
41 self.ipy_completer = ipy_completer
44
42
45 def get_completions(self, document, complete_event):
43 def get_completions(self, document, complete_event):
46 if not document.current_line.strip():
44 if not document.current_line.strip():
47 return
45 return
48
46
49 used, matches = self.ipy_completer.complete(
47 used, matches = self.ipy_completer.complete(
50 line_buffer=document.current_line,
48 line_buffer=document.current_line,
51 cursor_pos=document.cursor_position_col
49 cursor_pos=document.cursor_position_col
52 )
50 )
53 start_pos = -len(used)
51 start_pos = -len(used)
54 for m in matches:
52 for m in matches:
55 m = unicodedata.normalize('NFC', m)
53 m = unicodedata.normalize('NFC', m)
56
54
57 # When the first character of the completion has a zero length,
55 # When the first character of the completion has a zero length,
58 # then it's probably a decomposed unicode character. E.g. caused by
56 # then it's probably a decomposed unicode character. E.g. caused by
59 # the "\dot" completion. Try to compose again with the previous
57 # the "\dot" completion. Try to compose again with the previous
60 # character.
58 # character.
61 if wcwidth(m[0]) == 0:
59 if wcwidth(m[0]) == 0:
62 if document.cursor_position + start_pos > 0:
60 if document.cursor_position + start_pos > 0:
63 char_before = document.text[document.cursor_position + start_pos - 1]
61 char_before = document.text[document.cursor_position + start_pos - 1]
64 m = unicodedata.normalize('NFC', char_before + m)
62 m = unicodedata.normalize('NFC', char_before + m)
65
63
66 # Yield the modified completion instead, if this worked.
64 # Yield the modified completion instead, if this worked.
67 if wcwidth(m[0:1]) == 1:
65 if wcwidth(m[0:1]) == 1:
68 yield Completion(m, start_position=start_pos - 1)
66 yield Completion(m, start_position=start_pos - 1)
69 continue
67 continue
70
68
71 # TODO: Use Jedi to determine meta_text
69 # TODO: Use Jedi to determine meta_text
72 # (Jedi currently has a bug that results in incorrect information.)
70 # (Jedi currently has a bug that results in incorrect information.)
73 # meta_text = ''
71 # meta_text = ''
74 # yield Completion(m, start_position=start_pos,
72 # yield Completion(m, start_position=start_pos,
75 # display_meta=meta_text)
73 # display_meta=meta_text)
76 yield Completion(m, start_position=start_pos)
74 yield Completion(m, start_position=start_pos)
77
75
78 class IPythonPTLexer(Lexer):
76 class IPythonPTLexer(Lexer):
79 """
77 """
80 Wrapper around PythonLexer and BashLexer.
78 Wrapper around PythonLexer and BashLexer.
81 """
79 """
82 def __init__(self):
80 def __init__(self):
83 self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer)
81 self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer)
84 self.shell_lexer = PygmentsLexer(BashLexer)
82 self.shell_lexer = PygmentsLexer(BashLexer)
85
83
86 def lex_document(self, cli, document):
84 def lex_document(self, cli, document):
87 if document.text.startswith('!'):
85 if document.text.startswith('!'):
88 return self.shell_lexer.lex_document(cli, document)
86 return self.shell_lexer.lex_document(cli, document)
89 else:
87 else:
90 return self.python_lexer.lex_document(cli, document)
88 return self.python_lexer.lex_document(cli, document)
91
89
92
90
93 class TerminalInteractiveShell(InteractiveShell):
91 class TerminalInteractiveShell(InteractiveShell):
94 colors_force = True
92 colors_force = True
95
93
96 space_for_menu = Integer(6, config=True, help='Number of line at the bottom of the screen '
94 space_for_menu = Integer(6, config=True, help='Number of line at the bottom of the screen '
97 'to reserve for the completion menu')
95 'to reserve for the completion menu')
98
96
99 def _space_for_menu_changed(self, old, new):
97 def _space_for_menu_changed(self, old, new):
100 self._update_layout()
98 self._update_layout()
101
99
102 pt_cli = None
100 pt_cli = None
103
101
104 autoedit_syntax = CBool(False, config=True,
102 autoedit_syntax = CBool(False, config=True,
105 help="auto editing of files with syntax errors.")
103 help="auto editing of files with syntax errors.")
106
104
107 confirm_exit = CBool(True, config=True,
105 confirm_exit = CBool(True, config=True,
108 help="""
106 help="""
109 Set to confirm when you try to exit IPython with an EOF (Control-D
107 Set to confirm when you try to exit IPython with an EOF (Control-D
110 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
108 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
111 you can force a direct exit without any confirmation.""",
109 you can force a direct exit without any confirmation.""",
112 )
110 )
113 vi_mode = Bool(False, config=True,
111 vi_mode = Bool(False, config=True,
114 help="Use vi style keybindings at the prompt",
112 help="Use vi style keybindings at the prompt",
115 )
113 )
116
114
117 mouse_support = Bool(False, config=True,
115 mouse_support = Bool(False, config=True,
118 help="Enable mouse support in the prompt"
116 help="Enable mouse support in the prompt"
119 )
117 )
120
118
121 highlighting_style = Unicode('default', config=True,
119 highlighting_style = Unicode('default', config=True,
122 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
120 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
123 )
121 )
124
122
125 def _highlighting_style_changed(self, old, new):
123 def _highlighting_style_changed(self, old, new):
126 self._style = self._make_style_from_name(self.highlighting_style)
124 self._style = self._make_style_from_name(self.highlighting_style)
127
125
128 highlighting_style_overrides = Dict(config=True,
126 highlighting_style_overrides = Dict(config=True,
129 help="Override highlighting format for specific tokens"
127 help="Override highlighting format for specific tokens"
130 )
128 )
131
129
132 editor = Unicode(get_default_editor(), config=True,
130 editor = Unicode(get_default_editor(), config=True,
133 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
131 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
134 )
132 )
135
133
136 term_title = Bool(True, config=True,
134 term_title = Bool(True, config=True,
137 help="Automatically set the terminal title"
135 help="Automatically set the terminal title"
138 )
136 )
139 def _term_title_changed(self, name, new_value):
137 def _term_title_changed(self, name, new_value):
140 self.init_term_title()
138 self.init_term_title()
141
139
142 def init_term_title(self):
140 def init_term_title(self):
143 # Enable or disable the terminal title.
141 # Enable or disable the terminal title.
144 if self.term_title:
142 if self.term_title:
145 toggle_set_term_title(True)
143 toggle_set_term_title(True)
146 set_term_title('IPython: ' + abbrev_cwd())
144 set_term_title('IPython: ' + abbrev_cwd())
147 else:
145 else:
148 toggle_set_term_title(False)
146 toggle_set_term_title(False)
149
147
150 def get_prompt_tokens(self, cli):
148 def get_prompt_tokens(self, cli):
151 return [
149 return [
152 (Token.Prompt, 'In ['),
150 (Token.Prompt, 'In ['),
153 (Token.PromptNum, str(self.execution_count)),
151 (Token.PromptNum, str(self.execution_count)),
154 (Token.Prompt, ']: '),
152 (Token.Prompt, ']: '),
155 ]
153 ]
156
154
157 def get_continuation_tokens(self, cli, width):
155 def get_continuation_tokens(self, cli, width):
158 return [
156 return [
159 (Token.Prompt, (' ' * (width - 5)) + '...: '),
157 (Token.Prompt, (' ' * (width - 5)) + '...: '),
160 ]
158 ]
161
159
162 def init_prompt_toolkit_cli(self):
160 def init_prompt_toolkit_cli(self):
163 if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
161 if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
164 # Fall back to plain non-interactive output for tests.
162 # Fall back to plain non-interactive output for tests.
165 # This is very limited, and only accepts a single line.
163 # This is very limited, and only accepts a single line.
166 def prompt():
164 def prompt():
167 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
165 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
168 self.prompt_for_code = prompt
166 self.prompt_for_code = prompt
169 return
167 return
170
168
171 kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode)
169 kbmanager = KeyBindingManager.for_prompt()
172 insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT)
170 insert_mode = ViInsertMode() | EmacsInsertMode()
173 # Ctrl+J == Enter, seemingly
171 # Ctrl+J == Enter, seemingly
174 @kbmanager.registry.add_binding(Keys.ControlJ,
172 @kbmanager.registry.add_binding(Keys.ControlJ,
175 filter=(HasFocus(DEFAULT_BUFFER)
173 filter=(HasFocus(DEFAULT_BUFFER)
176 & ~HasSelection()
174 & ~HasSelection()
177 & insert_mode
175 & insert_mode
178 ))
176 ))
179 def _(event):
177 def _(event):
180 b = event.current_buffer
178 b = event.current_buffer
181 d = b.document
179 d = b.document
182 if not (d.on_last_line or d.cursor_position_row >= d.line_count
180 if not (d.on_last_line or d.cursor_position_row >= d.line_count
183 - d.empty_line_count_at_the_end()):
181 - d.empty_line_count_at_the_end()):
184 b.newline()
182 b.newline()
185 return
183 return
186
184
187 status, indent = self.input_splitter.check_complete(d.text)
185 status, indent = self.input_splitter.check_complete(d.text)
188
186
189 if (status != 'incomplete') and b.accept_action.is_returnable:
187 if (status != 'incomplete') and b.accept_action.is_returnable:
190 b.accept_action.validate_and_handle(event.cli, b)
188 b.accept_action.validate_and_handle(event.cli, b)
191 else:
189 else:
192 b.insert_text('\n' + (' ' * (indent or 0)))
190 b.insert_text('\n' + (' ' * (indent or 0)))
193
191
194 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
192 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
195 def _(event):
193 def _(event):
196 event.current_buffer.reset()
194 event.current_buffer.reset()
197
195
198 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
196 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
199 def _(event):
197 def _(event):
200 if event.current_buffer.document.text:
198 if event.current_buffer.document.text:
201 event.current_buffer.reset()
199 event.current_buffer.reset()
202 else:
200 else:
203 event.cli.push_focus(DEFAULT_BUFFER)
201 event.cli.push_focus(DEFAULT_BUFFER)
204
202
205 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
203 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
206
204
207 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
205 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
208 def _(event):
206 def _(event):
209 event.cli.suspend_to_background()
207 event.cli.suspend_to_background()
210
208
211 @Condition
209 @Condition
212 def cursor_in_leading_ws(cli):
210 def cursor_in_leading_ws(cli):
213 before = cli.application.buffer.document.current_line_before_cursor
211 before = cli.application.buffer.document.current_line_before_cursor
214 return (not before) or before.isspace()
212 return (not before) or before.isspace()
215
213
216 # Ctrl+I == Tab
214 # Ctrl+I == Tab
217 @kbmanager.registry.add_binding(Keys.ControlI,
215 @kbmanager.registry.add_binding(Keys.ControlI,
218 filter=(HasFocus(DEFAULT_BUFFER)
216 filter=(HasFocus(DEFAULT_BUFFER)
219 & ~HasSelection()
217 & ~HasSelection()
220 & insert_mode
218 & insert_mode
221 & cursor_in_leading_ws
219 & cursor_in_leading_ws
222 ))
220 ))
223 def _(event):
221 def _(event):
224 event.current_buffer.insert_text(' ' * 4)
222 event.current_buffer.insert_text(' ' * 4)
225
223
226 # Pre-populate history from IPython's history database
224 # Pre-populate history from IPython's history database
227 history = InMemoryHistory()
225 history = InMemoryHistory()
228 last_cell = u""
226 last_cell = u""
229 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,
230 include_latest=True):
228 include_latest=True):
231 # Ignore blank lines and consecutive duplicates
229 # Ignore blank lines and consecutive duplicates
232 cell = cell.rstrip()
230 cell = cell.rstrip()
233 if cell and (cell != last_cell):
231 if cell and (cell != last_cell):
234 history.append(cell)
232 history.append(cell)
235
233
236 self._style = self._make_style_from_name(self.highlighting_style)
234 self._style = self._make_style_from_name(self.highlighting_style)
237 style = DynamicStyle(lambda: self._style)
235 style = DynamicStyle(lambda: self._style)
238
236
237 editing_mode = EditingMode.VI if self.vi_mode else EditingMode.EMACS
238
239 self._app = create_prompt_application(
239 self._app = create_prompt_application(
240 editing_mode=editing_mode,
240 key_bindings_registry=kbmanager.registry,
241 key_bindings_registry=kbmanager.registry,
241 history=history,
242 history=history,
242 completer=IPythonPTCompleter(self.Completer),
243 completer=IPythonPTCompleter(self.Completer),
243 enable_history_search=True,
244 enable_history_search=True,
244 style=style,
245 style=style,
245 mouse_support=self.mouse_support,
246 mouse_support=self.mouse_support,
246 **self._layout_options()
247 **self._layout_options()
247 )
248 )
248 self.pt_cli = CommandLineInterface(self._app,
249 self.pt_cli = CommandLineInterface(self._app,
249 eventloop=create_eventloop(self.inputhook))
250 eventloop=create_eventloop(self.inputhook))
250
251
251 def _make_style_from_name(self, name):
252 def _make_style_from_name(self, name):
252 """
253 """
253 Small wrapper that make an IPython compatible style from a style name
254 Small wrapper that make an IPython compatible style from a style name
254
255
255 We need that to add style for prompt ... etc.
256 We need that to add style for prompt ... etc.
256 """
257 """
257 style_cls = get_style_by_name(name)
258 style_cls = get_style_by_name(name)
258 style_overrides = {
259 style_overrides = {
259 Token.Prompt: '#009900',
260 Token.Prompt: '#009900',
260 Token.PromptNum: '#00ff00 bold',
261 Token.PromptNum: '#00ff00 bold',
261 }
262 }
262 if name is 'default':
263 if name is 'default':
263 style_cls = get_style_by_name('default')
264 style_cls = get_style_by_name('default')
264 # The default theme needs to be visible on both a dark background
265 # The default theme needs to be visible on both a dark background
265 # and a light background, because we can't tell what the terminal
266 # and a light background, because we can't tell what the terminal
266 # looks like. These tweaks to the default theme help with that.
267 # looks like. These tweaks to the default theme help with that.
267 style_overrides.update({
268 style_overrides.update({
268 Token.Number: '#007700',
269 Token.Number: '#007700',
269 Token.Operator: 'noinherit',
270 Token.Operator: 'noinherit',
270 Token.String: '#BB6622',
271 Token.String: '#BB6622',
271 Token.Name.Function: '#2080D0',
272 Token.Name.Function: '#2080D0',
272 Token.Name.Class: 'bold #2080D0',
273 Token.Name.Class: 'bold #2080D0',
273 Token.Name.Namespace: 'bold #2080D0',
274 Token.Name.Namespace: 'bold #2080D0',
274 })
275 })
275 style_overrides.update(self.highlighting_style_overrides)
276 style_overrides.update(self.highlighting_style_overrides)
276 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
277 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
277 style_dict=style_overrides)
278 style_dict=style_overrides)
278
279
279 return style
280 return style
280
281
281 def _layout_options(self):
282 def _layout_options(self):
282 """
283 """
283 Return the current layout option for the current Terminal InteractiveShell
284 Return the current layout option for the current Terminal InteractiveShell
284 """
285 """
285 return {
286 return {
286 'lexer':IPythonPTLexer(),
287 'lexer':IPythonPTLexer(),
287 'reserve_space_for_menu':self.space_for_menu,
288 'reserve_space_for_menu':self.space_for_menu,
288 'get_prompt_tokens':self.get_prompt_tokens,
289 'get_prompt_tokens':self.get_prompt_tokens,
289 'get_continuation_tokens':self.get_continuation_tokens,
290 'get_continuation_tokens':self.get_continuation_tokens,
290 'multiline':True,
291 'multiline':True,
291 }
292 }
292
293
293
294
294 def _update_layout(self):
295 def _update_layout(self):
295 """
296 """
296 Ask for a re computation of the application layout, if for example ,
297 Ask for a re computation of the application layout, if for example ,
297 some configuration options have changed.
298 some configuration options have changed.
298 """
299 """
299 self._app.layout = create_prompt_layout(**self._layout_options())
300 self._app.layout = create_prompt_layout(**self._layout_options())
300
301
301 def prompt_for_code(self):
302 def prompt_for_code(self):
302 document = self.pt_cli.run(pre_run=self.pre_prompt)
303 document = self.pt_cli.run(
304 pre_run=self.pre_prompt, reset_current_buffer=True)
303 return document.text
305 return document.text
304
306
305 def init_io(self):
307 def init_io(self):
306 if sys.platform not in {'win32', 'cli'}:
308 if sys.platform not in {'win32', 'cli'}:
307 return
309 return
308
310
309 import colorama
311 import colorama
310 colorama.init()
312 colorama.init()
311
313
312 # For some reason we make these wrappers around stdout/stderr.
314 # For some reason we make these wrappers around stdout/stderr.
313 # For now, we need to reset them so all output gets coloured.
315 # For now, we need to reset them so all output gets coloured.
314 # https://github.com/ipython/ipython/issues/8669
316 # https://github.com/ipython/ipython/issues/8669
315 from IPython.utils import io
317 from IPython.utils import io
316 io.stdout = io.IOStream(sys.stdout)
318 io.stdout = io.IOStream(sys.stdout)
317 io.stderr = io.IOStream(sys.stderr)
319 io.stderr = io.IOStream(sys.stderr)
318
320
319 def init_magics(self):
321 def init_magics(self):
320 super(TerminalInteractiveShell, self).init_magics()
322 super(TerminalInteractiveShell, self).init_magics()
321 self.register_magics(TerminalMagics)
323 self.register_magics(TerminalMagics)
322
324
323 def init_alias(self):
325 def init_alias(self):
324 # The parent class defines aliases that can be safely used with any
326 # The parent class defines aliases that can be safely used with any
325 # frontend.
327 # frontend.
326 super(TerminalInteractiveShell, self).init_alias()
328 super(TerminalInteractiveShell, self).init_alias()
327
329
328 # Now define aliases that only make sense on the terminal, because they
330 # Now define aliases that only make sense on the terminal, because they
329 # need direct access to the console in a way that we can't emulate in
331 # need direct access to the console in a way that we can't emulate in
330 # GUI or web frontend
332 # GUI or web frontend
331 if os.name == 'posix':
333 if os.name == 'posix':
332 for cmd in ['clear', 'more', 'less', 'man']:
334 for cmd in ['clear', 'more', 'less', 'man']:
333 self.alias_manager.soft_define_alias(cmd, cmd)
335 self.alias_manager.soft_define_alias(cmd, cmd)
334
336
335
337
336 def __init__(self, *args, **kwargs):
338 def __init__(self, *args, **kwargs):
337 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
339 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
338 self.init_prompt_toolkit_cli()
340 self.init_prompt_toolkit_cli()
339 self.init_term_title()
341 self.init_term_title()
340 self.keep_running = True
342 self.keep_running = True
341
343
342 def ask_exit(self):
344 def ask_exit(self):
343 self.keep_running = False
345 self.keep_running = False
344
346
345 rl_next_input = None
347 rl_next_input = None
346
348
347 def pre_prompt(self):
349 def pre_prompt(self):
348 if self.rl_next_input:
350 if self.rl_next_input:
349 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
351 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
350 self.rl_next_input = None
352 self.rl_next_input = None
351
353
352 def interact(self):
354 def interact(self):
353 while self.keep_running:
355 while self.keep_running:
354 print(self.separate_in, end='')
356 print(self.separate_in, end='')
355
357
356 try:
358 try:
357 code = self.prompt_for_code()
359 code = self.prompt_for_code()
358 except EOFError:
360 except EOFError:
359 if (not self.confirm_exit) \
361 if (not self.confirm_exit) \
360 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
362 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
361 self.ask_exit()
363 self.ask_exit()
362
364
363 else:
365 else:
364 if code:
366 if code:
365 self.run_cell(code, store_history=True)
367 self.run_cell(code, store_history=True)
366 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
368 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
367 self.edit_syntax_error()
369 self.edit_syntax_error()
368
370
369 def mainloop(self):
371 def mainloop(self):
370 # An extra layer of protection in case someone mashing Ctrl-C breaks
372 # An extra layer of protection in case someone mashing Ctrl-C breaks
371 # out of our internal code.
373 # out of our internal code.
372 while True:
374 while True:
373 try:
375 try:
374 self.interact()
376 self.interact()
375 break
377 break
376 except KeyboardInterrupt:
378 except KeyboardInterrupt:
377 print("\nKeyboardInterrupt escaped interact()\n")
379 print("\nKeyboardInterrupt escaped interact()\n")
378
380
379 _inputhook = None
381 _inputhook = None
380 def inputhook(self, context):
382 def inputhook(self, context):
381 if self._inputhook is not None:
383 if self._inputhook is not None:
382 self._inputhook(context)
384 self._inputhook(context)
383
385
384 def enable_gui(self, gui=None):
386 def enable_gui(self, gui=None):
385 if gui:
387 if gui:
386 self._inputhook = get_inputhook_func(gui)
388 self._inputhook = get_inputhook_func(gui)
387 else:
389 else:
388 self._inputhook = None
390 self._inputhook = None
389
391
390 # Methods to support auto-editing of SyntaxErrors:
392 # Methods to support auto-editing of SyntaxErrors:
391
393
392 def edit_syntax_error(self):
394 def edit_syntax_error(self):
393 """The bottom half of the syntax error handler called in the main loop.
395 """The bottom half of the syntax error handler called in the main loop.
394
396
395 Loop until syntax error is fixed or user cancels.
397 Loop until syntax error is fixed or user cancels.
396 """
398 """
397
399
398 while self.SyntaxTB.last_syntax_error:
400 while self.SyntaxTB.last_syntax_error:
399 # copy and clear last_syntax_error
401 # copy and clear last_syntax_error
400 err = self.SyntaxTB.clear_err_state()
402 err = self.SyntaxTB.clear_err_state()
401 if not self._should_recompile(err):
403 if not self._should_recompile(err):
402 return
404 return
403 try:
405 try:
404 # may set last_syntax_error again if a SyntaxError is raised
406 # may set last_syntax_error again if a SyntaxError is raised
405 self.safe_execfile(err.filename, self.user_ns)
407 self.safe_execfile(err.filename, self.user_ns)
406 except:
408 except:
407 self.showtraceback()
409 self.showtraceback()
408 else:
410 else:
409 try:
411 try:
410 with open(err.filename) as f:
412 with open(err.filename) as f:
411 # This should be inside a display_trap block and I
413 # This should be inside a display_trap block and I
412 # think it is.
414 # think it is.
413 sys.displayhook(f.read())
415 sys.displayhook(f.read())
414 except:
416 except:
415 self.showtraceback()
417 self.showtraceback()
416
418
417 def _should_recompile(self, e):
419 def _should_recompile(self, e):
418 """Utility routine for edit_syntax_error"""
420 """Utility routine for edit_syntax_error"""
419
421
420 if e.filename in ('<ipython console>', '<input>', '<string>',
422 if e.filename in ('<ipython console>', '<input>', '<string>',
421 '<console>', '<BackgroundJob compilation>',
423 '<console>', '<BackgroundJob compilation>',
422 None):
424 None):
423 return False
425 return False
424 try:
426 try:
425 if (self.autoedit_syntax and
427 if (self.autoedit_syntax and
426 not self.ask_yes_no(
428 not self.ask_yes_no(
427 'Return to editor to correct syntax error? '
429 'Return to editor to correct syntax error? '
428 '[Y/n] ', 'y')):
430 '[Y/n] ', 'y')):
429 return False
431 return False
430 except EOFError:
432 except EOFError:
431 return False
433 return False
432
434
433 def int0(x):
435 def int0(x):
434 try:
436 try:
435 return int(x)
437 return int(x)
436 except TypeError:
438 except TypeError:
437 return 0
439 return 0
438
440
439 # always pass integer line and offset values to editor hook
441 # always pass integer line and offset values to editor hook
440 try:
442 try:
441 self.hooks.fix_error_editor(e.filename,
443 self.hooks.fix_error_editor(e.filename,
442 int0(e.lineno), int0(e.offset),
444 int0(e.lineno), int0(e.offset),
443 e.msg)
445 e.msg)
444 except TryNext:
446 except TryNext:
445 warn('Could not open editor')
447 warn('Could not open editor')
446 return False
448 return False
447 return True
449 return True
448
450
449 # Run !system commands directly, not through pipes, so terminal programs
451 # Run !system commands directly, not through pipes, so terminal programs
450 # work correctly.
452 # work correctly.
451 system = InteractiveShell.system_raw
453 system = InteractiveShell.system_raw
452
454
453
455
454 if __name__ == '__main__':
456 if __name__ == '__main__':
455 TerminalInteractiveShell.instance().interact()
457 TerminalInteractiveShell.instance().interact()
@@ -1,300 +1,300 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 v = sys.version_info
29 v = sys.version_info
30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
32 print(error, file=sys.stderr)
32 print(error, file=sys.stderr)
33 sys.exit(1)
33 sys.exit(1)
34
34
35 PY3 = (sys.version_info[0] >= 3)
35 PY3 = (sys.version_info[0] >= 3)
36
36
37 # At least we're on the python version we need, move on.
37 # At least we're on the python version we need, move on.
38
38
39 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
40 # Imports
40 # Imports
41 #-------------------------------------------------------------------------------
41 #-------------------------------------------------------------------------------
42
42
43 # Stdlib imports
43 # Stdlib imports
44 import os
44 import os
45
45
46 from glob import glob
46 from glob import glob
47
47
48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
49 # update it when the contents of directories change.
49 # update it when the contents of directories change.
50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
51
51
52 from distutils.core import setup
52 from distutils.core import setup
53
53
54 # Our own imports
54 # Our own imports
55 from setupbase import target_update
55 from setupbase import target_update
56
56
57 from setupbase import (
57 from setupbase import (
58 setup_args,
58 setup_args,
59 find_packages,
59 find_packages,
60 find_package_data,
60 find_package_data,
61 check_package_data_first,
61 check_package_data_first,
62 find_entry_points,
62 find_entry_points,
63 build_scripts_entrypt,
63 build_scripts_entrypt,
64 find_data_files,
64 find_data_files,
65 git_prebuild,
65 git_prebuild,
66 install_symlinked,
66 install_symlinked,
67 install_lib_symlink,
67 install_lib_symlink,
68 install_scripts_for_symlink,
68 install_scripts_for_symlink,
69 unsymlink,
69 unsymlink,
70 )
70 )
71
71
72 isfile = os.path.isfile
72 isfile = os.path.isfile
73 pjoin = os.path.join
73 pjoin = os.path.join
74
74
75 #-------------------------------------------------------------------------------
75 #-------------------------------------------------------------------------------
76 # Handle OS specific things
76 # Handle OS specific things
77 #-------------------------------------------------------------------------------
77 #-------------------------------------------------------------------------------
78
78
79 if os.name in ('nt','dos'):
79 if os.name in ('nt','dos'):
80 os_name = 'windows'
80 os_name = 'windows'
81 else:
81 else:
82 os_name = os.name
82 os_name = os.name
83
83
84 # Under Windows, 'sdist' has not been supported. Now that the docs build with
84 # Under Windows, 'sdist' has not been supported. Now that the docs build with
85 # Sphinx it might work, but let's not turn it on until someone confirms that it
85 # Sphinx it might work, but let's not turn it on until someone confirms that it
86 # actually works.
86 # actually works.
87 if os_name == 'windows' and 'sdist' in sys.argv:
87 if os_name == 'windows' and 'sdist' in sys.argv:
88 print('The sdist command is not available under Windows. Exiting.')
88 print('The sdist command is not available under Windows. Exiting.')
89 sys.exit(1)
89 sys.exit(1)
90
90
91
91
92 #-------------------------------------------------------------------------------
92 #-------------------------------------------------------------------------------
93 # Things related to the IPython documentation
93 # Things related to the IPython documentation
94 #-------------------------------------------------------------------------------
94 #-------------------------------------------------------------------------------
95
95
96 # update the manuals when building a source dist
96 # update the manuals when building a source dist
97 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
97 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
98
98
99 # List of things to be updated. Each entry is a triplet of args for
99 # List of things to be updated. Each entry is a triplet of args for
100 # target_update()
100 # target_update()
101 to_update = [
101 to_update = [
102 ('docs/man/ipython.1.gz',
102 ('docs/man/ipython.1.gz',
103 ['docs/man/ipython.1'],
103 ['docs/man/ipython.1'],
104 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
104 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
105 ]
105 ]
106
106
107
107
108 [ target_update(*t) for t in to_update ]
108 [ target_update(*t) for t in to_update ]
109
109
110 #---------------------------------------------------------------------------
110 #---------------------------------------------------------------------------
111 # Find all the packages, package data, and data_files
111 # Find all the packages, package data, and data_files
112 #---------------------------------------------------------------------------
112 #---------------------------------------------------------------------------
113
113
114 packages = find_packages()
114 packages = find_packages()
115 package_data = find_package_data()
115 package_data = find_package_data()
116
116
117 data_files = find_data_files()
117 data_files = find_data_files()
118
118
119 setup_args['packages'] = packages
119 setup_args['packages'] = packages
120 setup_args['package_data'] = package_data
120 setup_args['package_data'] = package_data
121 setup_args['data_files'] = data_files
121 setup_args['data_files'] = data_files
122
122
123 #---------------------------------------------------------------------------
123 #---------------------------------------------------------------------------
124 # custom distutils commands
124 # custom distutils commands
125 #---------------------------------------------------------------------------
125 #---------------------------------------------------------------------------
126 # imports here, so they are after setuptools import if there was one
126 # imports here, so they are after setuptools import if there was one
127 from distutils.command.sdist import sdist
127 from distutils.command.sdist import sdist
128 from distutils.command.upload import upload
128 from distutils.command.upload import upload
129
129
130 class UploadWindowsInstallers(upload):
130 class UploadWindowsInstallers(upload):
131
131
132 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
132 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
133 user_options = upload.user_options + [
133 user_options = upload.user_options + [
134 ('files=', 'f', 'exe file (or glob) to upload')
134 ('files=', 'f', 'exe file (or glob) to upload')
135 ]
135 ]
136 def initialize_options(self):
136 def initialize_options(self):
137 upload.initialize_options(self)
137 upload.initialize_options(self)
138 meta = self.distribution.metadata
138 meta = self.distribution.metadata
139 base = '{name}-{version}'.format(
139 base = '{name}-{version}'.format(
140 name=meta.get_name(),
140 name=meta.get_name(),
141 version=meta.get_version()
141 version=meta.get_version()
142 )
142 )
143 self.files = os.path.join('dist', '%s.*.exe' % base)
143 self.files = os.path.join('dist', '%s.*.exe' % base)
144
144
145 def run(self):
145 def run(self):
146 for dist_file in glob(self.files):
146 for dist_file in glob(self.files):
147 self.upload_file('bdist_wininst', 'any', dist_file)
147 self.upload_file('bdist_wininst', 'any', dist_file)
148
148
149 setup_args['cmdclass'] = {
149 setup_args['cmdclass'] = {
150 'build_py': \
150 'build_py': \
151 check_package_data_first(git_prebuild('IPython')),
151 check_package_data_first(git_prebuild('IPython')),
152 'sdist' : git_prebuild('IPython', sdist),
152 'sdist' : git_prebuild('IPython', sdist),
153 'upload_wininst' : UploadWindowsInstallers,
153 'upload_wininst' : UploadWindowsInstallers,
154 'symlink': install_symlinked,
154 'symlink': install_symlinked,
155 'install_lib_symlink': install_lib_symlink,
155 'install_lib_symlink': install_lib_symlink,
156 'install_scripts_sym': install_scripts_for_symlink,
156 'install_scripts_sym': install_scripts_for_symlink,
157 'unsymlink': unsymlink,
157 'unsymlink': unsymlink,
158 }
158 }
159
159
160
160
161 #---------------------------------------------------------------------------
161 #---------------------------------------------------------------------------
162 # Handle scripts, dependencies, and setuptools specific things
162 # Handle scripts, dependencies, and setuptools specific things
163 #---------------------------------------------------------------------------
163 #---------------------------------------------------------------------------
164
164
165 # For some commands, use setuptools. Note that we do NOT list install here!
165 # For some commands, use setuptools. Note that we do NOT list install here!
166 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
166 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
167 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
167 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
168 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
168 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
169 'egg_info', 'easy_install', 'upload', 'install_egg_info',
169 'egg_info', 'easy_install', 'upload', 'install_egg_info',
170 ))
170 ))
171
171
172 if len(needs_setuptools.intersection(sys.argv)) > 0:
172 if len(needs_setuptools.intersection(sys.argv)) > 0:
173 import setuptools
173 import setuptools
174
174
175 # This dict is used for passing extra arguments that are setuptools
175 # This dict is used for passing extra arguments that are setuptools
176 # specific to setup
176 # specific to setup
177 setuptools_extra_args = {}
177 setuptools_extra_args = {}
178
178
179 # setuptools requirements
179 # setuptools requirements
180
180
181 extras_require = dict(
181 extras_require = dict(
182 parallel = ['ipyparallel'],
182 parallel = ['ipyparallel'],
183 qtconsole = ['qtconsole'],
183 qtconsole = ['qtconsole'],
184 doc = ['Sphinx>=1.3'],
184 doc = ['Sphinx>=1.3'],
185 test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'],
185 test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'],
186 terminal = [],
186 terminal = [],
187 kernel = ['ipykernel'],
187 kernel = ['ipykernel'],
188 nbformat = ['nbformat'],
188 nbformat = ['nbformat'],
189 notebook = ['notebook', 'ipywidgets'],
189 notebook = ['notebook', 'ipywidgets'],
190 nbconvert = ['nbconvert'],
190 nbconvert = ['nbconvert'],
191 )
191 )
192 install_requires = [
192 install_requires = [
193 'setuptools>=18.5',
193 'setuptools>=18.5',
194 'jedi',
194 'jedi',
195 'decorator',
195 'decorator',
196 'pickleshare',
196 'pickleshare',
197 'simplegeneric>0.8',
197 'simplegeneric>0.8',
198 'traitlets',
198 'traitlets',
199 'prompt_toolkit>=0.60',
199 'prompt_toolkit>=1.0.0,<2.0.0',
200 'pygments',
200 'pygments',
201 ]
201 ]
202
202
203 # Platform-specific dependencies:
203 # Platform-specific dependencies:
204 # This is the correct way to specify these,
204 # This is the correct way to specify these,
205 # but requires pip >= 6. pip < 6 ignores these.
205 # but requires pip >= 6. pip < 6 ignores these.
206
206
207 extras_require.update({
207 extras_require.update({
208 ':python_version == "2.7"': ['backports.shutil_get_terminal_size'],
208 ':python_version == "2.7"': ['backports.shutil_get_terminal_size'],
209 ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'],
209 ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'],
210 ':sys_platform != "win32"': ['pexpect'],
210 ':sys_platform != "win32"': ['pexpect'],
211 ':sys_platform == "darwin"': ['appnope'],
211 ':sys_platform == "darwin"': ['appnope'],
212 ':sys_platform == "win32"': ['colorama'],
212 ':sys_platform == "win32"': ['colorama'],
213 'test:python_version == "2.7"': ['mock'],
213 'test:python_version == "2.7"': ['mock'],
214 })
214 })
215 # FIXME: re-specify above platform dependencies for pip < 6
215 # FIXME: re-specify above platform dependencies for pip < 6
216 # These would result in non-portable bdists.
216 # These would result in non-portable bdists.
217 if not any(arg.startswith('bdist') for arg in sys.argv):
217 if not any(arg.startswith('bdist') for arg in sys.argv):
218 if sys.version_info < (3, 3):
218 if sys.version_info < (3, 3):
219 extras_require['test'].append('mock')
219 extras_require['test'].append('mock')
220
220
221 if sys.platform == 'darwin':
221 if sys.platform == 'darwin':
222 install_requires.extend(['appnope'])
222 install_requires.extend(['appnope'])
223 have_readline = False
223 have_readline = False
224 try:
224 try:
225 import readline
225 import readline
226 except ImportError:
226 except ImportError:
227 pass
227 pass
228 else:
228 else:
229 if 'libedit' not in readline.__doc__:
229 if 'libedit' not in readline.__doc__:
230 have_readline = True
230 have_readline = True
231 if not have_readline:
231 if not have_readline:
232 install_requires.extend(['gnureadline'])
232 install_requires.extend(['gnureadline'])
233
233
234 if sys.platform.startswith('win'):
234 if sys.platform.startswith('win'):
235 extras_require['terminal'].append('pyreadline>=2.0')
235 extras_require['terminal'].append('pyreadline>=2.0')
236 else:
236 else:
237 install_requires.append('pexpect')
237 install_requires.append('pexpect')
238
238
239 # workaround pypa/setuptools#147, where setuptools misspells
239 # workaround pypa/setuptools#147, where setuptools misspells
240 # platform_python_implementation as python_implementation
240 # platform_python_implementation as python_implementation
241 if 'setuptools' in sys.modules:
241 if 'setuptools' in sys.modules:
242 for key in list(extras_require):
242 for key in list(extras_require):
243 if 'platform_python_implementation' in key:
243 if 'platform_python_implementation' in key:
244 new_key = key.replace('platform_python_implementation', 'python_implementation')
244 new_key = key.replace('platform_python_implementation', 'python_implementation')
245 extras_require[new_key] = extras_require.pop(key)
245 extras_require[new_key] = extras_require.pop(key)
246
246
247 everything = set()
247 everything = set()
248 for key, deps in extras_require.items():
248 for key, deps in extras_require.items():
249 if ':' not in key:
249 if ':' not in key:
250 everything.update(deps)
250 everything.update(deps)
251 extras_require['all'] = everything
251 extras_require['all'] = everything
252
252
253 if 'setuptools' in sys.modules:
253 if 'setuptools' in sys.modules:
254 setuptools_extra_args['zip_safe'] = False
254 setuptools_extra_args['zip_safe'] = False
255 setuptools_extra_args['entry_points'] = {
255 setuptools_extra_args['entry_points'] = {
256 'console_scripts': find_entry_points(),
256 'console_scripts': find_entry_points(),
257 'pygments.lexers': [
257 'pygments.lexers': [
258 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
258 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
259 'ipython = IPython.lib.lexers:IPythonLexer',
259 'ipython = IPython.lib.lexers:IPythonLexer',
260 'ipython3 = IPython.lib.lexers:IPython3Lexer',
260 'ipython3 = IPython.lib.lexers:IPython3Lexer',
261 ],
261 ],
262 }
262 }
263 setup_args['extras_require'] = extras_require
263 setup_args['extras_require'] = extras_require
264 requires = setup_args['install_requires'] = install_requires
264 requires = setup_args['install_requires'] = install_requires
265
265
266 # Script to be run by the windows binary installer after the default setup
266 # Script to be run by the windows binary installer after the default setup
267 # routine, to add shortcuts and similar windows-only things. Windows
267 # routine, to add shortcuts and similar windows-only things. Windows
268 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
268 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
269 # doesn't find them.
269 # doesn't find them.
270 if 'bdist_wininst' in sys.argv:
270 if 'bdist_wininst' in sys.argv:
271 if len(sys.argv) > 2 and \
271 if len(sys.argv) > 2 and \
272 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
272 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
273 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
273 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
274 sys.exit(1)
274 sys.exit(1)
275 setup_args['data_files'].append(
275 setup_args['data_files'].append(
276 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
276 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
277 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
277 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
278 setup_args['options'] = {"bdist_wininst":
278 setup_args['options'] = {"bdist_wininst":
279 {"install_script":
279 {"install_script":
280 "ipython_win_post_install.py"}}
280 "ipython_win_post_install.py"}}
281
281
282 else:
282 else:
283 # scripts has to be a non-empty list, or install_scripts isn't called
283 # scripts has to be a non-empty list, or install_scripts isn't called
284 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
284 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
285
285
286 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
286 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
287
287
288 #---------------------------------------------------------------------------
288 #---------------------------------------------------------------------------
289 # Do the actual setup now
289 # Do the actual setup now
290 #---------------------------------------------------------------------------
290 #---------------------------------------------------------------------------
291
291
292 setup_args.update(setuptools_extra_args)
292 setup_args.update(setuptools_extra_args)
293
293
294
294
295
295
296 def main():
296 def main():
297 setup(**setup_args)
297 setup(**setup_args)
298
298
299 if __name__ == '__main__':
299 if __name__ == '__main__':
300 main()
300 main()
General Comments 0
You need to be logged in to leave comments. Login now