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