Merge remote-tracking branch 'origin/issue479'

* origin/issue479:
  issue #490: log mitogen.unix server-side accept.
  issue #490: have Side._on_fork() empty _fork_refs
  issue #490: prevent double close() destroying unrelated Connection.
  docs: update Changelog; closes #479.
  issue #479: ModuleFinder special case for __main__ on Py3.x.
issue510
David Wilson 6 years ago
commit 104fa463af

@ -747,12 +747,16 @@ class Connection(ansible.plugins.connection.ConnectionBase):
self.broker = None self.broker = None
self.router = None self.router = None
# #420: Ansible executes "meta" actions in the top-level process, # #420: Ansible executes "meta" actions in the top-level process,
# meaning "reset_connection" will cause :class:`mitogen.core.Latch` FDs # meaning "reset_connection" will cause :class:`mitogen.core.Latch`
# to be cached and erroneously shared by children on subsequent # FDs to be cached and erroneously shared by children on subsequent
# WorkerProcess forks. To handle that, call on_fork() to ensure any # WorkerProcess forks. To handle that, call on_fork() to ensure any
# shared state is discarded. # shared state is discarded.
mitogen.fork.on_fork() # #490: only attempt to clean up when it's known that some
# resources exist to cleanup, otherwise later __del__ double-call
# to close() due to GC at random moment may obliterate an unrelated
# Connection's resources.
mitogen.fork.on_fork()
def close(self): def close(self):
""" """

@ -402,6 +402,10 @@ Core Library
Since correct group ownership is not required in most scenarios, when this Since correct group ownership is not required in most scenarios, when this
problem is detected, the PTY is allocated and opened directly by the library. problem is detected, the PTY is allocated and opened directly by the library.
* `#479 <https://github.com/dw/mitogen/issues/479>`_: Mitogen could fail to
import :mod:`__main__` on Python 3.4 and newer due to a breaking change in
the :mod:`pkgutil` API. The program's main script is now handled specially.
* `16ca111e <https://github.com/dw/mitogen/commit/16ca111e>`_: handle OpenSSH * `16ca111e <https://github.com/dw/mitogen/commit/16ca111e>`_: handle OpenSSH
7.5 permission denied prompts when ``~/.ssh/config`` rewrites are present. 7.5 permission denied prompts when ``~/.ssh/config`` rewrites are present.

@ -1415,7 +1415,9 @@ class Side(object):
@classmethod @classmethod
def _on_fork(cls): def _on_fork(cls):
for side in list(cls._fork_refs.values()): while cls._fork_refs:
_, side = cls._fork_refs.popitem()
_vv and IOLOG.debug('Side._on_fork() closing %r', side)
side.close() side.close()
def close(self): def close(self):

@ -409,9 +409,37 @@ class ModuleFinder(object):
if os.path.exists(path) and self._looks_like_script(path): if os.path.exists(path) and self._looks_like_script(path):
return path return path
def _get_main_module_defective_python_3x(self, fullname):
"""
Recent versions of Python 3.x introduced an incomplete notion of
importer specs, and in doing so created permanent asymmetry in the
:mod:`pkgutil` interface handling for the `__main__` module. Therefore
we must handle `__main__` specially.
"""
if fullname != '__main__':
return None
mod = sys.modules.get(fullname)
if not mod:
return None
path = getattr(mod, '__file__', None)
if not (os.path.exists(path) and self._looks_like_script(path)):
return None
fp = open(path, 'rb')
try:
source = fp.read()
finally:
fp.close()
return path, source, False
def _get_module_via_pkgutil(self, fullname): def _get_module_via_pkgutil(self, fullname):
"""Attempt to fetch source code via pkgutil. In an ideal world, this """
would be the only required implementation of get_module().""" Attempt to fetch source code via pkgutil. In an ideal world, this would
be the only required implementation of get_module().
"""
try: try:
# Pre-'import spec' this returned None, in Python3.6 it raises # Pre-'import spec' this returned None, in Python3.6 it raises
# ImportError. # ImportError.
@ -543,9 +571,12 @@ class ModuleFinder(object):
""" """
self._found_cache[fullname] = (path, source, is_pkg) self._found_cache[fullname] = (path, source, is_pkg)
get_module_methods = [_get_module_via_pkgutil, get_module_methods = [
_get_module_via_sys_modules, _get_main_module_defective_python_3x,
_get_module_via_parent_enumeration] _get_module_via_pkgutil,
_get_module_via_sys_modules,
_get_module_via_parent_enumeration,
]
def get_module_source(self, fullname): def get_module_source(self, fullname):
"""Given the name of a loaded module `fullname`, attempt to find its """Given the name of a loaded module `fullname`, attempt to find its

@ -117,6 +117,7 @@ class Listener(mitogen.core.BasicStream):
self, pid, sys.exc_info()[1]) self, pid, sys.exc_info()[1])
return return
LOG.debug('%r: accepted %r', self, stream)
stream.accept(sock.fileno(), sock.fileno()) stream.accept(sock.fileno(), sock.fileno())
self._router.register(context, stream) self._router.register(context, stream)

@ -50,6 +50,33 @@ class IsStdlibNameTest(testlib.TestCase):
self.assertFalse(self.func('mitogen.fakessh')) self.assertFalse(self.func('mitogen.fakessh'))
class GetMainModuleDefectivePython3x(testlib.TestCase):
klass = mitogen.master.ModuleFinder
def call(self, fullname):
return self.klass()._get_main_module_defective_python_3x(fullname)
def test_builtin(self):
self.assertEquals(None, self.call('sys'))
def test_not_main(self):
self.assertEquals(None, self.call('mitogen'))
def test_main(self):
import __main__
path, source, is_pkg = self.call('__main__')
self.assertTrue(path is not None)
self.assertTrue(os.path.exists(path))
self.assertEquals(path, __main__.__file__)
fp = open(path, 'rb')
try:
self.assertEquals(source, fp.read())
finally:
fp.close()
self.assertFalse(is_pkg)
class GetModuleViaPkgutilTest(testlib.TestCase): class GetModuleViaPkgutilTest(testlib.TestCase):
klass = mitogen.master.ModuleFinder klass = mitogen.master.ModuleFinder

Loading…
Cancel
Save