Show More
@@ -819,53 +819,32 b' class InteractiveShell(SingletonConfigurable):' | |||||
819 | # Things related to the "main" module |
|
819 | # Things related to the "main" module | |
820 | #------------------------------------------------------------------------- |
|
820 | #------------------------------------------------------------------------- | |
821 |
|
821 | |||
822 |
def new_main_mod(self, |
|
822 | def new_main_mod(self, filename): | |
823 | """Return a new 'main' module object for user code execution. |
|
823 | """Return a new 'main' module object for user code execution. | |
824 |
|
|
824 | ||
825 | main_mod = self._user_main_module |
|
825 | ``filename`` should be the path of the script which will be run in the | |
826 | init_fakemod_dict(main_mod,ns) |
|
826 | module. Requests with the same filename will get the same module, with | |
827 | return main_mod |
|
827 | its namespace cleared. | |
828 |
|
828 | |||
829 | def cache_main_mod(self,ns,fname): |
|
829 | When scripts are executed via %run, we must keep a reference to their | |
830 | """Cache a main module's namespace. |
|
830 | __main__ module (a FakeModule instance) around so that Python doesn't | |
831 |
|
831 | clear it, rendering references to module globals useless. | ||
832 | When scripts are executed via %run, we must keep a reference to the |
|
|||
833 | namespace of their __main__ module (a FakeModule instance) around so |
|
|||
834 | that Python doesn't clear it, rendering objects defined therein |
|
|||
835 | useless. |
|
|||
836 |
|
832 | |||
837 | This method keeps said reference in a private dict, keyed by the |
|
833 | This method keeps said reference in a private dict, keyed by the | |
838 | absolute path of the module object (which corresponds to the script |
|
834 | absolute path of the script. This way, for multiple executions of the | |
839 | path). This way, for multiple executions of the same script we only |
|
835 | same script we only keep one copy of the namespace (the last one), | |
840 | keep one copy of the namespace (the last one), thus preventing memory |
|
836 | thus preventing memory leaks from old references while allowing the | |
841 | leaks from old references while allowing the objects from the last |
|
837 | objects from the last execution to be accessible. | |
842 | execution to be accessible. |
|
|||
843 |
|
||||
844 | Note: we can not allow the actual FakeModule instances to be deleted, |
|
|||
845 | because of how Python tears down modules (it hard-sets all their |
|
|||
846 | references to None without regard for reference counts). This method |
|
|||
847 | must therefore make a *copy* of the given namespace, to allow the |
|
|||
848 | original module's __dict__ to be cleared and reused. |
|
|||
849 |
|
||||
850 |
|
||||
851 | Parameters |
|
|||
852 | ---------- |
|
|||
853 | ns : a namespace (a dict, typically) |
|
|||
854 |
|
||||
855 | fname : str |
|
|||
856 | Filename associated with the namespace. |
|
|||
857 |
|
||||
858 | Examples |
|
|||
859 | -------- |
|
|||
860 |
|
||||
861 | In [10]: import IPython |
|
|||
862 |
|
||||
863 | In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__) |
|
|||
864 |
|
||||
865 | In [12]: IPython.__file__ in _ip._main_ns_cache |
|
|||
866 | Out[12]: True |
|
|||
867 | """ |
|
838 | """ | |
868 |
|
|
839 | filename = os.path.abspath(filename) | |
|
840 | try: | |||
|
841 | main_mod = self._main_mod_cache[filename] | |||
|
842 | except KeyError: | |||
|
843 | main_mod = self._main_mod_cache[filename] = FakeModule() | |||
|
844 | else: | |||
|
845 | init_fakemod_dict(main_mod) | |||
|
846 | ||||
|
847 | return main_mod | |||
869 |
|
848 | |||
870 | def clear_main_mod_cache(self): |
|
849 | def clear_main_mod_cache(self): | |
871 | """Clear the cache of main modules. |
|
850 | """Clear the cache of main modules. | |
@@ -877,17 +856,17 b' class InteractiveShell(SingletonConfigurable):' | |||||
877 |
|
856 | |||
878 | In [15]: import IPython |
|
857 | In [15]: import IPython | |
879 |
|
858 | |||
880 |
In [16]: |
|
859 | In [16]: m = _ip.new_main_mod(IPython.__file__) | |
881 |
|
860 | |||
882 |
In [17]: len(_ip._main_ |
|
861 | In [17]: len(_ip._main_mod_cache) > 0 | |
883 | Out[17]: True |
|
862 | Out[17]: True | |
884 |
|
863 | |||
885 | In [18]: _ip.clear_main_mod_cache() |
|
864 | In [18]: _ip.clear_main_mod_cache() | |
886 |
|
865 | |||
887 |
In [19]: len(_ip._main_ |
|
866 | In [19]: len(_ip._main_mod_cache) == 0 | |
888 | Out[19]: True |
|
867 | Out[19]: True | |
889 | """ |
|
868 | """ | |
890 |
self._main_ |
|
869 | self._main_mod_cache.clear() | |
891 |
|
870 | |||
892 | #------------------------------------------------------------------------- |
|
871 | #------------------------------------------------------------------------- | |
893 | # Things related to debugging |
|
872 | # Things related to debugging | |
@@ -1017,10 +996,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
1017 | # and clear_main_mod_cache() methods for details on use. |
|
996 | # and clear_main_mod_cache() methods for details on use. | |
1018 |
|
997 | |||
1019 | # This is the cache used for 'main' namespaces |
|
998 | # This is the cache used for 'main' namespaces | |
1020 |
self._main_ |
|
999 | self._main_mod_cache = {} | |
1021 | # And this is the single instance of FakeModule whose __dict__ we keep |
|
|||
1022 | # copying and clearing for reuse on each %run |
|
|||
1023 | self._user_main_module = FakeModule() |
|
|||
1024 |
|
1000 | |||
1025 | # A table holding all the namespaces IPython deals with, so that |
|
1001 | # A table holding all the namespaces IPython deals with, so that | |
1026 | # introspection facilities can search easily. |
|
1002 | # introspection facilities can search easily. | |
@@ -1174,8 +1150,8 b' class InteractiveShell(SingletonConfigurable):' | |||||
1174 |
|
1150 | |||
1175 | Note that this does not include the displayhook, which also caches |
|
1151 | Note that this does not include the displayhook, which also caches | |
1176 | objects from the output.""" |
|
1152 | objects from the output.""" | |
1177 |
return [self.user_ns, self.user_global_ns |
|
1153 | return [self.user_ns, self.user_global_ns] + \ | |
1178 |
|
|
1154 | [m.__dict__ for m in self._main_mod_cache.values()] | |
1179 |
|
1155 | |||
1180 | def reset(self, new_session=True): |
|
1156 | def reset(self, new_session=True): | |
1181 | """Clear all internal namespaces, and attempt to release references to |
|
1157 | """Clear all internal namespaces, and attempt to release references to | |
@@ -1219,9 +1195,6 b' class InteractiveShell(SingletonConfigurable):' | |||||
1219 | # execution protection |
|
1195 | # execution protection | |
1220 | self.clear_main_mod_cache() |
|
1196 | self.clear_main_mod_cache() | |
1221 |
|
1197 | |||
1222 | # Clear out the namespace from the last %run |
|
|||
1223 | self.new_main_mod() |
|
|||
1224 |
|
||||
1225 | def del_var(self, varname, by_name=False): |
|
1198 | def del_var(self, varname, by_name=False): | |
1226 | """Delete a variable from the various namespaces, so that, as |
|
1199 | """Delete a variable from the various namespaces, so that, as | |
1227 | far as possible, we're not keeping any hidden references to it. |
|
1200 | far as possible, we're not keeping any hidden references to it. |
@@ -508,7 +508,7 b' python-profiler package from non-free.""")' | |||||
508 | prog_ns = self.shell.user_ns |
|
508 | prog_ns = self.shell.user_ns | |
509 | __name__save = self.shell.user_ns['__name__'] |
|
509 | __name__save = self.shell.user_ns['__name__'] | |
510 | prog_ns['__name__'] = '__main__' |
|
510 | prog_ns['__name__'] = '__main__' | |
511 |
main_mod = self.shell. |
|
511 | main_mod = self.shell.user_module | |
512 | else: |
|
512 | else: | |
513 | # Run in a fresh, empty namespace |
|
513 | # Run in a fresh, empty namespace | |
514 | if 'n' in opts: |
|
514 | if 'n' in opts: | |
@@ -516,7 +516,10 b' python-profiler package from non-free.""")' | |||||
516 | else: |
|
516 | else: | |
517 | name = '__main__' |
|
517 | name = '__main__' | |
518 |
|
518 | |||
519 | main_mod = self.shell.new_main_mod() |
|
519 | # The shell MUST hold a reference to prog_ns so after %run | |
|
520 | # exits, the python deletion mechanism doesn't zero it out | |||
|
521 | # (leaving dangling references). See interactiveshell for details | |||
|
522 | main_mod = self.shell.new_main_mod(filename) | |||
520 | prog_ns = main_mod.__dict__ |
|
523 | prog_ns = main_mod.__dict__ | |
521 | prog_ns['__name__'] = name |
|
524 | prog_ns['__name__'] = name | |
522 |
|
525 | |||
@@ -593,10 +596,6 b' python-profiler package from non-free.""")' | |||||
593 | if 'i' in opts: |
|
596 | if 'i' in opts: | |
594 | self.shell.user_ns['__name__'] = __name__save |
|
597 | self.shell.user_ns['__name__'] = __name__save | |
595 | else: |
|
598 | else: | |
596 | # The shell MUST hold a reference to prog_ns so after %run |
|
|||
597 | # exits, the python deletion mechanism doesn't zero it out |
|
|||
598 | # (leaving dangling references). |
|
|||
599 | self.shell.cache_main_mod(prog_ns, filename) |
|
|||
600 | # update IPython interactive namespace |
|
599 | # update IPython interactive namespace | |
601 |
|
600 | |||
602 | # Some forms of read errors on the file may mean the |
|
601 | # Some forms of read errors on the file may mean the |
@@ -244,7 +244,6 b' class TestMagicRunSimple(tt.TempFileMixin):' | |||||
244 | err = None |
|
244 | err = None | |
245 | tt.ipexec_validate(self.fname, 'object A deleted', err) |
|
245 | tt.ipexec_validate(self.fname, 'object A deleted', err) | |
246 |
|
246 | |||
247 | @dec.skip_known_failure |
|
|||
248 | def test_aggressive_namespace_cleanup(self): |
|
247 | def test_aggressive_namespace_cleanup(self): | |
249 | """Test that namespace cleanup is not too aggressive GH-238 |
|
248 | """Test that namespace cleanup is not too aggressive GH-238 | |
250 |
|
249 | |||
@@ -258,11 +257,26 b' class TestMagicRunSimple(tt.TempFileMixin):' | |||||
258 | " try:\n" |
|
257 | " try:\n" | |
259 | " ip.magic('run %s')\n" |
|
258 | " ip.magic('run %s')\n" | |
260 | " except NameError as e:\n" |
|
259 | " except NameError as e:\n" | |
261 |
" print |
|
260 | " print(i)\n" | |
262 | self.mktmp(py3compat.doctest_refactor_print(src)) |
|
261 | " break\n" % empty.fname) | |
|
262 | self.mktmp(src) | |||
263 | _ip.magic('run %s' % self.fname) |
|
263 | _ip.magic('run %s' % self.fname) | |
264 | _ip.run_cell('ip == get_ipython()') |
|
264 | _ip.run_cell('ip == get_ipython()') | |
265 |
nt.assert_equal(_ip.user_ns['i'], |
|
265 | nt.assert_equal(_ip.user_ns['i'], 4) | |
|
266 | ||||
|
267 | def test_run_second(self): | |||
|
268 | """Test that running a second file doesn't clobber the first, gh-3547 | |||
|
269 | """ | |||
|
270 | self.mktmp("avar = 1\n" | |||
|
271 | "def afunc():\n" | |||
|
272 | " return avar\n") | |||
|
273 | ||||
|
274 | empty = tt.TempFileMixin() | |||
|
275 | empty.mktmp("") | |||
|
276 | ||||
|
277 | _ip.magic('run %s' % self.fname) | |||
|
278 | _ip.magic('run %s' % empty.fname) | |||
|
279 | nt.assert_equal(_ip.user_ns['afunc'](), 1) | |||
266 |
|
280 | |||
267 | @dec.skip_win32 |
|
281 | @dec.skip_win32 | |
268 | def test_tclass(self): |
|
282 | def test_tclass(self): |
@@ -48,3 +48,7 b' Backwards incompatible changes' | |||||
48 | :func:`IPython.utils.doctestreload.doctest_reload` to make doctests run |
|
48 | :func:`IPython.utils.doctestreload.doctest_reload` to make doctests run | |
49 | correctly inside IPython. Python releases since those versions are unaffected. |
|
49 | correctly inside IPython. Python releases since those versions are unaffected. | |
50 | For details, see :ghpull:`3068` and `Python issue 8048 <http://bugs.python.org/issue8048>`_. |
|
50 | For details, see :ghpull:`3068` and `Python issue 8048 <http://bugs.python.org/issue8048>`_. | |
|
51 | * The ``InteractiveShell.cache_main_mod()`` method has been removed, and | |||
|
52 | :meth:`~IPython.core.interactiveshell.InteractiveShell.new_main_mod` has a | |||
|
53 | different signature, expecting a filename where earlier versions expected | |||
|
54 | a namespace. See :ghpull:`3555` for details. |
General Comments 0
You need to be logged in to leave comments.
Login now