##// END OF EJS Templates
Merge pull request #7564 from abalkin/issue-7558...
Thomas Kluyver -
r20135:f7a3a5df merge
parent child Browse files
Show More
@@ -1,502 +1,502 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Defines a variety of Pygments lexers for highlighting IPython code.
3 Defines a variety of Pygments lexers for highlighting IPython code.
4
4
5 This includes:
5 This includes:
6
6
7 IPythonLexer, IPython3Lexer
7 IPythonLexer, IPython3Lexer
8 Lexers for pure IPython (python + magic/shell commands)
8 Lexers for pure IPython (python + magic/shell commands)
9
9
10 IPythonPartialTracebackLexer, IPythonTracebackLexer
10 IPythonPartialTracebackLexer, IPythonTracebackLexer
11 Supports 2.x and 3.x via keyword `python3`. The partial traceback
11 Supports 2.x and 3.x via keyword `python3`. The partial traceback
12 lexer reads everything but the Python code appearing in a traceback.
12 lexer reads everything but the Python code appearing in a traceback.
13 The full lexer combines the partial lexer with an IPython lexer.
13 The full lexer combines the partial lexer with an IPython lexer.
14
14
15 IPythonConsoleLexer
15 IPythonConsoleLexer
16 A lexer for IPython console sessions, with support for tracebacks.
16 A lexer for IPython console sessions, with support for tracebacks.
17
17
18 IPyLexer
18 IPyLexer
19 A friendly lexer which examines the first line of text and from it,
19 A friendly lexer which examines the first line of text and from it,
20 decides whether to use an IPython lexer or an IPython console lexer.
20 decides whether to use an IPython lexer or an IPython console lexer.
21 This is probably the only lexer that needs to be explicitly added
21 This is probably the only lexer that needs to be explicitly added
22 to Pygments.
22 to Pygments.
23
23
24 """
24 """
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Copyright (c) 2013, the IPython Development Team.
26 # Copyright (c) 2013, the IPython Development Team.
27 #
27 #
28 # Distributed under the terms of the Modified BSD License.
28 # Distributed under the terms of the Modified BSD License.
29 #
29 #
30 # The full license is in the file COPYING.txt, distributed with this software.
30 # The full license is in the file COPYING.txt, distributed with this software.
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # Standard library
33 # Standard library
34 import re
34 import re
35
35
36 # Third party
36 # Third party
37 from pygments.lexers import BashLexer, PythonLexer, Python3Lexer
37 from pygments.lexers import BashLexer, PythonLexer, Python3Lexer
38 from pygments.lexer import (
38 from pygments.lexer import (
39 Lexer, DelegatingLexer, RegexLexer, do_insertions, bygroups, using,
39 Lexer, DelegatingLexer, RegexLexer, do_insertions, bygroups, using,
40 )
40 )
41 from pygments.token import (
41 from pygments.token import (
42 Comment, Generic, Keyword, Literal, Name, Operator, Other, Text, Error,
42 Comment, Generic, Keyword, Literal, Name, Operator, Other, Text, Error,
43 )
43 )
44 from pygments.util import get_bool_opt
44 from pygments.util import get_bool_opt
45
45
46 # Local
46 # Local
47 from IPython.testing.skipdoctest import skip_doctest
47 from IPython.testing.skipdoctest import skip_doctest
48
48
49 line_re = re.compile('.*?\n')
49 line_re = re.compile('.*?\n')
50
50
51 ipython_tokens = [
51 ipython_tokens = [
52 (r'(\%+)(\w+)\s+(\.*)(\n)', bygroups(Operator, Keyword,
52 (r'(\%+)(\w+)\s+(\.*)(\n)', bygroups(Operator, Keyword,
53 using(BashLexer), Text)),
53 using(BashLexer), Text)),
54 (r'(\%+)(\w+)\b', bygroups(Operator, Keyword)),
54 (r'(\%+)(\w+)\b', bygroups(Operator, Keyword)),
55 (r'^(!)(.+)(\n)', bygroups(Operator, using(BashLexer), Text)),
55 (r'^(!)(.+)(\n)', bygroups(Operator, using(BashLexer), Text)),
56 ]
56 ]
57
57
58 def build_ipy_lexer(python3):
58 def build_ipy_lexer(python3):
59 """Builds IPython lexers depending on the value of `python3`.
59 """Builds IPython lexers depending on the value of `python3`.
60
60
61 The lexer inherits from an appropriate Python lexer and then adds
61 The lexer inherits from an appropriate Python lexer and then adds
62 information about IPython specific keywords (i.e. magic commands,
62 information about IPython specific keywords (i.e. magic commands,
63 shell commands, etc.)
63 shell commands, etc.)
64
64
65 Parameters
65 Parameters
66 ----------
66 ----------
67 python3 : bool
67 python3 : bool
68 If `True`, then build an IPython lexer from a Python 3 lexer.
68 If `True`, then build an IPython lexer from a Python 3 lexer.
69
69
70 """
70 """
71 # It would be nice to have a single IPython lexer class which takes
71 # It would be nice to have a single IPython lexer class which takes
72 # a boolean `python3`. But since there are two Python lexer classes,
72 # a boolean `python3`. But since there are two Python lexer classes,
73 # we will also have two IPython lexer classes.
73 # we will also have two IPython lexer classes.
74 if python3:
74 if python3:
75 PyLexer = Python3Lexer
75 PyLexer = Python3Lexer
76 clsname = 'IPython3Lexer'
76 clsname = 'IPython3Lexer'
77 name = 'IPython3'
77 name = 'IPython3'
78 aliases = ['ipython3']
78 aliases = ['ipython3']
79 doc = """IPython3 Lexer"""
79 doc = """IPython3 Lexer"""
80 else:
80 else:
81 PyLexer = PythonLexer
81 PyLexer = PythonLexer
82 clsname = 'IPythonLexer'
82 clsname = 'IPythonLexer'
83 name = 'IPython'
83 name = 'IPython'
84 aliases = ['ipython2', 'ipython']
84 aliases = ['ipython2', 'ipython']
85 doc = """IPython Lexer"""
85 doc = """IPython Lexer"""
86
86
87 tokens = PyLexer.tokens.copy()
87 tokens = PyLexer.tokens.copy()
88 tokens['root'] = ipython_tokens + tokens['root']
88 tokens['root'] = ipython_tokens + tokens['root']
89
89
90 attrs = {'name': name, 'aliases': aliases,
90 attrs = {'name': name, 'aliases': aliases, 'filenames': [],
91 '__doc__': doc, 'tokens': tokens}
91 '__doc__': doc, 'tokens': tokens}
92
92
93 return type(name, (PyLexer,), attrs)
93 return type(name, (PyLexer,), attrs)
94
94
95
95
96 IPython3Lexer = build_ipy_lexer(python3=True)
96 IPython3Lexer = build_ipy_lexer(python3=True)
97 IPythonLexer = build_ipy_lexer(python3=False)
97 IPythonLexer = build_ipy_lexer(python3=False)
98
98
99
99
100 class IPythonPartialTracebackLexer(RegexLexer):
100 class IPythonPartialTracebackLexer(RegexLexer):
101 """
101 """
102 Partial lexer for IPython tracebacks.
102 Partial lexer for IPython tracebacks.
103
103
104 Handles all the non-python output. This works for both Python 2.x and 3.x.
104 Handles all the non-python output. This works for both Python 2.x and 3.x.
105
105
106 """
106 """
107 name = 'IPython Partial Traceback'
107 name = 'IPython Partial Traceback'
108
108
109 tokens = {
109 tokens = {
110 'root': [
110 'root': [
111 # Tracebacks for syntax errors have a different style.
111 # Tracebacks for syntax errors have a different style.
112 # For both types of tracebacks, we mark the first line with
112 # For both types of tracebacks, we mark the first line with
113 # Generic.Traceback. For syntax errors, we mark the filename
113 # Generic.Traceback. For syntax errors, we mark the filename
114 # as we mark the filenames for non-syntax tracebacks.
114 # as we mark the filenames for non-syntax tracebacks.
115 #
115 #
116 # These two regexps define how IPythonConsoleLexer finds a
116 # These two regexps define how IPythonConsoleLexer finds a
117 # traceback.
117 # traceback.
118 #
118 #
119 ## Non-syntax traceback
119 ## Non-syntax traceback
120 (r'^(\^C)?(-+\n)', bygroups(Error, Generic.Traceback)),
120 (r'^(\^C)?(-+\n)', bygroups(Error, Generic.Traceback)),
121 ## Syntax traceback
121 ## Syntax traceback
122 (r'^( File)(.*)(, line )(\d+\n)',
122 (r'^( File)(.*)(, line )(\d+\n)',
123 bygroups(Generic.Traceback, Name.Namespace,
123 bygroups(Generic.Traceback, Name.Namespace,
124 Generic.Traceback, Literal.Number.Integer)),
124 Generic.Traceback, Literal.Number.Integer)),
125
125
126 # (Exception Identifier)(Whitespace)(Traceback Message)
126 # (Exception Identifier)(Whitespace)(Traceback Message)
127 (r'(?u)(^[^\d\W]\w*)(\s*)(Traceback.*?\n)',
127 (r'(?u)(^[^\d\W]\w*)(\s*)(Traceback.*?\n)',
128 bygroups(Name.Exception, Generic.Whitespace, Text)),
128 bygroups(Name.Exception, Generic.Whitespace, Text)),
129 # (Module/Filename)(Text)(Callee)(Function Signature)
129 # (Module/Filename)(Text)(Callee)(Function Signature)
130 # Better options for callee and function signature?
130 # Better options for callee and function signature?
131 (r'(.*)( in )(.*)(\(.*\)\n)',
131 (r'(.*)( in )(.*)(\(.*\)\n)',
132 bygroups(Name.Namespace, Text, Name.Entity, Name.Tag)),
132 bygroups(Name.Namespace, Text, Name.Entity, Name.Tag)),
133 # Regular line: (Whitespace)(Line Number)(Python Code)
133 # Regular line: (Whitespace)(Line Number)(Python Code)
134 (r'(\s*?)(\d+)(.*?\n)',
134 (r'(\s*?)(\d+)(.*?\n)',
135 bygroups(Generic.Whitespace, Literal.Number.Integer, Other)),
135 bygroups(Generic.Whitespace, Literal.Number.Integer, Other)),
136 # Emphasized line: (Arrow)(Line Number)(Python Code)
136 # Emphasized line: (Arrow)(Line Number)(Python Code)
137 # Using Exception token so arrow color matches the Exception.
137 # Using Exception token so arrow color matches the Exception.
138 (r'(-*>?\s?)(\d+)(.*?\n)',
138 (r'(-*>?\s?)(\d+)(.*?\n)',
139 bygroups(Name.Exception, Literal.Number.Integer, Other)),
139 bygroups(Name.Exception, Literal.Number.Integer, Other)),
140 # (Exception Identifier)(Message)
140 # (Exception Identifier)(Message)
141 (r'(?u)(^[^\d\W]\w*)(:.*?\n)',
141 (r'(?u)(^[^\d\W]\w*)(:.*?\n)',
142 bygroups(Name.Exception, Text)),
142 bygroups(Name.Exception, Text)),
143 # Tag everything else as Other, will be handled later.
143 # Tag everything else as Other, will be handled later.
144 (r'.*\n', Other),
144 (r'.*\n', Other),
145 ],
145 ],
146 }
146 }
147
147
148
148
149 class IPythonTracebackLexer(DelegatingLexer):
149 class IPythonTracebackLexer(DelegatingLexer):
150 """
150 """
151 IPython traceback lexer.
151 IPython traceback lexer.
152
152
153 For doctests, the tracebacks can be snipped as much as desired with the
153 For doctests, the tracebacks can be snipped as much as desired with the
154 exception to the lines that designate a traceback. For non-syntax error
154 exception to the lines that designate a traceback. For non-syntax error
155 tracebacks, this is the line of hyphens. For syntax error tracebacks,
155 tracebacks, this is the line of hyphens. For syntax error tracebacks,
156 this is the line which lists the File and line number.
156 this is the line which lists the File and line number.
157
157
158 """
158 """
159 # The lexer inherits from DelegatingLexer. The "root" lexer is an
159 # The lexer inherits from DelegatingLexer. The "root" lexer is an
160 # appropriate IPython lexer, which depends on the value of the boolean
160 # appropriate IPython lexer, which depends on the value of the boolean
161 # `python3`. First, we parse with the partial IPython traceback lexer.
161 # `python3`. First, we parse with the partial IPython traceback lexer.
162 # Then, any code marked with the "Other" token is delegated to the root
162 # Then, any code marked with the "Other" token is delegated to the root
163 # lexer.
163 # lexer.
164 #
164 #
165 name = 'IPython Traceback'
165 name = 'IPython Traceback'
166 aliases = ['ipythontb']
166 aliases = ['ipythontb']
167
167
168 def __init__(self, **options):
168 def __init__(self, **options):
169 self.python3 = get_bool_opt(options, 'python3', False)
169 self.python3 = get_bool_opt(options, 'python3', False)
170 if self.python3:
170 if self.python3:
171 self.aliases = ['ipython3tb']
171 self.aliases = ['ipython3tb']
172 else:
172 else:
173 self.aliases = ['ipython2tb', 'ipythontb']
173 self.aliases = ['ipython2tb', 'ipythontb']
174
174
175 if self.python3:
175 if self.python3:
176 IPyLexer = IPython3Lexer
176 IPyLexer = IPython3Lexer
177 else:
177 else:
178 IPyLexer = IPythonLexer
178 IPyLexer = IPythonLexer
179
179
180 DelegatingLexer.__init__(self, IPyLexer,
180 DelegatingLexer.__init__(self, IPyLexer,
181 IPythonPartialTracebackLexer, **options)
181 IPythonPartialTracebackLexer, **options)
182
182
183 @skip_doctest
183 @skip_doctest
184 class IPythonConsoleLexer(Lexer):
184 class IPythonConsoleLexer(Lexer):
185 """
185 """
186 An IPython console lexer for IPython code-blocks and doctests, such as:
186 An IPython console lexer for IPython code-blocks and doctests, such as:
187
187
188 .. code-block:: rst
188 .. code-block:: rst
189
189
190 .. code-block:: ipythonconsole
190 .. code-block:: ipythonconsole
191
191
192 In [1]: a = 'foo'
192 In [1]: a = 'foo'
193
193
194 In [2]: a
194 In [2]: a
195 Out[2]: 'foo'
195 Out[2]: 'foo'
196
196
197 In [3]: print a
197 In [3]: print a
198 foo
198 foo
199
199
200 In [4]: 1 / 0
200 In [4]: 1 / 0
201
201
202
202
203 Support is also provided for IPython exceptions:
203 Support is also provided for IPython exceptions:
204
204
205 .. code-block:: rst
205 .. code-block:: rst
206
206
207 .. code-block:: ipythonconsole
207 .. code-block:: ipythonconsole
208
208
209 In [1]: raise Exception
209 In [1]: raise Exception
210
210
211 ---------------------------------------------------------------------------
211 ---------------------------------------------------------------------------
212 Exception Traceback (most recent call last)
212 Exception Traceback (most recent call last)
213 <ipython-input-1-fca2ab0ca76b> in <module>()
213 <ipython-input-1-fca2ab0ca76b> in <module>()
214 ----> 1 raise Exception
214 ----> 1 raise Exception
215
215
216 Exception:
216 Exception:
217
217
218 """
218 """
219 name = 'IPython console session'
219 name = 'IPython console session'
220 aliases = ['ipythonconsole']
220 aliases = ['ipythonconsole']
221 mimetypes = ['text/x-ipython-console']
221 mimetypes = ['text/x-ipython-console']
222
222
223 # The regexps used to determine what is input and what is output.
223 # The regexps used to determine what is input and what is output.
224 # The default prompts for IPython are:
224 # The default prompts for IPython are:
225 #
225 #
226 # c.PromptManager.in_template = 'In [\#]: '
226 # c.PromptManager.in_template = 'In [\#]: '
227 # c.PromptManager.in2_template = ' .\D.: '
227 # c.PromptManager.in2_template = ' .\D.: '
228 # c.PromptManager.out_template = 'Out[\#]: '
228 # c.PromptManager.out_template = 'Out[\#]: '
229 #
229 #
230 in1_regex = r'In \[[0-9]+\]: '
230 in1_regex = r'In \[[0-9]+\]: '
231 in2_regex = r' \.\.+\.: '
231 in2_regex = r' \.\.+\.: '
232 out_regex = r'Out\[[0-9]+\]: '
232 out_regex = r'Out\[[0-9]+\]: '
233
233
234 #: The regex to determine when a traceback starts.
234 #: The regex to determine when a traceback starts.
235 ipytb_start = re.compile(r'^(\^C)?(-+\n)|^( File)(.*)(, line )(\d+\n)')
235 ipytb_start = re.compile(r'^(\^C)?(-+\n)|^( File)(.*)(, line )(\d+\n)')
236
236
237 def __init__(self, **options):
237 def __init__(self, **options):
238 """Initialize the IPython console lexer.
238 """Initialize the IPython console lexer.
239
239
240 Parameters
240 Parameters
241 ----------
241 ----------
242 python3 : bool
242 python3 : bool
243 If `True`, then the console inputs are parsed using a Python 3
243 If `True`, then the console inputs are parsed using a Python 3
244 lexer. Otherwise, they are parsed using a Python 2 lexer.
244 lexer. Otherwise, they are parsed using a Python 2 lexer.
245 in1_regex : RegexObject
245 in1_regex : RegexObject
246 The compiled regular expression used to detect the start
246 The compiled regular expression used to detect the start
247 of inputs. Although the IPython configuration setting may have a
247 of inputs. Although the IPython configuration setting may have a
248 trailing whitespace, do not include it in the regex. If `None`,
248 trailing whitespace, do not include it in the regex. If `None`,
249 then the default input prompt is assumed.
249 then the default input prompt is assumed.
250 in2_regex : RegexObject
250 in2_regex : RegexObject
251 The compiled regular expression used to detect the continuation
251 The compiled regular expression used to detect the continuation
252 of inputs. Although the IPython configuration setting may have a
252 of inputs. Although the IPython configuration setting may have a
253 trailing whitespace, do not include it in the regex. If `None`,
253 trailing whitespace, do not include it in the regex. If `None`,
254 then the default input prompt is assumed.
254 then the default input prompt is assumed.
255 out_regex : RegexObject
255 out_regex : RegexObject
256 The compiled regular expression used to detect outputs. If `None`,
256 The compiled regular expression used to detect outputs. If `None`,
257 then the default output prompt is assumed.
257 then the default output prompt is assumed.
258
258
259 """
259 """
260 self.python3 = get_bool_opt(options, 'python3', False)
260 self.python3 = get_bool_opt(options, 'python3', False)
261 if self.python3:
261 if self.python3:
262 self.aliases = ['ipython3console']
262 self.aliases = ['ipython3console']
263 else:
263 else:
264 self.aliases = ['ipython2console', 'ipythonconsole']
264 self.aliases = ['ipython2console', 'ipythonconsole']
265
265
266 in1_regex = options.get('in1_regex', self.in1_regex)
266 in1_regex = options.get('in1_regex', self.in1_regex)
267 in2_regex = options.get('in2_regex', self.in2_regex)
267 in2_regex = options.get('in2_regex', self.in2_regex)
268 out_regex = options.get('out_regex', self.out_regex)
268 out_regex = options.get('out_regex', self.out_regex)
269
269
270 # So that we can work with input and output prompts which have been
270 # So that we can work with input and output prompts which have been
271 # rstrip'd (possibly by editors) we also need rstrip'd variants. If
271 # rstrip'd (possibly by editors) we also need rstrip'd variants. If
272 # we do not do this, then such prompts will be tagged as 'output'.
272 # we do not do this, then such prompts will be tagged as 'output'.
273 # The reason can't just use the rstrip'd variants instead is because
273 # The reason can't just use the rstrip'd variants instead is because
274 # we want any whitespace associated with the prompt to be inserted
274 # we want any whitespace associated with the prompt to be inserted
275 # with the token. This allows formatted code to be modified so as hide
275 # with the token. This allows formatted code to be modified so as hide
276 # the appearance of prompts, with the whitespace included. One example
276 # the appearance of prompts, with the whitespace included. One example
277 # use of this is in copybutton.js from the standard lib Python docs.
277 # use of this is in copybutton.js from the standard lib Python docs.
278 in1_regex_rstrip = in1_regex.rstrip() + '\n'
278 in1_regex_rstrip = in1_regex.rstrip() + '\n'
279 in2_regex_rstrip = in2_regex.rstrip() + '\n'
279 in2_regex_rstrip = in2_regex.rstrip() + '\n'
280 out_regex_rstrip = out_regex.rstrip() + '\n'
280 out_regex_rstrip = out_regex.rstrip() + '\n'
281
281
282 # Compile and save them all.
282 # Compile and save them all.
283 attrs = ['in1_regex', 'in2_regex', 'out_regex',
283 attrs = ['in1_regex', 'in2_regex', 'out_regex',
284 'in1_regex_rstrip', 'in2_regex_rstrip', 'out_regex_rstrip']
284 'in1_regex_rstrip', 'in2_regex_rstrip', 'out_regex_rstrip']
285 for attr in attrs:
285 for attr in attrs:
286 self.__setattr__(attr, re.compile(locals()[attr]))
286 self.__setattr__(attr, re.compile(locals()[attr]))
287
287
288 Lexer.__init__(self, **options)
288 Lexer.__init__(self, **options)
289
289
290 if self.python3:
290 if self.python3:
291 pylexer = IPython3Lexer
291 pylexer = IPython3Lexer
292 tblexer = IPythonTracebackLexer
292 tblexer = IPythonTracebackLexer
293 else:
293 else:
294 pylexer = IPythonLexer
294 pylexer = IPythonLexer
295 tblexer = IPythonTracebackLexer
295 tblexer = IPythonTracebackLexer
296
296
297 self.pylexer = pylexer(**options)
297 self.pylexer = pylexer(**options)
298 self.tblexer = tblexer(**options)
298 self.tblexer = tblexer(**options)
299
299
300 self.reset()
300 self.reset()
301
301
302 def reset(self):
302 def reset(self):
303 self.mode = 'output'
303 self.mode = 'output'
304 self.index = 0
304 self.index = 0
305 self.buffer = u''
305 self.buffer = u''
306 self.insertions = []
306 self.insertions = []
307
307
308 def buffered_tokens(self):
308 def buffered_tokens(self):
309 """
309 """
310 Generator of unprocessed tokens after doing insertions and before
310 Generator of unprocessed tokens after doing insertions and before
311 changing to a new state.
311 changing to a new state.
312
312
313 """
313 """
314 if self.mode == 'output':
314 if self.mode == 'output':
315 tokens = [(0, Generic.Output, self.buffer)]
315 tokens = [(0, Generic.Output, self.buffer)]
316 elif self.mode == 'input':
316 elif self.mode == 'input':
317 tokens = self.pylexer.get_tokens_unprocessed(self.buffer)
317 tokens = self.pylexer.get_tokens_unprocessed(self.buffer)
318 else: # traceback
318 else: # traceback
319 tokens = self.tblexer.get_tokens_unprocessed(self.buffer)
319 tokens = self.tblexer.get_tokens_unprocessed(self.buffer)
320
320
321 for i, t, v in do_insertions(self.insertions, tokens):
321 for i, t, v in do_insertions(self.insertions, tokens):
322 # All token indexes are relative to the buffer.
322 # All token indexes are relative to the buffer.
323 yield self.index + i, t, v
323 yield self.index + i, t, v
324
324
325 # Clear it all
325 # Clear it all
326 self.index += len(self.buffer)
326 self.index += len(self.buffer)
327 self.buffer = u''
327 self.buffer = u''
328 self.insertions = []
328 self.insertions = []
329
329
330 def get_mci(self, line):
330 def get_mci(self, line):
331 """
331 """
332 Parses the line and returns a 3-tuple: (mode, code, insertion).
332 Parses the line and returns a 3-tuple: (mode, code, insertion).
333
333
334 `mode` is the next mode (or state) of the lexer, and is always equal
334 `mode` is the next mode (or state) of the lexer, and is always equal
335 to 'input', 'output', or 'tb'.
335 to 'input', 'output', or 'tb'.
336
336
337 `code` is a portion of the line that should be added to the buffer
337 `code` is a portion of the line that should be added to the buffer
338 corresponding to the next mode and eventually lexed by another lexer.
338 corresponding to the next mode and eventually lexed by another lexer.
339 For example, `code` could be Python code if `mode` were 'input'.
339 For example, `code` could be Python code if `mode` were 'input'.
340
340
341 `insertion` is a 3-tuple (index, token, text) representing an
341 `insertion` is a 3-tuple (index, token, text) representing an
342 unprocessed "token" that will be inserted into the stream of tokens
342 unprocessed "token" that will be inserted into the stream of tokens
343 that are created from the buffer once we change modes. This is usually
343 that are created from the buffer once we change modes. This is usually
344 the input or output prompt.
344 the input or output prompt.
345
345
346 In general, the next mode depends on current mode and on the contents
346 In general, the next mode depends on current mode and on the contents
347 of `line`.
347 of `line`.
348
348
349 """
349 """
350 # To reduce the number of regex match checks, we have multiple
350 # To reduce the number of regex match checks, we have multiple
351 # 'if' blocks instead of 'if-elif' blocks.
351 # 'if' blocks instead of 'if-elif' blocks.
352
352
353 # Check for possible end of input
353 # Check for possible end of input
354 in2_match = self.in2_regex.match(line)
354 in2_match = self.in2_regex.match(line)
355 in2_match_rstrip = self.in2_regex_rstrip.match(line)
355 in2_match_rstrip = self.in2_regex_rstrip.match(line)
356 if (in2_match and in2_match.group().rstrip() == line.rstrip()) or \
356 if (in2_match and in2_match.group().rstrip() == line.rstrip()) or \
357 in2_match_rstrip:
357 in2_match_rstrip:
358 end_input = True
358 end_input = True
359 else:
359 else:
360 end_input = False
360 end_input = False
361 if end_input and self.mode != 'tb':
361 if end_input and self.mode != 'tb':
362 # Only look for an end of input when not in tb mode.
362 # Only look for an end of input when not in tb mode.
363 # An ellipsis could appear within the traceback.
363 # An ellipsis could appear within the traceback.
364 mode = 'output'
364 mode = 'output'
365 code = u''
365 code = u''
366 insertion = (0, Generic.Prompt, line)
366 insertion = (0, Generic.Prompt, line)
367 return mode, code, insertion
367 return mode, code, insertion
368
368
369 # Check for output prompt
369 # Check for output prompt
370 out_match = self.out_regex.match(line)
370 out_match = self.out_regex.match(line)
371 out_match_rstrip = self.out_regex_rstrip.match(line)
371 out_match_rstrip = self.out_regex_rstrip.match(line)
372 if out_match or out_match_rstrip:
372 if out_match or out_match_rstrip:
373 mode = 'output'
373 mode = 'output'
374 if out_match:
374 if out_match:
375 idx = out_match.end()
375 idx = out_match.end()
376 else:
376 else:
377 idx = out_match_rstrip.end()
377 idx = out_match_rstrip.end()
378 code = line[idx:]
378 code = line[idx:]
379 # Use the 'heading' token for output. We cannot use Generic.Error
379 # Use the 'heading' token for output. We cannot use Generic.Error
380 # since it would conflict with exceptions.
380 # since it would conflict with exceptions.
381 insertion = (0, Generic.Heading, line[:idx])
381 insertion = (0, Generic.Heading, line[:idx])
382 return mode, code, insertion
382 return mode, code, insertion
383
383
384
384
385 # Check for input or continuation prompt (non stripped version)
385 # Check for input or continuation prompt (non stripped version)
386 in1_match = self.in1_regex.match(line)
386 in1_match = self.in1_regex.match(line)
387 if in1_match or (in2_match and self.mode != 'tb'):
387 if in1_match or (in2_match and self.mode != 'tb'):
388 # New input or when not in tb, continued input.
388 # New input or when not in tb, continued input.
389 # We do not check for continued input when in tb since it is
389 # We do not check for continued input when in tb since it is
390 # allowable to replace a long stack with an ellipsis.
390 # allowable to replace a long stack with an ellipsis.
391 mode = 'input'
391 mode = 'input'
392 if in1_match:
392 if in1_match:
393 idx = in1_match.end()
393 idx = in1_match.end()
394 else: # in2_match
394 else: # in2_match
395 idx = in2_match.end()
395 idx = in2_match.end()
396 code = line[idx:]
396 code = line[idx:]
397 insertion = (0, Generic.Prompt, line[:idx])
397 insertion = (0, Generic.Prompt, line[:idx])
398 return mode, code, insertion
398 return mode, code, insertion
399
399
400 # Check for input or continuation prompt (stripped version)
400 # Check for input or continuation prompt (stripped version)
401 in1_match_rstrip = self.in1_regex_rstrip.match(line)
401 in1_match_rstrip = self.in1_regex_rstrip.match(line)
402 if in1_match_rstrip or (in2_match_rstrip and self.mode != 'tb'):
402 if in1_match_rstrip or (in2_match_rstrip and self.mode != 'tb'):
403 # New input or when not in tb, continued input.
403 # New input or when not in tb, continued input.
404 # We do not check for continued input when in tb since it is
404 # We do not check for continued input when in tb since it is
405 # allowable to replace a long stack with an ellipsis.
405 # allowable to replace a long stack with an ellipsis.
406 mode = 'input'
406 mode = 'input'
407 if in1_match_rstrip:
407 if in1_match_rstrip:
408 idx = in1_match_rstrip.end()
408 idx = in1_match_rstrip.end()
409 else: # in2_match
409 else: # in2_match
410 idx = in2_match_rstrip.end()
410 idx = in2_match_rstrip.end()
411 code = line[idx:]
411 code = line[idx:]
412 insertion = (0, Generic.Prompt, line[:idx])
412 insertion = (0, Generic.Prompt, line[:idx])
413 return mode, code, insertion
413 return mode, code, insertion
414
414
415 # Check for traceback
415 # Check for traceback
416 if self.ipytb_start.match(line):
416 if self.ipytb_start.match(line):
417 mode = 'tb'
417 mode = 'tb'
418 code = line
418 code = line
419 insertion = None
419 insertion = None
420 return mode, code, insertion
420 return mode, code, insertion
421
421
422 # All other stuff...
422 # All other stuff...
423 if self.mode in ('input', 'output'):
423 if self.mode in ('input', 'output'):
424 # We assume all other text is output. Multiline input that
424 # We assume all other text is output. Multiline input that
425 # does not use the continuation marker cannot be detected.
425 # does not use the continuation marker cannot be detected.
426 # For example, the 3 in the following is clearly output:
426 # For example, the 3 in the following is clearly output:
427 #
427 #
428 # In [1]: print 3
428 # In [1]: print 3
429 # 3
429 # 3
430 #
430 #
431 # But the following second line is part of the input:
431 # But the following second line is part of the input:
432 #
432 #
433 # In [2]: while True:
433 # In [2]: while True:
434 # print True
434 # print True
435 #
435 #
436 # In both cases, the 2nd line will be 'output'.
436 # In both cases, the 2nd line will be 'output'.
437 #
437 #
438 mode = 'output'
438 mode = 'output'
439 else:
439 else:
440 mode = 'tb'
440 mode = 'tb'
441
441
442 code = line
442 code = line
443 insertion = None
443 insertion = None
444
444
445 return mode, code, insertion
445 return mode, code, insertion
446
446
447 def get_tokens_unprocessed(self, text):
447 def get_tokens_unprocessed(self, text):
448 self.reset()
448 self.reset()
449 for match in line_re.finditer(text):
449 for match in line_re.finditer(text):
450 line = match.group()
450 line = match.group()
451 mode, code, insertion = self.get_mci(line)
451 mode, code, insertion = self.get_mci(line)
452
452
453 if mode != self.mode:
453 if mode != self.mode:
454 # Yield buffered tokens before transitioning to new mode.
454 # Yield buffered tokens before transitioning to new mode.
455 for token in self.buffered_tokens():
455 for token in self.buffered_tokens():
456 yield token
456 yield token
457 self.mode = mode
457 self.mode = mode
458
458
459 if insertion:
459 if insertion:
460 self.insertions.append((len(self.buffer), [insertion]))
460 self.insertions.append((len(self.buffer), [insertion]))
461 self.buffer += code
461 self.buffer += code
462 else:
462 else:
463 for token in self.buffered_tokens():
463 for token in self.buffered_tokens():
464 yield token
464 yield token
465
465
466 class IPyLexer(Lexer):
466 class IPyLexer(Lexer):
467 """
467 """
468 Primary lexer for all IPython-like code.
468 Primary lexer for all IPython-like code.
469
469
470 This is a simple helper lexer. If the first line of the text begins with
470 This is a simple helper lexer. If the first line of the text begins with
471 "In \[[0-9]+\]:", then the entire text is parsed with an IPython console
471 "In \[[0-9]+\]:", then the entire text is parsed with an IPython console
472 lexer. If not, then the entire text is parsed with an IPython lexer.
472 lexer. If not, then the entire text is parsed with an IPython lexer.
473
473
474 The goal is to reduce the number of lexers that are registered
474 The goal is to reduce the number of lexers that are registered
475 with Pygments.
475 with Pygments.
476
476
477 """
477 """
478 name = 'IPy session'
478 name = 'IPy session'
479 aliases = ['ipy']
479 aliases = ['ipy']
480
480
481 def __init__(self, **options):
481 def __init__(self, **options):
482 self.python3 = get_bool_opt(options, 'python3', False)
482 self.python3 = get_bool_opt(options, 'python3', False)
483 if self.python3:
483 if self.python3:
484 self.aliases = ['ipy3']
484 self.aliases = ['ipy3']
485 else:
485 else:
486 self.aliases = ['ipy2', 'ipy']
486 self.aliases = ['ipy2', 'ipy']
487
487
488 Lexer.__init__(self, **options)
488 Lexer.__init__(self, **options)
489
489
490 self.IPythonLexer = IPythonLexer(**options)
490 self.IPythonLexer = IPythonLexer(**options)
491 self.IPythonConsoleLexer = IPythonConsoleLexer(**options)
491 self.IPythonConsoleLexer = IPythonConsoleLexer(**options)
492
492
493 def get_tokens_unprocessed(self, text):
493 def get_tokens_unprocessed(self, text):
494 # Search for the input prompt anywhere...this allows code blocks to
494 # Search for the input prompt anywhere...this allows code blocks to
495 # begin with comments as well.
495 # begin with comments as well.
496 if re.match(r'.*(In \[[0-9]+\]:)', text.strip(), re.DOTALL):
496 if re.match(r'.*(In \[[0-9]+\]:)', text.strip(), re.DOTALL):
497 lex = self.IPythonConsoleLexer
497 lex = self.IPythonConsoleLexer
498 else:
498 else:
499 lex = self.IPythonLexer
499 lex = self.IPythonLexer
500 for token in lex.get_tokens_unprocessed(text):
500 for token in lex.get_tokens_unprocessed(text):
501 yield token
501 yield token
502
502
@@ -1,332 +1,339 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 import shutil
45 import shutil
46
46
47 from glob import glob
47 from glob import glob
48
48
49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 # update it when the contents of directories change.
50 # update it when the contents of directories change.
51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52
52
53 from distutils.core import setup
53 from distutils.core import setup
54
54
55 # Our own imports
55 # Our own imports
56 from setupbase import target_update
56 from setupbase import target_update
57
57
58 from setupbase import (
58 from setupbase import (
59 setup_args,
59 setup_args,
60 find_packages,
60 find_packages,
61 find_package_data,
61 find_package_data,
62 check_package_data_first,
62 check_package_data_first,
63 find_entry_points,
63 find_entry_points,
64 build_scripts_entrypt,
64 build_scripts_entrypt,
65 find_data_files,
65 find_data_files,
66 check_for_dependencies,
66 check_for_dependencies,
67 git_prebuild,
67 git_prebuild,
68 check_submodule_status,
68 check_submodule_status,
69 update_submodules,
69 update_submodules,
70 require_submodules,
70 require_submodules,
71 UpdateSubmodules,
71 UpdateSubmodules,
72 get_bdist_wheel,
72 get_bdist_wheel,
73 CompileCSS,
73 CompileCSS,
74 JavascriptVersion,
74 JavascriptVersion,
75 css_js_prerelease,
75 css_js_prerelease,
76 install_symlinked,
76 install_symlinked,
77 install_lib_symlink,
77 install_lib_symlink,
78 install_scripts_for_symlink,
78 install_scripts_for_symlink,
79 unsymlink,
79 unsymlink,
80 )
80 )
81 from setupext import setupext
81 from setupext import setupext
82
82
83 isfile = os.path.isfile
83 isfile = os.path.isfile
84 pjoin = os.path.join
84 pjoin = os.path.join
85
85
86 #-------------------------------------------------------------------------------
86 #-------------------------------------------------------------------------------
87 # Handle OS specific things
87 # Handle OS specific things
88 #-------------------------------------------------------------------------------
88 #-------------------------------------------------------------------------------
89
89
90 if os.name in ('nt','dos'):
90 if os.name in ('nt','dos'):
91 os_name = 'windows'
91 os_name = 'windows'
92 else:
92 else:
93 os_name = os.name
93 os_name = os.name
94
94
95 # Under Windows, 'sdist' has not been supported. Now that the docs build with
95 # Under Windows, 'sdist' has not been supported. Now that the docs build with
96 # Sphinx it might work, but let's not turn it on until someone confirms that it
96 # Sphinx it might work, but let's not turn it on until someone confirms that it
97 # actually works.
97 # actually works.
98 if os_name == 'windows' and 'sdist' in sys.argv:
98 if os_name == 'windows' and 'sdist' in sys.argv:
99 print('The sdist command is not available under Windows. Exiting.')
99 print('The sdist command is not available under Windows. Exiting.')
100 sys.exit(1)
100 sys.exit(1)
101
101
102 #-------------------------------------------------------------------------------
102 #-------------------------------------------------------------------------------
103 # Make sure we aren't trying to run without submodules
103 # Make sure we aren't trying to run without submodules
104 #-------------------------------------------------------------------------------
104 #-------------------------------------------------------------------------------
105 here = os.path.abspath(os.path.dirname(__file__))
105 here = os.path.abspath(os.path.dirname(__file__))
106
106
107 def require_clean_submodules():
107 def require_clean_submodules():
108 """Check on git submodules before distutils can do anything
108 """Check on git submodules before distutils can do anything
109
109
110 Since distutils cannot be trusted to update the tree
110 Since distutils cannot be trusted to update the tree
111 after everything has been set in motion,
111 after everything has been set in motion,
112 this is not a distutils command.
112 this is not a distutils command.
113 """
113 """
114 # PACKAGERS: Add a return here to skip checks for git submodules
114 # PACKAGERS: Add a return here to skip checks for git submodules
115
115
116 # don't do anything if nothing is actually supposed to happen
116 # don't do anything if nothing is actually supposed to happen
117 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
117 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
118 if do_nothing in sys.argv:
118 if do_nothing in sys.argv:
119 return
119 return
120
120
121 status = check_submodule_status(here)
121 status = check_submodule_status(here)
122
122
123 if status == "missing":
123 if status == "missing":
124 print("checking out submodules for the first time")
124 print("checking out submodules for the first time")
125 update_submodules(here)
125 update_submodules(here)
126 elif status == "unclean":
126 elif status == "unclean":
127 print('\n'.join([
127 print('\n'.join([
128 "Cannot build / install IPython with unclean submodules",
128 "Cannot build / install IPython with unclean submodules",
129 "Please update submodules with",
129 "Please update submodules with",
130 " python setup.py submodule",
130 " python setup.py submodule",
131 "or",
131 "or",
132 " git submodule update",
132 " git submodule update",
133 "or commit any submodule changes you have made."
133 "or commit any submodule changes you have made."
134 ]))
134 ]))
135 sys.exit(1)
135 sys.exit(1)
136
136
137 require_clean_submodules()
137 require_clean_submodules()
138
138
139 #-------------------------------------------------------------------------------
139 #-------------------------------------------------------------------------------
140 # Things related to the IPython documentation
140 # Things related to the IPython documentation
141 #-------------------------------------------------------------------------------
141 #-------------------------------------------------------------------------------
142
142
143 # update the manuals when building a source dist
143 # update the manuals when building a source dist
144 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
144 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
145
145
146 # List of things to be updated. Each entry is a triplet of args for
146 # List of things to be updated. Each entry is a triplet of args for
147 # target_update()
147 # target_update()
148 to_update = [
148 to_update = [
149 # FIXME - Disabled for now: we need to redo an automatic way
149 # FIXME - Disabled for now: we need to redo an automatic way
150 # of generating the magic info inside the rst.
150 # of generating the magic info inside the rst.
151 #('docs/magic.tex',
151 #('docs/magic.tex',
152 #['IPython/Magic.py'],
152 #['IPython/Magic.py'],
153 #"cd doc && ./update_magic.sh" ),
153 #"cd doc && ./update_magic.sh" ),
154
154
155 ('docs/man/ipcluster.1.gz',
155 ('docs/man/ipcluster.1.gz',
156 ['docs/man/ipcluster.1'],
156 ['docs/man/ipcluster.1'],
157 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
157 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
158
158
159 ('docs/man/ipcontroller.1.gz',
159 ('docs/man/ipcontroller.1.gz',
160 ['docs/man/ipcontroller.1'],
160 ['docs/man/ipcontroller.1'],
161 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
161 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
162
162
163 ('docs/man/ipengine.1.gz',
163 ('docs/man/ipengine.1.gz',
164 ['docs/man/ipengine.1'],
164 ['docs/man/ipengine.1'],
165 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
165 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
166
166
167 ('docs/man/ipython.1.gz',
167 ('docs/man/ipython.1.gz',
168 ['docs/man/ipython.1'],
168 ['docs/man/ipython.1'],
169 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
169 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
170
170
171 ]
171 ]
172
172
173
173
174 [ target_update(*t) for t in to_update ]
174 [ target_update(*t) for t in to_update ]
175
175
176 #---------------------------------------------------------------------------
176 #---------------------------------------------------------------------------
177 # Find all the packages, package data, and data_files
177 # Find all the packages, package data, and data_files
178 #---------------------------------------------------------------------------
178 #---------------------------------------------------------------------------
179
179
180 packages = find_packages()
180 packages = find_packages()
181 package_data = find_package_data()
181 package_data = find_package_data()
182
182
183 data_files = find_data_files()
183 data_files = find_data_files()
184
184
185 setup_args['packages'] = packages
185 setup_args['packages'] = packages
186 setup_args['package_data'] = package_data
186 setup_args['package_data'] = package_data
187 setup_args['data_files'] = data_files
187 setup_args['data_files'] = data_files
188
188
189 #---------------------------------------------------------------------------
189 #---------------------------------------------------------------------------
190 # custom distutils commands
190 # custom distutils commands
191 #---------------------------------------------------------------------------
191 #---------------------------------------------------------------------------
192 # imports here, so they are after setuptools import if there was one
192 # imports here, so they are after setuptools import if there was one
193 from distutils.command.sdist import sdist
193 from distutils.command.sdist import sdist
194 from distutils.command.upload import upload
194 from distutils.command.upload import upload
195
195
196 class UploadWindowsInstallers(upload):
196 class UploadWindowsInstallers(upload):
197
197
198 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
198 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
199 user_options = upload.user_options + [
199 user_options = upload.user_options + [
200 ('files=', 'f', 'exe file (or glob) to upload')
200 ('files=', 'f', 'exe file (or glob) to upload')
201 ]
201 ]
202 def initialize_options(self):
202 def initialize_options(self):
203 upload.initialize_options(self)
203 upload.initialize_options(self)
204 meta = self.distribution.metadata
204 meta = self.distribution.metadata
205 base = '{name}-{version}'.format(
205 base = '{name}-{version}'.format(
206 name=meta.get_name(),
206 name=meta.get_name(),
207 version=meta.get_version()
207 version=meta.get_version()
208 )
208 )
209 self.files = os.path.join('dist', '%s.*.exe' % base)
209 self.files = os.path.join('dist', '%s.*.exe' % base)
210
210
211 def run(self):
211 def run(self):
212 for dist_file in glob(self.files):
212 for dist_file in glob(self.files):
213 self.upload_file('bdist_wininst', 'any', dist_file)
213 self.upload_file('bdist_wininst', 'any', dist_file)
214
214
215 setup_args['cmdclass'] = {
215 setup_args['cmdclass'] = {
216 'build_py': css_js_prerelease(
216 'build_py': css_js_prerelease(
217 check_package_data_first(git_prebuild('IPython'))),
217 check_package_data_first(git_prebuild('IPython'))),
218 'sdist' : css_js_prerelease(git_prebuild('IPython', sdist)),
218 'sdist' : css_js_prerelease(git_prebuild('IPython', sdist)),
219 'upload_wininst' : UploadWindowsInstallers,
219 'upload_wininst' : UploadWindowsInstallers,
220 'submodule' : UpdateSubmodules,
220 'submodule' : UpdateSubmodules,
221 'css' : CompileCSS,
221 'css' : CompileCSS,
222 'symlink': install_symlinked,
222 'symlink': install_symlinked,
223 'install_lib_symlink': install_lib_symlink,
223 'install_lib_symlink': install_lib_symlink,
224 'install_scripts_sym': install_scripts_for_symlink,
224 'install_scripts_sym': install_scripts_for_symlink,
225 'unsymlink': unsymlink,
225 'unsymlink': unsymlink,
226 'jsversion' : JavascriptVersion,
226 'jsversion' : JavascriptVersion,
227 }
227 }
228
228
229 #---------------------------------------------------------------------------
229 #---------------------------------------------------------------------------
230 # Handle scripts, dependencies, and setuptools specific things
230 # Handle scripts, dependencies, and setuptools specific things
231 #---------------------------------------------------------------------------
231 #---------------------------------------------------------------------------
232
232
233 # For some commands, use setuptools. Note that we do NOT list install here!
233 # For some commands, use setuptools. Note that we do NOT list install here!
234 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
234 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
235 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
235 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
236 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
236 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
237 'egg_info', 'easy_install', 'upload', 'install_egg_info',
237 'egg_info', 'easy_install', 'upload', 'install_egg_info',
238 ))
238 ))
239
239
240 if len(needs_setuptools.intersection(sys.argv)) > 0:
240 if len(needs_setuptools.intersection(sys.argv)) > 0:
241 import setuptools
241 import setuptools
242
242
243 # This dict is used for passing extra arguments that are setuptools
243 # This dict is used for passing extra arguments that are setuptools
244 # specific to setup
244 # specific to setup
245 setuptools_extra_args = {}
245 setuptools_extra_args = {}
246
246
247 # setuptools requirements
247 # setuptools requirements
248
248
249 extras_require = dict(
249 extras_require = dict(
250 parallel = ['pyzmq>=2.1.11'],
250 parallel = ['pyzmq>=2.1.11'],
251 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
251 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
252 zmq = ['pyzmq>=2.1.11'],
252 zmq = ['pyzmq>=2.1.11'],
253 doc = ['Sphinx>=1.1', 'numpydoc'],
253 doc = ['Sphinx>=1.1', 'numpydoc'],
254 test = ['nose>=0.10.1', 'requests'],
254 test = ['nose>=0.10.1', 'requests'],
255 terminal = [],
255 terminal = [],
256 nbformat = ['jsonschema>=2.0'],
256 nbformat = ['jsonschema>=2.0'],
257 notebook = ['tornado>=4.0', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.5'],
257 notebook = ['tornado>=4.0', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.5'],
258 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
258 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
259 )
259 )
260
260
261 if sys.version_info < (3, 3):
261 if sys.version_info < (3, 3):
262 extras_require['test'].append('mock')
262 extras_require['test'].append('mock')
263
263
264 extras_require['notebook'].extend(extras_require['nbformat'])
264 extras_require['notebook'].extend(extras_require['nbformat'])
265 extras_require['nbconvert'].extend(extras_require['nbformat'])
265 extras_require['nbconvert'].extend(extras_require['nbformat'])
266
266
267 everything = set()
267 everything = set()
268 for deps in extras_require.values():
268 for deps in extras_require.values():
269 everything.update(deps)
269 everything.update(deps)
270 extras_require['all'] = everything
270 extras_require['all'] = everything
271
271
272 install_requires = []
272 install_requires = []
273
273
274 # add readline
274 # add readline
275 if sys.platform == 'darwin':
275 if sys.platform == 'darwin':
276 if 'bdist_wheel' in sys.argv[1:] or not setupext.check_for_readline():
276 if 'bdist_wheel' in sys.argv[1:] or not setupext.check_for_readline():
277 install_requires.append('gnureadline')
277 install_requires.append('gnureadline')
278 elif sys.platform.startswith('win'):
278 elif sys.platform.startswith('win'):
279 extras_require['terminal'].append('pyreadline>=2.0')
279 extras_require['terminal'].append('pyreadline>=2.0')
280
280
281
281
282 if 'setuptools' in sys.modules:
282 if 'setuptools' in sys.modules:
283 # setup.py develop should check for submodules
283 # setup.py develop should check for submodules
284 from setuptools.command.develop import develop
284 from setuptools.command.develop import develop
285 setup_args['cmdclass']['develop'] = require_submodules(develop)
285 setup_args['cmdclass']['develop'] = require_submodules(develop)
286 setup_args['cmdclass']['bdist_wheel'] = css_js_prerelease(get_bdist_wheel())
286 setup_args['cmdclass']['bdist_wheel'] = css_js_prerelease(get_bdist_wheel())
287
287
288 setuptools_extra_args['zip_safe'] = False
288 setuptools_extra_args['zip_safe'] = False
289 setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()}
289 setuptools_extra_args['entry_points'] = {
290 'console_scripts': find_entry_points(),
291 'pygments.lexers': [
292 'ipythonconsole = IPython.nbconvert.utils.lexers:IPythonConsoleLexer',
293 'ipython = IPython.nbconvert.utils.lexers:IPythonLexer',
294 'ipython3 = IPython.nbconvert.utils.lexers:IPython3Lexer',
295 ],
296 }
290 setup_args['extras_require'] = extras_require
297 setup_args['extras_require'] = extras_require
291 requires = setup_args['install_requires'] = install_requires
298 requires = setup_args['install_requires'] = install_requires
292
299
293 # Script to be run by the windows binary installer after the default setup
300 # Script to be run by the windows binary installer after the default setup
294 # routine, to add shortcuts and similar windows-only things. Windows
301 # routine, to add shortcuts and similar windows-only things. Windows
295 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
302 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
296 # doesn't find them.
303 # doesn't find them.
297 if 'bdist_wininst' in sys.argv:
304 if 'bdist_wininst' in sys.argv:
298 if len(sys.argv) > 2 and \
305 if len(sys.argv) > 2 and \
299 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
306 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
300 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
307 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
301 sys.exit(1)
308 sys.exit(1)
302 setup_args['data_files'].append(
309 setup_args['data_files'].append(
303 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
310 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
304 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
311 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
305 setup_args['options'] = {"bdist_wininst":
312 setup_args['options'] = {"bdist_wininst":
306 {"install_script":
313 {"install_script":
307 "ipython_win_post_install.py"}}
314 "ipython_win_post_install.py"}}
308
315
309 else:
316 else:
310 # If we are installing without setuptools, call this function which will
317 # If we are installing without setuptools, call this function which will
311 # check for dependencies an inform the user what is needed. This is
318 # check for dependencies an inform the user what is needed. This is
312 # just to make life easy for users.
319 # just to make life easy for users.
313 for install_cmd in ('install', 'symlink'):
320 for install_cmd in ('install', 'symlink'):
314 if install_cmd in sys.argv:
321 if install_cmd in sys.argv:
315 check_for_dependencies()
322 check_for_dependencies()
316 break
323 break
317 # scripts has to be a non-empty list, or install_scripts isn't called
324 # scripts has to be a non-empty list, or install_scripts isn't called
318 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
325 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
319
326
320 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
327 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
321
328
322 #---------------------------------------------------------------------------
329 #---------------------------------------------------------------------------
323 # Do the actual setup now
330 # Do the actual setup now
324 #---------------------------------------------------------------------------
331 #---------------------------------------------------------------------------
325
332
326 setup_args.update(setuptools_extra_args)
333 setup_args.update(setuptools_extra_args)
327
334
328 def main():
335 def main():
329 setup(**setup_args)
336 setup(**setup_args)
330
337
331 if __name__ == '__main__':
338 if __name__ == '__main__':
332 main()
339 main()
General Comments 0
You need to be logged in to leave comments. Login now