Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,18 +172,6 @@ jobs:
with:
python-version: ${{ matrix.python }}

- name: Install specific pytest version
if: matrix.pytest-version == 'pytest@pre-release'
run: |
python -m pip install --pre pytest

- name: Install specific pytest version
if: matrix.pytest-version != 'pytest@pre-release'
run: |
python -m pip install "${{ matrix.pytest-version }}"

- name: Install specific pytest version
run: python -m pytest --version
- name: Install base Python requirements
uses: brettcannon/pip-secure-install@92f400e3191171c1858cc0e0d9ac6320173fdb0c # v1.0.0
with:
Expand All @@ -193,6 +181,17 @@ jobs:
- name: Install test requirements
run: python -m pip install --upgrade -r build/test-requirements.txt

- name: Install specific pytest version (pre-release)
if: matrix.pytest-version == 'pytest@pre-release'
run: python -m pip install --upgrade --pre pytest

- name: Install specific pytest version
if: matrix.pytest-version != 'pytest@pre-release'
run: python -m pip install --upgrade "${{ matrix.pytest-version }}"

- name: Print pytest version
run: python -m pytest --version

- name: Run Python unit tests
run: python python_files/tests/run_all.py

Expand Down
4 changes: 0 additions & 4 deletions build/test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ pylint
pycodestyle
pydocstyle
prospector
# pytest-black 0.6.0 uses the deprecated `path` arg in pytest_collect_file,
# which was removed in pytest 8.1. Pin to <8.1 to maintain compatibility.
pytest<8.1
flask
fastapi
uvicorn
Expand Down Expand Up @@ -41,4 +38,3 @@ pytest-describe

# for pytest-ruff related tests
pytest-ruff
pytest-black
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
# Local replacement for the pytest-black plugin that supports pytest 7+.
# pytest-black 0.6.0 uses the deprecated `path` argument in pytest_collect_file,
# which was removed in pytest 8.1. This conftest provides a compatible implementation.

import re
import subprocess
import sys

import pytest

PYTEST_VER = tuple(int(x) for x in pytest.__version__.split(".")[:2])

try:
import tomllib

Check failure on line 15 in python_files/tests/pytestadapter/.data/2496-black-formatter/conftest.py

View workflow job for this annotation

GitHub Actions / Check Python types

Import "tomllib" could not be resolved (reportMissingImports)

Check failure on line 15 in python_files/tests/pytestadapter/.data/2496-black-formatter/conftest.py

View workflow job for this annotation

GitHub Actions / Check Python types

Import "tomllib" could not be resolved (reportMissingImports)
except ImportError:
try:
import tomli as tomllib # type: ignore[no-redef]
except ImportError:
tomllib = None # type: ignore[assignment]

HISTKEY = "black/mtimes"


def pytest_addoption(parser):
group = parser.getgroup("general")
group.addoption(
"--black", action="store_true", help="enable format checking with black"
)


def pytest_configure(config):
# load cached mtimes at session startup
if config.option.black and hasattr(config, "cache"):
config._blackmtimes = config.cache.get(HISTKEY, {})
config.addinivalue_line("markers", "black: enable format checking with black")


def pytest_unconfigure(config):
# save cached mtimes at end of session
if hasattr(config, "_blackmtimes"):
config.cache.set(HISTKEY, config._blackmtimes)


if PYTEST_VER >= (8, 1):

def pytest_collect_file(file_path, parent):

Check failure on line 47 in python_files/tests/pytestadapter/.data/2496-black-formatter/conftest.py

View workflow job for this annotation

GitHub Actions / Check Python types

Function declaration "pytest_collect_file" is obscured by a declaration of the same name (reportGeneralTypeIssues)

Check failure on line 47 in python_files/tests/pytestadapter/.data/2496-black-formatter/conftest.py

View workflow job for this annotation

GitHub Actions / Check Python types

Function declaration "pytest_collect_file" is obscured by a declaration of the same name (reportGeneralTypeIssues)
config = parent.config
if (
config.option.black
and file_path.suffix in (".py", ".pyi")
and file_path.name != "conftest.py"
):
return BlackFile.from_parent(parent, path=file_path)

elif PYTEST_VER >= (7, 0):

def pytest_collect_file(file_path, path, parent): # type: ignore[misc] # noqa: ARG001
# `path` must match the pytest 7.x hookspec; use file_path (pathlib.Path) in body.
config = parent.config
if (
config.option.black
and file_path.suffix in (".py", ".pyi")
and file_path.name != "conftest.py"
):
return BlackFile.from_parent(parent, path=file_path)


class BlackFile(pytest.File):
def collect(self):
"""Return a list of children (items and collectors) for this collection node."""
yield BlackItem.from_parent(self, name="black")


class BlackItem(pytest.Item):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add_marker("black")
try:
if tomllib is not None:
with open("pyproject.toml", "rb") as toml_file:
settings = tomllib.load(toml_file)["tool"]["black"]
if "include" in settings:
settings["include"] = self._re_fix_verbose(settings["include"])
if "exclude" in settings:
settings["exclude"] = self._re_fix_verbose(settings["exclude"])
self.pyproject = settings
else:
self.pyproject = {}
except Exception:
self.pyproject = {}

def setup(self):
pytest.importorskip("black")
mtimes = getattr(self.config, "_blackmtimes", {})
self._blackmtime = self.path.stat().st_mtime
old = mtimes.get(str(self.path), 0)
if self._blackmtime == old:
pytest.skip("file(s) previously passed black format checks")

if self._skip_test():
pytest.skip("file(s) excluded by pyproject.toml")

def runtest(self):
cmd = [
sys.executable,
"-m",
"black",
"--check",
"--diff",
"--quiet",
str(self.path),
]
try:
subprocess.run(cmd, check=True, stdout=subprocess.PIPE, text=True)
except subprocess.CalledProcessError as e:
raise BlackError(e)

mtimes = getattr(self.config, "_blackmtimes", {})
mtimes[str(self.path)] = self._blackmtime

def repr_failure(self, excinfo):
if excinfo.errisinstance(BlackError):
return excinfo.value.args[0].stdout
return super().repr_failure(excinfo)

def reportinfo(self):
return (self.path, -1, "Black format check")

def _skip_test(self):
return self._excluded() or (not self._included())

def _included(self):
if "include" not in self.pyproject:
return True
return re.search(self.pyproject["include"], str(self.path))

def _excluded(self):
if "exclude" not in self.pyproject:
return False
return re.search(self.pyproject["exclude"], str(self.path))

def _re_fix_verbose(self, regex):
if "\n" in regex:
regex = "(?x)" + regex
return re.compile(regex)


class BlackError(Exception):
pass
Loading