##// END OF EJS Templates
Fernando Perez -
Show More
@@ -0,0 +1,34 b''
1 """Test code for https://bugs.launchpad.net/ipython/+bug/239054
2
3 WARNING: this script exits IPython! It MUST be run in a subprocess.
4
5 When you run the following script from CPython it prints:
6 __init__ is here
7 __del__ is here
8
9 and creates the __del__.txt file
10
11 When you run it from IPython it prints:
12 __init__ is here
13
14 When you exit() or Exit from IPython neothing is printed and no file is created
15 (the file thing is to make sure __del__ is really never called and not that
16 just the output is eaten).
17
18 Note that if you call %reset in IPython then everything is Ok.
19
20 IPython should do the equivalent of %reset and release all the references it
21 holds before exit. This behavior is important when working with binding objects
22 that rely on __del__. If the current behavior has some use case then I suggest
23 to add a configuration option to IPython to control it.
24 """
25 import sys
26
27 class A(object):
28 def __del__(self):
29 print 'object A deleted'
30
31 a = A()
32
33 # Now, we force an exit, the caller will check that the del printout was given
34 _ip.IP.ask_exit()
@@ -0,0 +1,16 b''
1 """Tests for the key iplib module, where the main ipython class is defined.
2 """
3
4 import nose.tools as nt
5
6 def test_reset():
7 """reset must clear most namespaces."""
8 ip = _ip.IP
9 ip.reset() # first, it should run without error
10 # Then, check that most namespaces end up empty
11 for ns in ip.ns_refs_table:
12 if ns is ip.user_ns:
13 # The user namespace is reset with some data, so we can't check for
14 # it being empty
15 continue
16 nt.assert_equals(len(ns),0)
@@ -186,7 +186,6 b' class IPApi(object):'
186 186 self.set_custom_exc = ip.set_custom_exc
187 187
188 188 self.user_ns = ip.user_ns
189 self.user_ns['_ip'] = self
190 189
191 190 self.set_crash_handler = ip.set_crash_handler
192 191
@@ -285,6 +285,13 b' class InteractiveShell(object,Magic):'
285 285 # This is the namespace where all normal user variables live
286 286 self.user_ns = user_ns
287 287 self.user_global_ns = user_global_ns
288
289 # An auxiliary namespace that checks what parts of the user_ns were
290 # loaded at startup, so we can list later only variables defined in
291 # actual interactive use. Since it is always a subset of user_ns, it
292 # doesn't need to be seaparately tracked in the ns_table
293 self.user_config_ns = {}
294
288 295 # A namespace to keep track of internal data structures to prevent
289 296 # them from cluttering user-visible stuff. Will be updated later
290 297 self.internal_ns = {}
@@ -294,6 +301,24 b' class InteractiveShell(object,Magic):'
294 301 # of positional arguments of the alias.
295 302 self.alias_table = {}
296 303
304 # Now that FakeModule produces a real module, we've run into a nasty
305 # problem: after script execution (via %run), the module where the user
306 # code ran is deleted. Now that this object is a true module (needed
307 # so docetst and other tools work correctly), the Python module
308 # teardown mechanism runs over it, and sets to None every variable
309 # present in that module. Top-level references to objects from the
310 # script survive, because the user_ns is updated with them. However,
311 # calling functions defined in the script that use other things from
312 # the script will fail, because the function's closure had references
313 # to the original objects, which are now all None. So we must protect
314 # these modules from deletion by keeping a cache. To avoid keeping
315 # stale modules around (we only need the one from the last run), we use
316 # a dict keyed with the full path to the script, so only the last
317 # version of the module is held in the cache. The %reset command will
318 # flush this cache. See the cache_main_mod() and clear_main_mod_cache()
319 # methods for details on use.
320 self._user_main_modules = {}
321
297 322 # A table holding all the namespaces IPython deals with, so that
298 323 # introspection facilities can search easily.
299 324 self.ns_table = {'user':user_ns,
@@ -302,9 +327,14 b' class InteractiveShell(object,Magic):'
302 327 'internal':self.internal_ns,
303 328 'builtin':__builtin__.__dict__
304 329 }
305 # The user namespace MUST have a pointer to the shell itself.
306 self.user_ns[name] = self
307 330
331 # Similarly, track all namespaces where references can be held and that
332 # we can safely clear (so it can NOT include builtin). This one can be
333 # a simple list.
334 self.ns_refs_table = [ user_ns, user_global_ns, self.user_config_ns,
335 self.alias_table, self.internal_ns,
336 self._user_main_modules ]
337
308 338 # We need to insert into sys.modules something that looks like a
309 339 # module but which accesses the IPython namespace, for shelve and
310 340 # pickle to work interactively. Normally they rely on getting
@@ -329,32 +359,13 b' class InteractiveShell(object,Magic):'
329 359 #print "pickle hack in place" # dbg
330 360 #print 'main_name:',main_name # dbg
331 361 sys.modules[main_name] = FakeModule(self.user_ns)
332
333 # Now that FakeModule produces a real module, we've run into a nasty
334 # problem: after script execution (via %run), the module where the user
335 # code ran is deleted. Now that this object is a true module (needed
336 # so docetst and other tools work correctly), the Python module
337 # teardown mechanism runs over it, and sets to None every variable
338 # present in that module. Top-level references to objects from the
339 # script survive, because the user_ns is updated with them. However,
340 # calling functions defined in the script that use other things from
341 # the script will fail, because the function's closure had references
342 # to the original objects, which are now all None. So we must protect
343 # these modules from deletion by keeping a cache. To avoid keeping
344 # stale modules around (we only need the one from the last run), we use
345 # a dict keyed with the full path to the script, so only the last
346 # version of the module is held in the cache. The %reset command will
347 # flush this cache. See the cache_main_mod() and clear_main_mod_cache()
348 # methods for details on use.
349 self._user_main_modules = {}
350 362
351 363 # List of input with multi-line handling.
352 # Fill its zero entry, user counter starts at 1
353 self.input_hist = InputList(['\n'])
364 self.input_hist = InputList()
354 365 # This one will hold the 'raw' input history, without any
355 366 # pre-processing. This will allow users to retrieve the input just as
356 367 # it was exactly typed in by the user, with %hist -r.
357 self.input_hist_raw = InputList(['\n'])
368 self.input_hist_raw = InputList()
358 369
359 370 # list of visited directories
360 371 try:
@@ -380,17 +391,7 b' class InteractiveShell(object,Magic):'
380 391 no_alias[key] = 1
381 392 no_alias.update(__builtin__.__dict__)
382 393 self.no_alias = no_alias
383
384 # make global variables for user access to these
385 self.user_ns['_ih'] = self.input_hist
386 self.user_ns['_oh'] = self.output_hist
387 self.user_ns['_dh'] = self.dir_hist
388
389 # user aliases to input and output histories
390 self.user_ns['In'] = self.input_hist
391 self.user_ns['Out'] = self.output_hist
392 394
393 self.user_ns['_sh'] = IPython.shadowns
394 395 # Object variable to store code object waiting execution. This is
395 396 # used mainly by the multithreaded shells, but it can come in handy in
396 397 # other situations. No need to use a Queue here, since it's a single
@@ -583,11 +584,13 b' class InteractiveShell(object,Magic):'
583 584 else:
584 585 auto_alias = ()
585 586 self.auto_alias = [s.split(None,1) for s in auto_alias]
586
587 587
588 588 # Produce a public API instance
589 589 self.api = IPython.ipapi.IPApi(self)
590 590
591 # Initialize all user-visible namespaces
592 self.init_namespaces()
593
591 594 # Call the actual (public) initializer
592 595 self.init_auto_alias()
593 596
@@ -654,7 +657,6 b' class InteractiveShell(object,Magic):'
654 657 # Load readline proper
655 658 if rc.readline:
656 659 self.init_readline()
657
658 660
659 661 # local shortcut, this is used a LOT
660 662 self.log = self.logger.log
@@ -721,6 +723,39 b' class InteractiveShell(object,Magic):'
721 723 if batchrun and not self.rc.interact:
722 724 self.ask_exit()
723 725
726 def init_namespaces(self):
727 """Initialize all user-visible namespaces to their minimum defaults.
728
729 Certain history lists are also initialized here, as they effectively
730 act as user namespaces.
731
732 Note
733 ----
734 All data structures here are only filled in, they are NOT reset by this
735 method. If they were not empty before, data will simply be added to
736 therm.
737 """
738 # The user namespace MUST have a pointer to the shell itself.
739 self.user_ns[self.name] = self
740
741 # Store the public api instance
742 self.user_ns['_ip'] = self.api
743
744 # make global variables for user access to the histories
745 self.user_ns['_ih'] = self.input_hist
746 self.user_ns['_oh'] = self.output_hist
747 self.user_ns['_dh'] = self.dir_hist
748
749 # user aliases to input and output histories
750 self.user_ns['In'] = self.input_hist
751 self.user_ns['Out'] = self.output_hist
752
753 self.user_ns['_sh'] = IPython.shadowns
754
755 # Fill the history zero entry, user counter starts at 1
756 self.input_hist.append('\n')
757 self.input_hist_raw.append('\n')
758
724 759 def add_builtins(self):
725 760 """Store ipython references into the builtin namespace.
726 761
@@ -1249,7 +1284,27 b' want to merge them back into the new files.""" % locals()'
1249 1284 except OSError:
1250 1285 pass
1251 1286
1287 # Clear all user namespaces to release all references cleanly.
1288 self.reset()
1289
1290 # Run user hooks
1252 1291 self.hooks.shutdown_hook()
1292
1293 def reset(self):
1294 """Clear all internal namespaces.
1295
1296 Note that this is much more aggressive than %reset, since it clears
1297 fully all namespaces, as well as all input/output lists.
1298 """
1299 for ns in self.ns_refs_table:
1300 ns.clear()
1301
1302 # Clear input and output histories
1303 self.input_hist[:] = []
1304 self.input_hist_raw[:] = []
1305 self.output_hist.clear()
1306 # Restore the user namespaces to minimal usability
1307 self.init_namespaces()
1253 1308
1254 1309 def savehist(self):
1255 1310 """Save input history to a file (via readline library)."""
@@ -2012,7 +2067,6 b' want to merge them back into the new files.""" % locals()'
2012 2067 # NOT skip even a blank line if we are in a code block (more is
2013 2068 # true)
2014 2069
2015
2016 2070 if line or more:
2017 2071 # push to raw history, so hist line numbers stay in sync
2018 2072 self.input_hist_raw.append("# " + line + "\n")
@@ -107,8 +107,6 b' def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,'
107 107 IP.user_ns['help'] = _Helper()
108 108 except ImportError:
109 109 warn('help() not available - check site.py')
110 IP.user_config_ns = {}
111
112 110
113 111 if DEVDEBUG:
114 112 # For developer debugging only (global flag)
@@ -72,7 +72,7 b' class py_file_finder(object):'
72 72 def __call__(self,name):
73 73 from IPython.genutils import get_py_filename
74 74 try:
75 get_py_filename(name)
75 return get_py_filename(name)
76 76 except IOError:
77 77 test_dir = os.path.dirname(self.test_filename)
78 78 new_path = os.path.join(test_dir,name)
@@ -80,6 +80,14 b' def doctest_hist_r():'
80 80 """
81 81
82 82
83 def test_obj_del():
84 """Test that object's __del__ methods are called on exit."""
85 test_dir = os.path.dirname(__file__)
86 del_file = os.path.join(test_dir,'obj_del.py')
87 out = _ip.IP.getoutput('ipython %s' % del_file)
88 nt.assert_equals(out,'object A deleted')
89
90
83 91 def test_shist():
84 92 # Simple tests of ShadowHist class - test generator.
85 93 import os, shutil, tempfile
General Comments 0
You need to be logged in to leave comments. Login now