diff --git a/.cspell.json b/.cspell.json index 29d017c9..8f940d0a 100644 --- a/.cspell.json +++ b/.cspell.json @@ -37,7 +37,6 @@ "labels/*.toml", "pyproject.toml", "pyrightconfig.json", - "tox.ini", "typings" ], "language": "en-US", diff --git a/pyproject.toml b/pyproject.toml index a1425e0b..f2f481dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,6 @@ dev = [ "compwa-policy[sty]", "compwa-policy[test]", "labels", - "pydeps", "sphinx-autobuild", "tox >=1.9", # for skip_install, use_develop 'sphinx-autobuild!=2024.4.*; python_version <"3.10.0"', @@ -184,9 +183,6 @@ cmd = "tox -e doclive" [tool.pixi.feature.dev.tasks.linkcheck] cmd = "tox -e linkcheck" -[tool.pixi.feature.dev.tasks.pydeps] -cmd = "tox -e pydeps" - [tool.pixi.feature.dev.tasks.sty] cmd = "pre-commit run --all-files" @@ -344,3 +340,84 @@ sort_first = [ ] spaces_indent_inline_array = 4 trailing_comma_inline_array = true + +[tool.tox] +legacy_tox_ini = """ +[tox] +envlist = + cov + doc + linkcheck + sty +skip_install = True +skip_missing_interpreters = True +skipsdist = True + +[testenv] +allowlist_externals = + pytest +commands = + pytest {posargs} +description = Run all unit tests +passenv = * + +[testenv:cov] +allowlist_externals = + pytest +commands = + pytest {posargs} \ + --cov-fail-under=35 \ + --cov-report=html \ + --cov-report=xml \ + --cov=compwa_policy +description = Compute test coverage + +[testenv:doc] +allowlist_externals = + sphinx-build +commands = + sphinx-build \ + --builder=html \ + --fail-on-warning \ + --keep-going \ + --show-traceback \ + docs/ docs/_build/html +description = Build documentation and API through Sphinx + +[testenv:doclive] +allowlist_externals = + sphinx-autobuild +commands = + sphinx-autobuild \ + --ignore=docs/_build \ + --ignore=docs/api \ + --open-browser \ + --port=0 \ + --re-ignore='.*\\.egg-info' \ + --re-ignore='.*/__pycache__/.*' \ + --watch=docs \ + --watch=src \ + docs/ docs/_build/html +description = Set up a server to directly preview changes to the HTML pages + +[testenv:linkcheck] +allowlist_externals = + sphinx-build +commands = + sphinx-build \ + --builder=linkcheck \ + --show-traceback \ + docs/ docs/_build/linkcheck +description = Check external links in the documentation (requires internet connection) +setenv = + PYTHONWARNINGS = + +[testenv:sty] +allowlist_externals = + pre-commit +commands = + pre-commit run {posargs} --all-files +description = Perform all linting, formatting, and spelling checks +setenv = + SKIP = pyright +""" diff --git a/src/compwa_policy/check_dev_files/pixi.py b/src/compwa_policy/check_dev_files/pixi.py index c82458f6..9c7e119c 100644 --- a/src/compwa_policy/check_dev_files/pixi.py +++ b/src/compwa_policy/check_dev_files/pixi.py @@ -9,9 +9,9 @@ import yaml from tomlkit import inline_table, string +from compwa_policy.check_dev_files.tox import read_tox_config from compwa_policy.errors import PrecommitError from compwa_policy.utilities import CONFIG_PATH, append_safe, vscode -from compwa_policy.utilities.cfg import open_config from compwa_policy.utilities.executor import Executor from compwa_policy.utilities.match import filter_files from compwa_policy.utilities.pyproject import ( @@ -190,9 +190,9 @@ def __import_conda_environment(pyproject: ModifiablePyproject) -> None: def __import_tox_tasks(pyproject: ModifiablePyproject) -> None: - if not CONFIG_PATH.tox.exists(): + tox = read_tox_config() + if tox is None: return - tox = open_config(CONFIG_PATH.tox) tox_jobs = ___get_tox_job_names(tox) imported_tasks = [] blacklisted_jobs = {"jcache"} # cspell:ignore jcache @@ -308,9 +308,9 @@ def __install_package_editable(pyproject: ModifiablePyproject) -> None: def __outsource_pixi_tasks_to_tox(pyproject: ModifiablePyproject) -> None: - if not CONFIG_PATH.tox.exists(): + tox = read_tox_config() + if tox is None: return - tox = open_config(CONFIG_PATH.tox) blacklisted_jobs = {"sty"} updated_tasks = [] for tox_job, pixi_task in ___get_tox_job_names(tox).items(): diff --git a/src/compwa_policy/check_dev_files/tox.py b/src/compwa_policy/check_dev_files/tox.py index 34f89f31..6a98d3a0 100644 --- a/src/compwa_policy/check_dev_files/tox.py +++ b/src/compwa_policy/check_dev_files/tox.py @@ -2,24 +2,47 @@ from __future__ import annotations +import re from configparser import ConfigParser from pathlib import Path +from typing import TYPE_CHECKING from compwa_policy.errors import PrecommitError from compwa_policy.utilities import CONFIG_PATH +from compwa_policy.utilities.pyproject import ModifiablePyproject, Pyproject +from compwa_policy.utilities.toml import to_multiline_string + +if TYPE_CHECKING: + from tomlkit.items import String def main(has_notebooks: bool) -> None: - if not CONFIG_PATH.tox.exists(): + _merge_tox_ini_into_pyproject() + tox = read_tox_config() + if tox is None: return - tox = _read_tox_config(CONFIG_PATH.tox) _check_expected_sections(tox, has_notebooks) -def _read_tox_config(path: Path) -> ConfigParser: - config = ConfigParser() - config.read(path) - return config +def _merge_tox_ini_into_pyproject() -> None: + if not CONFIG_PATH.tox.is_file(): + return + with open(CONFIG_PATH.tox) as file: + tox_ini = file.read() + with ModifiablePyproject.load() as pyproject: + tox_table = pyproject.get_table("tool.tox", create=True) + tox_table["legacy_tox_ini"] = __ini_to_toml(tox_ini) + CONFIG_PATH.tox.unlink() + msg = f"Merged {CONFIG_PATH.tox} into {CONFIG_PATH.pyproject}" + pyproject.changelog.append(msg) + + +def __ini_to_toml(ini: str) -> String: + ini = re.sub(r"(? None: @@ -40,7 +63,28 @@ def _check_expected_sections(tox: ConfigParser, has_notebooks: bool) -> None: missing_sections = expected_sections - sections if missing_sections: msg = ( - f"{CONFIG_PATH.tox} is missing job definitions:" + f"Tox configuration is missing job definitions:" f" {', '.join(sorted(missing_sections))}" ) raise PrecommitError(msg) + + +def read_tox_config() -> ConfigParser | None: + if CONFIG_PATH.tox.is_file(): + return _load_tox_ini() + if CONFIG_PATH.pyproject.is_file(): + pyproject = Pyproject.load() + if not pyproject.has_table("tool.tox"): + return None + tox_table = pyproject.get_table("tool.tox") + tox_config_str = tox_table.get("legacy_tox_ini") + if tox_config_str is not None: + config = ConfigParser() + config.read_string(tox_config_str) + return None + + +def _load_tox_ini() -> ConfigParser: + config = ConfigParser() + config.read(CONFIG_PATH.tox) + return config diff --git a/src/compwa_policy/utilities/toml.py b/src/compwa_policy/utilities/toml.py index 293afa3d..0fdbc6dd 100644 --- a/src/compwa_policy/utilities/toml.py +++ b/src/compwa_policy/utilities/toml.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any, Iterable import tomlkit +from tomlkit.items import String, StringType, Trivia if TYPE_CHECKING: from tomlkit.items import Array @@ -18,3 +19,7 @@ def to_toml_array(items: Iterable[Any], multiline: bool | None = None) -> Array: else: array.multiline(multiline) return array + + +def to_multiline_string(value: str) -> String: + return String(StringType.MLB, value, value, Trivia()) diff --git a/tox.ini b/tox.ini deleted file mode 100644 index c50672ec..00000000 --- a/tox.ini +++ /dev/null @@ -1,102 +0,0 @@ -[tox] -envlist = - doc - py - sty -passenv = PYTHONPATH -skip_install = True -skip_missing_interpreters = True -skipsdist = True - -[testenv] -allowlist_externals = - pytest -commands = - pytest {posargs} -description = - Run all unit tests - -[testenv:cov] -allowlist_externals = - pytest -commands = - pytest {posargs} \ - --cov-fail-under=35 \ - --cov-report=html \ - --cov-report=xml \ - --cov=compwa_policy -description = - Compute test coverage - -[testenv:doc] -allowlist_externals = - sphinx-build -commands = - sphinx-build \ - --builder html \ - --fail-on-warning \ - --keep-going \ - --show-traceback \ - docs/ docs/_build/html -description = - Build documentation and API through Sphinx -passenv = * -setenv = - FORCE_COLOR = yes - -[testenv:doclive] -allowlist_externals = - sphinx-autobuild -commands = - sphinx-autobuild \ - --open-browser \ - --re-ignore '.*\.egg-info' \ - --re-ignore '.*/__pycache__/.*' \ - --re-ignore 'docs/_build/.*' \ - --re-ignore 'docs/api/.*' \ - --watch docs \ - --watch src \ - docs/ docs/_build/html -description = - Set up a server to directly preview changes to the HTML pages -passenv = * -setenv = - FORCE_COLOR = yes - -[testenv:linkcheck] -allowlist_externals = - sphinx-build -commands = - sphinx-build \ - --builder linkcheck \ - --show-traceback \ - docs/ docs/_build/linkcheck -description = - Check external links in the documentation (requires internet connection) -passenv = * -setenv = - FORCE_COLOR = yes - -[testenv:pydeps] -allowlist_externals = - pydeps -changedir = src -commands = - pydeps compwa_policy \ - -o module_structure.svg \ - --exclude '*._*' \ - --max-bacon=1 \ - --noshow -description = - Visualize module dependencies -passenv = * - -[testenv:sty] -allowlist_externals = - pre-commit -commands = - pre-commit run {posargs} --all-files -description = - Perform all linting, formatting, and spelling checks -setenv = - SKIP = pyright