From fa3a7a6d0046148a5f2f294eefc3b76bfb8f1714 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Tue, 8 Oct 2024 08:09:39 -0400 Subject: [PATCH] fix(templates): replace flake8 and pydocstyle with ruff --- .../init-django-framework/pyproject.toml.j2 | 41 +++++++++ .../init-django-framework/src/charm.py.j2 | 1 - .../init-django-framework/tox.ini.j2 | 84 +++++++++++++++++++ .../init-fastapi-framework/pyproject.toml.j2 | 41 +++++++++ .../init-fastapi-framework/src/charm.py.j2 | 1 - .../init-fastapi-framework/tox.ini.j2 | 84 +++++++++++++++++++ .../init-flask-framework/pyproject.toml.j2 | 41 +++++++++ .../init-flask-framework/src/charm.py.j2 | 1 - .../templates/init-flask-framework/tox.ini.j2 | 84 +++++++++++++++++++ .../init-go-framework/pyproject.toml.j2 | 41 +++++++++ .../init-go-framework/src/charm.py.j2 | 1 - .../templates/init-go-framework/tox.ini.j2 | 84 +++++++++++++++++++ .../init-kubernetes/pyproject.toml.j2 | 3 +- .../tests/unit/test_charm.py.j2 | 1 + .../templates/init-machine/pyproject.toml.j2 | 3 +- .../init-machine/tests/unit/test_charm.py.j2 | 1 + .../templates/init-simple/pyproject.toml.j2 | 3 +- .../init-simple/tests/unit/test_charm.py.j2 | 1 + pyproject.toml | 2 - requirements-dev.txt | 3 - tests/integration/commands/test_init.py | 34 +++----- 21 files changed, 521 insertions(+), 34 deletions(-) create mode 100644 charmcraft/templates/init-django-framework/pyproject.toml.j2 create mode 100644 charmcraft/templates/init-django-framework/tox.ini.j2 create mode 100644 charmcraft/templates/init-fastapi-framework/pyproject.toml.j2 create mode 100644 charmcraft/templates/init-fastapi-framework/tox.ini.j2 create mode 100644 charmcraft/templates/init-flask-framework/pyproject.toml.j2 create mode 100644 charmcraft/templates/init-flask-framework/tox.ini.j2 create mode 100644 charmcraft/templates/init-go-framework/pyproject.toml.j2 create mode 100644 charmcraft/templates/init-go-framework/tox.ini.j2 diff --git a/charmcraft/templates/init-django-framework/pyproject.toml.j2 b/charmcraft/templates/init-django-framework/pyproject.toml.j2 new file mode 100644 index 000000000..3cb1ce223 --- /dev/null +++ b/charmcraft/templates/init-django-framework/pyproject.toml.j2 @@ -0,0 +1,41 @@ +# Testing tools configuration +[tool.coverage.run] +branch = true + +[tool.coverage.report] +show_missing = true + +[tool.pytest.ini_options] +minversion = "6.0" +log_cli_level = "INFO" + +# Linting tools configuration +[tool.ruff] +line-length = 99 +lint.select = ["E", "W", "F", "C", "N", "D", "I001"] +lint.extend-ignore = [ + "D105", + "D107", + "D203", + "D204", + "D213", + "D215", + "D400", + "D404", + "D406", + "D407", + "D408", + "D409", + "D413", +] +extend-exclude = ["__pycache__", "*.egg_info"] +lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} + +[tool.ruff.lint.mccabe] +max-complexity = 10 + +[tool.codespell] +skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage" + +[tool.pyright] +include = ["src/**.py"] diff --git a/charmcraft/templates/init-django-framework/src/charm.py.j2 b/charmcraft/templates/init-django-framework/src/charm.py.j2 index 37ed37b9b..19946c2e2 100755 --- a/charmcraft/templates/init-django-framework/src/charm.py.j2 +++ b/charmcraft/templates/init-django-framework/src/charm.py.j2 @@ -8,7 +8,6 @@ import logging import typing import ops - import paas_app_charmer.django logger = logging.getLogger(__name__) diff --git a/charmcraft/templates/init-django-framework/tox.ini.j2 b/charmcraft/templates/init-django-framework/tox.ini.j2 new file mode 100644 index 000000000..351f36085 --- /dev/null +++ b/charmcraft/templates/init-django-framework/tox.ini.j2 @@ -0,0 +1,84 @@ +# Copyright {{ year }} {{ author }} +# See LICENSE file for licensing details. + +[tox] +no_package = True +skip_missing_interpreters = True +env_list = format, lint, static +min_version = 4.0.0 + +[vars] +src_path = {tox_root}/src +;tests_path = {tox_root}/tests +;lib_path = {tox_root}/lib/charms/operator_name_with_underscores +all_path = {[vars]src_path} + +[testenv] +set_env = + PYTHONPATH = {tox_root}/lib:{[vars]src_path} + PYTHONBREAKPOINT=pdb.set_trace + PY_COLORS=1 +pass_env = + PYTHONPATH + CHARM_BUILD_DIR + MODEL_SETTINGS + +[testenv:format] +description = Apply coding style standards to code +deps = + ruff +commands = + ruff format {[vars]all_path} + ruff check --fix {[vars]all_path} + +[testenv:lint] +description = Check code against coding style standards +deps = + ruff + codespell +commands = + # if this charm owns a lib, uncomment "lib_path" variable + # and uncomment the following line + # codespell {[vars]lib_path} + codespell {tox_root} + ruff check {[vars]all_path} + ruff format --check --diff {[vars]all_path} + +[testenv:unit] +description = Run unit tests +deps = + pytest + coverage[toml] + -r {tox_root}/requirements.txt +commands = + coverage run --source={[vars]src_path} \ + -m pytest \ + --tb native \ + -v \ + -s \ + {posargs} \ + {[vars]tests_path}/unit + coverage report + +[testenv:static] +description = Run static type checks +deps = + pyright + -r {tox_root}/requirements.txt +commands = + pyright {posargs} + +[testenv:integration] +description = Run integration tests +deps = + pytest + juju + pytest-operator + -r {tox_root}/requirements.txt +commands = + pytest -v \ + -s \ + --tb native \ + --log-cli-level=INFO \ + {posargs} \ + {[vars]tests_path}/integration diff --git a/charmcraft/templates/init-fastapi-framework/pyproject.toml.j2 b/charmcraft/templates/init-fastapi-framework/pyproject.toml.j2 new file mode 100644 index 000000000..3cb1ce223 --- /dev/null +++ b/charmcraft/templates/init-fastapi-framework/pyproject.toml.j2 @@ -0,0 +1,41 @@ +# Testing tools configuration +[tool.coverage.run] +branch = true + +[tool.coverage.report] +show_missing = true + +[tool.pytest.ini_options] +minversion = "6.0" +log_cli_level = "INFO" + +# Linting tools configuration +[tool.ruff] +line-length = 99 +lint.select = ["E", "W", "F", "C", "N", "D", "I001"] +lint.extend-ignore = [ + "D105", + "D107", + "D203", + "D204", + "D213", + "D215", + "D400", + "D404", + "D406", + "D407", + "D408", + "D409", + "D413", +] +extend-exclude = ["__pycache__", "*.egg_info"] +lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} + +[tool.ruff.lint.mccabe] +max-complexity = 10 + +[tool.codespell] +skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage" + +[tool.pyright] +include = ["src/**.py"] diff --git a/charmcraft/templates/init-fastapi-framework/src/charm.py.j2 b/charmcraft/templates/init-fastapi-framework/src/charm.py.j2 index 23bbab169..7a5d107fe 100755 --- a/charmcraft/templates/init-fastapi-framework/src/charm.py.j2 +++ b/charmcraft/templates/init-fastapi-framework/src/charm.py.j2 @@ -8,7 +8,6 @@ import logging import typing import ops - import paas_app_charmer.fastapi logger = logging.getLogger(__name__) diff --git a/charmcraft/templates/init-fastapi-framework/tox.ini.j2 b/charmcraft/templates/init-fastapi-framework/tox.ini.j2 new file mode 100644 index 000000000..351f36085 --- /dev/null +++ b/charmcraft/templates/init-fastapi-framework/tox.ini.j2 @@ -0,0 +1,84 @@ +# Copyright {{ year }} {{ author }} +# See LICENSE file for licensing details. + +[tox] +no_package = True +skip_missing_interpreters = True +env_list = format, lint, static +min_version = 4.0.0 + +[vars] +src_path = {tox_root}/src +;tests_path = {tox_root}/tests +;lib_path = {tox_root}/lib/charms/operator_name_with_underscores +all_path = {[vars]src_path} + +[testenv] +set_env = + PYTHONPATH = {tox_root}/lib:{[vars]src_path} + PYTHONBREAKPOINT=pdb.set_trace + PY_COLORS=1 +pass_env = + PYTHONPATH + CHARM_BUILD_DIR + MODEL_SETTINGS + +[testenv:format] +description = Apply coding style standards to code +deps = + ruff +commands = + ruff format {[vars]all_path} + ruff check --fix {[vars]all_path} + +[testenv:lint] +description = Check code against coding style standards +deps = + ruff + codespell +commands = + # if this charm owns a lib, uncomment "lib_path" variable + # and uncomment the following line + # codespell {[vars]lib_path} + codespell {tox_root} + ruff check {[vars]all_path} + ruff format --check --diff {[vars]all_path} + +[testenv:unit] +description = Run unit tests +deps = + pytest + coverage[toml] + -r {tox_root}/requirements.txt +commands = + coverage run --source={[vars]src_path} \ + -m pytest \ + --tb native \ + -v \ + -s \ + {posargs} \ + {[vars]tests_path}/unit + coverage report + +[testenv:static] +description = Run static type checks +deps = + pyright + -r {tox_root}/requirements.txt +commands = + pyright {posargs} + +[testenv:integration] +description = Run integration tests +deps = + pytest + juju + pytest-operator + -r {tox_root}/requirements.txt +commands = + pytest -v \ + -s \ + --tb native \ + --log-cli-level=INFO \ + {posargs} \ + {[vars]tests_path}/integration diff --git a/charmcraft/templates/init-flask-framework/pyproject.toml.j2 b/charmcraft/templates/init-flask-framework/pyproject.toml.j2 new file mode 100644 index 000000000..3cb1ce223 --- /dev/null +++ b/charmcraft/templates/init-flask-framework/pyproject.toml.j2 @@ -0,0 +1,41 @@ +# Testing tools configuration +[tool.coverage.run] +branch = true + +[tool.coverage.report] +show_missing = true + +[tool.pytest.ini_options] +minversion = "6.0" +log_cli_level = "INFO" + +# Linting tools configuration +[tool.ruff] +line-length = 99 +lint.select = ["E", "W", "F", "C", "N", "D", "I001"] +lint.extend-ignore = [ + "D105", + "D107", + "D203", + "D204", + "D213", + "D215", + "D400", + "D404", + "D406", + "D407", + "D408", + "D409", + "D413", +] +extend-exclude = ["__pycache__", "*.egg_info"] +lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} + +[tool.ruff.lint.mccabe] +max-complexity = 10 + +[tool.codespell] +skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage" + +[tool.pyright] +include = ["src/**.py"] diff --git a/charmcraft/templates/init-flask-framework/src/charm.py.j2 b/charmcraft/templates/init-flask-framework/src/charm.py.j2 index 6bf74a2f5..3fad7d3ef 100755 --- a/charmcraft/templates/init-flask-framework/src/charm.py.j2 +++ b/charmcraft/templates/init-flask-framework/src/charm.py.j2 @@ -8,7 +8,6 @@ import logging import typing import ops - import paas_app_charmer.flask logger = logging.getLogger(__name__) diff --git a/charmcraft/templates/init-flask-framework/tox.ini.j2 b/charmcraft/templates/init-flask-framework/tox.ini.j2 new file mode 100644 index 000000000..351f36085 --- /dev/null +++ b/charmcraft/templates/init-flask-framework/tox.ini.j2 @@ -0,0 +1,84 @@ +# Copyright {{ year }} {{ author }} +# See LICENSE file for licensing details. + +[tox] +no_package = True +skip_missing_interpreters = True +env_list = format, lint, static +min_version = 4.0.0 + +[vars] +src_path = {tox_root}/src +;tests_path = {tox_root}/tests +;lib_path = {tox_root}/lib/charms/operator_name_with_underscores +all_path = {[vars]src_path} + +[testenv] +set_env = + PYTHONPATH = {tox_root}/lib:{[vars]src_path} + PYTHONBREAKPOINT=pdb.set_trace + PY_COLORS=1 +pass_env = + PYTHONPATH + CHARM_BUILD_DIR + MODEL_SETTINGS + +[testenv:format] +description = Apply coding style standards to code +deps = + ruff +commands = + ruff format {[vars]all_path} + ruff check --fix {[vars]all_path} + +[testenv:lint] +description = Check code against coding style standards +deps = + ruff + codespell +commands = + # if this charm owns a lib, uncomment "lib_path" variable + # and uncomment the following line + # codespell {[vars]lib_path} + codespell {tox_root} + ruff check {[vars]all_path} + ruff format --check --diff {[vars]all_path} + +[testenv:unit] +description = Run unit tests +deps = + pytest + coverage[toml] + -r {tox_root}/requirements.txt +commands = + coverage run --source={[vars]src_path} \ + -m pytest \ + --tb native \ + -v \ + -s \ + {posargs} \ + {[vars]tests_path}/unit + coverage report + +[testenv:static] +description = Run static type checks +deps = + pyright + -r {tox_root}/requirements.txt +commands = + pyright {posargs} + +[testenv:integration] +description = Run integration tests +deps = + pytest + juju + pytest-operator + -r {tox_root}/requirements.txt +commands = + pytest -v \ + -s \ + --tb native \ + --log-cli-level=INFO \ + {posargs} \ + {[vars]tests_path}/integration diff --git a/charmcraft/templates/init-go-framework/pyproject.toml.j2 b/charmcraft/templates/init-go-framework/pyproject.toml.j2 new file mode 100644 index 000000000..3cb1ce223 --- /dev/null +++ b/charmcraft/templates/init-go-framework/pyproject.toml.j2 @@ -0,0 +1,41 @@ +# Testing tools configuration +[tool.coverage.run] +branch = true + +[tool.coverage.report] +show_missing = true + +[tool.pytest.ini_options] +minversion = "6.0" +log_cli_level = "INFO" + +# Linting tools configuration +[tool.ruff] +line-length = 99 +lint.select = ["E", "W", "F", "C", "N", "D", "I001"] +lint.extend-ignore = [ + "D105", + "D107", + "D203", + "D204", + "D213", + "D215", + "D400", + "D404", + "D406", + "D407", + "D408", + "D409", + "D413", +] +extend-exclude = ["__pycache__", "*.egg_info"] +lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} + +[tool.ruff.lint.mccabe] +max-complexity = 10 + +[tool.codespell] +skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage" + +[tool.pyright] +include = ["src/**.py"] diff --git a/charmcraft/templates/init-go-framework/src/charm.py.j2 b/charmcraft/templates/init-go-framework/src/charm.py.j2 index ab6569ede..81ca001f6 100755 --- a/charmcraft/templates/init-go-framework/src/charm.py.j2 +++ b/charmcraft/templates/init-go-framework/src/charm.py.j2 @@ -8,7 +8,6 @@ import logging import typing import ops - import paas_app_charmer.go logger = logging.getLogger(__name__) diff --git a/charmcraft/templates/init-go-framework/tox.ini.j2 b/charmcraft/templates/init-go-framework/tox.ini.j2 new file mode 100644 index 000000000..351f36085 --- /dev/null +++ b/charmcraft/templates/init-go-framework/tox.ini.j2 @@ -0,0 +1,84 @@ +# Copyright {{ year }} {{ author }} +# See LICENSE file for licensing details. + +[tox] +no_package = True +skip_missing_interpreters = True +env_list = format, lint, static +min_version = 4.0.0 + +[vars] +src_path = {tox_root}/src +;tests_path = {tox_root}/tests +;lib_path = {tox_root}/lib/charms/operator_name_with_underscores +all_path = {[vars]src_path} + +[testenv] +set_env = + PYTHONPATH = {tox_root}/lib:{[vars]src_path} + PYTHONBREAKPOINT=pdb.set_trace + PY_COLORS=1 +pass_env = + PYTHONPATH + CHARM_BUILD_DIR + MODEL_SETTINGS + +[testenv:format] +description = Apply coding style standards to code +deps = + ruff +commands = + ruff format {[vars]all_path} + ruff check --fix {[vars]all_path} + +[testenv:lint] +description = Check code against coding style standards +deps = + ruff + codespell +commands = + # if this charm owns a lib, uncomment "lib_path" variable + # and uncomment the following line + # codespell {[vars]lib_path} + codespell {tox_root} + ruff check {[vars]all_path} + ruff format --check --diff {[vars]all_path} + +[testenv:unit] +description = Run unit tests +deps = + pytest + coverage[toml] + -r {tox_root}/requirements.txt +commands = + coverage run --source={[vars]src_path} \ + -m pytest \ + --tb native \ + -v \ + -s \ + {posargs} \ + {[vars]tests_path}/unit + coverage report + +[testenv:static] +description = Run static type checks +deps = + pyright + -r {tox_root}/requirements.txt +commands = + pyright {posargs} + +[testenv:integration] +description = Run integration tests +deps = + pytest + juju + pytest-operator + -r {tox_root}/requirements.txt +commands = + pytest -v \ + -s \ + --tb native \ + --log-cli-level=INFO \ + {posargs} \ + {[vars]tests_path}/integration diff --git a/charmcraft/templates/init-kubernetes/pyproject.toml.j2 b/charmcraft/templates/init-kubernetes/pyproject.toml.j2 index ceeab132b..3cb1ce223 100644 --- a/charmcraft/templates/init-kubernetes/pyproject.toml.j2 +++ b/charmcraft/templates/init-kubernetes/pyproject.toml.j2 @@ -14,6 +14,8 @@ log_cli_level = "INFO" line-length = 99 lint.select = ["E", "W", "F", "C", "N", "D", "I001"] lint.extend-ignore = [ + "D105", + "D107", "D203", "D204", "D213", @@ -26,7 +28,6 @@ lint.extend-ignore = [ "D409", "D413", ] -lint.ignore = ["E501", "D107"] extend-exclude = ["__pycache__", "*.egg_info"] lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} diff --git a/charmcraft/templates/init-kubernetes/tests/unit/test_charm.py.j2 b/charmcraft/templates/init-kubernetes/tests/unit/test_charm.py.j2 index 6d43b2357..545178bc1 100644 --- a/charmcraft/templates/init-kubernetes/tests/unit/test_charm.py.j2 +++ b/charmcraft/templates/init-kubernetes/tests/unit/test_charm.py.j2 @@ -6,6 +6,7 @@ import ops import ops.testing import pytest + from charm import {{ class_name }} diff --git a/charmcraft/templates/init-machine/pyproject.toml.j2 b/charmcraft/templates/init-machine/pyproject.toml.j2 index ceeab132b..3cb1ce223 100644 --- a/charmcraft/templates/init-machine/pyproject.toml.j2 +++ b/charmcraft/templates/init-machine/pyproject.toml.j2 @@ -14,6 +14,8 @@ log_cli_level = "INFO" line-length = 99 lint.select = ["E", "W", "F", "C", "N", "D", "I001"] lint.extend-ignore = [ + "D105", + "D107", "D203", "D204", "D213", @@ -26,7 +28,6 @@ lint.extend-ignore = [ "D409", "D413", ] -lint.ignore = ["E501", "D107"] extend-exclude = ["__pycache__", "*.egg_info"] lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} diff --git a/charmcraft/templates/init-machine/tests/unit/test_charm.py.j2 b/charmcraft/templates/init-machine/tests/unit/test_charm.py.j2 index 0120cfbab..b9a2c095b 100644 --- a/charmcraft/templates/init-machine/tests/unit/test_charm.py.j2 +++ b/charmcraft/templates/init-machine/tests/unit/test_charm.py.j2 @@ -7,6 +7,7 @@ import unittest import ops import ops.testing + from charm import {{ class_name }} diff --git a/charmcraft/templates/init-simple/pyproject.toml.j2 b/charmcraft/templates/init-simple/pyproject.toml.j2 index ceeab132b..3cb1ce223 100644 --- a/charmcraft/templates/init-simple/pyproject.toml.j2 +++ b/charmcraft/templates/init-simple/pyproject.toml.j2 @@ -14,6 +14,8 @@ log_cli_level = "INFO" line-length = 99 lint.select = ["E", "W", "F", "C", "N", "D", "I001"] lint.extend-ignore = [ + "D105", + "D107", "D203", "D204", "D213", @@ -26,7 +28,6 @@ lint.extend-ignore = [ "D409", "D413", ] -lint.ignore = ["E501", "D107"] extend-exclude = ["__pycache__", "*.egg_info"] lint.per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]} diff --git a/charmcraft/templates/init-simple/tests/unit/test_charm.py.j2 b/charmcraft/templates/init-simple/tests/unit/test_charm.py.j2 index 67ac35c9d..eba72e45e 100644 --- a/charmcraft/templates/init-simple/tests/unit/test_charm.py.j2 +++ b/charmcraft/templates/init-simple/tests/unit/test_charm.py.j2 @@ -6,6 +6,7 @@ import ops import ops.testing import pytest + from charm import {{ class_name }} diff --git a/pyproject.toml b/pyproject.toml index 179746404..ccdee08e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,10 +48,8 @@ charmcraft = "charmcraft.application.main:main" [project.optional-dependencies] dev = [ # When updating these, also update the dev/lint/types groups in renovate. "coverage", - "flake8", "freezegun", "hypothesis", - "pydocstyle", "pyfakefs", "pylint", "pytest", diff --git a/requirements-dev.txt b/requirements-dev.txt index 85bf935ed..517b24306 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,7 +18,6 @@ cryptography==43.0.1 dill==0.3.9 distro==1.9.0 docker==7.1.0 -flake8==7.1.1 freezegun==1.5.1 httplib2==0.22.0 humanize==4.10.0 @@ -47,12 +46,10 @@ packaging==24.1 platformdirs==4.2.2 pluggy==1.5.0 protobuf==5.27.3 -pycodestyle==2.12.1 pycparser==2.22 pydantic==2.8.2 pydantic-core==2.20.1 pydantic-yaml==1.3.0 -pydocstyle==6.3.0 pyfakefs==5.6.0 pyflakes==3.2.0 pygit2==1.14.1 diff --git a/tests/integration/commands/test_init.py b/tests/integration/commands/test_init.py index a4f632809..acae2c0a4 100644 --- a/tests/integration/commands/test_init.py +++ b/tests/integration/commands/test_init.py @@ -24,7 +24,6 @@ import sys from unittest import mock -import pydocstyle import pytest import pytest_check @@ -285,7 +284,7 @@ def test_tox_success(new_path, init_command, profile): pytest.skip("init template doesn't contain tox.ini file") result = subprocess.run( - ["tox", "-v"], + ["tox", "-v", "run", "-e", "lint,static"], cwd=new_path, env=env, text=True, @@ -295,23 +294,14 @@ def test_tox_success(new_path, init_command, profile): ) assert result.returncode == 0, "Tox run failed:\n" + result.stdout - -@pytest.mark.parametrize("profile", list(commands.init.PROFILES)) -def test_pep257(new_path, init_command, profile): - to_ignore = { - "D105", # Missing docstring in magic method - "D107", # Missing docstring in __init__ - } - to_include = pydocstyle.violations.conventions.pep257 - to_ignore - - init_command.run(create_namespace(profile=profile)) - - python_paths = (str(path) for path in new_path.rglob("*.py")) - python_paths = (path for path in python_paths if "tests" not in path) - errors = list(pydocstyle.check(python_paths, select=to_include)) - - if errors: - report = [f"Please fix files as suggested by pydocstyle ({len(errors):d} issues):"] - report.extend(str(e) for e in errors) - msg = "\n".join(report) - pytest.fail(msg, pytrace=False) + if list((new_path / "tests").glob("*.py")): # If any tests exist + result = subprocess.run( + ["tox", "-v", "run", "-e", "unit"], + cwd=new_path, + env=env, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=False, + ) + assert result.returncode == 0, "Tox run failed:\n" + result.stdout