##// END OF EJS Templates
Stop monkeypatching `linecache`...
Ben Longbons -
Show More
@@ -73,25 +73,6 b' class CachingCompiler(codeop.Compile):'
73 73 def __init__(self):
74 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 76 # Caching a dictionary { filename: execution_count } for nicely
96 77 # rendered tracebacks. The filename corresponds to the filename
97 78 # argument used for the builtins.compile function.
@@ -161,14 +142,24 b' class CachingCompiler(codeop.Compile):'
161 142 # Save the execution count
162 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 156 entry = (
165 157 len(transformed_code),
166 time.time(),
158 None,
167 159 [line + "\n" for line in transformed_code.splitlines()],
168 160 name,
169 161 )
170 162 linecache.cache[name] = entry
171 linecache._ipython_cache[name] = entry
172 163 return name
173 164
174 165 @contextmanager
@@ -187,10 +178,20 b' class CachingCompiler(codeop.Compile):'
187 178
188 179
189 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
193 linecache._checkcache_ori(*args)
194 # Then, update back the cache with our data, so that tracebacks related
195 # to our compiled codes can be produced.
196 linecache.cache.update(linecache._ipython_cache)
192 import warnings
193 warnings.warn(
194 'Just call linecache.checkcache() directly.',
195 DeprecationWarning
196 )
197 linecache.checkcache()
@@ -61,7 +61,7 b' from IPython.core import magic, oinspect, page, prefilter, ultratb'
61 61 from IPython.core.alias import Alias, AliasManager
62 62 from IPython.core.autocall import ExitAutocall
63 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 65 from IPython.core.debugger import InterruptiblePdb
66 66 from IPython.core.display_trap import DisplayTrap
67 67 from IPython.core.displayhook import DisplayHook
@@ -1810,7 +1810,6 b' class InteractiveShell(SingletonConfigurable):'
1810 1810 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1811 1811 color_scheme='NoColor',
1812 1812 tb_offset = 1,
1813 check_cache=check_linecache_ipython,
1814 1813 debugger_cls=self.debugger_cls, parent=self)
1815 1814
1816 1815 # The instance will store a pointer to the system-wide exception hook,
@@ -644,10 +644,8 b' class VerboseTB(TBTools):'
644 644 self.long_header = long_header
645 645 self.include_vars = include_vars
646 646 # By default we use linecache.checkcache, but the user can provide a
647 # different check_cache implementation. This is used by the IPython
648 # kernel to provide tracebacks for interactive code that is cached,
649 # by a compiler instance that flushes the linecache but preserves its
650 # own code cache.
647 # different check_cache implementation. This was formerly used by the
648 # IPython kernel for interactive code, but is no longer necessary.
651 649 if check_cache is None:
652 650 check_cache = linecache.checkcache
653 651 self.check_cache = check_cache
General Comments 0
You need to be logged in to leave comments. Login now