blob: 0bfeda74a1a6a9874ee5c06abe704672f0928bc7 [file] [log] [blame]
Tor Norbye1aa2e092014-08-20 17:01:23 -07001"""
2The UserModuleDeleter and runfile methods are copied from
3Spyder and carry their own license agreement.
4http://code.google.com/p/spyderlib/source/browse/spyderlib/widgets/externalshell/sitecustomize.py
5
6Spyder License Agreement (MIT License)
7--------------------------------------
8
9Copyright (c) 2009-2012 Pierre Raybaut
10
11Permission is hereby granted, free of charge, to any person
12obtaining a copy of this software and associated documentation
13files (the "Software"), to deal in the Software without
14restriction, including without limitation the rights to use,
15copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the
17Software is furnished to do so, subject to the following
18conditions:
19
20The above copyright notice and this permission notice shall be
21included in all copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30OTHER DEALINGS IN THE SOFTWARE.
31"""
32
33import sys
34import os
35
36# The following classes and functions are mainly intended to be used from
37# an interactive Python session
38class UserModuleDeleter:
39 """
40 User Module Deleter (UMD) aims at deleting user modules
41 to force Python to deeply reload them during import
42
43 pathlist [list]: blacklist in terms of module path
44 namelist [list]: blacklist in terms of module name
45 """
46 def __init__(self, namelist=None, pathlist=None):
47 if namelist is None:
48 namelist = []
49 self.namelist = namelist
50 if pathlist is None:
51 pathlist = []
52 self.pathlist = pathlist
53 try:
54 # blacklist all files in org.python.pydev/pysrc
55 import pydev_pysrc, inspect
56 self.pathlist.append(os.path.dirname(pydev_pysrc.__file__))
57 except:
58 pass
59 self.previous_modules = list(sys.modules.keys())
60
61 def is_module_blacklisted(self, modname, modpath):
62 for path in [sys.prefix] + self.pathlist:
63 if modpath.startswith(path):
64 return True
65 else:
66 return set(modname.split('.')) & set(self.namelist)
67
68 def run(self, verbose=False):
69 """
70 Del user modules to force Python to deeply reload them
71
72 Do not del modules which are considered as system modules, i.e.
73 modules installed in subdirectories of Python interpreter's binary
74 Do not del C modules
75 """
76 log = []
77 modules_copy = dict(sys.modules)
78 for modname, module in modules_copy.items():
79 if modname == 'aaaaa':
80 print(modname, module)
81 print(self.previous_modules)
82 if modname not in self.previous_modules:
83 modpath = getattr(module, '__file__', None)
84 if modpath is None:
85 # *module* is a C module that is statically linked into the
86 # interpreter. There is no way to know its path, so we
87 # choose to ignore it.
88 continue
89 if not self.is_module_blacklisted(modname, modpath):
90 log.append(modname)
91 del sys.modules[modname]
92 if verbose and log:
93 print("\x1b[4;33m%s\x1b[24m%s\x1b[0m" % ("UMD has deleted",
94 ": " + ", ".join(log)))
95
96__umd__ = None
97
98_get_globals_callback = None
99def _set_globals_function(get_globals):
100 global _get_globals_callback
101 _get_globals_callback = get_globals
102def _get_globals():
103 """Return current Python interpreter globals namespace"""
104 if _get_globals_callback is not None:
105 return _get_globals_callback()
106 else:
107 try:
108 from __main__ import __dict__ as namespace
109 except ImportError:
110 try:
111 # The import fails on IronPython
112 import __main__
113 namespace = __main__.__dict__
114 except:
115 namespace
116 shell = namespace.get('__ipythonshell__')
117 if shell is not None and hasattr(shell, 'user_ns'):
118 # IPython 0.12+ kernel
119 return shell.user_ns
120 else:
121 # Python interpreter
122 return namespace
123 return namespace
124
125
126def runfile(filename, args=None, wdir=None, namespace=None):
127 """
128 Run filename
129 args: command line arguments (string)
130 wdir: working directory
131 """
132 try:
133 if hasattr(filename, 'decode'):
134 filename = filename.decode('utf-8')
135 except (UnicodeError, TypeError):
136 pass
137 global __umd__
138 if os.environ.get("PYDEV_UMD_ENABLED", "").lower() == "true":
139 if __umd__ is None:
140 namelist = os.environ.get("PYDEV_UMD_NAMELIST", None)
141 if namelist is not None:
142 namelist = namelist.split(',')
143 __umd__ = UserModuleDeleter(namelist=namelist)
144 else:
145 verbose = os.environ.get("PYDEV_UMD_VERBOSE", "").lower() == "true"
146 __umd__.run(verbose=verbose)
147 if args is not None and not isinstance(args, basestring):
148 raise TypeError("expected a character buffer object")
149 if namespace is None:
150 namespace = _get_globals()
151 if '__file__' in namespace:
152 old_file = namespace['__file__']
153 else:
154 old_file = None
155 namespace['__file__'] = filename
156 sys.argv = [filename]
157 if args is not None:
158 for arg in args.split():
159 sys.argv.append(arg)
160 if wdir is not None:
161 try:
162 if hasattr(wdir, 'decode'):
163 wdir = wdir.decode('utf-8')
164 except (UnicodeError, TypeError):
165 pass
166 os.chdir(wdir)
167 execfile(filename, namespace)
168 sys.argv = ['']
169 if old_file is None:
170 del namespace['__file__']
171 else:
172 namespace['__file__'] = old_file