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( |
|
|
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