##// END OF EJS Templates
Merge pull request #1715 from jstenar/ultratb-pycolorize-unicode...
Jörgen Stenarson -
r8390:5d645a20 merge
parent child Browse files
Show More
@@ -0,0 +1,45 b''
1 """Wrapper around linecache which decodes files to unicode according to PEP 263.
2
3 This is only needed for Python 2 - linecache in Python 3 does the same thing
4 itself.
5 """
6 import functools
7 import linecache
8 import sys
9
10 from IPython.utils import py3compat
11 from IPython.utils import openpy
12
13 if py3compat.PY3:
14 getline = linecache.getline
15
16 # getlines has to be looked up at runtime, because doctests monkeypatch it.
17 @functools.wraps(linecache.getlines)
18 def getlines(filename, module_globals=None):
19 return linecache.getlines(filename, module_globals=module_globals)
20
21 else:
22 def getlines(filename, module_globals=None):
23 """Get the lines (as unicode) for a file from the cache.
24 Update the cache if it doesn't contain an entry for this file already."""
25 filename = py3compat.cast_bytes(filename, sys.getfilesystemencoding())
26 lines = linecache.getlines(filename, module_globals=module_globals)
27
28 # The bits we cache ourselves can be unicode.
29 if (not lines) or isinstance(lines[0], unicode):
30 return lines
31
32 readline = openpy._list_readline(lines)
33 try:
34 encoding, _ = openpy.detect_encoding(readline)
35 except SyntaxError:
36 encoding = 'ascii'
37 return [l.decode(encoding, 'replace') for l in lines]
38
39 # This is a straight copy of linecache.getline
40 def getline(filename, lineno, module_globals=None):
41 lines = getlines(filename, module_globals)
42 if 1 <= lineno <= len(lines):
43 return lines[lineno-1]
44 else:
45 return ''
@@ -30,9 +30,9 b' import bdb'
30 import linecache
30 import linecache
31 import sys
31 import sys
32
32
33 from IPython.utils import PyColorize
33 from IPython.utils import PyColorize, ulinecache
34 from IPython.core import ipapi
34 from IPython.core import ipapi
35 from IPython.utils import coloransi, io
35 from IPython.utils import coloransi, io, openpy, py3compat
36 from IPython.core.excolors import exception_colors
36 from IPython.core.excolors import exception_colors
37
37
38 # See if we can use pydb.
38 # See if we can use pydb.
@@ -304,16 +304,16 b' class Pdb(OldPdb):'
304 # vds: <<
304 # vds: <<
305
305
306 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
306 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
307 import linecache, repr
307 import repr
308
308
309 ret = []
309 ret = []
310
310
311 Colors = self.color_scheme_table.active_colors
311 Colors = self.color_scheme_table.active_colors
312 ColorsNormal = Colors.Normal
312 ColorsNormal = Colors.Normal
313 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
313 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
314 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
314 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
315 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
315 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
316 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
316 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
317 ColorsNormal)
317 ColorsNormal)
318
318
319 frame, lineno = frame_lineno
319 frame, lineno = frame_lineno
@@ -327,7 +327,7 b' class Pdb(OldPdb):'
327
327
328 #s = filename + '(' + `lineno` + ')'
328 #s = filename + '(' + `lineno` + ')'
329 filename = self.canonic(frame.f_code.co_filename)
329 filename = self.canonic(frame.f_code.co_filename)
330 link = tpl_link % filename
330 link = tpl_link % py3compat.cast_unicode(filename)
331
331
332 if frame.f_code.co_name:
332 if frame.f_code.co_name:
333 func = frame.f_code.co_name
333 func = frame.f_code.co_name
@@ -348,10 +348,10 b' class Pdb(OldPdb):'
348 ret.append('> ')
348 ret.append('> ')
349 else:
349 else:
350 ret.append(' ')
350 ret.append(' ')
351 ret.append('%s(%s)%s\n' % (link,lineno,call))
351 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
352
352
353 start = lineno - 1 - context//2
353 start = lineno - 1 - context//2
354 lines = linecache.getlines(filename)
354 lines = ulinecache.getlines(filename)
355 start = max(start, 0)
355 start = max(start, 0)
356 start = min(start, len(lines) - context)
356 start = min(start, len(lines) - context)
357 lines = lines[start : start + context]
357 lines = lines[start : start + context]
@@ -364,7 +364,6 b' class Pdb(OldPdb):'
364 ret.append(self.__format_line(linetpl, filename,
364 ret.append(self.__format_line(linetpl, filename,
365 start + 1 + i, line,
365 start + 1 + i, line,
366 arrow = show_arrow) )
366 arrow = show_arrow) )
367
368 return ''.join(ret)
367 return ''.join(ret)
369
368
370 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
369 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
@@ -422,8 +421,11 b' class Pdb(OldPdb):'
422 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
421 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
423 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
422 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
424 src = []
423 src = []
424 if filename == "<string>" and hasattr(self, "_exec_filename"):
425 filename = self._exec_filename
426
425 for lineno in range(first, last+1):
427 for lineno in range(first, last+1):
426 line = linecache.getline(filename, lineno)
428 line = ulinecache.getline(filename, lineno)
427 if not line:
429 if not line:
428 break
430 break
429
431
@@ -2908,7 +2908,7 b' class InteractiveShell(SingletonConfigurable):'
2908 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
2908 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
2909 return "\n".join(x for _, _, x in lines)
2909 return "\n".join(x for _, _, x in lines)
2910
2910
2911 def find_user_code(self, target, raw=True, py_only=False):
2911 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True):
2912 """Get a code string from history, file, url, or a string or macro.
2912 """Get a code string from history, file, url, or a string or macro.
2913
2913
2914 This is mainly used by magic functions.
2914 This is mainly used by magic functions.
@@ -2945,7 +2945,7 b' class InteractiveShell(SingletonConfigurable):'
2945 utarget = unquote_filename(target)
2945 utarget = unquote_filename(target)
2946 try:
2946 try:
2947 if utarget.startswith(('http://', 'https://')):
2947 if utarget.startswith(('http://', 'https://')):
2948 return openpy.read_py_url(utarget, skip_encoding_cookie=True)
2948 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
2949 except UnicodeDecodeError:
2949 except UnicodeDecodeError:
2950 if not py_only :
2950 if not py_only :
2951 response = urllib.urlopen(target)
2951 response = urllib.urlopen(target)
@@ -2961,7 +2961,7 b' class InteractiveShell(SingletonConfigurable):'
2961 for tgt in potential_target :
2961 for tgt in potential_target :
2962 if os.path.isfile(tgt): # Read file
2962 if os.path.isfile(tgt): # Read file
2963 try :
2963 try :
2964 return openpy.read_py_file(tgt, skip_encoding_cookie=True)
2964 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
2965 except UnicodeDecodeError :
2965 except UnicodeDecodeError :
2966 if not py_only :
2966 if not py_only :
2967 with io_open(tgt,'r', encoding='latin1') as f :
2967 with io_open(tgt,'r', encoding='latin1') as f :
@@ -554,6 +554,8 b' python-profiler package from non-free.""")'
554 print "%s prompt to start your script." % deb.prompt
554 print "%s prompt to start your script." % deb.prompt
555 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
555 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
556 try:
556 try:
557 #save filename so it can be used by methods on the deb object
558 deb._exec_filename = filename
557 deb.run('execfile("%s", prog_ns)' % filename, ns)
559 deb.run('execfile("%s", prog_ns)' % filename, ns)
558
560
559 except:
561 except:
@@ -23,6 +23,7 b' from IPython.core.error import StdinNotImplementedError, UsageError'
23 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.utils.encoding import DEFAULT_ENCODING
25 from IPython.utils.encoding import DEFAULT_ENCODING
26 from IPython.utils.openpy import read_py_file
26 from IPython.utils.path import get_py_filename
27 from IPython.utils.path import get_py_filename
27
28
28 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
@@ -118,7 +119,7 b' class NamespaceMagics(Magics):'
118 except IOError as msg:
119 except IOError as msg:
119 print msg
120 print msg
120 return
121 return
121 page.page(self.shell.inspector.format(open(filename).read()))
122 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
122
123
123 @line_magic
124 @line_magic
124 def psearch(self, parameter_s=''):
125 def psearch(self, parameter_s=''):
@@ -32,6 +32,7 b' from IPython.core.magic import ('
32 )
32 )
33 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils.io import file_read, nlprint
34 from IPython.utils.io import file_read, nlprint
35 from IPython.utils.openpy import source_to_unicode
35 from IPython.utils.path import get_py_filename, unquote_filename
36 from IPython.utils.path import get_py_filename, unquote_filename
36 from IPython.utils.process import abbrev_cwd
37 from IPython.utils.process import abbrev_cwd
37 from IPython.utils.terminal import set_term_title
38 from IPython.utils.terminal import set_term_title
@@ -686,12 +687,12 b' class OSMagics(Magics):'
686 'or macro.')
687 'or macro.')
687
688
688 try :
689 try :
689 cont = self.shell.find_user_code(parameter_s)
690 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
690 except (ValueError, IOError):
691 except (ValueError, IOError):
691 print "Error: no such file, variable, URL, history range or macro"
692 print "Error: no such file, variable, URL, history range or macro"
692 return
693 return
693
694
694 page.page(self.shell.pycolorize(cont))
695 page.page(self.shell.pycolorize(source_to_unicode(cont)))
695
696
696 @magic_arguments.magic_arguments()
697 @magic_arguments.magic_arguments()
697 @magic_arguments.argument(
698 @magic_arguments.argument(
@@ -24,6 +24,8 b' import linecache'
24 import os
24 import os
25 import sys
25 import sys
26 import types
26 import types
27 import io as stdlib_io
28
27 from collections import namedtuple
29 from collections import namedtuple
28 try:
30 try:
29 from itertools import izip_longest
31 from itertools import izip_longest
@@ -35,10 +37,12 b' from IPython.core import page'
35 from IPython.testing.skipdoctest import skip_doctest_py3
37 from IPython.testing.skipdoctest import skip_doctest_py3
36 from IPython.utils import PyColorize
38 from IPython.utils import PyColorize
37 from IPython.utils import io
39 from IPython.utils import io
40 from IPython.utils import openpy
38 from IPython.utils import py3compat
41 from IPython.utils import py3compat
39 from IPython.utils.text import indent
42 from IPython.utils.text import indent
40 from IPython.utils.wildcard import list_namespace
43 from IPython.utils.wildcard import list_namespace
41 from IPython.utils.coloransi import *
44 from IPython.utils.coloransi import *
45 from IPython.utils.py3compat import cast_unicode
42
46
43 #****************************************************************************
47 #****************************************************************************
44 # Builtin color schemes
48 # Builtin color schemes
@@ -90,6 +94,29 b' def object_info(**kw):'
90 return infodict
94 return infodict
91
95
92
96
97 def get_encoding(obj):
98 """Get encoding for python source file defining obj
99
100 Returns None if obj is not defined in a sourcefile.
101 """
102 ofile = find_file(obj)
103 # run contents of file through pager starting at line where the object
104 # is defined, as long as the file isn't binary and is actually on the
105 # filesystem.
106 if ofile is None:
107 return None
108 elif ofile.endswith(('.so', '.dll', '.pyd')):
109 return None
110 elif not os.path.isfile(ofile):
111 return None
112 else:
113 # Print only text files, not extension binaries. Note that
114 # getsourcelines returns lineno with 1-offset and page() uses
115 # 0-offset, so we must adjust.
116 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
117 encoding, lines = openpy.detect_encoding(buffer.readline)
118 return encoding
119
93 def getdoc(obj):
120 def getdoc(obj):
94 """Stable wrapper around inspect.getdoc.
121 """Stable wrapper around inspect.getdoc.
95
122
@@ -109,10 +136,13 b' def getdoc(obj):'
109 return inspect.cleandoc(ds)
136 return inspect.cleandoc(ds)
110
137
111 try:
138 try:
112 return inspect.getdoc(obj)
139 docstr = inspect.getdoc(obj)
140 encoding = get_encoding(obj)
141 return py3compat.cast_unicode(docstr, encoding=encoding)
113 except Exception:
142 except Exception:
114 # Harden against an inspect failure, which can occur with
143 # Harden against an inspect failure, which can occur with
115 # SWIG-wrapped extensions.
144 # SWIG-wrapped extensions.
145 raise
116 return None
146 return None
117
147
118
148
@@ -143,7 +173,8 b' def getsource(obj,is_binary=False):'
143 except TypeError:
173 except TypeError:
144 if hasattr(obj,'__class__'):
174 if hasattr(obj,'__class__'):
145 src = inspect.getsource(obj.__class__)
175 src = inspect.getsource(obj.__class__)
146 return src
176 encoding = get_encoding(obj)
177 return cast_unicode(src, encoding=encoding)
147
178
148 def getargspec(obj):
179 def getargspec(obj):
149 """Get the names and default values of a function's arguments.
180 """Get the names and default values of a function's arguments.
@@ -319,9 +350,8 b' class Inspector:'
319 exception is suppressed."""
350 exception is suppressed."""
320
351
321 try:
352 try:
322 # We need a plain string here, NOT unicode!
323 hdef = oname + inspect.formatargspec(*getargspec(obj))
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
324 return py3compat.unicode_to_str(hdef, 'ascii')
354 return cast_unicode(hdef)
325 except:
355 except:
326 return None
356 return None
327
357
@@ -435,7 +465,7 b' class Inspector:'
435 except:
465 except:
436 self.noinfo('source',oname)
466 self.noinfo('source',oname)
437 else:
467 else:
438 page.page(self.format(py3compat.unicode_to_str(src)))
468 page.page(self.format(src))
439
469
440 def pfile(self, obj, oname=''):
470 def pfile(self, obj, oname=''):
441 """Show the whole file where an object was defined."""
471 """Show the whole file where an object was defined."""
@@ -457,7 +487,7 b' class Inspector:'
457 # Print only text files, not extension binaries. Note that
487 # Print only text files, not extension binaries. Note that
458 # getsourcelines returns lineno with 1-offset and page() uses
488 # getsourcelines returns lineno with 1-offset and page() uses
459 # 0-offset, so we must adjust.
489 # 0-offset, so we must adjust.
460 page.page(self.format(open(ofile).read()), lineno-1)
490 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
461
491
462 def _format_fields(self, fields, title_width=12):
492 def _format_fields(self, fields, title_width=12):
463 """Formats a list of fields for display.
493 """Formats a list of fields for display.
@@ -476,7 +506,7 b' class Inspector:'
476 title = header(title + ":") + "\n"
506 title = header(title + ":") + "\n"
477 else:
507 else:
478 title = header((title+":").ljust(title_width))
508 title = header((title+":").ljust(title_width))
479 out.append(title + content)
509 out.append(cast_unicode(title) + cast_unicode(content))
480 return "\n".join(out)
510 return "\n".join(out)
481
511
482 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
512 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
@@ -536,7 +566,8 b' class Inspector:'
536 # Source or docstring, depending on detail level and whether
566 # Source or docstring, depending on detail level and whether
537 # source found.
567 # source found.
538 if detail_level > 0 and info['source'] is not None:
568 if detail_level > 0 and info['source'] is not None:
539 displayfields.append(("Source", self.format(py3compat.cast_bytes_py2(info['source']))))
569 displayfields.append(("Source",
570 self.format(cast_unicode(info['source']))))
540 elif info['docstring'] is not None:
571 elif info['docstring'] is not None:
541 displayfields.append(("Docstring", info["docstring"]))
572 displayfields.append(("Docstring", info["docstring"]))
542
573
@@ -1,6 +1,7 b''
1 # encoding: utf-8
1 """Tests for IPython.core.ultratb
2 """Tests for IPython.core.ultratb
2 """
3 """
3
4 import io
4 import os.path
5 import os.path
5 import unittest
6 import unittest
6
7
@@ -49,3 +50,26 b' class ChangedPyFileTest(unittest.TestCase):'
49 ip.run_cell("foo.f()")
50 ip.run_cell("foo.f()")
50 with tt.AssertPrints("ZeroDivisionError"):
51 with tt.AssertPrints("ZeroDivisionError"):
51 ip.run_cell("foo.f()")
52 ip.run_cell("foo.f()")
53
54 iso_8859_5_file = u'''# coding: iso-8859-5
55
56 def fail():
57 """дбИЖ"""
58 1/0 # дбИЖ
59 '''
60
61 class NonAsciiTest(unittest.TestCase):
62 def test_iso8859_5(self):
63 # Non-ascii directory name as well.
64 with TemporaryDirectory(suffix=u'é') as td:
65 fname = os.path.join(td, 'dfghjkl.py')
66
67 with io.open(fname, 'w', encoding='iso-8859-5') as f:
68 f.write(iso_8859_5_file)
69
70 with prepended_to_syspath(td):
71 ip.run_cell("from dfghjkl import fail")
72
73 with tt.AssertPrints("ZeroDivisionError"):
74 with tt.AssertPrints(u'дбИЖ', suppress=False):
75 ip.run_cell('fail()')
@@ -69,7 +69,7 b' possible inclusion in future releases.'
69 # the file COPYING, distributed as part of this software.
69 # the file COPYING, distributed as part of this software.
70 #*****************************************************************************
70 #*****************************************************************************
71
71
72 from __future__ import with_statement
72 from __future__ import unicode_literals
73
73
74 import inspect
74 import inspect
75 import keyword
75 import keyword
@@ -99,9 +99,12 b' from IPython.core.display_trap import DisplayTrap'
99 from IPython.core.excolors import exception_colors
99 from IPython.core.excolors import exception_colors
100 from IPython.utils import PyColorize
100 from IPython.utils import PyColorize
101 from IPython.utils import io
101 from IPython.utils import io
102 from IPython.utils import path as util_path
102 from IPython.utils import py3compat
103 from IPython.utils import py3compat
103 from IPython.utils import pyfile
104 from IPython.utils import pyfile
105 from IPython.utils import ulinecache
104 from IPython.utils.data import uniq_stable
106 from IPython.utils.data import uniq_stable
107 from IPython.utils.openpy import read_py_file
105 from IPython.utils.warn import info, error
108 from IPython.utils.warn import info, error
106
109
107 # Globals
110 # Globals
@@ -229,7 +232,6 b' def fix_frame_records_filenames(records):'
229
232
230
233
231 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
234 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
232 import linecache
233 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
235 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
234
236
235 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
237 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
@@ -251,7 +253,7 b' def _fixed_getinnerframes(etb, context=1,tb_offset=0):'
251 maybeStart = lnum-1 - context//2
253 maybeStart = lnum-1 - context//2
252 start = max(maybeStart, 0)
254 start = max(maybeStart, 0)
253 end = start + context
255 end = start + context
254 lines = linecache.getlines(file)[start:end]
256 lines = ulinecache.getlines(file)[start:end]
255 buf = list(records[i])
257 buf = list(records[i])
256 buf[LNUM_POS] = lnum
258 buf[LNUM_POS] = lnum
257 buf[INDEX_POS] = lnum - 1 - start
259 buf[INDEX_POS] = lnum - 1 - start
@@ -282,12 +284,7 b' def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):'
282 _line_format = _parser.format2
284 _line_format = _parser.format2
283
285
284 for line in lines:
286 for line in lines:
285 # FIXME: we need to ensure the source is a pure string at this point,
287 line = py3compat.cast_unicode(line)
286 # else the coloring code makes a royal mess. This is in need of a
287 # serious refactoring, so that all of the ultratb and PyColorize code
288 # is unicode-safe. So for now this is rather an ugly hack, but
289 # necessary to at least have readable tracebacks. Improvements welcome!
290 line = py3compat.cast_bytes_py2(line, 'utf-8')
291
288
292 new_line, err = _line_format(line, 'str', scheme)
289 new_line, err = _line_format(line, 'str', scheme)
293 if not err: line = new_line
290 if not err: line = new_line
@@ -547,14 +544,13 b' class ListTB(TBTools):'
547
544
548 Also lifted nearly verbatim from traceback.py
545 Also lifted nearly verbatim from traceback.py
549 """
546 """
550
551 have_filedata = False
547 have_filedata = False
552 Colors = self.Colors
548 Colors = self.Colors
553 list = []
549 list = []
554 stype = Colors.excName + etype.__name__ + Colors.Normal
550 stype = Colors.excName + etype.__name__ + Colors.Normal
555 if value is None:
551 if value is None:
556 # Not sure if this can still happen in Python 2.6 and above
552 # Not sure if this can still happen in Python 2.6 and above
557 list.append( str(stype) + '\n')
553 list.append( py3compat.cast_unicode(stype) + '\n')
558 else:
554 else:
559 if etype is SyntaxError:
555 if etype is SyntaxError:
560 have_filedata = True
556 have_filedata = True
@@ -562,18 +558,22 b' class ListTB(TBTools):'
562 if not value.filename: value.filename = "<string>"
558 if not value.filename: value.filename = "<string>"
563 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
559 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
564 (Colors.normalEm,
560 (Colors.normalEm,
565 Colors.filenameEm, value.filename, Colors.normalEm,
561 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
566 Colors.linenoEm, value.lineno, Colors.Normal ))
562 Colors.linenoEm, value.lineno, Colors.Normal ))
567 if value.text is not None:
563 textline = ulinecache.getline(value.filename, value.lineno)
564 if textline == '':
565 textline = py3compat.cast_unicode(value.text, "utf-8")
566
567 if textline is not None:
568 i = 0
568 i = 0
569 while i < len(value.text) and value.text[i].isspace():
569 while i < len(textline) and textline[i].isspace():
570 i += 1
570 i += 1
571 list.append('%s %s%s\n' % (Colors.line,
571 list.append('%s %s%s\n' % (Colors.line,
572 value.text.strip(),
572 textline.strip(),
573 Colors.Normal))
573 Colors.Normal))
574 if value.offset is not None:
574 if value.offset is not None:
575 s = ' '
575 s = ' '
576 for c in value.text[i:value.offset-1]:
576 for c in textline[i:value.offset-1]:
577 if c.isspace():
577 if c.isspace():
578 s += c
578 s += c
579 else:
579 else:
@@ -779,10 +779,9 b' class VerboseTB(TBTools):'
779 abspath = os.path.abspath
779 abspath = os.path.abspath
780 for frame, file, lnum, func, lines, index in records:
780 for frame, file, lnum, func, lines, index in records:
781 #print '*** record:',file,lnum,func,lines,index # dbg
781 #print '*** record:',file,lnum,func,lines,index # dbg
782
783 if not file:
782 if not file:
784 file = '?'
783 file = '?'
785 elif not(file.startswith("<") and file.endswith(">")):
784 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
786 # Guess that filenames like <string> aren't real filenames, so
785 # Guess that filenames like <string> aren't real filenames, so
787 # don't call abspath on them.
786 # don't call abspath on them.
788 try:
787 try:
@@ -791,7 +790,7 b' class VerboseTB(TBTools):'
791 # Not sure if this can still happen: abspath now works with
790 # Not sure if this can still happen: abspath now works with
792 # file names like <string>
791 # file names like <string>
793 pass
792 pass
794
793 file = py3compat.cast_unicode(file, util_path.fs_encoding)
795 link = tpl_link % file
794 link = tpl_link % file
796 args, varargs, varkw, locals = inspect.getargvalues(frame)
795 args, varargs, varkw, locals = inspect.getargvalues(frame)
797
796
@@ -831,7 +830,7 b' class VerboseTB(TBTools):'
831 # Look up the corresponding source file.
830 # Look up the corresponding source file.
832 file = pyfile.source_from_cache(file)
831 file = pyfile.source_from_cache(file)
833
832
834 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
833 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
835 line = getline(file, lnum[0])
834 line = getline(file, lnum[0])
836 lnum[0] += 1
835 lnum[0] += 1
837 return line
836 return line
@@ -926,7 +925,7 b' class VerboseTB(TBTools):'
926 etype_str,evalue_str = map(str,(etype,evalue))
925 etype_str,evalue_str = map(str,(etype,evalue))
927 # ... and format it
926 # ... and format it
928 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
927 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
929 ColorsNormal, evalue_str)]
928 ColorsNormal, py3compat.cast_unicode(evalue_str))]
930 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
929 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
931 try:
930 try:
932 names = [w for w in dir(evalue) if isinstance(w, basestring)]
931 names = [w for w in dir(evalue) if isinstance(w, basestring)]
@@ -938,7 +937,7 b' class VerboseTB(TBTools):'
938 exception.append(_m % (Colors.excName,ColorsNormal))
937 exception.append(_m % (Colors.excName,ColorsNormal))
939 etype_str,evalue_str = map(str,sys.exc_info()[:2])
938 etype_str,evalue_str = map(str,sys.exc_info()[:2])
940 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
939 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
941 ColorsNormal, evalue_str))
940 ColorsNormal, py3compat.cast_unicode(evalue_str)))
942 names = []
941 names = []
943 for name in names:
942 for name in names:
944 value = text_repr(getattr(evalue, name))
943 value = text_repr(getattr(evalue, name))
@@ -5,7 +5,7 b' import subprocess'
5 import sys
5 import sys
6
6
7 from IPython.core.error import TryNext
7 from IPython.core.error import TryNext
8
8 import IPython.utils.py3compat as py3compat
9
9
10 def win32_clipboard_get():
10 def win32_clipboard_get():
11 """ Get the current clipboard's text on Windows.
11 """ Get the current clipboard's text on Windows.
@@ -31,6 +31,7 b' def osx_clipboard_get():'
31 text, stderr = p.communicate()
31 text, stderr = p.communicate()
32 # Text comes in with old Mac \r line endings. Change them to \n.
32 # Text comes in with old Mac \r line endings. Change them to \n.
33 text = text.replace('\r', '\n')
33 text = text.replace('\r', '\n')
34 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
34 return text
35 return text
35
36
36 def tkinter_clipboard_get():
37 def tkinter_clipboard_get():
@@ -49,6 +50,7 b' def tkinter_clipboard_get():'
49 root.withdraw()
50 root.withdraw()
50 text = root.clipboard_get()
51 text = root.clipboard_get()
51 root.destroy()
52 root.destroy()
53 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
52 return text
54 return text
53
55
54
56
@@ -1,3 +1,6 b''
1 from __future__ import unicode_literals
2
3
1 """Module for interactive demos using IPython.
4 """Module for interactive demos using IPython.
2
5
3 This module implements a few classes for running Python scripts interactively
6 This module implements a few classes for running Python scripts interactively
@@ -179,7 +182,7 b' from IPython.utils.PyColorize import Parser'
179 from IPython.utils import io
182 from IPython.utils import io
180 from IPython.utils.io import file_read, file_readlines
183 from IPython.utils.io import file_read, file_readlines
181 from IPython.utils.text import marquee
184 from IPython.utils.text import marquee
182
185 from IPython.utils import openpy
183 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
186 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
184
187
185 class DemoError(Exception): pass
188 class DemoError(Exception): pass
@@ -264,13 +267,13 b' class Demo(object):'
264 self.fobj = self.src
267 self.fobj = self.src
265 else:
268 else:
266 # Assume it's a string or something that can be converted to one
269 # Assume it's a string or something that can be converted to one
267 self.fobj = open(self.fname)
270 self.fobj = openpy.open(self.fname)
268
271
269 def reload(self):
272 def reload(self):
270 """Reload source from disk and initialize state."""
273 """Reload source from disk and initialize state."""
271 self.fload()
274 self.fload()
272
275
273 self.src = self.fobj.read()
276 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
274 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
277 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
275 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
278 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
276 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
279 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
@@ -30,6 +30,8 b' formatting (which is the hard part).'
30 """
30 """
31 from __future__ import print_function
31 from __future__ import print_function
32
32
33 from __future__ import unicode_literals
34
33 __all__ = ['ANSICodeColors','Parser']
35 __all__ = ['ANSICodeColors','Parser']
34
36
35 _scheme_default = 'Linux'
37 _scheme_default = 'Linux'
@@ -7,7 +7,7 b' Much of the code is taken from the tokenize module in Python 3.2.'
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import io
9 import io
10 from io import TextIOWrapper
10 from io import TextIOWrapper, BytesIO
11 import re
11 import re
12 import urllib
12 import urllib
13
13
@@ -120,6 +120,32 b' except ImportError:'
120 text.mode = 'r'
120 text.mode = 'r'
121 return text
121 return text
122
122
123 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
124 """Converts a bytes string with python source code to unicode.
125
126 Unicode strings are passed through unchanged. Byte strings are checked
127 for the python source file encoding cookie to determine encoding.
128 txt can be either a bytes buffer or a string containing the source
129 code.
130 """
131 if isinstance(txt, unicode):
132 return txt
133 if isinstance(txt, bytes):
134 buffer = BytesIO(txt)
135 else:
136 buffer = txt
137 try:
138 encoding, _ = detect_encoding(buffer.readline)
139 except SyntaxError:
140 encoding = "ascii"
141 buffer.seek(0)
142 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
143 text.mode = 'r'
144 if skip_encoding_cookie:
145 return u"".join(strip_encoding_cookie(text))
146 else:
147 return text.read()
148
123 def strip_encoding_cookie(filelike):
149 def strip_encoding_cookie(filelike):
124 """Generator to pull lines from a text-mode file, skipping the encoding
150 """Generator to pull lines from a text-mode file, skipping the encoding
125 cookie if it is found in the first two lines.
151 cookie if it is found in the first two lines.
@@ -181,12 +207,13 b" def read_py_url(url, errors='replace', skip_encoding_cookie=True):"
181 """
207 """
182 response = urllib.urlopen(url)
208 response = urllib.urlopen(url)
183 buffer = io.BytesIO(response.read())
209 buffer = io.BytesIO(response.read())
184 encoding, lines = detect_encoding(buffer.readline)
210 return source_to_unicode(buffer, errors, skip_encoding_cookie)
185 buffer.seek(0)
186 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
187 text.mode = 'r'
188 if skip_encoding_cookie:
189 return "".join(strip_encoding_cookie(text))
190 else:
191 return text.read()
192
211
212 def _list_readline(x):
213 """Given a list, returns a readline() function that returns the next element
214 with each call.
215 """
216 x = iter(x)
217 def readline():
218 return next(x)
219 return readline
@@ -38,7 +38,7 b' from IPython.lib.kernel import ('
38 get_connection_file, get_connection_info, connect_qtconsole
38 get_connection_file, get_connection_info, connect_qtconsole
39 )
39 )
40 from IPython.testing.skipdoctest import skip_doctest
40 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.utils import io
41 from IPython.utils import io, openpy
42 from IPython.utils.jsonutil import json_clean, encode_images
42 from IPython.utils.jsonutil import json_clean, encode_images
43 from IPython.utils.process import arg_split
43 from IPython.utils.process import arg_split
44 from IPython.utils import py3compat
44 from IPython.utils import py3compat
@@ -355,7 +355,9 b' class KernelMagics(Magics):'
355
355
356 cont = open(arg_s).read()
356 cont = open(arg_s).read()
357 if arg_s.endswith('.py'):
357 if arg_s.endswith('.py'):
358 cont = self.shell.pycolorize(cont)
358 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
359 else:
360 cont = open(arg_s).read()
359 page.page(cont)
361 page.page(cont)
360
362
361 more = line_magic('more')(less)
363 more = line_magic('more')(less)
@@ -1,9 +1,12 b''
1 # -*- coding: utf-8 -*-
1 """A simple interactive demo to illustrate the use of IPython's Demo class.
2 """A simple interactive demo to illustrate the use of IPython's Demo class.
2
3
3 Any python script can be run as a demo, but that does little more than showing
4 Any python script can be run as a demo, but that does little more than showing
4 it on-screen, syntax-highlighted in one shot. If you add a little simple
5 it on-screen, syntax-highlighted in one shot. If you add a little simple
5 markup, you can stop at specified intervals and return to the ipython prompt,
6 markup, you can stop at specified intervals and return to the ipython prompt,
6 resuming execution later.
7 resuming execution later.
8
9 This is a unicode test, åäö
7 """
10 """
8 from __future__ import print_function
11 from __future__ import print_function
9
12
General Comments 0
You need to be logged in to leave comments. Login now