##// END OF EJS Templates
Describe arguments for CachingCompiler.ast_parse
Thomas Kluyver -
Show More
@@ -1,128 +1,131 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 * Thomas Kluyver
10 * Thomas Kluyver
11 """
11 """
12
12
13 # Note: though it might be more natural to name this module 'compiler', that
13 # Note: though it might be more natural to name this module 'compiler', that
14 # name is in the stdlib and name collisions with the stdlib tend to produce
14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 # weird problems (often with third-party tools).
15 # weird problems (often with third-party tools).
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2010 The IPython Development Team.
18 # Copyright (C) 2010 The IPython Development Team.
19 #
19 #
20 # Distributed under the terms of the BSD License.
20 # Distributed under the terms of the BSD License.
21 #
21 #
22 # The full license is in the file COPYING.txt, distributed with this software.
22 # The full license is in the file COPYING.txt, distributed with this software.
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Imports
26 # Imports
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 from __future__ import print_function
28 from __future__ import print_function
29
29
30 # Stdlib imports
30 # Stdlib imports
31 from ast import PyCF_ONLY_AST
31 from ast import PyCF_ONLY_AST
32 import codeop
32 import codeop
33 import hashlib
33 import hashlib
34 import linecache
34 import linecache
35 import time
35 import time
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Local utilities
38 # Local utilities
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 def code_name(code, number=0):
41 def code_name(code, number=0):
42 """ Compute a (probably) unique name for code for caching.
42 """ Compute a (probably) unique name for code for caching.
43
43
44 This now expects code to be unicode.
44 This now expects code to be unicode.
45 """
45 """
46 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
46 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
47 # Include the number and 12 characters of the hash in the name. It's
47 # Include the number and 12 characters of the hash in the name. It's
48 # pretty much impossible that in a single session we'll have collisions
48 # pretty much impossible that in a single session we'll have collisions
49 # even with truncated hashes, and the full one makes tracebacks too long
49 # even with truncated hashes, and the full one makes tracebacks too long
50 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
50 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Classes and functions
53 # Classes and functions
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class CachingCompiler(codeop.Compile):
56 class CachingCompiler(codeop.Compile):
57 """A compiler that caches code compiled from interactive statements.
57 """A compiler that caches code compiled from interactive statements.
58 """
58 """
59
59
60 def __init__(self):
60 def __init__(self):
61 codeop.Compile.__init__(self)
61 codeop.Compile.__init__(self)
62
62
63 # This is ugly, but it must be done this way to allow multiple
63 # This is ugly, but it must be done this way to allow multiple
64 # simultaneous ipython instances to coexist. Since Python itself
64 # simultaneous ipython instances to coexist. Since Python itself
65 # directly accesses the data structures in the linecache module, and
65 # directly accesses the data structures in the linecache module, and
66 # the cache therein is global, we must work with that data structure.
66 # the cache therein is global, we must work with that data structure.
67 # We must hold a reference to the original checkcache routine and call
67 # We must hold a reference to the original checkcache routine and call
68 # that in our own check_cache() below, but the special IPython cache
68 # that in our own check_cache() below, but the special IPython cache
69 # must also be shared by all IPython instances. If we were to hold
69 # must also be shared by all IPython instances. If we were to hold
70 # separate caches (one in each CachingCompiler instance), any call made
70 # separate caches (one in each CachingCompiler instance), any call made
71 # by Python itself to linecache.checkcache() would obliterate the
71 # by Python itself to linecache.checkcache() would obliterate the
72 # cached data from the other IPython instances.
72 # cached data from the other IPython instances.
73 if not hasattr(linecache, '_ipython_cache'):
73 if not hasattr(linecache, '_ipython_cache'):
74 linecache._ipython_cache = {}
74 linecache._ipython_cache = {}
75 if not hasattr(linecache, '_checkcache_ori'):
75 if not hasattr(linecache, '_checkcache_ori'):
76 linecache._checkcache_ori = linecache.checkcache
76 linecache._checkcache_ori = linecache.checkcache
77 # Now, we must monkeypatch the linecache directly so that parts of the
77 # Now, we must monkeypatch the linecache directly so that parts of the
78 # stdlib that call it outside our control go through our codepath
78 # stdlib that call it outside our control go through our codepath
79 # (otherwise we'd lose our tracebacks).
79 # (otherwise we'd lose our tracebacks).
80 linecache.checkcache = self.check_cache
80 linecache.checkcache = self.check_cache
81
81
82 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
82 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
83 """Parse code to an AST with the current compiler flags active."""
83 """Parse code to an AST with the current compiler flags active.
84
85 Arguments are exactly the same as ast.parse (in the standard library),
86 and are passed to the built-in compile function."""
84 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
87 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
85
88
86 def reset_compiler_flags(self):
89 def reset_compiler_flags(self):
87 """Reset compiler flags to default state."""
90 """Reset compiler flags to default state."""
88 # This value is copied from codeop.Compile.__init__, so if that ever
91 # This value is copied from codeop.Compile.__init__, so if that ever
89 # changes, it will need to be updated.
92 # changes, it will need to be updated.
90 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
93 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
91
94
92 @property
95 @property
93 def compiler_flags(self):
96 def compiler_flags(self):
94 """Flags currently active in the compilation process.
97 """Flags currently active in the compilation process.
95 """
98 """
96 return self.flags
99 return self.flags
97
100
98 def cache(self, code, number=0):
101 def cache(self, code, number=0):
99 """Make a name for a block of code, and cache the code.
102 """Make a name for a block of code, and cache the code.
100
103
101 Parameters
104 Parameters
102 ----------
105 ----------
103 code : str
106 code : str
104 The Python source code to cache.
107 The Python source code to cache.
105 number : int
108 number : int
106 A number which forms part of the code's name. Used for the execution
109 A number which forms part of the code's name. Used for the execution
107 counter.
110 counter.
108
111
109 Returns
112 Returns
110 -------
113 -------
111 The name of the cached code (as a string). Pass this as the filename
114 The name of the cached code (as a string). Pass this as the filename
112 argument to compilation, so that tracebacks are correctly hooked up.
115 argument to compilation, so that tracebacks are correctly hooked up.
113 """
116 """
114 name = code_name(code, number)
117 name = code_name(code, number)
115 entry = (len(code), time.time(),
118 entry = (len(code), time.time(),
116 [line+'\n' for line in code.splitlines()], name)
119 [line+'\n' for line in code.splitlines()], name)
117 linecache.cache[name] = entry
120 linecache.cache[name] = entry
118 linecache._ipython_cache[name] = entry
121 linecache._ipython_cache[name] = entry
119 return name
122 return name
120
123
121 def check_cache(self, *args):
124 def check_cache(self, *args):
122 """Call linecache.checkcache() safely protecting our cached values.
125 """Call linecache.checkcache() safely protecting our cached values.
123 """
126 """
124 # First call the orignal checkcache as intended
127 # First call the orignal checkcache as intended
125 linecache._checkcache_ori(*args)
128 linecache._checkcache_ori(*args)
126 # Then, update back the cache with our data, so that tracebacks related
129 # Then, update back the cache with our data, so that tracebacks related
127 # to our compiled codes can be produced.
130 # to our compiled codes can be produced.
128 linecache.cache.update(linecache._ipython_cache)
131 linecache.cache.update(linecache._ipython_cache)
General Comments 0
You need to be logged in to leave comments. Login now