##// END OF EJS Templates
Stop monkeypatching `linecache`...
Ben Longbons -
Show More
@@ -73,25 +73,6 b' class CachingCompiler(codeop.Compile):'
73 def __init__(self):
73 def __init__(self):
74 codeop.Compile.__init__(self)
74 codeop.Compile.__init__(self)
75
75
76 # This is ugly, but it must be done this way to allow multiple
77 # simultaneous ipython instances to coexist. Since Python itself
78 # directly accesses the data structures in the linecache module, and
79 # the cache therein is global, we must work with that data structure.
80 # We must hold a reference to the original checkcache routine and call
81 # that in our own check_cache() below, but the special IPython cache
82 # must also be shared by all IPython instances. If we were to hold
83 # separate caches (one in each CachingCompiler instance), any call made
84 # by Python itself to linecache.checkcache() would obliterate the
85 # cached data from the other IPython instances.
86 if not hasattr(linecache, '_ipython_cache'):
87 linecache._ipython_cache = {}
88 if not hasattr(linecache, '_checkcache_ori'):
89 linecache._checkcache_ori = linecache.checkcache
90 # Now, we must monkeypatch the linecache directly so that parts of the
91 # stdlib that call it outside our control go through our codepath
92 # (otherwise we'd lose our tracebacks).
93 linecache.checkcache = check_linecache_ipython
94
95 # Caching a dictionary { filename: execution_count } for nicely
76 # Caching a dictionary { filename: execution_count } for nicely
96 # rendered tracebacks. The filename corresponds to the filename
77 # rendered tracebacks. The filename corresponds to the filename
97 # argument used for the builtins.compile function.
78 # argument used for the builtins.compile function.
@@ -161,14 +142,24 b' class CachingCompiler(codeop.Compile):'
161 # Save the execution count
142 # Save the execution count
162 self._filename_map[name] = number
143 self._filename_map[name] = number
163
144
145 # Since Python 2.5, setting mtime to `None` means the lines will
146 # never be removed by `linecache.checkcache`. This means all the
147 # monkeypatching has *never* been necessary, since this code was
148 # only added in 2010, at which point IPython had already stopped
149 # supporting Python 2.4.
150 #
151 # Note that `linecache.clearcache` and `linecache.updatecache` may
152 # still remove our code from the cache, but those show explicit
153 # intent, and we should not try to interfere. Normally the former
154 # is never called except when out of memory, and the latter is only
155 # called for lines *not* in the cache.
164 entry = (
156 entry = (
165 len(transformed_code),
157 len(transformed_code),
166 time.time(),
158 None,
167 [line + "\n" for line in transformed_code.splitlines()],
159 [line + "\n" for line in transformed_code.splitlines()],
168 name,
160 name,
169 )
161 )
170 linecache.cache[name] = entry
162 linecache.cache[name] = entry
171 linecache._ipython_cache[name] = entry
172 return name
163 return name
173
164
174 @contextmanager
165 @contextmanager
@@ -187,10 +178,20 b' class CachingCompiler(codeop.Compile):'
187
178
188
179
189 def check_linecache_ipython(*args):
180 def check_linecache_ipython(*args):
190 """Call linecache.checkcache() safely protecting our cached values.
181 """Deprecated since IPython 8.6. Call linecache.checkcache() directly.
182
183 It was already not necessary to call this function directly. If no
184 CachingCompiler had been created, this function would fail badly. If
185 an instance had been created, this function would've been monkeypatched
186 into place.
187
188 As of IPython 8.6, the monkeypatching has gone away entirely. But there
189 were still internal callers of this function, so maybe external callers
190 also existed?
191 """
191 """
192 # First call the original checkcache as intended
192 import warnings
193 linecache._checkcache_ori(*args)
193 warnings.warn(
194 # Then, update back the cache with our data, so that tracebacks related
194 'Just call linecache.checkcache() directly.',
195 # to our compiled codes can be produced.
195 DeprecationWarning
196 linecache.cache.update(linecache._ipython_cache)
196 )
197 linecache.checkcache()
@@ -61,7 +61,7 b' from IPython.core import magic, oinspect, page, prefilter, ultratb'
61 from IPython.core.alias import Alias, AliasManager
61 from IPython.core.alias import Alias, AliasManager
62 from IPython.core.autocall import ExitAutocall
62 from IPython.core.autocall import ExitAutocall
63 from IPython.core.builtin_trap import BuiltinTrap
63 from IPython.core.builtin_trap import BuiltinTrap
64 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
64 from IPython.core.compilerop import CachingCompiler
65 from IPython.core.debugger import InterruptiblePdb
65 from IPython.core.debugger import InterruptiblePdb
66 from IPython.core.display_trap import DisplayTrap
66 from IPython.core.display_trap import DisplayTrap
67 from IPython.core.displayhook import DisplayHook
67 from IPython.core.displayhook import DisplayHook
@@ -1810,7 +1810,6 b' class InteractiveShell(SingletonConfigurable):'
1810 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1810 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1811 color_scheme='NoColor',
1811 color_scheme='NoColor',
1812 tb_offset = 1,
1812 tb_offset = 1,
1813 check_cache=check_linecache_ipython,
1814 debugger_cls=self.debugger_cls, parent=self)
1813 debugger_cls=self.debugger_cls, parent=self)
1815
1814
1816 # The instance will store a pointer to the system-wide exception hook,
1815 # The instance will store a pointer to the system-wide exception hook,
@@ -644,10 +644,8 b' class VerboseTB(TBTools):'
644 self.long_header = long_header
644 self.long_header = long_header
645 self.include_vars = include_vars
645 self.include_vars = include_vars
646 # By default we use linecache.checkcache, but the user can provide a
646 # By default we use linecache.checkcache, but the user can provide a
647 # different check_cache implementation. This is used by the IPython
647 # different check_cache implementation. This was formerly used by the
648 # kernel to provide tracebacks for interactive code that is cached,
648 # IPython kernel for interactive code, but is no longer necessary.
649 # by a compiler instance that flushes the linecache but preserves its
650 # own code cache.
651 if check_cache is None:
649 if check_cache is None:
652 check_cache = linecache.checkcache
650 check_cache = linecache.checkcache
653 self.check_cache = check_cache
651 self.check_cache = check_cache
General Comments 0
You need to be logged in to leave comments. Login now