Merge pull request #800 from moreati/0.2-backport

Prepare 0.2.10rc1
0.2-release v0.2.10rc1
Alex Willmer 4 years ago committed by GitHub
commit 9d404e0b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,7 +16,7 @@ batches = [
] ]
batches.extend( batches.extend(
['docker pull %s' % (ci_lib.image_for_distro(distro),)] ['docker pull %s' % (ci_lib.image_for_distro(distro),), 'sleep 1']
for distro in ci_lib.DISTROS for distro in ci_lib.DISTROS
) )

@ -37,9 +37,6 @@ with ci_lib.Fold('docker_setup'):
with ci_lib.Fold('job_setup'): with ci_lib.Fold('job_setup'):
# Don't set -U as that will upgrade Paramiko to a non-2.6 compatible version.
run("pip install -q ansible==%s", ci_lib.ANSIBLE_VERSION)
os.chdir(TESTS_DIR) os.chdir(TESTS_DIR)
os.chmod('../data/docker/mitogen__has_sudo_pubkey.key', int('0600', 7)) os.chmod('../data/docker/mitogen__has_sudo_pubkey.key', int('0600', 7))
@ -69,8 +66,6 @@ with ci_lib.Fold('job_setup'):
run("sudo apt-get update") run("sudo apt-get update")
run("sudo apt-get install -y sshpass") run("sudo apt-get install -y sshpass")
run("bash -c 'sudo ln -vfs /usr/lib/python2.7/plat-x86_64-linux-gnu/_sysconfigdata_nd.py /usr/lib/python2.7 || true'")
run("bash -c 'sudo ln -vfs /usr/lib/python2.7/plat-x86_64-linux-gnu/_sysconfigdata_nd.py $VIRTUAL_ENV/lib/python2.7 || true'")
with ci_lib.Fold('ansible'): with ci_lib.Fold('ansible'):
playbook = os.environ.get('PLAYBOOK', 'all.yml') playbook = os.environ.get('PLAYBOOK', 'all.yml')

@ -14,17 +14,25 @@ steps:
# stuff into. The virtualenv can probably be removed again, but this was a # stuff into. The virtualenv can probably be removed again, but this was a
# hard-fought battle and for now I am tired of this crap. # hard-fought battle and for now I am tired of this crap.
- script: | - script: |
# need wheel before building virtualenv because of bdist_wheel and setuptools deps
# Mac's System Integrity Protection prevents symlinking /usr/bin
# and Azure isn't allowing disabling it apparently: https://developercommunityapi.westus.cloudapp.azure.com/idea/558702/allow-disabling-sip-on-microsoft-hosted-macos-agen.html
# the || will activate when running python3 tests
# TODO: get python3 tests passing # TODO: get python3 tests passing
(sudo ln -fs /usr/bin/python$(python.version) /usr/bin/python && set -o errexit
/usr/bin/python -m pip install -U pip wheel setuptools && set -o nounset
/usr/bin/python -m pip install -U virtualenv && set -o pipefail
/usr/bin/python -m virtualenv /tmp/venv -p /usr/bin/python$(python.version)) || set -x
(sudo /usr/bin/python$(python.version) -m pip install -U pip wheel setuptools &&
/usr/bin/python$(python.version) -m venv /tmp/venv) # Ensure virtualenv is in system-wide $PATH on OSX, for Ansible test tasks
# that use it, e.g. regression/issue_152__virtualenv_python_fails.yml
if [[ -d /Library/Frameworks/Python.framework/Versions/2.7/bin ]]; then
echo $PATH
which python
python -m pip install -U pip virtualenv
ln -s /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenv /usr/local/bin/virtualenv
virtualenv --version
fi
# Create virtualenv using desired Python version, to run the testcases
python$(python.version) -m pip install -U pip wheel setuptools virtualenv
python$(python.version) -m virtualenv /tmp/venv -p python$(python.version)
echo "##vso[task.prependpath]/tmp/venv/bin" echo "##vso[task.prependpath]/tmp/venv/bin"
displayName: activate venv displayName: activate venv
@ -37,3 +45,5 @@ steps:
- script: .ci/$(MODE)_tests.py - script: .ci/$(MODE)_tests.py
displayName: "Run $(MODE)_tests.py" displayName: "Run $(MODE)_tests.py"
env:
NOCOVERAGE: 1

@ -13,10 +13,10 @@ jobs:
strategy: strategy:
matrix: matrix:
Mito27_27: Mito27_27:
python.version: '2.7.18' python.version: '2.7'
MODE: mitogen MODE: mitogen
Ans288_27: Ans288_27:
python.version: '2.7.18' python.version: '2.7'
MODE: localhost_ansible MODE: localhost_ansible
VER: 2.8.8 VER: 2.8.8

@ -80,12 +80,28 @@ if 'TRAVIS_HOME' in os.environ:
# ----------------- # -----------------
def _argv(s, *args): def _argv(s, *args):
"""Interpolate a command line using *args, return an argv style list.
>>> _argv('git commit -m "Use frobnicate 2.0 (fixes #%d)"', 1234)
['git', commit', '-m', 'Use frobnicate 2.0 (fixes #1234)']
"""
if args: if args:
s %= args s %= args
return shlex.split(s) return shlex.split(s)
def run(s, *args, **kwargs): def run(s, *args, **kwargs):
""" Run a command, with arguments, and print timing information
>>> rc = run('echo "%s %s"', 'foo', 'bar')
Running: ['/usr/bin/time', '--', 'echo', 'foo bar']
foo bar
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata 1964maxresident)k
0inputs+0outputs (0major+71minor)pagefaults 0swaps
Finished running: ['/usr/bin/time', '--', 'echo', 'foo bar']
>>> rc
0
"""
argv = ['/usr/bin/time', '--'] + _argv(s, *args) argv = ['/usr/bin/time', '--'] + _argv(s, *args)
print('Running: %s' % (argv,)) print('Running: %s' % (argv,))
try: try:
@ -98,12 +114,36 @@ def run(s, *args, **kwargs):
return ret return ret
def run_batches(batches): def combine(batch):
combine = lambda batch: 'set -x; ' + (' && '.join( """
>>> combine(['ls -l', 'echo foo'])
'set -x; ( ls -l; ) && ( echo foo; )'
"""
return 'set -x; ' + (' && '.join(
'( %s; )' % (cmd,) '( %s; )' % (cmd,)
for cmd in batch for cmd in batch
)) ))
def run_batches(batches):
""" Run shell commands grouped into batches, showing an execution trace.
Raise AssertionError if any command has exits with a non-zero status.
>>> run_batches([['echo foo', 'true']])
+ echo foo
foo
+ true
>>> run_batches([['true', 'echo foo'], ['false']])
+ true
+ echo foo
foo
+ false
Traceback (most recent call last):
File "...", line ..., in <module>
File "...", line ..., in run_batches
AssertionError
"""
procs = [ procs = [
subprocess.Popen(combine(batch), shell=True) subprocess.Popen(combine(batch), shell=True)
for batch in batches for batch in batches
@ -112,12 +152,28 @@ def run_batches(batches):
def get_output(s, *args, **kwargs): def get_output(s, *args, **kwargs):
"""
Print and run command line s, %-interopolated using *args. Return stdout.
>>> s = get_output('echo "%s %s"', 'foo', 'bar')
Running: ['echo', 'foo bar']
>>> s
'foo bar\n'
"""
argv = _argv(s, *args) argv = _argv(s, *args)
print('Running: %s' % (argv,)) print('Running: %s' % (argv,))
return subprocess.check_output(argv, **kwargs) return subprocess.check_output(argv, **kwargs)
def exists_in_path(progname): def exists_in_path(progname):
"""
Return True if proganme exists in $PATH.
>>> exists_in_path('echo')
True
>>> exists_in_path('kwyjibo') # Only found in North American cartoons
False
"""
return any(os.path.exists(os.path.join(dirname, progname)) return any(os.path.exists(os.path.join(dirname, progname))
for dirname in os.environ['PATH'].split(os.pathsep)) for dirname in os.environ['PATH'].split(os.pathsep))
@ -132,6 +188,18 @@ class TempDir(object):
class Fold(object): class Fold(object):
"""
Bracket a section of stdout with travis_fold markers.
This allows the section to be collapsed or expanded in Travis CI web UI.
>>> with Fold('stage 1'):
... print('Frobnicate the frobnitz')
...
travis_fold:start:stage 1
Frobnicate the frobnitz
travis_fold:end:stage 1
"""
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -171,6 +239,8 @@ os.environ['PYTHONPATH'] = '%s:%s' % (
) )
def get_docker_hostname(): def get_docker_hostname():
"""Return the hostname where the docker daemon is running.
"""
url = os.environ.get('DOCKER_HOST') url = os.environ.get('DOCKER_HOST')
if url in (None, 'http+docker://localunixsocket'): if url in (None, 'http+docker://localunixsocket'):
return 'localhost' return 'localhost'
@ -180,10 +250,34 @@ def get_docker_hostname():
def image_for_distro(distro): def image_for_distro(distro):
return 'mitogen/%s-test' % (distro.partition('-')[0],) """Return the container image name or path for a test distro name.
The returned value is suitable for use with `docker pull`.
>>> image_for_distro('centos5')
'public.ecr.aws/n5z0e8q9/centos5-test'
>>> image_for_distro('centos5-something_custom')
'public.ecr.aws/n5z0e8q9/centos5-test'
"""
return 'public.ecr.aws/n5z0e8q9/%s-test' % (distro.partition('-')[0],)
def make_containers(name_prefix='', port_offset=0): def make_containers(name_prefix='', port_offset=0):
"""
>>> import pprint
>>> BASE_PORT=2200; DISTROS=['debian', 'centos6']
>>> pprint.pprint(make_containers())
[{'distro': 'debian',
'hostname': 'localhost',
'name': 'target-debian-1',
'port': 2201,
'python_path': '/usr/bin/python'},
{'distro': 'centos6',
'hostname': 'localhost',
'name': 'target-centos6-2',
'port': 2202,
'python_path': '/usr/bin/python'}]
"""
docker_hostname = get_docker_hostname() docker_hostname = get_docker_hostname()
firstbit = lambda s: (s+'-').split('-')[0] firstbit = lambda s: (s+'-').split('-')[0]
secondbit = lambda s: (s+'-').split('-')[1] secondbit = lambda s: (s+'-').split('-')[1]
@ -256,6 +350,14 @@ def get_interesting_procs(container_name=None):
def start_containers(containers): def start_containers(containers):
"""Run docker containers in the background, with sshd on specified ports.
>>> containers = start_containers([
... {'distro': 'debian', 'hostname': 'localhost',
... 'name': 'target-debian-1', 'port': 2201,
... 'python_path': '/usr/bin/python'},
... ])
"""
if os.environ.get('KEEP'): if os.environ.get('KEEP'):
return return

@ -20,12 +20,15 @@ with ci_lib.Fold('unit_tests'):
with ci_lib.Fold('job_setup'): with ci_lib.Fold('job_setup'):
# Don't set -U as that will upgrade Paramiko to a non-2.6 compatible version.
run("pip install -q virtualenv ansible==%s", ci_lib.ANSIBLE_VERSION)
os.chmod(KEY_PATH, int('0600', 8)) os.chmod(KEY_PATH, int('0600', 8))
# NOTE: sshpass v1.06 causes errors so pegging to 1.05 -> "msg": "Error when changing password","out": "passwd: DS error: eDSAuthFailed\n",
# there's a checksum error with "brew install http://git.io/sshpass.rb" though, so installing manually
if not ci_lib.exists_in_path('sshpass'): if not ci_lib.exists_in_path('sshpass'):
run("brew install http://git.io/sshpass.rb") os.system("curl -O -L https://sourceforge.net/projects/sshpass/files/sshpass/1.05/sshpass-1.05.tar.gz && \
tar xvf sshpass-1.05.tar.gz && \
cd sshpass-1.05 && \
./configure && \
sudo make install")
with ci_lib.Fold('machine_prep'): with ci_lib.Fold('machine_prep'):

@ -43,12 +43,4 @@ if ci_lib.have_apt():
.format(pv=os.environ['PYTHONVERSION']) .format(pv=os.environ['PYTHONVERSION'])
]) ])
if ci_lib.have_docker():
batches.extend(
['docker pull %s' % (ci_lib.image_for_distro(distro),)]
for distro in ci_lib.DISTROS
)
ci_lib.run_batches(batches) ci_lib.run_batches(batches)

@ -16,6 +16,9 @@ cache:
- directories: - directories:
- /home/travis/virtualenv - /home/travis/virtualenv
env:
- NOCOVERAGE=1
install: install:
- grep -Erl git-lfs\|couchdb /etc/apt | sudo xargs rm -v - grep -Erl git-lfs\|couchdb /etc/apt | sudo xargs rm -v
- .ci/${MODE}_install.py - .ci/${MODE}_install.py

@ -1,4 +1,4 @@
Copyright 2019, David Wilson Copyright 2021, the Mitogen authors
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:

@ -5,8 +5,8 @@
![](https://i.imgur.com/eBM6LhJ.gif) ![](https://i.imgur.com/eBM6LhJ.gif)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/dw/mitogen.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/dw/mitogen/alerts/) [![Total alerts](https://img.shields.io/lgtm/alerts/g/mitogen-hq/mitogen.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mitogen-hq/mitogen/alerts/)
[![Build Status](https://travis-ci.org/dw/mitogen.svg?branch=master)](https://travis-ci.org/dw/mitogen) [![Build Status](https://api.travis-ci.com/mitogen-hq/mitogen.svg?branch=master)](https://api.travis-ci.com/mitogen-hq/mitogen)
[![Pipelines Status](https://dev.azure.com/dw-mitogen/Mitogen/_apis/build/status/dw.mitogen?branchName=master)](https://dev.azure.com/dw-mitogen/Mitogen/_build/latest?definitionId=1?branchName=master) [![Pipelines Status](https://dev.azure.com/mitogen-hq/mitogen/_apis/build/status/mitogen-hq.mitogen?branchName=master)](https://dev.azure.com/mitogen-hq/mitogen/_build/latest?definitionId=1&branchName=master)

@ -145,7 +145,7 @@ Testimonials
Noteworthy Differences Noteworthy Differences
---------------------- ----------------------
* Ansible 2.3-2.8 are supported along with Python 2.6, 2.7, 3.6 and 3.7. Verify * Ansible 2.3-2.9 are supported along with Python 2.6, 2.7, 3.6 and 3.7. Verify
your installation is running one of these versions by checking ``ansible your installation is running one of these versions by checking ``ansible
--version`` output. --version`` output.

@ -14,18 +14,23 @@ Release Notes
} }
</style> </style>
To avail of fixes in an unreleased version, please download a ZIP file
`directly from GitHub <https://github.com/dw/mitogen/>`_.
v0.2.10 (unreleased) v0.2.10 (unreleased)
-------------------- --------------------
To avail of fixes in an unreleased version, please download a ZIP file * :gh:issue:`597` mitogen does not support Ansible 2.8 Python interpreter detection
`directly from GitHub <https://github.com/dw/mitogen/>`_. * :gh:issue:`655` wait_for_connection gives errors
* :gh:issue:`672` cannot perform relative import error
* :gh:issue:`673` mitogen fails on RHEL8 server with bash /usr/bin/python: No such file or directory
* :gh:issue:`676` mitogen fail to run playbook without “/usr/bin/python” on target host
* :gh:issue:`716` fetch fails with "AttributeError: 'ShellModule' object has no attribute 'tmpdir'"
* :gh:issue:`756` ssh connections with `check_host_keys='accept'` would * :gh:issue:`756` ssh connections with `check_host_keys='accept'` would
timeout, when using recent OpenSSH client versions. timeout, when using recent OpenSSH client versions.
* :gh:issue:`758` fix initilialisation of callback plugins in test suite, to * :gh:issue:`758` fix initilialisation of callback plugins in test suite, to address a `KeyError` in
to address a `KeyError` in
:method:`ansible.plugins.callback.CallbackBase.v2_runner_on_start` :method:`ansible.plugins.callback.CallbackBase.v2_runner_on_start`
* :gh:issue:`775` Add msvcrt to the default module deny list
v0.2.9 (2019-11-02) v0.2.9 (2019-11-02)

@ -7,7 +7,7 @@ import mitogen
VERSION = '%s.%s.%s' % mitogen.__version__ VERSION = '%s.%s.%s' % mitogen.__version__
author = u'Network Genomics' author = u'Network Genomics'
copyright = u'2019, Network Genomics' copyright = u'2021, the Mitogen authors'
exclude_patterns = ['_build', '.venv'] exclude_patterns = ['_build', '.venv']
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinxcontrib.programoutput', 'domainrefs'] extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinxcontrib.programoutput', 'domainrefs']

@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup.
#: Library version as a tuple. #: Library version as a tuple.
__version__ = (0, 2, 9) __version__ = (0, 2, 10, 'rc', 1)
#: This is :data:`False` in slave contexts. Previously it was used to prevent #: This is :data:`False` in slave contexts. Previously it was used to prevent

@ -1269,6 +1269,13 @@ class Importer(object):
# a negative round-trip. # a negative round-trip.
'builtins', 'builtins',
'__builtin__', '__builtin__',
# On some Python releases (e.g. 3.8, 3.9) the subprocess module tries
# to import of this Windows-only builtin module.
'msvcrt',
# Python 2.x module that was renamed to _thread in 3.x.
# This entry avoids a roundtrip on 2.x -> 3.x.
'thread', 'thread',
# org.python.core imported by copy, pickle, xml.sax; breaks Jython, but # org.python.core imported by copy, pickle, xml.sax; breaks Jython, but
@ -3860,7 +3867,7 @@ class ExternalContext(object):
else: else:
core_src_fd = self.config.get('core_src_fd', 101) core_src_fd = self.config.get('core_src_fd', 101)
if core_src_fd: if core_src_fd:
fp = os.fdopen(core_src_fd, 'rb', 1) fp = os.fdopen(core_src_fd, 'rb', 0)
try: try:
core_src = fp.read() core_src = fp.read()
# Strip "ExternalContext.main()" call from last line. # Strip "ExternalContext.main()" call from last line.

@ -1,3 +1,6 @@
[bdist_wheel]
universal=1
[coverage:run] [coverage:run]
branch = true branch = true
source = source =

@ -37,29 +37,46 @@ def grep_version():
for line in fp: for line in fp:
if line.startswith('__version__'): if line.startswith('__version__'):
_, _, s = line.partition('=') _, _, s = line.partition('=')
return '.'.join(map(str, eval(s))) return '%i.%i.%i%s%i' % eval(s)
def long_description():
here = os.path.dirname(__file__)
readme_path = os.path.join(here, 'README.md')
with open(readme_path) as fp:
readme = fp.read()
return readme
setup( setup(
name = 'mitogen', name = 'mitogen',
version = grep_version(), version = grep_version(),
description = 'Library for writing distributed self-replicating programs.', description = 'Library for writing distributed self-replicating programs.',
long_description = long_description(),
long_description_content_type='text/markdown',
author = 'David Wilson', author = 'David Wilson',
license = 'New BSD', license = 'New BSD',
url = 'https://github.com/dw/mitogen/', url = 'https://github.com/mitogen-hq/mitogen/',
packages = find_packages(exclude=['tests', 'examples']), packages = find_packages(exclude=['tests', 'examples']),
python_requires='>=2.4, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4',
zip_safe = False, zip_safe = False,
classifiers = [ classifiers = [
'Environment :: Console', 'Environment :: Console',
'Intended Audience :: System Administrators', 'Intended Audience :: System Administrators',
'License :: OSI Approved :: BSD License', 'License :: OSI Approved :: BSD License',
'Operating System :: MacOS :: MacOS X',
'Operating System :: POSIX', 'Operating System :: POSIX',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.4',
'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: CPython',
'Topic :: System :: Distributed Computing', 'Topic :: System :: Distributed Computing',
'Topic :: System :: Systems Administration', 'Topic :: System :: Systems Administration',

@ -51,10 +51,14 @@
shell: whoami > /tmp/delegate_to.yml.txt shell: whoami > /tmp/delegate_to.yml.txt
delegate_to: localhost delegate_to: localhost
become: true become: true
tags:
- requires_local_sudo
- name: "delegate_to, sudo" - name: "delegate_to, sudo"
assert: assert:
that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'root'" that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'root'"
tags:
- requires_local_sudo
- name: "delegate_to, sudo" - name: "delegate_to, sudo"
file: file:
@ -62,6 +66,8 @@
state: absent state: absent
delegate_to: localhost delegate_to: localhost
become: true become: true
tags:
- requires_local_sudo
# #
@ -71,10 +77,14 @@
shell: whoami > /tmp/delegate_to.yml.txt shell: whoami > /tmp/delegate_to.yml.txt
connection: local connection: local
become: true become: true
tags:
- requires_local_sudo
- name: "connection:local, sudo" - name: "connection:local, sudo"
assert: assert:
that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'root'" that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'root'"
tags:
- requires_local_sudo
- name: "connection:local, sudo" - name: "connection:local, sudo"
file: file:
@ -82,3 +92,5 @@
state: absent state: absent
connection: local connection: local
become: true become: true
tags:
- requires_local_sudo

@ -15,7 +15,7 @@
content: | content: |
#!/bin/bash #!/bin/bash
export CUSTOM_INTERPRETER=1 export CUSTOM_INTERPRETER=1
exec python2.7 "$@" exec python "$@"
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:

@ -1,4 +1,4 @@
paramiko==2.3.2 # Last 2.6-compat version. paramiko==2.3.2 # Last 2.6-compat version.
hdrhistogram==0.6.1 hdrhistogram==0.6.1
PyYAML==3.11; python_version < '2.7' PyYAML==3.11; python_version < '2.7'
PyYAML==3.13; python_version >= '2.7' PyYAML==5.3.1; python_version >= '2.7' # Latest release (Jan 2021)

@ -308,7 +308,6 @@ if sys.version_info > (2, 6):
# AttributeError: module 'html.parser' has no attribute # AttributeError: module 'html.parser' has no attribute
# 'HTMLParseError' # 'HTMLParseError'
# #
import pkg_resources._vendor.six
from django.utils.six.moves import html_parser as _html_parser from django.utils.six.moves import html_parser as _html_parser
_html_parser.HTMLParseError = Exception _html_parser.HTMLParseError = Exception

@ -3,7 +3,7 @@ coverage==4.5.1
Django==1.6.11 # Last version supporting 2.6. Django==1.6.11 # Last version supporting 2.6.
mock==2.0.0 mock==2.0.0
pytz==2018.5 pytz==2018.5
cffi==1.11.2 # Random pin to try and fix pyparser==2.18 not having effect cffi==1.14.3 # Random pin to try and fix pyparser==2.18 not having effect
pycparser==2.18 # Last version supporting 2.6. pycparser==2.18 # Last version supporting 2.6.
faulthandler==3.1; python_version < '3.3' # used by testlib faulthandler==3.1; python_version < '3.3' # used by testlib
pytest-catchlog==1.2.2 pytest-catchlog==1.2.2

@ -103,6 +103,18 @@ if hasattr(subprocess.Popen, 'terminate'):
Popen__terminate = subprocess.Popen.terminate Popen__terminate = subprocess.Popen.terminate
def threading__thread_is_alive(thread):
"""Return whether the thread is alive (Python version compatibility shim).
On Python >= 3.8 thread.isAlive() is deprecated (removed in Python 3.9).
On Python <= 2.5 thread.is_alive() isn't present (added in Python 2.6).
"""
try:
return thread.is_alive()
except AttributeError:
return thread.isAlive()
def wait_for_port( def wait_for_port(
host, host,
port, port,
@ -334,7 +346,9 @@ class TestCase(unittest2.TestCase):
for thread in threading.enumerate(): for thread in threading.enumerate():
name = thread.getName() name = thread.getName()
# Python 2.4: enumerate() may return stopped threads. # Python 2.4: enumerate() may return stopped threads.
assert (not thread.isAlive()) or name in self.ALLOWED_THREADS, \ assert \
not threading__thread_is_alive(thread) \
or name in self.ALLOWED_THREADS, \
'Found thread %r still running after tests.' % (name,) 'Found thread %r still running after tests.' % (name,)
counts[name] = counts.get(name, 0) + 1 counts[name] = counts.get(name, 0) + 1

@ -31,14 +31,14 @@ class RunWithRouterTest(testlib.TestCase):
def test_run_with_broker(self): def test_run_with_broker(self):
router = mitogen.utils.run_with_router(func0) router = mitogen.utils.run_with_router(func0)
self.assertIsInstance(router, mitogen.master.Router) self.assertIsInstance(router, mitogen.master.Router)
self.assertFalse(router.broker._thread.isAlive()) self.assertFalse(testlib.threading__thread_is_alive(router.broker._thread))
class WithRouterTest(testlib.TestCase): class WithRouterTest(testlib.TestCase):
def test_with_broker(self): def test_with_broker(self):
router = func() router = func()
self.assertIsInstance(router, mitogen.master.Router) self.assertIsInstance(router, mitogen.master.Router)
self.assertFalse(router.broker._thread.isAlive()) self.assertFalse(testlib.threading__thread_is_alive(router.broker._thread))
class Dict(dict): pass class Dict(dict): pass

@ -1,44 +1,89 @@
# This file is a local convenience. It is not a substitute for the full CI
# suite, and does not cover the full range of Python versions for Mitogen.
# I use this on Ubuntu 20.04, with the following additions
#
# sudo add-apt-repository ppa:deadsnakes/ppa
# sudo apt update
# sudo apt install python3.5 python3.6 python3.7 python3.9 tox libsasl2-dev libldap2-dev libssl-dev ssh-pass
# Last version to support each python version
#
# tox vir'env pip ansible coverage
# ========== ======== ======== ======== ======== ========
# python2.4 1.4 1.8 1.1 ???
# python2.5 1.6.1 1.9.1 1.3.1 ???
# python2.6 2.9.1 15.2.0 9.0.3 2.6.20 4.5.4
[tox] [tox]
envlist = envlist =
init, init,
py26, py{27,36,39}-mode_ansible,
py27, py{27,36,39}-mode_mitogen,
py35, py{27,36,39}-mode_mitogen-distro_centos7,
py36,
py37,
report, report,
requires =
tox-factor
[testenv] [testenv]
usedevelop = True basepython =
deps = py26: python2.6
-r{toxinidir}/dev_requirements.txt py27: python2.7
-r{toxinidir}/tests/ansible/requirements.txt py36: python3.6
py37: python3.7
py38: python3.8
py39: python3.9
commands_pre =
mode_ansible: {toxinidir}/.ci/ansible_install.py
mode_debops_common: {toxinidir}/.ci/debops_common_install.py
mode_mitogen: {toxinidir}/.ci/mitogen_install.py
commands = commands =
{posargs:bash run_tests} mode_ansible: {toxinidir}/.ci/ansible_tests.py
whitelist_externals = mode_debops_common: {toxinidir}/.ci/debops_common_tests.py
bash mode_mitogen: {toxinidir}/.ci/mitogen_tests.py
passenv =
ANSIBLE_*
HOME
setenv = setenv =
ANSIBLE_SKIP_TAGS = requires_local_sudo
NOCOVERAGE_ERASE = 1 NOCOVERAGE_ERASE = 1
NOCOVERAGE_REPORT = 1 NOCOVERAGE_REPORT = 1
ansible2.3: VER=2.3.3.0
ansible2.4: VER=2.4.6.0
ansible2.8: VER=2.8.3
ansible2.9: VER=2.9.6
ansible2.10: VER=2.10.0
distro_centos5: DISTRO=centos5
distro_centos6: DISTRO=centos6
distro_centos7: DISTRO=centos7
distro_debian: DISTRO=debian
distro_debianpy3: DISTRO=debian-py3
distros_centos5: DISTROS=centos5
distros_debian: DISTROS=debian
mode_ansible: MODE=ansible
mode_debops_common: MODE=debops_common
mode_mitogen: MODE=mitogen
strategy_linear: STRATEGY=linear
[testenv:init] [testenv:init]
basepython = python3
commands = commands =
coverage erase coverage erase
deps = deps =
coverage coverage==4.5.4
[testenv:report] [testenv:report]
basepython = python3
commands = commands =
coverage html coverage html
echo "coverage report is at file://{toxinidir}/htmlcov/index.html" echo "coverage report is at file://{toxinidir}/htmlcov/index.html"
deps = deps =
coverage coverage==4.5.4
whitelist_externals = whitelist_externals =
echo echo
[testenv:docs] [testenv:docs]
basepython = python basepython = python3
changedir = docs changedir = docs
commands = commands =
sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html

Loading…
Cancel
Save