Add hacks to allow Mock to be imported.

wip-fakessh-exit-status
David Wilson 7 years ago
parent 91ff12f8d8
commit 38a9482860

@ -0,0 +1,44 @@
Module Import Wall Of Shame
---------------------------
The following modules and packages run magic during ``__init.py__`` that makes
life hard for Mitogen. Executing code during module import is always bad, and
Mitogen is a concrete benchmark for why it's bad.
``pkg_resources``
=================
Anything that imports ``pkg_resources`` will eventually cause
pkg_resources to try and import and scan ``__main__`` for its ``__requires__``
attribute (``pkg_resources/__init__.py::_build_master()``). This breaks any app
that is not expecting its ``__main__`` to suddenly be sucked over a network and
injected into a remote process, like py.test.
A future version of Mitogen might have a more general hack that doesn't import
the master's ``__main__`` as ``__main__`` in the slave, avoiding all kinds of
issues like these.
**What could it do instead?**
* Explicit is better than implicit: wait until the magical behaviour is
explicitly requested (i.e. an API call).
* Use ``get("__main__")`` on :py:attr:`sys.modules` rather than ``import``, but
this method isn't general enough, it only really helps tools like Mitogen.
``pbr``
=======
It claims to use ``pkg_resources`` to read version information
(``_get_version_from_pkg_metadata()``), which would result in PEP-302 being
reused and everything just working wonderfully, but instead it actually does
direct filesystem access. So we smodge the environment with a ``PBR_VERSION``
environment variable to override any version that was defined. This will
probably break code I haven't seen yet.
**What could it do instead?**
* ``pkg_resources.get_resource_stream()``

@ -11,3 +11,4 @@ Table Of Contents
getting_started getting_started
api api
internals internals
shame

@ -368,8 +368,31 @@ class Importer(object):
finally: finally:
del self.tls.running del self.tls.running
def _load_module_hacks(self, fullname):
f = sys._getframe(2)
requestee = f.f_globals['__name__']
if fullname == '__main__' and requestee == 'pkg_resources':
# Anything that imports pkg_resources will eventually cause
# pkg_resources to try and scan __main__ for its __requires__
# attribute (pkg_resources/__init__.py::_build_master()). This
# breaks any app that is not expecting its __main__ to suddenly be
# sucked over a network and injected into a remote process, like
# py.test.
raise ImportError('Refused')
if fullname == 'pbr':
# It claims to use pkg_resources to read version information, which
# would result in PEP-302 being used, but it actually does direct
# filesystem access. So instead smodge the environment to override
# any version that was defined. This will probably break something
# later.
os.environ['PBR_VERSION'] = '0.0.0'
def load_module(self, fullname): def load_module(self, fullname):
LOG.debug('Importer.load_module(%r)', fullname) LOG.debug('Importer.load_module(%r)', fullname)
self._load_module_hacks(fullname)
try: try:
ret = self._cache[fullname] ret = self._cache[fullname]
except KeyError: except KeyError:

Loading…
Cancel
Save