Show More
@@ -0,0 +1,51 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Tests for shellapp module. | |||
|
3 | ||||
|
4 | Authors | |||
|
5 | ------- | |||
|
6 | * Bradley Froehle | |||
|
7 | """ | |||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2012 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | import unittest | |||
|
19 | ||||
|
20 | import nose.tools as nt | |||
|
21 | ||||
|
22 | from IPython.testing import decorators as dec | |||
|
23 | from IPython.testing import tools as tt | |||
|
24 | ||||
|
25 | class TestFileToRun(unittest.TestCase, tt.TempFileMixin): | |||
|
26 | """Test the behavior of the file_to_run parameter.""" | |||
|
27 | ||||
|
28 | def test_py_script_file_attribute(self): | |||
|
29 | """Test that `__file__` is set when running `ipython file.py`""" | |||
|
30 | src = "print(__file__)\n" | |||
|
31 | self.mktmp(src) | |||
|
32 | ||||
|
33 | if dec.module_not_available('sqlite3'): | |||
|
34 | err = 'WARNING: IPython History requires SQLite, your history will not be saved\n' | |||
|
35 | else: | |||
|
36 | err = None | |||
|
37 | tt.ipexec_validate(self.fname, self.fname, err) | |||
|
38 | ||||
|
39 | def test_ipy_script_file_attribute(self): | |||
|
40 | """Test that `__file__` is set when running `ipython file.ipy`""" | |||
|
41 | src = "print(__file__)\n" | |||
|
42 | self.mktmp(src, ext='.ipy') | |||
|
43 | ||||
|
44 | if dec.module_not_available('sqlite3'): | |||
|
45 | err = 'WARNING: IPython History requires SQLite, your history will not be saved\n' | |||
|
46 | else: | |||
|
47 | err = None | |||
|
48 | tt.ipexec_validate(self.fname, self.fname, err) | |||
|
49 | ||||
|
50 | # Ideally we would also test that `__file__` is not set in the | |||
|
51 | # interactive namespace after running `ipython -i <file>`. |
@@ -0,0 +1,71 b'' | |||||
|
1 | # encoding: utf-8 | |||
|
2 | """ | |||
|
3 | Context managers for temporarily updating dictionaries. | |||
|
4 | ||||
|
5 | Authors: | |||
|
6 | ||||
|
7 | * Bradley Froehle | |||
|
8 | """ | |||
|
9 | ||||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | # Copyright (C) 2012 The IPython Development Team | |||
|
12 | # | |||
|
13 | # Distributed under the terms of the BSD License. The full license is in | |||
|
14 | # the file COPYING, distributed as part of this software. | |||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | ||||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | # Code | |||
|
19 | #----------------------------------------------------------------------------- | |||
|
20 | ||||
|
21 | class preserve_keys(object): | |||
|
22 | """Preserve a set of keys in a dictionary. | |||
|
23 | ||||
|
24 | Upon entering the context manager the current values of the keys | |||
|
25 | will be saved. Upon exiting, the dictionary will be updated to | |||
|
26 | restore the original value of the preserved keys. Preserved keys | |||
|
27 | which did not exist when entering the context manager will be | |||
|
28 | deleted. | |||
|
29 | ||||
|
30 | Example | |||
|
31 | ------- | |||
|
32 | ||||
|
33 | >>> d = {'a': 1, 'b': 2, 'c': 3} | |||
|
34 | >>> with preserve_keys(d, 'b', 'c', 'd'): | |||
|
35 | ... del d['a'] | |||
|
36 | ... del d['b'] # will be reset to 2 | |||
|
37 | ... d['c'] = None # will be reset to 3 | |||
|
38 | ... d['d'] = 4 # will be deleted | |||
|
39 | ... d['e'] = 5 | |||
|
40 | ... print(sorted(d.items())) | |||
|
41 | ... | |||
|
42 | [('c', None), ('d', 4), ('e', 5)] | |||
|
43 | >>> print(sorted(d.items())) | |||
|
44 | [('b', 2), ('c', 3), ('e', 5)] | |||
|
45 | """ | |||
|
46 | ||||
|
47 | def __init__(self, dictionary, *keys): | |||
|
48 | self.dictionary = dictionary | |||
|
49 | self.keys = keys | |||
|
50 | ||||
|
51 | def __enter__(self): | |||
|
52 | # Actions to perform upon exiting. | |||
|
53 | to_delete = [] | |||
|
54 | to_update = {} | |||
|
55 | ||||
|
56 | d = self.dictionary | |||
|
57 | for k in self.keys: | |||
|
58 | if k in d: | |||
|
59 | to_update[k] = d[k] | |||
|
60 | else: | |||
|
61 | to_delete.append(k) | |||
|
62 | ||||
|
63 | self.to_delete = to_delete | |||
|
64 | self.to_update = to_update | |||
|
65 | ||||
|
66 | def __exit__(self, *exc_info): | |||
|
67 | d = self.dictionary | |||
|
68 | ||||
|
69 | for k in self.to_delete: | |||
|
70 | d.pop(k, None) | |||
|
71 | d.update(self.to_update) |
@@ -42,6 +42,7 b' from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,' | |||||
42 | line_cell_magic, on_off, needs_local_scope) |
|
42 | line_cell_magic, on_off, needs_local_scope) | |
43 | from IPython.testing.skipdoctest import skip_doctest |
|
43 | from IPython.testing.skipdoctest import skip_doctest | |
44 | from IPython.utils import py3compat |
|
44 | from IPython.utils import py3compat | |
|
45 | from IPython.utils.contexts import preserve_keys | |||
45 | from IPython.utils.io import capture_output |
|
46 | from IPython.utils.io import capture_output | |
46 | from IPython.utils.ipstruct import Struct |
|
47 | from IPython.utils.ipstruct import Struct | |
47 | from IPython.utils.module_paths import find_mod |
|
48 | from IPython.utils.module_paths import find_mod | |
@@ -478,7 +479,9 b' python-profiler package from non-free.""")' | |||||
478 | return |
|
479 | return | |
479 |
|
480 | |||
480 | if filename.lower().endswith('.ipy'): |
|
481 | if filename.lower().endswith('.ipy'): | |
481 | self.shell.safe_execfile_ipy(filename) |
|
482 | with preserve_keys(self.shell.user_ns, '__file__'): | |
|
483 | self.shell.user_ns['__file__'] = filename | |||
|
484 | self.shell.safe_execfile_ipy(filename) | |||
482 | return |
|
485 | return | |
483 |
|
486 | |||
484 | # Control the response to exit() calls made by the script being run |
|
487 | # Control the response to exit() calls made by the script being run | |
@@ -644,7 +647,8 b' python-profiler package from non-free.""")' | |||||
644 | # worry about a possible KeyError. |
|
647 | # worry about a possible KeyError. | |
645 | prog_ns.pop('__name__', None) |
|
648 | prog_ns.pop('__name__', None) | |
646 |
|
649 | |||
647 |
self.shell.user_ns |
|
650 | with preserve_keys(self.shell.user_ns, '__file__'): | |
|
651 | self.shell.user_ns.update(prog_ns) | |||
648 | finally: |
|
652 | finally: | |
649 | # It's a bit of a mystery why, but __builtins__ can change from |
|
653 | # It's a bit of a mystery why, but __builtins__ can change from | |
650 | # being a module to becoming a dict missing some key data after |
|
654 | # being a module to becoming a dict missing some key data after |
@@ -31,6 +31,7 b' from IPython.config.configurable import Configurable' | |||||
31 | from IPython.config.loader import Config |
|
31 | from IPython.config.loader import Config | |
32 | from IPython.core import pylabtools |
|
32 | from IPython.core import pylabtools | |
33 | from IPython.utils import py3compat |
|
33 | from IPython.utils import py3compat | |
|
34 | from IPython.utils.contexts import preserve_keys | |||
34 | from IPython.utils.path import filefind |
|
35 | from IPython.utils.path import filefind | |
35 | from IPython.utils.traitlets import ( |
|
36 | from IPython.utils.traitlets import ( | |
36 | Unicode, Instance, List, Bool, CaselessStrEnum |
|
37 | Unicode, Instance, List, Bool, CaselessStrEnum | |
@@ -277,20 +278,18 b' class InteractiveShellApp(Configurable):' | |||||
277 | sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ] |
|
278 | sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ] | |
278 | try: |
|
279 | try: | |
279 | if os.path.isfile(full_filename): |
|
280 | if os.path.isfile(full_filename): | |
280 | if full_filename.endswith('.ipy'): |
|
281 | self.log.info("Running file in user namespace: %s" % | |
281 | self.log.info("Running file in user namespace: %s" % |
|
282 | full_filename) | |
282 | full_filename) |
|
283 | # Ensure that __file__ is always defined to match Python | |
283 | self.shell.safe_execfile_ipy(full_filename) |
|
284 | # behavior. | |
284 | else: |
|
285 | with preserve_keys(self.shell.user_ns, '__file__'): | |
285 | # default to python, even without extension |
|
|||
286 | self.log.info("Running file in user namespace: %s" % |
|
|||
287 | full_filename) |
|
|||
288 | # Ensure that __file__ is always defined to match Python behavior |
|
|||
289 | self.shell.user_ns['__file__'] = fname |
|
286 | self.shell.user_ns['__file__'] = fname | |
290 | try: |
|
287 | if full_filename.endswith('.ipy'): | |
291 |
self.shell.safe_execfile(full_filename |
|
288 | self.shell.safe_execfile_ipy(full_filename) | |
292 |
|
|
289 | else: | |
293 | del self.shell.user_ns['__file__'] |
|
290 | # default to python, even without extension | |
|
291 | self.shell.safe_execfile(full_filename, | |||
|
292 | self.shell.user_ns) | |||
294 | finally: |
|
293 | finally: | |
295 | sys.argv = save_argv |
|
294 | sys.argv = save_argv | |
296 |
|
295 |
@@ -298,3 +298,35 b' tclass.py: deleting object: C-third' | |||||
298 | na = os.path.join(mydir, 'nonascii.py') |
|
298 | na = os.path.join(mydir, 'nonascii.py') | |
299 | _ip.magic('run "%s"' % na) |
|
299 | _ip.magic('run "%s"' % na) | |
300 | nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф') |
|
300 | nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф') | |
|
301 | ||||
|
302 | def test_run_py_file_attribute(self): | |||
|
303 | """Test handling of `__file__` attribute in `%run <file>.py`.""" | |||
|
304 | src = "t = __file__\n" | |||
|
305 | self.mktmp(src) | |||
|
306 | _missing = object() | |||
|
307 | file1 = _ip.user_ns.get('__file__', _missing) | |||
|
308 | _ip.magic('run %s' % self.fname) | |||
|
309 | file2 = _ip.user_ns.get('__file__', _missing) | |||
|
310 | ||||
|
311 | # Check that __file__ was equal to the filename in the script's | |||
|
312 | # namespace. | |||
|
313 | nt.assert_equal(_ip.user_ns['t'], self.fname) | |||
|
314 | ||||
|
315 | # Check that __file__ was not leaked back into user_ns. | |||
|
316 | nt.assert_equal(file1, file2) | |||
|
317 | ||||
|
318 | def test_run_ipy_file_attribute(self): | |||
|
319 | """Test handling of `__file__` attribute in `%run <file.ipy>`.""" | |||
|
320 | src = "t = __file__\n" | |||
|
321 | self.mktmp(src, ext='.ipy') | |||
|
322 | _missing = object() | |||
|
323 | file1 = _ip.user_ns.get('__file__', _missing) | |||
|
324 | _ip.magic('run %s' % self.fname) | |||
|
325 | file2 = _ip.user_ns.get('__file__', _missing) | |||
|
326 | ||||
|
327 | # Check that __file__ was equal to the filename in the script's | |||
|
328 | # namespace. | |||
|
329 | nt.assert_equal(_ip.user_ns['t'], self.fname) | |||
|
330 | ||||
|
331 | # Check that __file__ was not leaked back into user_ns. | |||
|
332 | nt.assert_equal(file1, file2) |
General Comments 0
You need to be logged in to leave comments.
Login now