Merge pull request #842 from nicoddemus/drop-py36-add-py311

Drop Python 3.6 and add Python 3.11
This commit is contained in:
Bruno Oliveira
2022-11-05 14:36:30 -03:00
committed by GitHub
14 changed files with 132 additions and 119 deletions

33
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: deploy
on:
push:
tags:
- "v*"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
# Needed to fetch tags, which are required by setuptools-scm.
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.10"
- name: Install build
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: |
python -m build
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.pypi_token }}

View File

@@ -1,87 +0,0 @@
name: build
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
tox_env:
- "py36-pytestlatest"
- "py37-pytestlatest"
- "py38-pytestlatest"
- "py39-pytestlatest"
- "py310-pytestlatest"
- "py38-pytestmain"
- "py38-psutil"
- "py38-setproctitle"
os: [ubuntu-latest, windows-latest]
include:
- tox_env: "py36-pytestlatest"
python: "3.6"
- tox_env: "py37-pytestlatest"
python: "3.7"
- tox_env: "py38-pytestlatest"
python: "3.8"
- tox_env: "py39-pytestlatest"
python: "3.9"
- tox_env: "py310-pytestlatest"
python: "3.10"
- tox_env: "py38-pytestmain"
python: "3.8"
- tox_env: "py38-psutil"
python: "3.8"
- tox_env: "py38-setproctitle"
python: "3.8"
steps:
- uses: actions/checkout@v3
with:
# Needed to fetch tags, which are required by setuptools-scm.
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: Install tox
run: |
python -m pip install --upgrade pip
pip install tox
- name: Test
run: |
tox -e ${{ matrix.tox_env }}
deploy:
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
with:
# Needed to fetch tags, which are required by setuptools-scm.
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.7"
- name: Install wheel
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: |
python -m build
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.pypi_token }}

67
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: test
on:
push:
branches:
- "*"
pull_request:
branches:
- "*"
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
tox_env:
- "py37-pytestlatest"
- "py38-pytestlatest"
- "py39-pytestlatest"
- "py310-pytestlatest"
- "py310-pytestmain"
- "py311-pytestlatest"
- "py311-pytestmain"
- "py310-psutil"
- "py310-setproctitle"
os: [ubuntu-latest, windows-latest]
include:
- tox_env: "py37-pytestlatest"
python: "3.7"
- tox_env: "py38-pytestlatest"
python: "3.8"
- tox_env: "py39-pytestlatest"
python: "3.9"
- tox_env: "py310-pytestlatest"
python: "3.10"
- tox_env: "py310-pytestmain"
python: "3.10"
- tox_env: "py311-pytestlatest"
python: "3.11"
- tox_env: "py311-pytestmain"
python: "3.11"
- tox_env: "py310-psutil"
python: "3.10"
- tox_env: "py310-setproctitle"
python: "3.10"
steps:
- uses: actions/checkout@v3
with:
# Needed to fetch tags, which are required by setuptools-scm.
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: Install tox
run: |
python -m pip install --upgrade pip
pip install tox
- name: Test
run: |
tox -e ${{ matrix.tox_env }}

View File

@@ -13,7 +13,7 @@ pytest-xdist
:alt: Python versions :alt: Python versions
:target: https://pypi.python.org/pypi/pytest-xdist :target: https://pypi.python.org/pypi/pytest-xdist
.. image:: https://github.com/pytest-dev/pytest-xdist/workflows/build/badge.svg .. image:: https://github.com/pytest-dev/pytest-xdist/workflows/test/badge.svg
:target: https://github.com/pytest-dev/pytest-xdist/actions :target: https://github.com/pytest-dev/pytest-xdist/actions
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg .. image:: https://img.shields.io/badge/code%20style-black-000000.svg

View File

@@ -0,0 +1 @@
Python 3.11 is now officially supported.

View File

@@ -0,0 +1 @@
Python 3.6 is no longer supported.

View File

@@ -24,11 +24,11 @@ classifiers =
Programming Language :: Python Programming Language :: Python
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
license_file = LICENSE license_file = LICENSE
project_urls = project_urls =
Documentation=https://pytest-xdist.readthedocs.io/en/latest Documentation=https://pytest-xdist.readthedocs.io/en/latest
@@ -40,7 +40,7 @@ project_urls =
packages = find: packages = find:
package_dir = =src package_dir = =src
zip_safe = False zip_safe = False
python_requires = >=3.6 python_requires = >=3.7
install_requires = install_requires =
execnet>=1.1 execnet>=1.1
pytest>=6.2.0 pytest>=6.2.0

View File

@@ -169,7 +169,7 @@ class DSession:
""" """
self.config.hook.pytest_testnodedown(node=node, error=None) self.config.hook.pytest_testnodedown(node=node, error=None)
if node.workeroutput["exitstatus"] == 2: # keyboard-interrupt if node.workeroutput["exitstatus"] == 2: # keyboard-interrupt
self.shouldstop = "{} received keyboard-interrupt".format(node) self.shouldstop = f"{node} received keyboard-interrupt"
self.worker_errordown(node, "keyboard-interrupt") self.worker_errordown(node, "keyboard-interrupt")
return return
if node in self.sched.nodes: if node in self.sched.nodes:
@@ -230,7 +230,7 @@ class DSession:
@pytest.hookimpl @pytest.hookimpl
def pytest_terminal_summary(self, terminalreporter): def pytest_terminal_summary(self, terminalreporter):
if self.config.option.verbose >= 0 and self._summary_report: if self.config.option.verbose >= 0 and self._summary_report:
terminalreporter.write_sep("=", "xdist: {}".format(self._summary_report)) terminalreporter.write_sep("=", f"xdist: {self._summary_report}")
def worker_collectionfinish(self, node, ids): def worker_collectionfinish(self, node, ids):
"""worker has finished test collection. """worker has finished test collection.
@@ -345,7 +345,7 @@ class DSession:
# XXX count no of failures and retry N times # XXX count no of failures and retry N times
runner = self.config.pluginmanager.getplugin("runner") runner = self.config.pluginmanager.getplugin("runner")
fspath = nodeid.split("::")[0] fspath = nodeid.split("::")[0]
msg = "worker {!r} crashed while running {!r}".format(worker.gateway.id, nodeid) msg = f"worker {worker.gateway.id!r} crashed while running {nodeid!r}"
rep = runner.TestReport( rep = runner.TestReport(
nodeid, (fspath, None, fspath), (), "failed", msg, "???" nodeid, (fspath, None, fspath), (), "failed", msg, "???"
) )
@@ -381,9 +381,7 @@ class TerminalDistReporter:
def getstatus(self): def getstatus(self):
if self.config.option.verbose >= 0: if self.config.option.verbose >= 0:
parts = [ parts = [f"{spec.id} {self._status[spec.id]}" for spec in self._specs]
"{} {}".format(spec.id, self._status[spec.id]) for spec in self._specs
]
return " / ".join(parts) return " / ".join(parts)
else: else:
return "bringing up nodes..." return "bringing up nodes..."
@@ -431,7 +429,7 @@ class TerminalDistReporter:
def pytest_testnodedown(self, node, error): def pytest_testnodedown(self, node, error):
if not error: if not error:
return return
self.write_line("[{}] node down: {}".format(node.gateway.id, error)) self.write_line(f"[{node.gateway.id}] node down: {error}")
def get_default_max_worker_restart(config): def get_default_max_worker_restart(config):

View File

@@ -146,7 +146,7 @@ def repr_pytest_looponfailinfo(failreports, rootdirs):
tr.line(report, red=True) tr.line(report, red=True)
tr.sep("#", "waiting for changes", bold=True) tr.sep("#", "waiting for changes", bold=True)
for rootdir in rootdirs: for rootdir in rootdirs:
tr.line("### Watching: {}".format(rootdir), bold=True) tr.line(f"### Watching: {rootdir}", bold=True)
def init_worker_session(channel, args, option_dict): def init_worker_session(channel, args, option_dict):

View File

@@ -149,7 +149,7 @@ class WorkerInteractor:
if len(mark.args) > 0 if len(mark.args) > 0
else mark.kwargs.get("name", "default") else mark.kwargs.get("name", "default")
) )
item._nodeid = "{}@{}".format(item.nodeid, gname) item._nodeid = f"{item.nodeid}@{gname}"
@pytest.hookimpl @pytest.hookimpl
def pytest_collection_finish(self, session): def pytest_collection_finish(self, session):

View File

@@ -361,12 +361,12 @@ class LoadScopeScheduling:
extra_nodes = len(self.nodes) - len(self.workqueue) extra_nodes = len(self.nodes) - len(self.workqueue)
if extra_nodes > 0: if extra_nodes > 0:
self.log("Shutting down {} nodes".format(extra_nodes)) self.log(f"Shutting down {extra_nodes} nodes")
for _ in range(extra_nodes): for _ in range(extra_nodes):
unused_node, assigned = self.assigned_work.popitem(last=True) unused_node, assigned = self.assigned_work.popitem(last=True)
self.log("Shutting down unused node {}".format(unused_node)) self.log(f"Shutting down unused node {unused_node}")
unused_node.shutdown() unused_node.shutdown()
# Assign initial workload # Assign initial workload

View File

@@ -112,7 +112,7 @@ class NodeManager:
for root in candidates: for root in candidates:
root = Path(root).resolve() root = Path(root).resolve()
if not root.exists(): if not root.exists():
raise pytest.UsageError("rsyncdir doesn't exist: {!r}".format(root)) raise pytest.UsageError(f"rsyncdir doesn't exist: {root!r}")
if root not in roots: if root not in roots:
roots.append(root) roots.append(root)
return roots return roots
@@ -192,7 +192,7 @@ class HostRSync(execnet.RSync):
if self._verbose > 0: if self._verbose > 0:
path = os.path.basename(self._sourcedir) + "/" + modified_rel_path path = os.path.basename(self._sourcedir) + "/" + modified_rel_path
remotepath = gateway.spec.chdir remotepath = gateway.spec.chdir
print("{}:{} <= {}".format(gateway.spec, remotepath, path)) print(f"{gateway.spec}:{remotepath} <= {path}")
def make_reltoroot(roots: Sequence[Path], args: List[str]) -> List[str]: def make_reltoroot(roots: Sequence[Path], args: List[str]) -> List[str]:
@@ -219,7 +219,7 @@ def make_reltoroot(roots: Sequence[Path], args: List[str]) -> List[str]:
parts[0] = root.name + "/" + str(x) parts[0] = root.name + "/" + str(x)
break break
else: else:
raise ValueError("arg {} not relative to an rsync root".format(arg)) raise ValueError(f"arg {arg} not relative to an rsync root")
result.append(splitcode.join(parts)) result.append(splitcode.join(parts))
return result return result
@@ -249,7 +249,7 @@ class WorkerController:
self.log = Producer(f"workerctl-{gateway.id}", enabled=config.option.debug) self.log = Producer(f"workerctl-{gateway.id}", enabled=config.option.debug)
def __repr__(self): def __repr__(self):
return "<{} {}>".format(self.__class__.__name__, self.gateway.id) return f"<{self.__class__.__name__} {self.gateway.id}>"
@property @property
def shutting_down(self): def shutting_down(self):
@@ -310,11 +310,11 @@ class WorkerController:
def sendcommand(self, name, **kwargs): def sendcommand(self, name, **kwargs):
"""send a named parametrized command to the other side.""" """send a named parametrized command to the other side."""
self.log("sending command {}(**{})".format(name, kwargs)) self.log(f"sending command {name}(**{kwargs})")
self.channel.send((name, kwargs)) self.channel.send((name, kwargs))
def notify_inproc(self, eventname, **kwargs): def notify_inproc(self, eventname, **kwargs):
self.log("queuing {}(**{})".format(eventname, kwargs)) self.log(f"queuing {eventname}(**{kwargs})")
self.putevent((eventname, kwargs)) self.putevent((eventname, kwargs))
def process_from_remote(self, eventcall): # noqa too complex def process_from_remote(self, eventcall): # noqa too complex
@@ -336,7 +336,7 @@ class WorkerController:
return return
eventname, kwargs = eventcall eventname, kwargs = eventcall
if eventname in ("collectionstart",): if eventname in ("collectionstart",):
self.log("ignoring {}({})".format(eventname, kwargs)) self.log(f"ignoring {eventname}({kwargs})")
elif eventname == "workerready": elif eventname == "workerready":
self.notify_inproc(eventname, node=self, **kwargs) self.notify_inproc(eventname, node=self, **kwargs)
elif eventname == "internal_error": elif eventname == "internal_error":
@@ -389,7 +389,7 @@ class WorkerController:
location=kwargs["location"], location=kwargs["location"],
) )
else: else:
raise ValueError("unknown event: {}".format(eventname)) raise ValueError(f"unknown event: {eventname}")
except KeyboardInterrupt: except KeyboardInterrupt:
# should not land in receiver-thread # should not land in receiver-thread
raise raise

View File

@@ -25,7 +25,7 @@ class EventCall:
self.name, self.kwargs = eventcall self.name, self.kwargs = eventcall
def __str__(self): def __str__(self):
return "<EventCall {}(**{})>".format(self.name, self.kwargs) return f"<EventCall {self.name}(**{self.kwargs})>"
class WorkerSetup: class WorkerSetup:
@@ -60,7 +60,7 @@ class WorkerSetup:
ev = EventCall(data) ev = EventCall(data)
if name is None or ev.name == name: if name is None or ev.name == name:
return ev return ev
print("skipping {}".format(ev)) print(f"skipping {ev}")
def sendcommand(self, name, **kwargs): def sendcommand(self, name, **kwargs):
self.slp.sendcommand(name, **kwargs) self.slp.sendcommand(name, **kwargs)

16
tox.ini
View File

@@ -1,10 +1,10 @@
[tox] [tox]
envlist= envlist=
linting linting
py{36,37,38,39,310}-pytestlatest py{37,38,39,310,311}-pytestlatest
py38-pytestmain py310-pytestmain
py38-psutil py310-psutil
py38-setproctitle py310-setproctitle
isolated_build = true isolated_build = true
[testenv] [testenv]
extras = testing extras = testing
@@ -14,14 +14,14 @@ deps =
commands= commands=
pytest {posargs} pytest {posargs}
[testenv:py38-psutil] [testenv:py310-psutil]
extras = extras =
testing testing
psutil psutil
commands = commands =
pytest {posargs:-k psutil} pytest {posargs:-k psutil}
[testenv:py38-setproctitle] [testenv:py310-setproctitle]
extras = extras =
testing testing
setproctitle setproctitle
@@ -40,7 +40,7 @@ commands = pre-commit run --all-files --show-diff-on-failure
[testenv:release] [testenv:release]
changedir= changedir=
description = do a release, required posarg of the version number description = do a release, required posarg of the version number
basepython = python3.7 basepython = python3.10
skipsdist = True skipsdist = True
usedevelop = True usedevelop = True
passenv = * passenv = *
@@ -50,7 +50,7 @@ commands =
towncrier build --version {posargs} --yes towncrier build --version {posargs} --yes
[testenv:docs] [testenv:docs]
basepython = python3 basepython = python3.10
usedevelop = True usedevelop = True
deps = deps =
sphinx sphinx