| """ |
| The UserModuleDeleter and runfile methods are copied from |
| Spyder and carry their own license agreement. |
| http://code.google.com/p/spyderlib/source/browse/spyderlib/widgets/externalshell/sitecustomize.py |
| |
| Spyder License Agreement (MIT License) |
| -------------------------------------- |
| |
| Copyright (c) 2009-2012 Pierre Raybaut |
| |
| Permission is hereby granted, free of charge, to any person |
| obtaining a copy of this software and associated documentation |
| files (the "Software"), to deal in the Software without |
| restriction, including without limitation the rights to use, |
| copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following |
| conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| OTHER DEALINGS IN THE SOFTWARE. |
| """ |
| |
| import sys |
| import os |
| |
| # The following classes and functions are mainly intended to be used from |
| # an interactive Python session |
| class UserModuleDeleter: |
| """ |
| User Module Deleter (UMD) aims at deleting user modules |
| to force Python to deeply reload them during import |
| |
| pathlist [list]: blacklist in terms of module path |
| namelist [list]: blacklist in terms of module name |
| """ |
| def __init__(self, namelist=None, pathlist=None): |
| if namelist is None: |
| namelist = [] |
| self.namelist = namelist |
| if pathlist is None: |
| pathlist = [] |
| self.pathlist = pathlist |
| try: |
| # blacklist all files in org.python.pydev/pysrc |
| import pydev_pysrc, inspect |
| self.pathlist.append(os.path.dirname(pydev_pysrc.__file__)) |
| except: |
| pass |
| self.previous_modules = list(sys.modules.keys()) |
| |
| def is_module_blacklisted(self, modname, modpath): |
| for path in [sys.prefix] + self.pathlist: |
| if modpath.startswith(path): |
| return True |
| else: |
| return set(modname.split('.')) & set(self.namelist) |
| |
| def run(self, verbose=False): |
| """ |
| Del user modules to force Python to deeply reload them |
| |
| Do not del modules which are considered as system modules, i.e. |
| modules installed in subdirectories of Python interpreter's binary |
| Do not del C modules |
| """ |
| log = [] |
| modules_copy = dict(sys.modules) |
| for modname, module in modules_copy.items(): |
| if modname == 'aaaaa': |
| print(modname, module) |
| print(self.previous_modules) |
| if modname not in self.previous_modules: |
| modpath = getattr(module, '__file__', None) |
| if modpath is None: |
| # *module* is a C module that is statically linked into the |
| # interpreter. There is no way to know its path, so we |
| # choose to ignore it. |
| continue |
| if not self.is_module_blacklisted(modname, modpath): |
| log.append(modname) |
| del sys.modules[modname] |
| if verbose and log: |
| print("\x1b[4;33m%s\x1b[24m%s\x1b[0m" % ("UMD has deleted", |
| ": " + ", ".join(log))) |
| |
| __umd__ = None |
| |
| _get_globals_callback = None |
| def _set_globals_function(get_globals): |
| global _get_globals_callback |
| _get_globals_callback = get_globals |
| def _get_globals(): |
| """Return current Python interpreter globals namespace""" |
| if _get_globals_callback is not None: |
| return _get_globals_callback() |
| else: |
| try: |
| from __main__ import __dict__ as namespace |
| except ImportError: |
| try: |
| # The import fails on IronPython |
| import __main__ |
| namespace = __main__.__dict__ |
| except: |
| namespace |
| shell = namespace.get('__ipythonshell__') |
| if shell is not None and hasattr(shell, 'user_ns'): |
| # IPython 0.12+ kernel |
| return shell.user_ns |
| else: |
| # Python interpreter |
| return namespace |
| return namespace |
| |
| |
| def runfile(filename, args=None, wdir=None, namespace=None): |
| """ |
| Run filename |
| args: command line arguments (string) |
| wdir: working directory |
| """ |
| try: |
| if hasattr(filename, 'decode'): |
| filename = filename.decode('utf-8') |
| except (UnicodeError, TypeError): |
| pass |
| global __umd__ |
| if os.environ.get("PYDEV_UMD_ENABLED", "").lower() == "true": |
| if __umd__ is None: |
| namelist = os.environ.get("PYDEV_UMD_NAMELIST", None) |
| if namelist is not None: |
| namelist = namelist.split(',') |
| __umd__ = UserModuleDeleter(namelist=namelist) |
| else: |
| verbose = os.environ.get("PYDEV_UMD_VERBOSE", "").lower() == "true" |
| __umd__.run(verbose=verbose) |
| if args is not None and not isinstance(args, basestring): |
| raise TypeError("expected a character buffer object") |
| if namespace is None: |
| namespace = _get_globals() |
| if '__file__' in namespace: |
| old_file = namespace['__file__'] |
| else: |
| old_file = None |
| namespace['__file__'] = filename |
| sys.argv = [filename] |
| if args is not None: |
| for arg in args.split(): |
| sys.argv.append(arg) |
| if wdir is not None: |
| try: |
| if hasattr(wdir, 'decode'): |
| wdir = wdir.decode('utf-8') |
| except (UnicodeError, TypeError): |
| pass |
| os.chdir(wdir) |
| execfile(filename, namespace) |
| sys.argv = [''] |
| if old_file is None: |
| del namespace['__file__'] |
| else: |
| namespace['__file__'] = old_file |