##// END OF EJS Templates
Start refactoring handling of color....
Matthias Bussonnier -
Show More
@@ -239,7 +239,7 b' class Pdb(OldPdb, object):'
239 if color_scheme is not None:
239 if color_scheme is not None:
240 warnings.warn(
240 warnings.warn(
241 "The `color_scheme` argument is deprecated since version 5.1",
241 "The `color_scheme` argument is deprecated since version 5.1",
242 DeprecationWarning)
242 DeprecationWarning, stacklevel=2)
243 else:
243 else:
244 color_scheme = self.shell.colors
244 color_scheme = self.shell.colors
245
245
@@ -269,11 +269,11 b' class Pdb(OldPdb, object):'
269 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
269 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
270 cst['Neutral'].colors.breakpoint_disabled = C.Red
270 cst['Neutral'].colors.breakpoint_disabled = C.Red
271
271
272 self.set_colors(color_scheme)
273
272
274 # Add a python parser so we can syntax highlight source while
273 # Add a python parser so we can syntax highlight source while
275 # debugging.
274 # debugging.
276 self.parser = PyColorize.Parser()
275 self.parser = PyColorize.Parser(style=color_scheme)
276 self.set_colors(color_scheme)
277
277
278 # Set the prompt - the default prompt is '(Pdb)'
278 # Set the prompt - the default prompt is '(Pdb)'
279 self.prompt = prompt
279 self.prompt = prompt
@@ -281,6 +281,7 b' class Pdb(OldPdb, object):'
281 def set_colors(self, scheme):
281 def set_colors(self, scheme):
282 """Shorthand access to the color table scheme selector method."""
282 """Shorthand access to the color table scheme selector method."""
283 self.color_scheme_table.set_active_scheme(scheme)
283 self.color_scheme_table.set_active_scheme(scheme)
284 self.parser.style = scheme
284
285
285 def trace_dispatch(self, frame, event, arg):
286 def trace_dispatch(self, frame, event, arg):
286 try:
287 try:
@@ -451,9 +452,9 b' class Pdb(OldPdb, object):'
451 bp_mark = ""
452 bp_mark = ""
452 bp_mark_color = ""
453 bp_mark_color = ""
453
454
454 scheme = self.color_scheme_table.active_scheme_name
455 new_line, err = self.parser.format2(line, 'str')
455 new_line, err = self.parser.format2(line, 'str', scheme)
456 if not err:
456 if not err: line = new_line
457 line = new_line
457
458
458 bp = None
459 bp = None
459 if lineno in self.get_file_breaks(filename):
460 if lineno in self.get_file_breaks(filename):
@@ -473,10 +473,7 b' class InteractiveShell(SingletonConfigurable):'
473
473
474 # The following was in post_config_initialization
474 # The following was in post_config_initialization
475 self.init_inspector()
475 self.init_inspector()
476 if py3compat.PY3:
477 self.raw_input_original = input
476 self.raw_input_original = input
478 else:
479 self.raw_input_original = raw_input
480 self.init_completer()
477 self.init_completer()
481 # TODO: init_io() needs to happen before init_traceback handlers
478 # TODO: init_io() needs to happen before init_traceback handlers
482 # because the traceback handlers hardcode the stdout/stderr streams.
479 # because the traceback handlers hardcode the stdout/stderr streams.
@@ -577,10 +574,12 b' class InteractiveShell(SingletonConfigurable):'
577 except AttributeError:
574 except AttributeError:
578 self.stdin_encoding = 'ascii'
575 self.stdin_encoding = 'ascii'
579
576
580 def init_syntax_highlighting(self):
577
578 @observe('colors')
579 def init_syntax_highlighting(self, changes=None):
581 # Python source parser/formatter for syntax highlighting
580 # Python source parser/formatter for syntax highlighting
582 pyformat = PyColorize.Parser().format
581 pyformat = PyColorize.Parser(style=self.colors).format
583 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
582 self.pycolorize = lambda src: pyformat(src,'str')
584
583
585 def refresh_style(self):
584 def refresh_style(self):
586 # No-op here, used in subclass
585 # No-op here, used in subclass
@@ -132,7 +132,6 b' def test_unicode_completions():'
132 nt.assert_true(isinstance(text, string_types))
132 nt.assert_true(isinstance(text, string_types))
133 nt.assert_true(isinstance(matches, list))
133 nt.assert_true(isinstance(matches, list))
134
134
135 @dec.onlyif(sys.version_info[0] >= 3, 'This test only applies in Py>=3')
136 def test_latex_completions():
135 def test_latex_completions():
137 from IPython.core.latex_symbols import latex_symbols
136 from IPython.core.latex_symbols import latex_symbols
138 import random
137 import random
@@ -41,9 +41,14 b' ip = get_ipython()'
41 # updated. Do NOT insert any whitespace between the next line and the function
41 # updated. Do NOT insert any whitespace between the next line and the function
42 # definition below.
42 # definition below.
43 THIS_LINE_NUMBER = 43 # Put here the actual number of this line
43 THIS_LINE_NUMBER = 43 # Put here the actual number of this line
44 def test_find_source_lines():
44
45 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
45 from unittest import TestCase
46 THIS_LINE_NUMBER+1)
46
47 class Test(TestCase):
48
49 def test_find_source_lines(self):
50 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
51 THIS_LINE_NUMBER+6)
47
52
48
53
49 # A couple of utilities to ensure these tests work the same from a source or a
54 # A couple of utilities to ensure these tests work the same from a source or a
@@ -322,7 +327,7 b' def test_bool_raise():'
322
327
323 def test_info_serialliar():
328 def test_info_serialliar():
324 fib_tracker = [0]
329 fib_tracker = [0]
325 i = inspector.info(SerialLiar(fib_tracker))
330 inspector.info(SerialLiar(fib_tracker))
326
331
327 # Nested attribute access should be cut off at 100 levels deep to avoid
332 # Nested attribute access should be cut off at 100 levels deep to avoid
328 # infinite loops: https://github.com/ipython/ipython/issues/9122
333 # infinite loops: https://github.com/ipython/ipython/issues/9122
@@ -335,10 +340,9 b' def test_calldef_none():'
335 i = inspector.info(obj)
340 i = inspector.info(obj)
336 nt.assert_is(i['call_def'], None)
341 nt.assert_is(i['call_def'], None)
337
342
338 if py3compat.PY3:
343 def f_kwarg(pos, *, kwonly):
339 exec("def f_kwarg(pos, *, kwonly): pass")
344 pass
340
345
341 @skipif(not py3compat.PY3)
342 def test_definition_kwonlyargs():
346 def test_definition_kwonlyargs():
343 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
347 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
344 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
348 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
@@ -386,28 +386,18 b' def _fixed_getinnerframes(etb, context=1, tb_offset=0):'
386 # can be recognized properly by ipython.el's py-traceback-line-re
386 # can be recognized properly by ipython.el's py-traceback-line-re
387 # (SyntaxErrors have to be treated specially because they have no traceback)
387 # (SyntaxErrors have to be treated specially because they have no traceback)
388
388
389 _parser = PyColorize.Parser()
390
391
389
392 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
390 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
393 numbers_width = INDENT_SIZE - 1
391 numbers_width = INDENT_SIZE - 1
394 res = []
392 res = []
395 i = lnum - index
393 i = lnum - index
396
394
397 # This lets us get fully syntax-highlighted tracebacks.
395 _line_format = PyColorize.Parser(style=scheme).format2
398 if scheme is None:
399 ipinst = get_ipython()
400 if ipinst is not None:
401 scheme = ipinst.colors
402 else:
403 scheme = DEFAULT_SCHEME
404
405 _line_format = _parser.format2
406
396
407 for line in lines:
397 for line in lines:
408 line = py3compat.cast_unicode(line)
398 line = py3compat.cast_unicode(line)
409
399
410 new_line, err = _line_format(line, 'str', scheme)
400 new_line, err = _line_format(line, 'str')
411 if not err: line = new_line
401 if not err: line = new_line
412
402
413 if i == lnum:
403 if i == lnum:
@@ -1227,8 +1217,7 b' class VerboseTB(TBTools):'
1227
1217
1228 if force or self.call_pdb:
1218 if force or self.call_pdb:
1229 if self.pdb is None:
1219 if self.pdb is None:
1230 self.pdb = self.debugger_cls(
1220 self.pdb = self.debugger_cls()
1231 self.color_scheme_table.active_scheme_name)
1232 # the system displayhook may have changed, restore the original
1221 # the system displayhook may have changed, restore the original
1233 # for pdb
1222 # for pdb
1234 display_trap = DisplayTrap(hook=sys.__displayhook__)
1223 display_trap = DisplayTrap(hook=sys.__displayhook__)
@@ -185,6 +185,8 b' LightBGColors = ColorScheme('
185 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors, NeutralColors],
185 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors, NeutralColors],
186 _scheme_default)
186 _scheme_default)
187
187
188 Undefined = object()
189
188 class Parser(Colorable):
190 class Parser(Colorable):
189 """ Format colored Python source.
191 """ Format colored Python source.
190 """
192 """
@@ -199,11 +201,21 b' class Parser(Colorable):'
199
201
200 self.color_table = color_table and color_table or ANSICodeColors
202 self.color_table = color_table and color_table or ANSICodeColors
201 self.out = out
203 self.out = out
204 if not style:
205 self.style = self.default_style
206 else:
207 self.style = style
208
202
209
203 def format(self, raw, out = None, scheme = ''):
210 def format(self, raw, out=None, scheme=Undefined):
204 return self.format2(raw, out, scheme)[0]
211 import warnings
212 if scheme is not Undefined:
213 warnings.warn('The `scheme` argument of IPython.utils.PyColorize:Parser.format is deprecated since IPython 6.0.'
214 'It will have no effect. Set the parser `style` directly.',
215 stacklevel=2)
216 return self.format2(raw, out)[0]
205
217
206 def format2(self, raw, out = None, scheme = ''):
218 def format2(self, raw, out = None):
207 """ Parse and send the colored source.
219 """ Parse and send the colored source.
208
220
209 If out and scheme are not specified, the defaults (given to
221 If out and scheme are not specified, the defaults (given to
@@ -227,7 +239,7 b' class Parser(Colorable):'
227 self.out = out
239 self.out = out
228
240
229 # Fast return of the unmodified input for NoColor scheme
241 # Fast return of the unmodified input for NoColor scheme
230 if scheme == 'NoColor':
242 if self.style == 'NoColor':
231 error = False
243 error = False
232 self.out.write(raw)
244 self.out.write(raw)
233 if string_output:
245 if string_output:
@@ -236,7 +248,7 b' class Parser(Colorable):'
236 return None,error
248 return None,error
237
249
238 # local shorthands
250 # local shorthands
239 colors = self.color_table[scheme].colors
251 colors = self.color_table[self.style].colors
240 self.colors = colors # put in object so __call__ sees it
252 self.colors = colors # put in object so __call__ sees it
241
253
242 # Remove trailing whitespace and normalize tabs
254 # Remove trailing whitespace and normalize tabs
@@ -318,65 +330,3 b' class Parser(Colorable):'
318
330
319 # send text
331 # send text
320 owrite('%s%s%s' % (color,toktext,colors.normal))
332 owrite('%s%s%s' % (color,toktext,colors.normal))
321
322 def main(argv=None):
323 """Run as a command-line script: colorize a python file or stdin using ANSI
324 color escapes and print to stdout.
325
326 Inputs:
327
328 - argv(None): a list of strings like sys.argv[1:] giving the command-line
329 arguments. If None, use sys.argv[1:].
330 """
331
332 usage_msg = """%prog [options] [filename]
333
334 Colorize a python file or stdin using ANSI color escapes and print to stdout.
335 If no filename is given, or if filename is -, read standard input."""
336
337 import optparse
338 parser = optparse.OptionParser(usage=usage_msg)
339 newopt = parser.add_option
340 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
341 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
342 help="give the color scheme to use. Currently only 'Linux'\
343 (default) and 'LightBG' and 'NoColor' are implemented (give without\
344 quotes)")
345
346 opts,args = parser.parse_args(argv)
347
348 if len(args) > 1:
349 parser.error("you must give at most one filename.")
350
351 if len(args) == 0:
352 fname = '-' # no filename given; setup to read from stdin
353 else:
354 fname = args[0]
355
356 if fname == '-':
357 stream = sys.stdin
358 else:
359 try:
360 stream = open(fname)
361 except IOError as msg:
362 print(msg, file=sys.stderr)
363 sys.exit(1)
364
365 parser = Parser()
366
367 # we need nested try blocks because pre-2.5 python doesn't support unified
368 # try-except-finally
369 try:
370 try:
371 # write colorized version to stdout
372 parser.format(stream.read(),scheme=opts.scheme_name)
373 except IOError as msg:
374 # if user reads through a pager and quits, don't print traceback
375 if msg.args != (32,'Broken pipe'):
376 raise
377 finally:
378 if stream is not sys.stdin:
379 stream.close() # in case a non-handled exception happened above
380
381 if __name__ == "__main__":
382 main()
@@ -22,5 +22,5 b' class Colorable(Configurable):'
22 """
22 """
23 A subclass of configurable for all the classes that have a `default_scheme`
23 A subclass of configurable for all the classes that have a `default_scheme`
24 """
24 """
25 default_style=Unicode('lightbg').tag(config=True)
25 default_style=Unicode('LightBG').tag(config=True)
26
26
@@ -49,28 +49,28 b' class Bar(Super):'
49
49
50 def test_loop_colors():
50 def test_loop_colors():
51
51
52 for scheme in ('Linux', 'NoColor','LightBG', 'Neutral'):
52 for style in ('Linux', 'NoColor','LightBG', 'Neutral'):
53
53
54 def test_unicode_colorize():
54 def test_unicode_colorize():
55 p = Parser()
55 p = Parser(style=style)
56 f1 = p.format('1/0', 'str', scheme=scheme)
56 f1 = p.format('1/0', 'str')
57 f2 = p.format(u'1/0', 'str', scheme=scheme)
57 f2 = p.format(u'1/0', 'str')
58 nt.assert_equal(f1, f2)
58 nt.assert_equal(f1, f2)
59
59
60 def test_parse_sample():
60 def test_parse_sample():
61 """and test writing to a buffer"""
61 """and test writing to a buffer"""
62 buf = io.StringIO()
62 buf = io.StringIO()
63 p = Parser()
63 p = Parser(style=style)
64 p.format(sample, buf, scheme=scheme)
64 p.format(sample, buf)
65 buf.seek(0)
65 buf.seek(0)
66 f1 = buf.read()
66 f1 = buf.read()
67
67
68 nt.assert_not_in('ERROR', f1)
68 nt.assert_not_in('ERROR', f1)
69
69
70 def test_parse_error():
70 def test_parse_error():
71 p = Parser()
71 p = Parser(style=style)
72 f1 = p.format(')', 'str', scheme=scheme)
72 f1 = p.format(')', 'str')
73 if scheme != 'NoColor':
73 if style != 'NoColor':
74 nt.assert_in('ERROR', f1)
74 nt.assert_in('ERROR', f1)
75
75
76 yield test_unicode_colorize
76 yield test_unicode_colorize
General Comments 0
You need to be logged in to leave comments. Login now