##// 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,6 +467,8 b' python-profiler package from non-free.""")'
466 467 return
467 468
468 469 if filename.lower().endswith('.ipy'):
470 with preserve_keys(self.shell.user_ns, '__file__'):
471 self.shell.user_ns['__file__'] = filename
469 472 self.shell.safe_execfile_ipy(filename)
470 473 return
471 474
@@ -624,6 +627,7 b' python-profiler package from non-free.""")'
624 627 # worry about a possible KeyError.
625 628 prog_ns.pop('__name__', None)
626 629
630 with preserve_keys(self.shell.user_ns, '__file__'):
627 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
@@ -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 281 self.log.info("Running file in user namespace: %s" %
282 282 full_filename)
283 # Ensure that __file__ is always defined to match Python
284 # behavior.
285 with preserve_keys(self.shell.user_ns, '__file__'):
286 self.shell.user_ns['__file__'] = fname
287 if full_filename.endswith('.ipy'):
283 288 self.shell.safe_execfile_ipy(full_filename)
284 289 else:
285 290 # 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
290 try:
291 self.shell.safe_execfile(full_filename, self.shell.user_ns)
292 finally:
293 del self.shell.user_ns['__file__']
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