From 75dbae75fe0165e91e901a44eb38d36f067fafeb Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 1 Jun 2023 15:36:24 -0400 Subject: [PATCH] refactor: move functions to files that make more sense (#65) Signed-off-by: Henry Schreiner --- src/scikit_hep_repo_review/__init__.py | 2 +- src/scikit_hep_repo_review/checks/__init__.py | 34 ++++++- src/scikit_hep_repo_review/families.py | 17 +++- src/scikit_hep_repo_review/fixtures.py | 54 ++++++++++- src/scikit_hep_repo_review/ghpath.py | 6 ++ src/scikit_hep_repo_review/processor.py | 94 ++----------------- tests/test_checks.py | 3 +- tests/test_fixtures.py | 8 +- 8 files changed, 118 insertions(+), 100 deletions(-) diff --git a/src/scikit_hep_repo_review/__init__.py b/src/scikit_hep_repo_review/__init__.py index 8cf9a5e..8559946 100644 --- a/src/scikit_hep_repo_review/__init__.py +++ b/src/scikit_hep_repo_review/__init__.py @@ -9,4 +9,4 @@ __version__ = "0.5.1" -__all__ = ("__version__",) +__all__ = ["__version__"] diff --git a/src/scikit_hep_repo_review/checks/__init__.py b/src/scikit_hep_repo_review/checks/__init__.py index 8220c02..4f534c5 100644 --- a/src/scikit_hep_repo_review/checks/__init__.py +++ b/src/scikit_hep_repo_review/checks/__init__.py @@ -1,7 +1,12 @@ from __future__ import annotations -from collections.abc import Set -from typing import ClassVar, Protocol +import importlib.metadata +from collections.abc import Mapping, Set +from typing import Any, ClassVar, Protocol + +from ..fixtures import apply_fixtures + +__all__ = ["Check", "collect_checks", "is_allowed"] class Check(Protocol): @@ -10,3 +15,28 @@ class Check(Protocol): def check(self) -> bool | None: ... + + +def collect_checks(fixtures: Mapping[str, Any]) -> dict[str, Check]: + check_functions = ( + ep.load() + for ep in importlib.metadata.entry_points(group="scikit_hep_repo_review.checks") + ) + + return { + k: v + for func in check_functions + for k, v in apply_fixtures(fixtures, func).items() + } + + +def is_allowed(ignore_list: Set[str], name: str) -> bool: + """ + Skips the check if the name is in the ignore list or if the name without + the number is in the ignore list. + """ + if name in ignore_list: + return False + if name.rstrip("0123456789") in ignore_list: + return False + return True diff --git a/src/scikit_hep_repo_review/families.py b/src/scikit_hep_repo_review/families.py index a715b7f..b799a2b 100644 --- a/src/scikit_hep_repo_review/families.py +++ b/src/scikit_hep_repo_review/families.py @@ -1,19 +1,30 @@ from __future__ import annotations -from typing import TypedDict +import importlib.metadata +import typing -__all__ = ["Family", "get_familes"] +__all__ = ["Family", "collect_families", "get_familes"] def __dir__() -> list[str]: return __all__ -class Family(TypedDict, total=False): +class Family(typing.TypedDict, total=False): name: str # defaults to key order: int # defaults to 0 +def collect_families() -> dict[str, Family]: + return { + name: family + for ep in importlib.metadata.entry_points( + group="scikit_hep_repo_review.families" + ) + for name, family in ep.load()().items() + } + + def get_familes() -> dict[str, Family]: return { "general": Family( diff --git a/src/scikit_hep_repo_review/fixtures.py b/src/scikit_hep_repo_review/fixtures.py index 7cc1acc..51774fc 100644 --- a/src/scikit_hep_repo_review/fixtures.py +++ b/src/scikit_hep_repo_review/fixtures.py @@ -1,11 +1,22 @@ from __future__ import annotations +import graphlib +import importlib.metadata +import inspect +import typing +from collections.abc import Callable, Mapping from typing import Any from ._compat import tomllib from ._compat.importlib.resources.abc import Traversable -__all__ = ["pyproject", "package"] +__all__ = [ + "pyproject", + "package", + "compute_fixtures", + "apply_fixtures", + "collect_fixtures", +] def __dir__() -> list[str]: @@ -22,3 +33,44 @@ def pyproject(package: Traversable) -> dict[str, Any]: def package(package: Traversable) -> Traversable: return package + + +def compute_fixtures( + package: Traversable, fixtures: Mapping[str, Callable[..., Any]] +) -> dict[str, Any]: + results: dict[str, Any] = {"package": package} + graph = { + name: set() if name == "package" else inspect.signature(fix).parameters.keys() + for name, fix in fixtures.items() + } + ts = graphlib.TopologicalSorter(graph) + for fixture_name in ts.static_order(): + if fixture_name == "package": + continue + func = fixtures[fixture_name] + signature = inspect.signature(func) + kwargs = {name: results[name] for name in signature.parameters} + results[fixture_name] = fixtures[fixture_name](**kwargs) + return results + + +T = typing.TypeVar("T") + + +def apply_fixtures(computed_fixtures: Mapping[str, Any], func: Callable[..., T]) -> T: + signature = inspect.signature(func) + kwargs = { + name: value + for name, value in computed_fixtures.items() + if name in signature.parameters + } + return func(**kwargs) + + +def collect_fixtures() -> dict[str, Callable[[Traversable], Any]]: + return { + ep.name: ep.load() + for ep in importlib.metadata.entry_points( + group="scikit_hep_repo_review.fixtures" + ) + } diff --git a/src/scikit_hep_repo_review/ghpath.py b/src/scikit_hep_repo_review/ghpath.py index 0ecdaf6..3291d67 100644 --- a/src/scikit_hep_repo_review/ghpath.py +++ b/src/scikit_hep_repo_review/ghpath.py @@ -11,6 +11,12 @@ from ._compat.importlib.resources.abc import Traversable +__all__ = ["GHPath"] + + +def __dir__() -> list[str]: + return __all__ + @dataclasses.dataclass(frozen=True, kw_only=True) class GHPath(Traversable): diff --git a/src/scikit_hep_repo_review/processor.py b/src/scikit_hep_repo_review/processor.py index 33a0a70..275966e 100644 --- a/src/scikit_hep_repo_review/processor.py +++ b/src/scikit_hep_repo_review/processor.py @@ -1,20 +1,17 @@ from __future__ import annotations import dataclasses -import importlib.metadata -import inspect +import graphlib import textwrap import typing -from collections.abc import Callable, Mapping, Sequence -from graphlib import TopologicalSorter -from typing import Any, TypeVar +from collections.abc import Sequence -from markdown_it import MarkdownIt +import markdown_it from ._compat.importlib.resources.abc import Traversable -from .checks import Check -from .families import Family -from .fixtures import pyproject +from .checks import Check, collect_checks, is_allowed +from .families import Family, collect_families +from .fixtures import apply_fixtures, collect_fixtures, compute_fixtures, pyproject __all__ = ["Result", "ResultDict", "ProcessReturn", "process", "as_simple_dict"] @@ -23,9 +20,7 @@ def __dir__() -> list[str]: return __all__ -T = TypeVar("T") - -md = MarkdownIt() +md = markdown_it.MarkdownIt() # Helper to get the type in the JSON style returns @@ -54,79 +49,6 @@ class ProcessReturn(typing.NamedTuple): results: list[Result] -def is_allowed(ignore_list: set[str], name: str) -> bool: - """ - Skips the check if the name is in the ignore list or if the name without - the number is in the ignore list. - """ - if name in ignore_list: - return False - if name.rstrip("0123456789") in ignore_list: - return False - return True - - -def compute_fixtures( - package: Traversable, fixtures: Mapping[str, Callable[..., Any]] -) -> dict[str, Any]: - results: dict[str, Any] = {"package": package} - graph = { - name: set() if name == "package" else inspect.signature(fix).parameters.keys() - for name, fix in fixtures.items() - } - ts = TopologicalSorter(graph) - for fixture_name in ts.static_order(): - if fixture_name == "package": - continue - func = fixtures[fixture_name] - signature = inspect.signature(func) - kwargs = {name: results[name] for name in signature.parameters} - results[fixture_name] = fixtures[fixture_name](**kwargs) - return results - - -def apply_fixtures(computed_fixtures: Mapping[str, Any], func: Callable[..., T]) -> T: - signature = inspect.signature(func) - kwargs = { - name: value - for name, value in computed_fixtures.items() - if name in signature.parameters - } - return func(**kwargs) - - -def collect_fixtures() -> dict[str, Callable[[Traversable], Any]]: - return { - ep.name: ep.load() - for ep in importlib.metadata.entry_points( - group="scikit_hep_repo_review.fixtures" - ) - } - - -def collect_checks(fixtures: Mapping[str, Any]) -> dict[str, Check]: - check_functions = ( - ep.load() - for ep in importlib.metadata.entry_points(group="scikit_hep_repo_review.checks") - ) - - return { - k: v - for func in check_functions - for k, v in apply_fixtures(fixtures, func).items() - } - - -def collect_families() -> dict[str, Family]: - return { - name: family - for ep in importlib.metadata.entry_points( - group="scikit_hep_repo_review.families" - ) - for name, family in ep.load()().items() - } - - def process(package: Traversable, *, ignore: Sequence[str] = ()) -> ProcessReturn: """ Process the package and return a dictionary of results. @@ -167,7 +89,7 @@ def process(package: Traversable, *, ignore: Sequence[str] = ()) -> ProcessRetur completed: dict[str, bool | None] = {} # Run all the checks in topological order - ts = TopologicalSorter(graph) + ts = graphlib.TopologicalSorter(graph) for name in ts.static_order(): if all(completed.get(n, False) for n in graph[name]): completed[name] = apply_fixtures(fixtures, tasks[name].check) diff --git a/tests/test_checks.py b/tests/test_checks.py index 7157068..4c84d51 100644 --- a/tests/test_checks.py +++ b/tests/test_checks.py @@ -7,6 +7,7 @@ import scikit_hep_repo_review.processor from scikit_hep_repo_review._compat.importlib.resources.abc import Traversable +from scikit_hep_repo_review.checks import collect_checks class D100: @@ -51,7 +52,7 @@ def test_load_entry_point(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr( importlib.metadata, "entry_points", lambda group: [ep] # noqa: ARG005 ) - checks = scikit_hep_repo_review.processor.collect_checks({"package": Path(".")}) + checks = collect_checks({"package": Path(".")}) assert len(checks) == 2 assert "D100" in checks diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index de94c74..9344274 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -6,12 +6,8 @@ import pytest from scikit_hep_repo_review._compat.importlib.resources.abc import Traversable -from scikit_hep_repo_review.fixtures import package -from scikit_hep_repo_review.processor import ( - apply_fixtures, - collect_checks, - compute_fixtures, -) +from scikit_hep_repo_review.checks import collect_checks +from scikit_hep_repo_review.fixtures import apply_fixtures, compute_fixtures, package class D100: