diff --git a/CLAUDE.md b/CLAUDE.md index c911bbb..d9983aa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,4 +91,4 @@ When writing new tests: - Use `pytest.mark.xfail(strict=True)` for known failures (strict=True means unexpected passes also fail) - Hand-written per-issue regression tests go in `tests/nodenorm/by_issue/` - GitHub-issue-driven tests are picked up automatically by `tests/github_issues/test_github_issues.py` via `GitHubIssuesTestCases` -- Import shared classes from `src.babel_validation.*` (e.g. `from src.babel_validation.services.nodenorm import CachedNodeNorm`) +- Import shared classes from `babel_validation.*` (e.g. `from babel_validation.services.nodenorm import CachedNodeNorm`) diff --git a/pyproject.toml b/pyproject.toml index 0d8c88a..38c0eb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,37 +5,48 @@ description = "A set of programs for validating the output of the Babel pipeline license = "MIT" readme = "README.md" requires-python = ">=3.11" +# Runtime dependencies needed to USE the library (fetch GitHub-issue tests, +# parse them, and run them against NodeNorm/NameRes). PyGitHub is a core +# dependency because the test definitions live in GitHub issues, so every +# consumer needs it to obtain them. dependencies = [ - "black>=25.9.0", "click>=8.1", "pyyaml>=6.0", "requests>=2.32.5", "tqdm>=4.67.1", "filelock", - "deepdiff>=8.6.1", "python-dotenv>=0.9.9", - "openapi-spec-validator>=0.7.2", "pygithub>=2.8.1", +] + +[project.urls] +Repository = "https://github.com/TranslatorSRI/babel-validation" + +# Tooling for developing babel-validation itself (its pytest suite + formatter). +# A uv dependency-group is auto-installed by `uv run` / `uv sync` for local work +# and CI, but — unlike an extra — is NOT shipped to library consumers. +[dependency-groups] +dev = [ + "black>=25.9.0", + "deepdiff>=8.6.1", + "openapi-spec-validator>=0.7.2", "pytest>=9.0.2", "pytest-timeout>=2.4.0", "pytest-xdist[psutil]", "pytest-subtests", ] -[project.urls] -Repository = "https://github.com/TranslatorSRI/babel-validation" - [project.scripts] -csv-to-babeltests = "src.babel_validation.tools.csv_to_babeltests:main" +csv-to-babeltests = "babel_validation.tools.csv_to_babeltests:main" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -# Package the entire `src/` directory so existing imports -# (`from src.babel_validation.X import Y`) continue to work after install. -packages = ["src"] +# src-layout: ship `src/babel_validation` as the top-level import package +# `babel_validation`, so consumers `import babel_validation` (not `src.…`). +packages = ["src/babel_validation"] [tool.pytest.ini_options] # Without testpaths, a bare `pytest` would also scan the website directories diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/babel_validation/assertions/README.md b/src/babel_validation/assertions/README.md index 9cc4ef7..9023632 100644 --- a/src/babel_validation/assertions/README.md +++ b/src/babel_validation/assertions/README.md @@ -1,5 +1,5 @@ + Regenerate with: uv run python -m babel_validation.assertions.gen_docs --> # BabelTest Assertion Types @@ -240,4 +240,4 @@ babel_tests: 3. Import it in `__init__.py` and add an instance to `ASSERTION_HANDLERS`. -4. Run `uv run python -m src.babel_validation.assertions.gen_docs` to regenerate `README.md`. +4. Run `uv run python -m babel_validation.assertions.gen_docs` to regenerate `README.md`. diff --git a/src/babel_validation/assertions/__init__.py b/src/babel_validation/assertions/__init__.py index 4ac70ed..0dde257 100644 --- a/src/babel_validation/assertions/__init__.py +++ b/src/babel_validation/assertions/__init__.py @@ -16,13 +16,13 @@ 3. Set PARAMETERS, WIKI_EXAMPLES, and YAML_PARAMS class attributes for documentation. 4. Override test_param_set(). 5. Import it here and add an instance to ASSERTION_HANDLERS. -6. Run `uv run python -m src.babel_validation.assertions.gen_docs` to regenerate README.md. +6. Run `uv run python -m babel_validation.assertions.gen_docs` to regenerate README.md. """ import re from typing import Iterator -from src.babel_validation.core.testrow import TestResult, TestStatus +from babel_validation.core.testrow import TestResult, TestStatus class AssertionHandler: @@ -166,12 +166,12 @@ def test_param_set(self, params: list[str], nodenorm, nameres, # Registry — import submodules after base classes are defined to avoid circular imports. -from src.babel_validation.assertions.nodenorm import ( # noqa: E402 +from babel_validation.assertions.nodenorm import ( # noqa: E402 ResolvesHandler, DoesNotResolveHandler, ResolvesWithHandler, ResolvesWithTypeHandler, DoesNotResolveWithHandler, HasLabelHandler, ) -from src.babel_validation.assertions.nameres import SearchByNameHandler # noqa: E402 -from src.babel_validation.assertions.common import NeededHandler # noqa: E402 +from babel_validation.assertions.nameres import SearchByNameHandler # noqa: E402 +from babel_validation.assertions.common import NeededHandler # noqa: E402 ASSERTION_HANDLERS: dict[str, AssertionHandler] = { h.NAME: h for h in [ diff --git a/src/babel_validation/assertions/common.py b/src/babel_validation/assertions/common.py index 68c5db2..c38296d 100644 --- a/src/babel_validation/assertions/common.py +++ b/src/babel_validation/assertions/common.py @@ -1,4 +1,4 @@ -from src.babel_validation.assertions import AssertionHandler +from babel_validation.assertions import AssertionHandler class NeededHandler(AssertionHandler): diff --git a/src/babel_validation/assertions/gen_docs.py b/src/babel_validation/assertions/gen_docs.py index c5a77a4..b40dc49 100644 --- a/src/babel_validation/assertions/gen_docs.py +++ b/src/babel_validation/assertions/gen_docs.py @@ -1,12 +1,12 @@ """Generate assertions/README.md from handler class attributes. Run: - uv run python -m src.babel_validation.assertions.gen_docs + uv run python -m babel_validation.assertions.gen_docs """ from pathlib import Path -from src.babel_validation.assertions import ( +from babel_validation.assertions import ( ASSERTION_HANDLERS, AssertionHandler, NodeNormTest, NameResTest, ) @@ -14,7 +14,7 @@ INTRO = """\ + Regenerate with: uv run python -m babel_validation.assertions.gen_docs --> # BabelTest Assertion Types @@ -69,7 +69,7 @@ 3. Import it in `__init__.py` and add an instance to `ASSERTION_HANDLERS`. -4. Run `uv run python -m src.babel_validation.assertions.gen_docs` to regenerate `README.md`. +4. Run `uv run python -m babel_validation.assertions.gen_docs` to regenerate `README.md`. """ _GROUP_HEADERS: dict[str, str] = { diff --git a/src/babel_validation/assertions/nameres.py b/src/babel_validation/assertions/nameres.py index da4cb39..9502a26 100644 --- a/src/babel_validation/assertions/nameres.py +++ b/src/babel_validation/assertions/nameres.py @@ -2,10 +2,10 @@ import logging from typing import Iterator -from src.babel_validation.assertions import NameResTest -from src.babel_validation.core.testrow import TestResult -from src.babel_validation.services.nameres import CachedNameRes -from src.babel_validation.services.nodenorm import CachedNodeNorm +from babel_validation.assertions import NameResTest +from babel_validation.core.testrow import TestResult +from babel_validation.services.nameres import CachedNameRes +from babel_validation.services.nodenorm import CachedNodeNorm class SearchByNameHandler(NameResTest): diff --git a/src/babel_validation/assertions/nodenorm.py b/src/babel_validation/assertions/nodenorm.py index bcd010a..3d0d558 100644 --- a/src/babel_validation/assertions/nodenorm.py +++ b/src/babel_validation/assertions/nodenorm.py @@ -1,8 +1,8 @@ from typing import Iterator -from src.babel_validation.assertions import NodeNormTest -from src.babel_validation.core.testrow import TestResult -from src.babel_validation.services.nodenorm import CachedNodeNorm +from babel_validation.assertions import NodeNormTest +from babel_validation.core.testrow import TestResult +from babel_validation.services.nodenorm import CachedNodeNorm class ResolvesHandler(NodeNormTest): diff --git a/src/babel_validation/sources/github/github_issues_test_cases.py b/src/babel_validation/sources/github/github_issues_test_cases.py index fa33dab..51e0c82 100644 --- a/src/babel_validation/sources/github/github_issues_test_cases.py +++ b/src/babel_validation/sources/github/github_issues_test_cases.py @@ -33,10 +33,10 @@ from github import Github, Auth, Issue from tqdm import tqdm -from src.babel_validation.assertions import ASSERTION_HANDLERS -from src.babel_validation.core.testrow import TestResult -from src.babel_validation.services.nameres import CachedNameRes -from src.babel_validation.services.nodenorm import CachedNodeNorm +from babel_validation.assertions import ASSERTION_HANDLERS +from babel_validation.core.testrow import TestResult +from babel_validation.services.nameres import CachedNameRes +from babel_validation.services.nodenorm import CachedNodeNorm _logger = logging.getLogger(__name__) diff --git a/src/babel_validation/sources/google_sheets/google_sheet_test_cases.py b/src/babel_validation/sources/google_sheets/google_sheet_test_cases.py index 935b019..dc19185 100644 --- a/src/babel_validation/sources/google_sheets/google_sheet_test_cases.py +++ b/src/babel_validation/sources/google_sheets/google_sheet_test_cases.py @@ -15,7 +15,7 @@ from _pytest.mark import ParameterSet from filelock import FileLock -from src.babel_validation.core.testrow import TestRow +from babel_validation.core.testrow import TestRow class GoogleSheetTestCases: diff --git a/src/babel_validation/tools/csv_to_babeltests.py b/src/babel_validation/tools/csv_to_babeltests.py index 565f23f..cf6c2df 100644 --- a/src/babel_validation/tools/csv_to_babeltests.py +++ b/src/babel_validation/tools/csv_to_babeltests.py @@ -28,9 +28,9 @@ import click import yaml -from src.babel_validation.assertions import ASSERTION_HANDLERS -from src.babel_validation.core.testrow import TestStatus -from src.babel_validation.services.nodenorm import CachedNodeNorm +from babel_validation.assertions import ASSERTION_HANDLERS +from babel_validation.core.testrow import TestStatus +from babel_validation.services.nodenorm import CachedNodeNorm # --- YAML emission --------------------------------------------------------- diff --git a/tests/github_issues/conftest.py b/tests/github_issues/conftest.py index ec1bdb2..3379cac 100644 --- a/tests/github_issues/conftest.py +++ b/tests/github_issues/conftest.py @@ -9,7 +9,7 @@ from filelock import FileLock from github import GithubException, Issue -from src.babel_validation.sources.github.github_issues_test_cases import GitHubIssuesTestCases +from babel_validation.sources.github.github_issues_test_cases import GitHubIssuesTestCases from tests._pytest_helpers import deselected_by_markexpr _github_token = None diff --git a/tests/github_issues/test_github_issues.py b/tests/github_issues/test_github_issues.py index 32aa579..4dd7e81 100644 --- a/tests/github_issues/test_github_issues.py +++ b/tests/github_issues/test_github_issues.py @@ -3,10 +3,10 @@ import pytest -from src.babel_validation.assertions import ASSERTION_HANDLERS -from src.babel_validation.services.nameres import CachedNameRes -from src.babel_validation.services.nodenorm import CachedNodeNorm -from src.babel_validation.core.testrow import TestResult, TestStatus +from babel_validation.assertions import ASSERTION_HANDLERS +from babel_validation.services.nameres import CachedNameRes +from babel_validation.services.nodenorm import CachedNodeNorm +from babel_validation.core.testrow import TestResult, TestStatus def test_github_issue(request, target_info, github_issue_id, github_issue, github_issues_test_cases, subtests): diff --git a/tests/github_issues/test_system.py b/tests/github_issues/test_system.py index dafc93e..7705d58 100644 --- a/tests/github_issues/test_system.py +++ b/tests/github_issues/test_system.py @@ -4,8 +4,8 @@ import pytest import yaml -from src.babel_validation.core.testrow import TestStatus -from src.babel_validation.sources.github.github_issues_test_cases import GitHubIssuesTestCases +from babel_validation.core.testrow import TestStatus +from babel_validation.sources.github.github_issues_test_cases import GitHubIssuesTestCases pytestmark = pytest.mark.unit diff --git a/tests/nameres/test_blocklist.py b/tests/nameres/test_blocklist.py index c1d803d..380a7ee 100644 --- a/tests/nameres/test_blocklist.py +++ b/tests/nameres/test_blocklist.py @@ -3,7 +3,7 @@ import requests import pytest -from src.babel_validation.sources.google_sheets.blocklist import load_blocklist_from_gsheet +from babel_validation.sources.google_sheets.blocklist import load_blocklist_from_gsheet from tests._pytest_helpers import deselected_by_markexpr # The blocklist Google Sheet is downloaded lazily in pytest_generate_tests so diff --git a/tests/nameres/test_nameres_from_gsheet.py b/tests/nameres/test_nameres_from_gsheet.py index 1b9403f..c4b4be5 100644 --- a/tests/nameres/test_nameres_from_gsheet.py +++ b/tests/nameres/test_nameres_from_gsheet.py @@ -1,7 +1,7 @@ import urllib.parse import requests import pytest -from src.babel_validation.sources.google_sheets.google_sheet_test_cases import GoogleSheetTestCases +from babel_validation.sources.google_sheets.google_sheet_test_cases import GoogleSheetTestCases from tests._pytest_helpers import deselected_by_markexpr # Configuration options diff --git a/tests/nodenorm/test_nodenorm_from_gsheet.py b/tests/nodenorm/test_nodenorm_from_gsheet.py index 057e8a7..8af066e 100644 --- a/tests/nodenorm/test_nodenorm_from_gsheet.py +++ b/tests/nodenorm/test_nodenorm_from_gsheet.py @@ -1,7 +1,7 @@ import urllib.parse import requests import pytest -from src.babel_validation.sources.google_sheets.google_sheet_test_cases import GoogleSheetTestCases +from babel_validation.sources.google_sheets.google_sheet_test_cases import GoogleSheetTestCases from tests._pytest_helpers import deselected_by_markexpr # The Google Sheet is downloaded lazily in pytest_generate_tests so that runs diff --git a/tests/test_environment/test_assertions_docs.py b/tests/test_environment/test_assertions_docs.py index 03e5b90..acd97d5 100644 --- a/tests/test_environment/test_assertions_docs.py +++ b/tests/test_environment/test_assertions_docs.py @@ -1,6 +1,6 @@ import pytest -from src.babel_validation.assertions.gen_docs import generate_readme, README_PATH +from babel_validation.assertions.gen_docs import generate_readme, README_PATH @pytest.mark.unit @@ -10,5 +10,5 @@ def test_assertions_readme_is_up_to_date(): assert actual == expected, ( "assertions/README.md is out of date.\n" "Regenerate it with:\n" - " uv run python -m src.babel_validation.assertions.gen_docs" + " uv run python -m babel_validation.assertions.gen_docs" ) diff --git a/tests/test_environment/test_env.py b/tests/test_environment/test_env.py index 5302198..9db6d50 100644 --- a/tests/test_environment/test_env.py +++ b/tests/test_environment/test_env.py @@ -1,7 +1,7 @@ # Test whether the test environment is functional. import json -from src.babel_validation.sources.google_sheets.google_sheet_test_cases import GoogleSheetTestCases +from babel_validation.sources.google_sheets.google_sheet_test_cases import GoogleSheetTestCases def test_google_sheet_has_test_cases(): diff --git a/tests/tools/test_csv_to_babeltests.py b/tests/tools/test_csv_to_babeltests.py index 32aad26..e2b7fc5 100644 --- a/tests/tools/test_csv_to_babeltests.py +++ b/tests/tools/test_csv_to_babeltests.py @@ -11,7 +11,7 @@ import pytest import yaml -from src.babel_validation.tools.csv_to_babeltests import ( +from babel_validation.tools.csv_to_babeltests import ( BlockEntry, build_blocks, emit_yaml, @@ -213,7 +213,7 @@ def test_emit_yaml_single_element_param_sets_emit_as_bare_strings(): def test_emitted_assertion_names_match_handler_registry(): """The names build_blocks emits must each resolve in ASSERTION_HANDLERS.""" - from src.babel_validation.assertions import ASSERTION_HANDLERS + from babel_validation.assertions import ASSERTION_HANDLERS blocks, _ = build_blocks( ROWS, curie_column="OutputID", label_column="Label", diff --git a/uv.lock b/uv.lock index c428e43..3e90657 100644 --- a/uv.lock +++ b/uv.lock @@ -25,40 +25,48 @@ name = "babel-validation" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "black" }, { name = "click" }, - { name = "deepdiff" }, { name = "filelock" }, - { name = "openapi-spec-validator" }, { name = "pygithub" }, - { name = "pytest" }, - { name = "pytest-subtests" }, - { name = "pytest-timeout" }, - { name = "pytest-xdist", extra = ["psutil"] }, { name = "python-dotenv" }, { name = "pyyaml" }, { name = "requests" }, { name = "tqdm" }, ] +[package.dev-dependencies] +dev = [ + { name = "black" }, + { name = "deepdiff" }, + { name = "openapi-spec-validator" }, + { name = "pytest" }, + { name = "pytest-subtests" }, + { name = "pytest-timeout" }, + { name = "pytest-xdist", extra = ["psutil"] }, +] + [package.metadata] requires-dist = [ - { name = "black", specifier = ">=25.9.0" }, { name = "click", specifier = ">=8.1" }, - { name = "deepdiff", specifier = ">=8.6.1" }, { name = "filelock" }, - { name = "openapi-spec-validator", specifier = ">=0.7.2" }, { name = "pygithub", specifier = ">=2.8.1" }, - { name = "pytest", specifier = ">=9.0.2" }, - { name = "pytest-subtests" }, - { name = "pytest-timeout", specifier = ">=2.4.0" }, - { name = "pytest-xdist", extras = ["psutil"] }, { name = "python-dotenv", specifier = ">=0.9.9" }, { name = "pyyaml", specifier = ">=6.0" }, { name = "requests", specifier = ">=2.32.5" }, { name = "tqdm", specifier = ">=4.67.1" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "black", specifier = ">=25.9.0" }, + { name = "deepdiff", specifier = ">=8.6.1" }, + { name = "openapi-spec-validator", specifier = ">=0.7.2" }, + { name = "pytest", specifier = ">=9.0.2" }, + { name = "pytest-subtests" }, + { name = "pytest-timeout", specifier = ">=2.4.0" }, + { name = "pytest-xdist", extras = ["psutil"] }, +] + [[package]] name = "black" version = "26.1.0"