Use hatch over tox (#262)
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index de34370..ae4e4f1 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -2,7 +2,7 @@
on:
workflow_dispatch:
push:
- branches: "main"
+ branches: ["main"]
tags-ignore: ["**"]
pull_request:
schedule:
@@ -36,8 +36,18 @@
uses: actions/setup-python@v5
with:
python-version: "3.12"
- - name: Install tox
- run: python -m pip install tox
+ - name: Pick environment to run
+ run: |
+ import codecs; import os
+ py = "${{ matrix.py }}"
+ py = "test.{}".format(py if py.startswith("pypy") else f"py{py}")
+ print(f"Picked {py}")
+ with codecs.open(os.environ["GITHUB_ENV"], mode="a", encoding="utf-8") as file_handler:
+ file_handler.write("FORCE_COLOR=1\n")
+ file_handler.write(f"ENV={py}\n")
+ shell: python
+ - name: Install hatch
+ run: python -m pip install hatch
- uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -45,36 +55,28 @@
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.py }}
- - name: Pick environment to run
+ - name: Setup test environment
run: |
- import codecs
- import os
- import platform
- import sys
- cpy = platform.python_implementation() == "CPython"
- base =("{}{}{}" if cpy else "{}{}").format("py" if cpy else "pypy", *sys.version_info[0:2])
- env = "TOXENV={}\n".format(base)
- print("Picked:\n{}for{}".format(env, sys.version))
- with codecs.open(os.environ["GITHUB_ENV"], "a", "utf-8") as file_handler:
- file_handler.write(env)
- shell: python
- - name: Setup test suite
- run: tox -vv --notest
+ hatch -v env create ${ENV}
+ hatch run ${ENV}:pip freeze
+ shell: bash
- name: Run test suite
- run: tox --skip-pkg-install
+ run: hatch -v run ${ENV}:run
env:
PYTEST_ADDOPTS: "-vv --durations=20"
CI_RUN: "yes"
+ shell: bash
- name: Rename coverage report file
run: |
import os; import sys;
- os.rename(f".tox/.coverage.{os.environ['TOXENV']}", f".tox/.coverage.{os.environ['TOXENV']}-{sys.platform}")
+ os.rename(f"report{os.sep}.coverage.${{ matrix.py }}", f"report{os.sep}.coverage.${{ matrix.py }}-{sys.platform}")
shell: python
- name: Upload coverage data
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: coverage-data
- path: ".tox/.coverage.*"
+ name: coverage-${{ matrix.os }}-${{ matrix.py }}
+ path: "report/.coverage.*"
+ retention-days: 3
coverage:
name: Combine coverage
@@ -87,29 +89,30 @@
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- - name: Install tox
- run: python -m pip install tox
+ - name: Let us have colors
+ run: echo "FORCE_COLOR=true" >> "$GITHUB_ENV"
+ - name: Install hatch
+ run: python -m pip install hatch
- name: Setup coverage tool
- run: tox -e coverage --notest
- - name: Install package builder
- run: python -m pip install build
- - name: Build package
- run: pyproject-build --wheel .
+ run: |
+ hatch -v env create coverage
+ hatch run coverage:pip freeze
- name: Download coverage data
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
- name: coverage-data
- path: .tox
+ path: report
+ pattern: coverage-*
+ merge-multiple: true
- name: Combine and report coverage
- run: tox -e coverage
+ run: hatch run coverage:run
- name: Upload HTML report
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: html-report
- path: .tox/htmlcov
+ path: report/html
check:
- name: ${{ matrix.tox_env }} - ${{ matrix.os }}
+ name: ${{ matrix.env.name }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
@@ -117,13 +120,11 @@
os:
- ubuntu-22.04
- windows-2022
- tox_env:
- - dev
- - type
- - docs
- - readme
- exclude:
- - { os: windows-latest, tox_env: readme }
+ env:
+ - {"name": "default", "target": "show"}
+ - {"name": "type", "target": "run"}
+ - {"name": "docs", "target": "build"}
+ - {"name": "readme", "target": "run"}
steps:
- uses: actions/checkout@v4
with:
@@ -132,9 +133,11 @@
uses: actions/setup-python@v5
with:
python-version: "3.12"
- - name: Install tox
- run: python -m pip install tox
- - name: Setup test suite
- run: tox -vv --notest -e ${{ matrix.tox_env }}
- - name: Run test suite
- run: tox --skip-pkg-install -e ${{ matrix.tox_env }}
+ - name: Install hatch
+ run: python -m pip install hatch
+ - name: Setup ${{ matrix.env.name }}
+ run: |
+ hatch -v env create ${{ matrix.env.name }}
+ hatch run ${{ matrix.env.name }}:pip freeze
+ - name: Run ${{ matrix.env.name }}
+ run: hatch -v run ${{ matrix.env.name }}:${{ matrix.env.target }}
diff --git a/.gitignore b/.gitignore
index f5f1096..86a75e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,7 @@
-/.idea/
-/.vscode/
-
*.pyc
*.egg-info
-tmp/
-build/
-dist/
-.tox/
+/dist
+/.tox
/src/platformdirs/version.py
+/report
+/docs/build
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c3856aa..705598f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,11 +21,6 @@
- id: ruff-format
- id: ruff
args: [ "--fix", "--unsafe-fixes", "--exit-non-zero-on-fix" ]
- - repo: https://github.com/tox-dev/tox-ini-fmt
- rev: "1.3.1"
- hooks:
- - id: tox-ini-fmt
- args: ["-p", "fix"]
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "1.7.0"
hooks:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..90ba3d8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,3 @@
+This project uses [hatch](https://hatch.pypa.io) development, therefore consult that documentation for more in-depth how
+to. To see a list of available environments use `hatch env show`, for example to run the test suite under Python 3.12
+can type in a shell `hatch run test.py3.12:run`.
diff --git a/pyproject.toml b/pyproject.toml
index 3e051c8..6ae2403 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -57,6 +57,9 @@
"pytest-cov>=4.1",
"pytest-mock>=3.12",
]
+optional-dependencies.type = [
+ "mypy>=1.8",
+]
urls.Documentation = "https://platformdirs.readthedocs.io"
urls.Homepage = "https://github.com/platformdirs/platformdirs"
urls.Source = "https://github.com/platformdirs/platformdirs"
@@ -67,6 +70,77 @@
build.targets.sdist.include = ["/src", "/tests", "/tox.ini"]
version.source = "vcs"
+[tool.hatch.envs.default]
+description = "Development environment"
+features = ["test", "docs", "type"]
+scripts = { show = ["python -m pip list --format=columns", 'python -c "import sys; print(sys.executable)"'] }
+
+[tool.hatch.envs.test]
+template = "test"
+# dev-mode = false # cannot enable this until https://github.com/pypa/hatch/issues/1237
+description = "Run the test suite"
+matrix = [{ python = ["3.12", "3.11", "3.10", "3.9", "3.8", "pypy3.9"] }]
+features = ["test"]
+env-vars = { COVERAGE_FILE = "report/.coverage.{matrix:python}", COVERAGE_PROCESS_START = "pyproject.toml", _COVERAGE_SRC = "src/platformdirs" }
+[tool.hatch.envs.test.scripts]
+run = ["""
+ pytest --junitxml report/junit.{matrix:python}.xml --cov src/platformdirs --cov tests \
+ --cov-config=pyproject.toml --no-cov-on-fail --cov-report term-missing:skip-covered --cov-context=test \
+ --cov-report html:report/html{matrix:python} --cov-report xml:report/coverage{matrix:python}.xml \
+ tests
+"""]
+
+[tool.hatch.envs.coverage]
+template = "coverage"
+description = "combine coverage files and generate diff"
+dependencies = ["covdefaults>=2.3", "coverage[toml]>=7.3.2", "diff-cover>=8.0.1"]
+env-vars = { COVERAGE_FILE = "report/.coverage" }
+[tool.hatch.envs.coverage.scripts]
+run = [
+ "coverage combine report",
+ "coverage report --skip-covered --show-missing",
+ "coverage xml -o report/coverage.xml",
+ "coverage html -d report/html",
+ "diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} report/coverage.xml",
+]
+
+[tool.hatch.envs.type]
+template = "type"
+description = "Run the type checker"
+python = "3.12"
+dev-mode = false
+features = ["type", "test"]
+scripts = { run = ["mypy --strict src", "mypy --strict tests"] }
+
+[tool.hatch.envs.fix]
+template = "fix"
+description = "Run the pre-commit tool to lint and autofix issues"
+python = "3.12"
+detached = true
+dependencies = ["pre-commit>=3.6"]
+scripts = { "run" = ["pre-commit run --all-files --show-diff-on-failure"] }
+
+[tool.hatch.envs.docs]
+template = "docs"
+description = "Build documentation using Sphinx"
+python = "3.12"
+dev-mode = false
+features = ["docs"]
+[tool.hatch.envs.docs.scripts]
+build = [
+ """python -c "import glob; import subprocess; subprocess.call(['proselint'] + glob.glob('docs/*.rst'))" """,
+ """python -c "from shutil import rmtree; rmtree('docs/build', ignore_errors=True)" """,
+ "sphinx-build -d docs/build/tree docs docs/build --color -b html",
+ """python -c "from pathlib import Path; p=(Path('docs')/'build'/'index.html').absolute().as_uri(); print('Documentation built under '+p)" """,
+]
+
+[tool.hatch.envs.readme]
+template = "readme"
+description = "check that the long description is valid"
+python = "3.12"
+dependencies = ["build[virtualenv]>=1.0.3", "twine>=4.0.2", "check-wheel-contents>=0.6.0"]
+scripts = { "run" = ["python -m build -o dist", "twine check dist/*.whl dist/*.tar.gz", "check-wheel-contents dist"] }
+
[tool.ruff]
select = ["ALL"]
line-length = 120
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index a6d51ad..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,115 +0,0 @@
-[tox]
-requires =
- tox>=4.2
-env_list =
- fix
- py312
- py311
- py310
- py39
- py38
- pypy3
- type
- coverage
- readme
- docs
-skip_missing_interpreters = true
-
-[testenv]
-description = run the unit tests with pytest under {basepython}
-package = wheel
-wheel_build_env = .pkg
-extras =
- test
-pass_env =
- ANDROID_DATA
- ANDROID_ROOT
-set_env =
- COVERAGE_FILE = {toxworkdir}/.coverage.{envname}
- COVERAGE_PROCESS_START = {toxinidir}/pyproject.toml
- _COVERAGE_SRC = {envsitepackagesdir}/platformdirs
-commands =
- pytest {tty:--color=yes} {posargs: \
- --junitxml {toxworkdir}{/}junit.{envname}.xml --cov {envsitepackagesdir}{/}platformdirs \
- --cov {toxinidir}{/}tests \
- --cov-config=pyproject.toml --no-cov-on-fail --cov-report term-missing:skip-covered --cov-context=test \
- --cov-report html:{envtmpdir}{/}htmlcov --cov-report xml:{toxworkdir}{/}coverage.{envname}.xml \
- tests}
-
-[testenv:fix]
-description = run static analysis and style check using flake8
-skip_install = true
-deps =
- pre-commit>=3.5
-pass_env =
- HOMEPATH
- PROGRAMDATA
-commands =
- pre-commit run --all-files --show-diff-on-failure
-
-[testenv:type]
-description = run type check on code base
-deps =
- mypy==1.7.1
-set_env =
- {tty:MYPY_FORCE_COLOR = 1}
-commands =
- mypy --strict src
- mypy --strict tests
-
-[testenv:coverage]
-description = combine coverage files and generate diff (against DIFF_AGAINST defaulting to origin/main)
-skip_install = true
-deps =
- covdefaults>=2.3
- coverage[toml]>=7.3.2
- diff-cover>=8.0.1
-extras =
-parallel_show_output = true
-pass_env =
- DIFF_AGAINST
-set_env =
- COVERAGE_FILE = {toxworkdir}/.coverage
-commands =
- coverage combine
- coverage report --skip-covered --show-missing
- coverage xml -o {toxworkdir}/coverage.xml
- coverage html -d {toxworkdir}/htmlcov
- diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} {toxworkdir}/coverage.xml
-depends =
- py312
- py311
- py310
- py39
- py38
- pypy3
-
-[testenv:readme]
-description = check that the long description is valid
-skip_install = true
-deps =
- build[virtualenv]>=1.0.3
- twine>=4.0.2
-pass_env =
- *
-change_dir = {toxinidir}
-commands =
- python -m build -o {envtmpdir} .
- twine check {envtmpdir}/*
-
-[testenv:docs]
-extras =
- docs
-commands =
- python -c 'import glob; import subprocess; subprocess.call(["proselint"] + glob.glob("docs/*.rst"))'
- sphinx-build -d "{envtmpdir}/doctree" docs "{toxworkdir}/docs_out" --color -b html {posargs}
- python -c 'import pathlib; print("documentation available under \{0\}".format((pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html").as_uri()))'
-
-[testenv:dev]
-description = generate a DEV environment
-package = editable
-extras =
- test
-commands =
- python -m pip list --format=columns
- python -c 'import sys; print(sys.executable)'