##// 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 self.set_custom_exc = ip.set_custom_exc
186 self.set_custom_exc = ip.set_custom_exc
187
187
188 self.user_ns = ip.user_ns
188 self.user_ns = ip.user_ns
189 self.user_ns['_ip'] = self
190
189
191 self.set_crash_handler = ip.set_crash_handler
190 self.set_crash_handler = ip.set_crash_handler
192
191
@@ -285,6 +285,13 b' class InteractiveShell(object,Magic):'
285 # This is the namespace where all normal user variables live
285 # This is the namespace where all normal user variables live
286 self.user_ns = user_ns
286 self.user_ns = user_ns
287 self.user_global_ns = user_global_ns
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 # A namespace to keep track of internal data structures to prevent
295 # A namespace to keep track of internal data structures to prevent
289 # them from cluttering user-visible stuff. Will be updated later
296 # them from cluttering user-visible stuff. Will be updated later
290 self.internal_ns = {}
297 self.internal_ns = {}
@@ -294,6 +301,24 b' class InteractiveShell(object,Magic):'
294 # of positional arguments of the alias.
301 # of positional arguments of the alias.
295 self.alias_table = {}
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 # A table holding all the namespaces IPython deals with, so that
322 # A table holding all the namespaces IPython deals with, so that
298 # introspection facilities can search easily.
323 # introspection facilities can search easily.
299 self.ns_table = {'user':user_ns,
324 self.ns_table = {'user':user_ns,
@@ -302,9 +327,14 b' class InteractiveShell(object,Magic):'
302 'internal':self.internal_ns,
327 'internal':self.internal_ns,
303 'builtin':__builtin__.__dict__
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 # We need to insert into sys.modules something that looks like a
338 # We need to insert into sys.modules something that looks like a
309 # module but which accesses the IPython namespace, for shelve and
339 # module but which accesses the IPython namespace, for shelve and
310 # pickle to work interactively. Normally they rely on getting
340 # pickle to work interactively. Normally they rely on getting
@@ -329,32 +359,13 b' class InteractiveShell(object,Magic):'
329 #print "pickle hack in place" # dbg
359 #print "pickle hack in place" # dbg
330 #print 'main_name:',main_name # dbg
360 #print 'main_name:',main_name # dbg
331 sys.modules[main_name] = FakeModule(self.user_ns)
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 # List of input with multi-line handling.
363 # List of input with multi-line handling.
352 # Fill its zero entry, user counter starts at 1
364 self.input_hist = InputList()
353 self.input_hist = InputList(['\n'])
354 # This one will hold the 'raw' input history, without any
365 # This one will hold the 'raw' input history, without any
355 # pre-processing. This will allow users to retrieve the input just as
366 # pre-processing. This will allow users to retrieve the input just as
356 # it was exactly typed in by the user, with %hist -r.
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 # list of visited directories
370 # list of visited directories
360 try:
371 try:
@@ -380,17 +391,7 b' class InteractiveShell(object,Magic):'
380 no_alias[key] = 1
391 no_alias[key] = 1
381 no_alias.update(__builtin__.__dict__)
392 no_alias.update(__builtin__.__dict__)
382 self.no_alias = no_alias
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 # Object variable to store code object waiting execution. This is
395 # Object variable to store code object waiting execution. This is
395 # used mainly by the multithreaded shells, but it can come in handy in
396 # used mainly by the multithreaded shells, but it can come in handy in
396 # other situations. No need to use a Queue here, since it's a single
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 else:
584 else:
584 auto_alias = ()
585 auto_alias = ()
585 self.auto_alias = [s.split(None,1) for s in auto_alias]
586 self.auto_alias = [s.split(None,1) for s in auto_alias]
586
587
587
588 # Produce a public API instance
588 # Produce a public API instance
589 self.api = IPython.ipapi.IPApi(self)
589 self.api = IPython.ipapi.IPApi(self)
590
590
591 # Initialize all user-visible namespaces
592 self.init_namespaces()
593
591 # Call the actual (public) initializer
594 # Call the actual (public) initializer
592 self.init_auto_alias()
595 self.init_auto_alias()
593
596
@@ -654,7 +657,6 b' class InteractiveShell(object,Magic):'
654 # Load readline proper
657 # Load readline proper
655 if rc.readline:
658 if rc.readline:
656 self.init_readline()
659 self.init_readline()
657
658
660
659 # local shortcut, this is used a LOT
661 # local shortcut, this is used a LOT
660 self.log = self.logger.log
662 self.log = self.logger.log
@@ -721,6 +723,39 b' class InteractiveShell(object,Magic):'
721 if batchrun and not self.rc.interact:
723 if batchrun and not self.rc.interact:
722 self.ask_exit()
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 def add_builtins(self):
759 def add_builtins(self):
725 """Store ipython references into the builtin namespace.
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 except OSError:
1284 except OSError:
1250 pass
1285 pass
1251
1286
1287 # Clear all user namespaces to release all references cleanly.
1288 self.reset()
1289
1290 # Run user hooks
1252 self.hooks.shutdown_hook()
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 def savehist(self):
1309 def savehist(self):
1255 """Save input history to a file (via readline library)."""
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 # NOT skip even a blank line if we are in a code block (more is
2067 # NOT skip even a blank line if we are in a code block (more is
2013 # true)
2068 # true)
2014
2069
2015
2016 if line or more:
2070 if line or more:
2017 # push to raw history, so hist line numbers stay in sync
2071 # push to raw history, so hist line numbers stay in sync
2018 self.input_hist_raw.append("# " + line + "\n")
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 IP.user_ns['help'] = _Helper()
107 IP.user_ns['help'] = _Helper()
108 except ImportError:
108 except ImportError:
109 warn('help() not available - check site.py')
109 warn('help() not available - check site.py')
110 IP.user_config_ns = {}
111
112
110
113 if DEVDEBUG:
111 if DEVDEBUG:
114 # For developer debugging only (global flag)
112 # For developer debugging only (global flag)
@@ -72,7 +72,7 b' class py_file_finder(object):'
72 def __call__(self,name):
72 def __call__(self,name):
73 from IPython.genutils import get_py_filename
73 from IPython.genutils import get_py_filename
74 try:
74 try:
75 get_py_filename(name)
75 return get_py_filename(name)
76 except IOError:
76 except IOError:
77 test_dir = os.path.dirname(self.test_filename)
77 test_dir = os.path.dirname(self.test_filename)
78 new_path = os.path.join(test_dir,name)
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 def test_shist():
91 def test_shist():
84 # Simple tests of ShadowHist class - test generator.
92 # Simple tests of ShadowHist class - test generator.
85 import os, shutil, tempfile
93 import os, shutil, tempfile
General Comments 0
You need to be logged in to leave comments. Login now