##// END OF EJS Templates
Fix compilerop to handle unicode input.
Thomas Kluyver -
Show More
@@ -1,119 +1,121 b''
1 """Compiler tools with improved interactive support.
1 """Compiler tools with improved interactive support.
2
2
3 Provides compilation machinery similar to codeop, but with caching support so
3 Provides compilation machinery similar to codeop, but with caching support so
4 we can provide interactive tracebacks.
4 we can provide interactive tracebacks.
5
5
6 Authors
6 Authors
7 -------
7 -------
8 * Robert Kern
8 * Robert Kern
9 * Fernando Perez
9 * Fernando Perez
10 """
10 """
11
11
12 # Note: though it might be more natural to name this module 'compiler', that
12 # Note: though it might be more natural to name this module 'compiler', that
13 # name is in the stdlib and name collisions with the stdlib tend to produce
13 # name is in the stdlib and name collisions with the stdlib tend to produce
14 # weird problems (often with third-party tools).
14 # weird problems (often with third-party tools).
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2010 The IPython Development Team.
17 # Copyright (C) 2010 The IPython Development Team.
18 #
18 #
19 # Distributed under the terms of the BSD License.
19 # Distributed under the terms of the BSD License.
20 #
20 #
21 # The full license is in the file COPYING.txt, distributed with this software.
21 # The full license is in the file COPYING.txt, distributed with this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 # Stdlib imports
29 # Stdlib imports
30 import codeop
30 import codeop
31 import hashlib
31 import hashlib
32 import linecache
32 import linecache
33 import time
33 import time
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Local utilities
36 # Local utilities
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 def code_name(code, number=0):
39 def code_name(code, number=0):
40 """ Compute a (probably) unique name for code for caching.
40 """ Compute a (probably) unique name for code for caching.
41
42 This now expects code to be unicode.
41 """
43 """
42 hash_digest = hashlib.md5(code).hexdigest()
44 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
43 # Include the number and 12 characters of the hash in the name. It's
45 # Include the number and 12 characters of the hash in the name. It's
44 # pretty much impossible that in a single session we'll have collisions
46 # pretty much impossible that in a single session we'll have collisions
45 # even with truncated hashes, and the full one makes tracebacks too long
47 # even with truncated hashes, and the full one makes tracebacks too long
46 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
48 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
47
49
48 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
49 # Classes and functions
51 # Classes and functions
50 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
51
53
52 class CachingCompiler(object):
54 class CachingCompiler(object):
53 """A compiler that caches code compiled from interactive statements.
55 """A compiler that caches code compiled from interactive statements.
54 """
56 """
55
57
56 def __init__(self):
58 def __init__(self):
57 self._compiler = codeop.CommandCompiler()
59 self._compiler = codeop.CommandCompiler()
58
60
59 # This is ugly, but it must be done this way to allow multiple
61 # This is ugly, but it must be done this way to allow multiple
60 # simultaneous ipython instances to coexist. Since Python itself
62 # simultaneous ipython instances to coexist. Since Python itself
61 # directly accesses the data structures in the linecache module, and
63 # directly accesses the data structures in the linecache module, and
62 # the cache therein is global, we must work with that data structure.
64 # the cache therein is global, we must work with that data structure.
63 # We must hold a reference to the original checkcache routine and call
65 # We must hold a reference to the original checkcache routine and call
64 # that in our own check_cache() below, but the special IPython cache
66 # that in our own check_cache() below, but the special IPython cache
65 # must also be shared by all IPython instances. If we were to hold
67 # must also be shared by all IPython instances. If we were to hold
66 # separate caches (one in each CachingCompiler instance), any call made
68 # separate caches (one in each CachingCompiler instance), any call made
67 # by Python itself to linecache.checkcache() would obliterate the
69 # by Python itself to linecache.checkcache() would obliterate the
68 # cached data from the other IPython instances.
70 # cached data from the other IPython instances.
69 if not hasattr(linecache, '_ipython_cache'):
71 if not hasattr(linecache, '_ipython_cache'):
70 linecache._ipython_cache = {}
72 linecache._ipython_cache = {}
71 if not hasattr(linecache, '_checkcache_ori'):
73 if not hasattr(linecache, '_checkcache_ori'):
72 linecache._checkcache_ori = linecache.checkcache
74 linecache._checkcache_ori = linecache.checkcache
73 # Now, we must monkeypatch the linecache directly so that parts of the
75 # Now, we must monkeypatch the linecache directly so that parts of the
74 # stdlib that call it outside our control go through our codepath
76 # stdlib that call it outside our control go through our codepath
75 # (otherwise we'd lose our tracebacks).
77 # (otherwise we'd lose our tracebacks).
76 linecache.checkcache = self.check_cache
78 linecache.checkcache = self.check_cache
77
79
78 @property
80 @property
79 def compiler_flags(self):
81 def compiler_flags(self):
80 """Flags currently active in the compilation process.
82 """Flags currently active in the compilation process.
81 """
83 """
82 return self._compiler.compiler.flags
84 return self._compiler.compiler.flags
83
85
84 def __call__(self, code, symbol, number=0):
86 def __call__(self, code, symbol, number=0):
85 """Compile some code while caching its contents such that the inspect
87 """Compile some code while caching its contents such that the inspect
86 module can find it later.
88 module can find it later.
87
89
88 Parameters
90 Parameters
89 ----------
91 ----------
90 code : str
92 code : str
91 Source code to be compiled, one or more lines.
93 Source code to be compiled, one or more lines.
92
94
93 symbol : str
95 symbol : str
94 One of 'single', 'exec' or 'eval' (see the builtin ``compile``
96 One of 'single', 'exec' or 'eval' (see the builtin ``compile``
95 documentation for further details on these fields).
97 documentation for further details on these fields).
96
98
97 number : int, optional
99 number : int, optional
98 An integer argument identifying the code, useful for informational
100 An integer argument identifying the code, useful for informational
99 purposes in tracebacks (typically it will be the IPython prompt
101 purposes in tracebacks (typically it will be the IPython prompt
100 number).
102 number).
101 """
103 """
102 name = code_name(code, number)
104 name = code_name(code, number)
103 code_obj = self._compiler(code, name, symbol)
105 code_obj = self._compiler(code, name, symbol)
104 entry = (len(code), time.time(),
106 entry = (len(code), time.time(),
105 [line+'\n' for line in code.splitlines()], name)
107 [line+'\n' for line in code.splitlines()], name)
106 # Cache the info both in the linecache (a global cache used internally
108 # Cache the info both in the linecache (a global cache used internally
107 # by most of Python's inspect/traceback machinery), and in our cache
109 # by most of Python's inspect/traceback machinery), and in our cache
108 linecache.cache[name] = entry
110 linecache.cache[name] = entry
109 linecache._ipython_cache[name] = entry
111 linecache._ipython_cache[name] = entry
110 return code_obj
112 return code_obj
111
113
112 def check_cache(self, *args):
114 def check_cache(self, *args):
113 """Call linecache.checkcache() safely protecting our cached values.
115 """Call linecache.checkcache() safely protecting our cached values.
114 """
116 """
115 # First call the orignal checkcache as intended
117 # First call the orignal checkcache as intended
116 linecache._checkcache_ori(*args)
118 linecache._checkcache_ori(*args)
117 # Then, update back the cache with our data, so that tracebacks related
119 # Then, update back the cache with our data, so that tracebacks related
118 # to our compiled codes can be produced.
120 # to our compiled codes can be produced.
119 linecache.cache.update(linecache._ipython_cache)
121 linecache.cache.update(linecache._ipython_cache)
General Comments 0
You need to be logged in to leave comments. Login now