forked from ChelseaKR/tods-validate
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
145 lines (130 loc) · 5.46 KB
/
Copy pathpyproject.toml
File metadata and controls
145 lines (130 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# `examples/sample-feed` lives outside src/tods_validate, so hatchling's
# default wheel packaging (source-directory-only) does not pick it up.
# `tods-validate init` copies its rows into scaffolded packages (see
# src/tods_validate/init.py), so it must ship in the wheel too, not just the
# sdist -- otherwise `pip install tods-validate` (as opposed to a source
# checkout) silently gets a headers-only scaffold.
[tool.hatch.build.targets.wheel.force-include]
"examples/sample-feed" = "tods_validate/_sample_feed"
[project]
name = "tods-validate"
version = "0.6.0"
description = "Validator for Transit Operational Data Standard (TODS) feeds, formerly the Operational Data Standard (ODS)"
readme = "README.md"
license = "Apache-2.0"
license-files = ["LICENSE"]
requires-python = ">=3.11"
authors = [{ name = "Chelsea Kelly-Reif" }]
keywords = ["transit", "gtfs", "tods", "ods", "validation", "cal-itp"]
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Other Audience",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: GIS",
]
dependencies = ["click>=8.1"]
[project.urls]
Repository = "https://github.com/ChelseaKR/tods-validate"
"TODS specification" = "https://tods-transit.org/spec/"
[project.scripts]
tods-validate = "tods_validate.cli:main"
tods-validate-lsp = "tods_validate.lsp:main"
[project.optional-dependencies]
lsp = ["pygls>=2"]
# tods_validate.read.to_dataframe(); the rest of the read namespace has no
# dependency on pandas.
dataframe = ["pandas>=2"]
dev = [
"pytest>=8",
"pytest-cov>=5",
"mypy>=1.18",
"ruff>=0.15",
"pre-commit>=3.7",
"jsonschema>=4.21",
"pygls>=2",
"pip-audit>=2.7",
"hypothesis>=6.100",
]
# Advisory mutation testing (not part of the gate). Kept out of `dev` so the CI
# gate install stays lean; installed only where mutation runs. See
# docs/mutation-testing.md.
mutation = ["mutmut>=3.6"]
[tool.ruff]
line-length = 100
target-version = "py311"
src = ["src", "tests"]
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "SIM", "C4", "RET", "PT", "S", "C901"]
# S101 (assert-use) is allowed only where justified per call site with a coded
# `# noqa: S101` comment (see rules/references.py, rules/semantics.py: these
# asserts type-narrow `context.gtfs` immediately after the rule engine's
# `needs_gtfs` gate has already guaranteed it is not None -- not a stripped
# security control on untrusted input). `assert` in tests is fine; test files
# are excluded below.
[tool.ruff.lint.mccabe]
max-complexity = 10
[tool.ruff.lint.per-file-ignores]
# pytest's `assert` idiom is not the security-sensitive pattern S101 targets.
"tests/**" = ["S101"]
# Each `assert context.gtfs is not None` here type-narrows immediately after
# the rule engine's `needs_gtfs` gate (rules/__init__.py `_rule_status`) has
# already guaranteed gtfs is present for any rule that reaches this point --
# an internal invariant, not a security control over untrusted input that
# `python -O` could silently disable. Justified per CQ-04/CODE-QUALITY-STANDARD;
# tracked in docs/CONFORMANCE-GAPS.md#code-quality.
"src/tods_validate/rules/references.py" = ["S101"]
"src/tods_validate/rules/semantics.py" = ["S101"]
"src/tods_validate/rules/coverage.py" = ["S101"]
[tool.mypy]
strict = true
files = ["src"]
[[tool.mypy.overrides]]
# pandas is an optional extra (tods_validate.read.to_dataframe); its stubs are
# not part of the dev install, so only relax the missing-import check for it.
module = "pandas"
ignore_missing_imports = true
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-q --strict-markers --strict-config --import-mode=importlib"
pythonpath = ["tests"]
[tool.coverage.run]
source = ["tods_validate"]
branch = true
[tool.coverage.report]
fail_under = 90
[tool.mutmut]
# Advisory mutation testing, scoped to the validation rules engine (the checks
# that emit TODS-E/W/I findings). The whole package is copied so imports
# resolve, but only the rules modules are mutated. Not part of the CI gate; see
# docs/mutation-testing.md for the baseline and how to run it.
source_paths = ["src/tods_validate"]
# `only_mutate` is an allowlist, not a denylist: anything outside
# src/tods_validate/rules/ is already excluded, which is why the shared
# run-event parsing (src/tods_validate/run_events.py — _Event, parse_events,
# events_by_run, parse_time) lives there rather than in a rules/ module. It is
# exercised indirectly by nearly every semantic rule, so mutants there would
# get killed by whichever test runs first rather than pointing at a specific
# rule's coverage gap (see FIX-03 in docs/ideation/02-large-scale-fixes.md).
only_mutate = ["src/tods_validate/rules/*"]
# Drive mutants with the rule test modules: each one asserts rule behaviour
# against the fixture feeds (a passing + failing fixture per rule). Other
# suites (CLI, config, playground) make cwd/file assumptions that do not hold
# inside mutmut's mutants/ copy, so they are left out of the mutation run.
pytest_add_cli_args_test_selection = [
"tests/test_structure.py",
"tests/test_fields.py",
"tests/test_references.py",
"tests/test_semantics.py",
"tests/test_coverage_advisory.py",
"tests/test_conformance.py",
"tests/test_spec_examples.py",
"tests/test_valid_feed.py",
"tests/test_registry.py",
]