Skip to content

Commit fca7578

Browse files
authored
Merge pull request #1213 from moreati/spring-clean-2025
Spring clean 2025
2 parents 0953a93 + e97d20c commit fca7578

File tree

10 files changed

+84
-42
lines changed

10 files changed

+84
-42
lines changed

ansible_mitogen/mixins.py

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,10 @@ def __init__(self, task, connection, *args, **kwargs):
103103

104104
# required for python interpreter discovery
105105
connection.templar = self._templar
106-
self._finding_python_interpreter = False
107-
self._rediscovered_python = False
108-
# redeclaring interpreter discovery vars here in case running ansible < 2.8.0
109-
self._discovered_interpreter_key = None
110-
self._discovered_interpreter = False
111-
self._discovery_deprecation_warnings = []
112-
self._discovery_warnings = []
106+
107+
self._mitogen_discovering_interpreter = False
108+
self._mitogen_interpreter_candidate = None
109+
self._mitogen_rediscovered_interpreter = False
113110

114111
def run(self, tmp=None, task_vars=None):
115112
"""
@@ -402,7 +399,7 @@ def _execute_module(self, module_name=None, module_args=None, tmp=None,
402399
# only cache discovered_interpreter if we're not running a rediscovery
403400
# rediscovery happens in places like docker connections that could have different
404401
# python interpreters than the main host
405-
if not self._rediscovered_python:
402+
if not self._mitogen_rediscovered_interpreter:
406403
result['ansible_facts'][self._discovered_interpreter_key] = self._discovered_interpreter
407404

408405
if self._discovery_warnings:
@@ -462,7 +459,7 @@ def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
462459
# calling exec_command until we run into the right python we'll use
463460
# chicken-and-egg issue, mitogen needs a python to run low_level_execute_command
464461
# which is required by Ansible's discover_interpreter function
465-
if self._finding_python_interpreter:
462+
if self._mitogen_discovering_interpreter:
466463
possible_pythons = [
467464
'/usr/bin/python',
468465
'python3',
@@ -479,32 +476,27 @@ def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
479476
# not used, just adding a filler value
480477
possible_pythons = ['python']
481478

482-
def _run_cmd():
483-
return self._connection.exec_command(
484-
cmd=cmd,
485-
in_data=in_data,
486-
sudoable=sudoable,
487-
mitogen_chdir=chdir,
488-
)
489-
490479
for possible_python in possible_pythons:
491480
try:
492-
self._possible_python_interpreter = possible_python
493-
rc, stdout, stderr = _run_cmd()
481+
self._mitogen_interpreter_candidate = possible_python
482+
rc, stdout, stderr = self._connection.exec_command(
483+
cmd, in_data, sudoable, mitogen_chdir=chdir,
484+
)
494485
# TODO: what exception is thrown?
495486
except:
496487
# we've reached the last python attempted and failed
497-
# TODO: could use enumerate(), need to check which version of python first had it though
498-
if possible_python == 'python':
488+
if possible_python == possible_pythons[-1]:
499489
raise
500490
else:
501491
continue
502492

503493
stdout_text = to_text(stdout, errors=encoding_errors)
494+
stderr_text = to_text(stderr, errors=encoding_errors)
504495

505496
return {
506497
'rc': rc,
507498
'stdout': stdout_text,
508499
'stdout_lines': stdout_text.splitlines(),
509-
'stderr': stderr,
500+
'stderr': stderr_text,
501+
'stderr_lines': stderr_text.splitlines(),
510502
}

ansible_mitogen/transport_config.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_pyth
8787
it could be different than what's ran on the host
8888
"""
8989
# keep trying different interpreters until we don't error
90-
if action._finding_python_interpreter:
91-
return action._possible_python_interpreter
90+
if action._mitogen_discovering_interpreter:
91+
return action._mitogen_interpreter_candidate
9292

9393
if s in ['auto', 'auto_legacy', 'auto_silent', 'auto_legacy_silent']:
9494
# python is the only supported interpreter_name as of Ansible 2.8.8
@@ -102,13 +102,13 @@ def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_pyth
102102
# if we're rediscovering python then chances are we're running something like a docker connection
103103
# this will handle scenarios like running a playbook that does stuff + then dynamically creates a docker container,
104104
# then runs the rest of the playbook inside that container, and then rerunning the playbook again
105-
action._rediscovered_python = True
105+
action._mitogen_rediscovered_interpreter = True
106106

107107
# blow away the discovered_interpreter_config cache and rediscover
108108
del task_vars['ansible_facts'][discovered_interpreter_config]
109109

110110
if discovered_interpreter_config not in task_vars['ansible_facts']:
111-
action._finding_python_interpreter = True
111+
action._mitogen_discovering_interpreter = True
112112
# fake pipelining so discover_interpreter can be happy
113113
action._connection.has_pipelining = True
114114
s = ansible.executor.interpreter_discovery.discover_interpreter(
@@ -128,7 +128,7 @@ def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_pyth
128128
action._discovered_interpreter_key = discovered_interpreter_config
129129
action._discovered_interpreter = s
130130

131-
action._finding_python_interpreter = False
131+
action._mitogen_discovering_interpreter = False
132132
return s
133133

134134

docs/changelog.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ To avail of fixes in an unreleased version, please download a ZIP file
2121
In progress (unreleased)
2222
------------------------
2323

24+
* :gh:issue:`1213` tests: Enable default Python warnings
25+
* :gh:issue:`1111` :mod:`mitogen`: Replace uses of deprecated
26+
:py:func:`pkgutil.find_loader`
27+
* :gh:issue:`1213` :mod:`mitogen`: Fix unclosed file in first stage
28+
* :gh:issue:`1213` tests: Fix unclosed file in fd_check script
29+
* :gh:issue:`1213` :mod:`ansible_mitogen`: Don't redeclare Ansible interpreter
30+
discovery attributes
31+
* :gh:issue:`1213` :mod:`ansible_mitogen`: Rename Mitogen interpreter discovery
32+
attributes
33+
* :gh:issue:`1213` :mod:`ansible_mitogen`: Decouple possible_pythons order &
34+
error handling
35+
* :gh:issue:`1213` :mod:`ansible_mitogen`: Return ``stderr_lines`` from
36+
``_low_level_execute_command()``
2437

2538

2639
v0.3.21 (2025-01-20)

mitogen/master.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,33 @@
5454
import importlib.machinery
5555
import importlib.util
5656
from _imp import is_builtin as _is_builtin
57+
58+
def _find_loader(fullname):
59+
try:
60+
maybe_spec = importlib.util.find_spec(fullname)
61+
except (ImportError, AttributeError, TypeError, ValueError):
62+
exc = sys.exc_info()[1]
63+
raise ImportError(*exc.args)
64+
try:
65+
return maybe_spec.loader
66+
except AttributeError:
67+
return None
5768
except ImportError:
5869
# Python < 3.4, PEP 302 Import Hooks
5970
import imp
6071
from imp import is_builtin as _is_builtin
6172

73+
try:
74+
from pkgutil import find_loader as _find_loader
75+
except ImportError:
76+
# Python < 2.5
77+
from mitogen.compat.pkgutil import find_loader as _find_loader
78+
6279
try:
6380
import sysconfig
6481
except ImportError:
6582
sysconfig = None
6683

67-
if not hasattr(pkgutil, 'find_loader'):
68-
# find_loader() was new in >=2.5, but the modern pkgutil.py syntax has
69-
# been kept intentionally 2.3 compatible so we can reuse it.
70-
from mitogen.compat import pkgutil
71-
7284
import mitogen
7385
import mitogen.core
7486
import mitogen.minify
@@ -175,7 +187,7 @@ def get_child_modules(path, fullname):
175187
return [to_text(name) for _, name, _ in pkgutil.iter_modules([mod_path])]
176188
else:
177189
# we loaded some weird package in memory, so we'll see if it has a custom loader we can use
178-
loader = pkgutil.find_loader(fullname)
190+
loader = _find_loader(fullname)
179191
return [to_text(name) for name, _ in loader.iter_modules(None)] if loader else []
180192

181193

@@ -528,7 +540,7 @@ def find(self, fullname):
528540
# then the containing package is imported.
529541
# Pre-'import spec' this returned None, in Python3.6 it raises
530542
# ImportError.
531-
loader = pkgutil.find_loader(fullname)
543+
loader = _find_loader(fullname)
532544
except ImportError:
533545
e = sys.exc_info()[1]
534546
LOG.debug('%r: find_loader(%r) failed: %s', self, fullname, e)

mitogen/parent.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1429,7 +1429,9 @@ def _first_stage():
14291429
os.environ['ARGV0']=sys.executable
14301430
os.execl(sys.executable,sys.executable+'(mitogen:CONTEXT_NAME)')
14311431
os.write(1,'MITO000\n'.encode())
1432-
C=zlib.decompress(os.fdopen(0,'rb').read(PREAMBLE_COMPRESSED_LEN))
1432+
fp=os.fdopen(0,'rb')
1433+
C=zlib.decompress(fp.read(PREAMBLE_COMPRESSED_LEN))
1434+
fp.close()
14331435
fp=os.fdopen(W,'wb',0)
14341436
fp.write(C)
14351437
fp.close()

tests/ansible/ansible.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ callbacks_enabled =
1010
callback_whitelist =
1111
profile_tasks,
1212
timer
13+
duplicate_dict_key = error
1314
inventory = hosts
1415
gathering = explicit
1516
strategy_plugins = ../../ansible_mitogen/plugins/strategy
@@ -46,9 +47,13 @@ timeout = 30
4647
host_key_checking = False
4748

4849
[inventory]
50+
# Fatal error if any inventory source is unparsed by every available plugin.
4951
any_unparsed_is_failed = true
52+
# Fatal error if no inventory sources have a match for a host pattern.
5053
host_pattern_mismatch = error
5154
ignore_extensions = ~, .bak, .disabled
55+
# Fatal error if no inventory sources are successfully parsed.
56+
unparsed_is_failed = true
5257

5358
[callback_profile_tasks]
5459
task_output_limit = 10

tests/ansible/integration/runner/_reset_conn.yml

Lines changed: 0 additions & 2 deletions
This file was deleted.

tests/ansible/tests/connection_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ def make_connection(self):
4545
conn = self.klass(play_context, new_stdin=False)
4646
# conn functions don't fetch ActionModuleMixin objs from _get_task_vars()
4747
# through the usual walk-the-stack approach so we'll not run interpreter discovery here
48-
conn._action = mock.MagicMock(_possible_python_interpreter=testlib.base_executable())
48+
conn._action = mock.MagicMock(
49+
_mitogen_interpreter_candidate=testlib.base_executable(),
50+
)
4951
conn.on_action_run(
5052
task_vars={},
5153
delegate_to_hostname=None,

tests/data/fd_check.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def controlling_tty():
2626
return None
2727

2828

29+
out_path = sys.argv[1]
2930
fd = int(sys.argv[2])
3031
st = os.fstat(fd)
3132

@@ -35,12 +36,29 @@ def controlling_tty():
3536
else:
3637
buf = os.read(fd, 4).decode()
3738

38-
open(sys.argv[1], 'w').write(repr({
39+
output = repr({
3940
'buf': buf,
4041
'flags': fcntl.fcntl(fd, fcntl.F_GETFL),
4142
'st_mode': st.st_mode,
4243
'st_dev': st.st_dev,
4344
'st_ino': st.st_ino,
4445
'ttyname': ttyname(fd),
4546
'controlling_tty': controlling_tty(),
46-
}))
47+
})
48+
49+
try:
50+
out_f = open(out_path, 'w')
51+
except Exception:
52+
exc = sys.exc_info()[1]
53+
sys.stderr.write("Failed to open %r: %r" % (out_path, exc))
54+
sys.exit(1)
55+
56+
try:
57+
out_f.write(output)
58+
except Exception:
59+
out_f.close()
60+
exc = sys.exc_info()[1]
61+
sys.stderr.write("Failed to write to %r: %r" % (out_path, exc))
62+
sys.exit(2)
63+
64+
out_f.close()

tox.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ setenv =
105105
NOCOVERAGE_ERASE = 1
106106
NOCOVERAGE_REPORT = 1
107107
PIP_CONSTRAINT={toxinidir}/tests/constraints.txt
108+
# Print warning on the first occurence at each module:linenno in Mitogen. Available Python 2.7, 3.2+.
109+
PYTHONWARNINGS=default:::ansible_mitogen,default:::mitogen
108110
# Ansible 6 - 8 (ansible-core 2.13 - 2.15) require Python 2.7 or >= 3.5 on targets
109111
ansible6: MITOGEN_TEST_DISTRO_SPECS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004
110112
ansible7: MITOGEN_TEST_DISTRO_SPECS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004
@@ -140,7 +142,6 @@ allowlist_externals =
140142
# Added: Tox 3.18: Tox 4.0+
141143
*_install.py
142144
*_tests.py
143-
aws
144145
docker
145146
docker-credential-secretservice
146147
echo
@@ -150,7 +151,6 @@ whitelist_externals =
150151
# Deprecated: Tox 3.18+; Removed: Tox 4.0
151152
*_install.py
152153
*_tests.py
153-
aws
154154
docker
155155
docker-credential-secretservice
156156
echo

0 commit comments

Comments
 (0)