Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys.modules unpatching more trouble than it's worth #141

Closed
wickman opened this issue Aug 4, 2015 · 1 comment
Closed

sys.modules unpatching more trouble than it's worth #141

wickman opened this issue Aug 4, 2015 · 1 comment

Comments

@wickman
Copy link
Contributor

wickman commented Aug 4, 2015

pex/pex.py has the following gem:

  # Thar be dragons -- when this contextmanager exits, the interpreter is
  # potentially in a wonky state since the patches here (minimum_sys_modules
  # for example) actually mutate global state.  This should not be
  # considered a reversible operation despite being a contextmanager.
  @classmethod
  @contextmanager
  def patch_sys(cls):
    """Patch sys with all site scrubbed."""
    def patch_dict(old_value, new_value):
      old_value.clear()
      old_value.update(new_value)

    def patch_all(path, path_importer_cache, modules):
      sys.path[:] = path
      patch_dict(sys.path_importer_cache, path_importer_cache)
      patch_dict(sys.modules, modules)

    old_sys_path, old_sys_path_importer_cache, old_sys_modules = (
        sys.path[:], sys.path_importer_cache.copy(), sys.modules.copy())
    new_sys_path, new_sys_path_importer_cache, new_sys_modules = cls.minimum_sys()

    patch_all(new_sys_path, new_sys_path_importer_cache, new_sys_modules)

    try:
      yield   
    finally:
      patch_all(old_sys_path, old_sys_path_importer_cache, old_sys_modules)

The first patch_all replaces the global sys.path, sys.path_importer_cache and sys.modules. This is fine, but the second patch_all replaces sys.modules with the original set, and thus de-refcounting all the modules that were imported during the lifecycle of the PEX. If you've registered sys.excepthook, atexit handlers or __del__, chances are you've seen inscrutable exceptions like 'NoneType' object has no attribute 'TBinaryProtocolAccelerated' or something. This is because of CPython interpreter teardown behavior: https://bugs.python.org/issue18214. This has since been "fixed" in CPython 3.4 but we can't mandate its use for everyone.

I'm proposing that we get rid of the unpatch. It is only used during PEX.execute, which behaves like "exec()" and should be the last call in any sensible program. I can't think of any reason to keep it other than some misguided sense of functional purity.

@jsirois
Copy link
Member

jsirois commented Aug 4, 2015

+1

wickman added a commit to wickman/pex that referenced this issue Aug 4, 2015
wickman added a commit that referenced this issue Aug 4, 2015
Address #141.  Update version.py to reflect 1.0.2.dev0.
@wickman wickman closed this as completed Aug 4, 2015
lorencarvalho added a commit to lorencarvalho/pex that referenced this issue Oct 8, 2015
* upstream/master:
  Migrate to the new travis-ci infra.
  [docs] update header in index.rst
  Add docs, change default behavior to use namesake command as pex.
  bdist_pex: Nicer output filename
  Don't choke if pkg has no console_scripts
  Allows --pex-args to take an argument
  Initial implementation of bdist_pex.
  Fix missed mock of safe_mkdir.  Pin pytest to 2.5.2.
  Add pex-identifying User-Agent to requests sessions.
  Fix the docs release headers.
  Normalize all names in ResolvableSet.  Fixes pex-tool#147.
  Release 1.0.3
  Fix pex-tool#139: PEX_SCRIPT fails for scripts from not-zip-safe eggs.
  Fix a logging typo when determining the minimum sys.path
  Remove unnecessary stderr print on SystemExit().code == None
  Bump the pre-release version and update the change log.
  Accomodate OSX `Python` python binaries.
  Release 1.0.2
  Address pex-tool#141.  Update version.py to reflect 1.0.2.dev0.
  Fix from_env to capture only explicitly set values.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants