##// END OF EJS Templates
Better handling of `__file__` when running scripts....
Bradley M. Froehle -
Show More
@@ -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)
@@ -41,6 +41,7 b' from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,'
41 41 line_cell_magic, on_off, needs_local_scope)
42 42 from IPython.testing.skipdoctest import skip_doctest
43 43 from IPython.utils import py3compat
44 from IPython.utils.contexts import preserve_keys
44 45 from IPython.utils.io import capture_output
45 46 from IPython.utils.ipstruct import Struct
46 47 from IPython.utils.module_paths import find_mod
@@ -466,7 +467,9 b' python-profiler package from non-free.""")'
466 467 return
467 468
468 469 if filename.lower().endswith('.ipy'):
469 self.shell.safe_execfile_ipy(filename)
470 with preserve_keys(self.shell.user_ns, '__file__'):
471 self.shell.user_ns['__file__'] = filename
472 self.shell.safe_execfile_ipy(filename)
470 473 return
471 474
472 475 # Control the response to exit() calls made by the script being run
@@ -624,7 +627,8 b' python-profiler package from non-free.""")'
624 627 # worry about a possible KeyError.
625 628 prog_ns.pop('__name__', None)
626 629
627 self.shell.user_ns.update(prog_ns)
630 with preserve_keys(self.shell.user_ns, '__file__'):
631 self.shell.user_ns.update(prog_ns)
628 632 finally:
629 633 # It's a bit of a mystery why, but __builtins__ can change from
630 634 # being a module to becoming a dict missing some key data after
@@ -31,6 +31,7 b' from IPython.config.configurable import Configurable'
31 31 from IPython.config.loader import Config
32 32 from IPython.core import pylabtools
33 33 from IPython.utils import py3compat
34 from IPython.utils.contexts import preserve_keys
34 35 from IPython.utils.path import filefind
35 36 from IPython.utils.traitlets import (
36 37 Unicode, Instance, List, Bool, CaselessStrEnum
@@ -277,20 +278,18 b' class InteractiveShellApp(Configurable):'
277 278 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
278 279 try:
279 280 if os.path.isfile(full_filename):
280 if full_filename.endswith('.ipy'):
281 self.log.info("Running file in user namespace: %s" %
282 full_filename)
283 self.shell.safe_execfile_ipy(full_filename)
284 else:
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
281 self.log.info("Running file in user namespace: %s" %
282 full_filename)
283 # Ensure that __file__ is always defined to match Python
284 # behavior.
285 with preserve_keys(self.shell.user_ns, '__file__'):
289 286 self.shell.user_ns['__file__'] = fname
290 try:
291 self.shell.safe_execfile(full_filename, self.shell.user_ns)
292 finally:
293 del self.shell.user_ns['__file__']
287 if full_filename.endswith('.ipy'):
288 self.shell.safe_execfile_ipy(full_filename)
289 else:
290 # default to python, even without extension
291 self.shell.safe_execfile(full_filename,
292 self.shell.user_ns)
294 293 finally:
295 294 sys.argv = save_argv
296 295
General Comments 0
You need to be logged in to leave comments. Login now