-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
avikstroem
committed
Aug 4, 2023
1 parent
65b0922
commit c895315
Showing
17 changed files
with
941 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
branches: [ main ] | ||
|
||
jobs: | ||
build: | ||
strategy: | ||
matrix: | ||
python_version: ["3.8", "3.9", "3.10", "3.11"] | ||
runs-on: "ubuntu-latest" | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Python ${{ matrix.python_version }} | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${{ matrix.python_version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip wheel | ||
python -m pip install tox==4.* tox-gh-actions==3.* | ||
- name: Run tox | ||
run: tox | ||
- name: System test | ||
run: ./tests/system_test/system_test.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Thanks to: Sean Hammond | ||
# https://www.seanh.cc/2022/05/21/publishing-python-packages-from-github-actions | ||
name: Publish to PyPI.org | ||
on: | ||
release: | ||
types: [published] | ||
jobs: | ||
pypi: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
- run: python3 -m pip install --upgrade build && python3 -m build | ||
- name: Publish package | ||
uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
password: ${{ secrets.PYPI_API_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
[project] | ||
name = "pytest-litter" | ||
description = "Pytest plugin which verifies that tests do not modify file trees." | ||
# readme = "README.md" | ||
# license = {file = "LICENSE"} | ||
urls = {repo = "https://github.com/mam-dev/pytest-litter"} | ||
requires-python = ">=3.8" | ||
dependencies = ["pytest >= 6.1"] | ||
dynamic = ["version"] | ||
version = "0.0.1.dev0" | ||
classifiers = [ | ||
# "Development Status :: 5 - Production/Stable", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: 3.10", | ||
"Programming Language :: Python :: 3.11", | ||
"Topic :: Software Development :: Testing", | ||
"Topic :: Software Development :: Testing :: Unit", | ||
"Framework :: Pytest", | ||
"License :: OSI Approved :: Apache Software License", | ||
] | ||
|
||
[project.entry-points.pytest11] | ||
pytest-litter = "pytest_litter.plugin.plugin" | ||
|
||
[build-system] | ||
requires = ["setuptools>=51", "wheel", "setuptools_scm[toml]>=6.2"] | ||
build-backend = "setuptools.build_meta" | ||
|
||
[tool.setuptools_scm] | ||
|
||
[tool.setuptools.packages.find] | ||
where = ["src"] | ||
namespaces = false | ||
|
||
[tool.pytest.ini_options] | ||
addopts = "--random-order -p no:pytest-litter -p pytester -vv" | ||
testpaths = ["tests"] | ||
pytester_example_dir = "tests/pytester" | ||
|
||
[tool.coverage.run] | ||
branch = true | ||
source_pkgs = ["pytest_litter"] | ||
|
||
[tool.coverage.report] | ||
show_missing = true | ||
fail_under = 100 | ||
|
||
[tool.mypy] | ||
files = ["src", "tests"] | ||
warn_no_return = true | ||
warn_return_any = true | ||
warn_unused_configs = true | ||
warn_unused_ignores = true | ||
warn_redundant_casts = true | ||
warn_unreachable = true | ||
check_untyped_defs = true | ||
disallow_any_generics = true | ||
disallow_subclassing_any = true | ||
disallow_untyped_calls = true | ||
disallow_untyped_defs = true | ||
disallow_incomplete_defs = true | ||
disallow_untyped_decorators = true | ||
no_implicit_optional = true | ||
no_implicit_reexport = true | ||
strict_equality = true | ||
strict_concatenate = true | ||
|
||
[tool.ruff] | ||
src = ["src", "tests"] | ||
select = [ | ||
"E", # pycodestyle | ||
"F", # pyflakes | ||
"UP", # pyupgrade | ||
"S", # flake8-bandit | ||
"D", # pydocstyle | ||
"PT", # flake8-pytest-style | ||
"I", # isort | ||
"RUF", # Ruff-specific rules | ||
"PTH", # flake8-use-pathlib | ||
"ERA", # eradicate | ||
"PL", # pylint | ||
"FBT", # flake8-boolean-trap | ||
"B", # flake8-bugbear | ||
"A", # flake8-builtins | ||
"ISC", # flake8-implicit-str-concat | ||
"INP", # flake8-no-pep420 | ||
"SLF", # flake8-self | ||
"SIM", # flake8-simplify | ||
"TID", # flake8-tidy-imports | ||
"ARG", # flake8-unused-arguments | ||
"TRY", # tryceratops | ||
"FLY", # flynt | ||
"RSE", # flake8-raise | ||
"RET", # flake8-return | ||
"FIX", # flake8-fixme | ||
"Q", # flake8-quotes | ||
"C4", # flake8-comprehensions | ||
"DTZ", # flake8-datetimez | ||
"T10", # flake8-debugger | ||
"T20", # flake8-print | ||
"TCH", # flake8-type-checking | ||
] | ||
ignore = [ | ||
"D100", "D102", "D103", "D104", "D105", "D107", | ||
"PTH123", | ||
"TRY003", "TRY301", | ||
] | ||
|
||
[tool.ruff.per-file-ignores] | ||
"tests/**/*.py" = [ | ||
"S101", "S105", | ||
"D103", | ||
"FBT001", | ||
"SLF001", | ||
"PLR2004", "PLR0913", | ||
"ARG001", | ||
"INP001", | ||
] | ||
|
||
[tool.ruff.pydocstyle] | ||
convention = "google" | ||
|
||
[tool.ruff.flake8-pytest-style] | ||
fixture-parentheses = false | ||
mark-parentheses = false | ||
parametrize-names-type = "csv" | ||
parametrize-values-type = "list" | ||
|
||
[tool.ruff.flake8-tidy-imports] | ||
ban-relative-imports = "parents" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
ruff | ||
black | ||
mypy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pytest | ||
coverage>=5.3 | ||
pytest-random-order | ||
pytest-integration |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Pytest plugin which verifies that tests do not modify file trees.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Pytest plugin code.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"""Pytest plugin code.""" | ||
|
||
from typing import Optional | ||
|
||
import pytest | ||
|
||
from pytest_litter.plugin.utils import ( | ||
COMPARATOR_KEY, | ||
SNAPSHOT_KEY, | ||
raise_test_error_from_comparison, | ||
run_snapshot_comparison, | ||
) | ||
from pytest_litter.snapshots import ( | ||
DirectoryIgnoreSpec, | ||
IgnoreSpec, | ||
RegexIgnoreSpec, | ||
SnapshotComparator, | ||
TreeSnapshot, | ||
) | ||
|
||
|
||
def pytest_configure(config: pytest.Config) -> None: | ||
"""Configure pytest-litter plugin (pytest hook function).""" | ||
ignore_specs: list[IgnoreSpec] = [] | ||
basetemp: Optional[str] = config.getoption("basetemp", None) | ||
if basetemp is not None: | ||
ignore_specs.append( | ||
DirectoryIgnoreSpec( | ||
directory=config.rootpath / basetemp, | ||
) | ||
) | ||
ignore_specs.append(RegexIgnoreSpec(regex=r".*/__pycache__.*")) | ||
config.stash[SNAPSHOT_KEY] = TreeSnapshot(root=config.rootpath) | ||
config.stash[COMPARATOR_KEY] = SnapshotComparator(ignore_specs=ignore_specs) | ||
|
||
|
||
@pytest.hookimpl(hookwrapper=True) # type: ignore[misc] | ||
def pytest_runtest_call(item: pytest.Item): # type: ignore[no-untyped-def] | ||
yield | ||
run_snapshot_comparison( | ||
test_name=item.name, | ||
config=item.config, | ||
mismatch_cb=raise_test_error_from_comparison, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
from pathlib import Path | ||
from typing import Callable, Iterable | ||
|
||
import pytest | ||
|
||
from pytest_litter.snapshots import SnapshotComparator, SnapshotComparison, TreeSnapshot | ||
|
||
SNAPSHOT_KEY = pytest.StashKey[TreeSnapshot]() | ||
COMPARATOR_KEY = pytest.StashKey[SnapshotComparator]() | ||
|
||
|
||
class ProblematicTestLitterError(Exception): | ||
"""Raised when a test causes littering, i.e., modifies file tree.""" | ||
|
||
|
||
def format_test_snapshot_mismatch_message( | ||
test_name: str, paths_added: Iterable[Path], paths_deleted: Iterable[Path] | ||
) -> str: | ||
def _iterable_to_human_readable(iterable: Iterable[Path]) -> str: | ||
return ", ".join(f"'{x}'" for x in iterable) | ||
|
||
message = f"The test '{test_name}'" | ||
if paths_added: | ||
message += f" added {_iterable_to_human_readable(paths_added)}" | ||
if paths_deleted: | ||
message += " and" | ||
if paths_deleted: | ||
message += f" deleted {_iterable_to_human_readable(paths_deleted)}" | ||
return message | ||
|
||
|
||
def raise_test_error_from_comparison( | ||
test_name: str, comparison: SnapshotComparison | ||
) -> None: | ||
"""Raise ProblematicTestLitterError for test_name based on comparison.""" | ||
raise ProblematicTestLitterError( | ||
format_test_snapshot_mismatch_message( | ||
test_name=test_name, | ||
paths_added=tuple(p.path for p in comparison.only_b), | ||
paths_deleted=tuple(p.path for p in comparison.only_a), | ||
) | ||
) | ||
|
||
|
||
def run_snapshot_comparison( | ||
test_name: str, | ||
config: pytest.Config, | ||
mismatch_cb: Callable[[str, SnapshotComparison], None], | ||
) -> None: | ||
"""Compare current and old snapshots and call mismatch_cb if there is a mismatch.""" | ||
original_snapshot: TreeSnapshot = config.stash[SNAPSHOT_KEY] | ||
new_snapshot: TreeSnapshot = TreeSnapshot(root=original_snapshot.root) | ||
config.stash[SNAPSHOT_KEY] = new_snapshot | ||
|
||
comparator: SnapshotComparator = config.stash[COMPARATOR_KEY] | ||
comparison: SnapshotComparison = comparator.compare(original_snapshot, new_snapshot) | ||
|
||
if not comparison.matches: | ||
mismatch_cb(test_name, comparison) |
Oops, something went wrong.