diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1e876a2..0bdc2c4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -29,7 +29,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -60,7 +60,7 @@ jobs: cd example echo "os: $RUNNER_OS" hatch build - hatch run cov + hatch run test Build: needs: Validate diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 376803b..7d8bd95 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -53,4 +53,4 @@ jobs: cd example echo "os: $RUNNER_OS" hatch build - hatch run cov + hatch run test diff --git a/COVERAGE.md b/COVERAGE.md index ad0de4b..42492d6 100644 --- a/COVERAGE.md +++ b/COVERAGE.md @@ -4,7 +4,7 @@ | src/hatch\_cython/config.py | 276 | 19 | 120 | 12 | 92% | | src/hatch\_cython/devel.py | 5 | 0 | 0 | 0 | 100% | | src/hatch\_cython/hooks.py | 5 | 1 | 2 | 0 | 86% | -| src/hatch\_cython/plugin.py | 191 | 10 | 100 | 9 | 93% | -| src/hatch\_cython/types.py | 15 | 4 | 2 | 1 | 71% | -| src/hatch\_cython/utils.py | 11 | 0 | 2 | 0 | 100% | -| **TOTAL** | **505** | **34** | **226** | **22** | **92%** | +| src/hatch\_cython/plugin.py | 191 | 9 | 100 | 8 | 94% | +| src/hatch\_cython/types.py | 19 | 5 | 2 | 1 | 71% | +| src/hatch\_cython/utils.py | 10 | 0 | 2 | 0 | 100% | +| **TOTAL** | **508** | **34** | **226** | **21** | **92%** | diff --git a/example/hatch.toml b/example/hatch.toml index 1d66f44..ce777c2 100644 --- a/example/hatch.toml +++ b/example/hatch.toml @@ -85,7 +85,10 @@ dependencies = [ [envs.default.scripts] install = "python bootstrap.py" -test = "pytest {args:tests}" +test = [ + "install", + "pytest {args:tests}" +] test-cov = "coverage run -m pytest {args:tests}" cov-report = [ "- coverage combine", diff --git a/example/src/example_lib/normal.py b/example/src/example_lib/normal.py new file mode 100644 index 0000000..16ac566 --- /dev/null +++ b/example/src/example_lib/normal.py @@ -0,0 +1,2 @@ +def normal_func(a: int, b: int): + return a + b diff --git a/example/tests/test_normal.py b/example/tests/test_normal.py new file mode 100644 index 0000000..e3f58eb --- /dev/null +++ b/example/tests/test_normal.py @@ -0,0 +1,5 @@ +from example_lib.normal import normal_func + + +def test_normal(): + assert normal_func(1, 2) == 3 diff --git a/src/hatch_cython/__about__.py b/src/hatch_cython/__about__.py index bacb2fb..ce9bbc3 100644 --- a/src/hatch_cython/__about__.py +++ b/src/hatch_cython/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present joshua-auchincloss # # SPDX-License-Identifier: MIT -__version__ = "0.2.1" +__version__ = "0.2.2" diff --git a/src/hatch_cython/config.py b/src/hatch_cython/config.py index e8252ee..1f7dcde 100644 --- a/src/hatch_cython/config.py +++ b/src/hatch_cython/config.py @@ -1,5 +1,5 @@ import platform -from collections.abc import Callable, Generator, Hashable +from collections.abc import Generator, Hashable from dataclasses import asdict, dataclass, field from importlib import import_module from os import environ, path @@ -9,7 +9,7 @@ from hatchling.builders.hooks.plugin.interface import BuildHookInterface from packaging.markers import Marker -from hatch_cython.types import CorePlatforms, ListStr, list_t, union_t +from hatch_cython.types import CorePlatforms, ListStr, callable_t, dict_t, list_t, union_t from hatch_cython.utils import memo EXIST_TRIM = 2 @@ -83,7 +83,7 @@ class PlatformBase(Hashable): arch: union_t[ListStr, str] = "*" depends_path: bool = False marker: str = None - apply_to_marker: Callable[[], bool] = None + apply_to_marker: callable_t[[], bool] = None def __post_init__(self): self.do_rewrite("platforms") @@ -182,10 +182,10 @@ class EnvFlags: AR: PlatformArgs = None ARFLAGS: PlatformArgs = None - custom: dict[str, PlatformArgs] = field(default_factory=dict) + custom: dict_t[str, PlatformArgs] = field(default_factory=dict) env: dict = field(default_factory=environ.copy) - __known__: ClassVar[dict[str, EnvFlag]] = {e.env: e for e in __flags__} + __known__: ClassVar[dict_t[str, EnvFlag]] = {e.env: e for e in __flags__} def __post_init__(self): for flag in __flags__: @@ -193,7 +193,7 @@ def __post_init__(self): for flag in self.custom.values(): self.merge_to_env(flag, self.get_from_custom) - def merge_to_env(self, flag: EnvFlag, get: Callable[[str], EnvFlag]): + def merge_to_env(self, flag: EnvFlag, get: callable_t[[str], EnvFlag]): var = environ.get(flag.env) override: EnvFlag = get(flag.env) if override and flag.merges: @@ -242,7 +242,7 @@ def parse_to_plat(cls, arg, args: union_t[list, dict], key: union_t[int, str], r def parse_platform_args( kwargs: dict, name: str, - default: Callable, + default: callable_t[[], list_t[PlatformArgs]], ) -> list_t[union_t[str, PlatformArgs]]: try: args = [*default(), *kwargs.pop(name)] @@ -369,8 +369,8 @@ def _post_import_attr( im: Autoimport, att: str, mod: any, - extend: Callable[[ListStr], None], - append: Callable[[str], None], + extend: callable_t[[ListStr], None], + append: callable_t[[str], None], ): attr = getattr(im, att) if attr is not None: diff --git a/src/hatch_cython/plugin.py b/src/hatch_cython/plugin.py index 58c4a0a..7068e3d 100644 --- a/src/hatch_cython/plugin.py +++ b/src/hatch_cython/plugin.py @@ -72,6 +72,7 @@ class CythonBuildHook(BuildHookInterface): PLUGIN_NAME = "cython" precompiled_extension: ClassVar[list] = [ + ".py", ".pyx", ".pxd", ] diff --git a/src/hatch_cython/types.py b/src/hatch_cython/types.py index 075258e..62ed357 100644 --- a/src/hatch_cython/types.py +++ b/src/hatch_cython/types.py @@ -5,15 +5,18 @@ vmaj = (version_info[0], version_info[1]) if vmaj >= (3, 10): + from collections.abc import Callable from typing import ParamSpec + dict_t = dict list_t = list ListStr = list[str] else: - from typing import List # noqa: UP035 + from typing import Callable, Dict, List # noqa: UP035 from typing_extensions import ParamSpec + dict_t = Dict # noqa: UP006 list_t = List # noqa: UP006 ListStr = List[str] # noqa: UP006 @@ -24,3 +27,5 @@ "linux", "windows", ] + +callable_t = Callable diff --git a/src/hatch_cython/utils.py b/src/hatch_cython/utils.py index 3a26c1b..b833f70 100644 --- a/src/hatch_cython/utils.py +++ b/src/hatch_cython/utils.py @@ -1,9 +1,7 @@ -from collections.abc import Callable +from hatch_cython.types import P, T, callable_t -from hatch_cython.types import P, T - -def memo(func: Callable[P, T]) -> T: +def memo(func: callable_t[P, T]) -> T: value = None ran = False diff --git a/taskfile.yaml b/taskfile.yaml index 45d85d6..4e497e4 100644 --- a/taskfile.yaml +++ b/taskfile.yaml @@ -9,7 +9,7 @@ tasks: cmds: - hatch build --clean # - pip install dist/example-0.0.1-*.whl - - hatch run cov + - hatch run test clean: cmds: @@ -32,6 +32,7 @@ tasks: - black . - isort . - ruff src --fix + - ruff . --fix missed: cmds: diff --git a/tests/test_plugin.py b/tests/test_plugin.py index a9e163e..7f28759 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -59,37 +59,72 @@ def test_build_hook(new_proj): proj = "./src/example_lib" assert hook.project_dir == proj - assert hook.precompiled_globs == [ - "./src/example_lib/*.pyx", - "./src/example_lib/**/*.pyx", - "./src/example_lib/*.pxd", - "./src/example_lib/**/*.pxd", - ] - - with override_dir(new_proj): - assert hook.normalized_included_files == [ - "./src/example_lib/test.pyx", - "./src/example_lib/mod_a/adds.pyx", - "./src/example_lib/mod_a/some_defn.pxd", + assert sorted(hook.precompiled_globs) == sorted( + [ + "./src/example_lib/*.py", + "./src/example_lib/**/*.py", + "./src/example_lib/*.pyx", + "./src/example_lib/**/*.pyx", + "./src/example_lib/*.pxd", + "./src/example_lib/**/*.pxd", ] + ) - assert hook.grouped_included_files == [ + with override_dir(new_proj): + assert sorted(hook.normalized_included_files) == sorted( + [ + "./src/example_lib/normal.py", + "./src/example_lib/__init__.py", + "./src/example_lib/__about__.py", + "./src/example_lib/mod_a/__init__.py", + "./src/example_lib/mod_a/some_defn.py", + "./src/example_lib/test.pyx", + "./src/example_lib/mod_a/adds.pyx", + "./src/example_lib/mod_a/some_defn.pxd", + ] + ) + + assert sorted([sorted(ls) for ls in hook.grouped_included_files]) == sorted([sorted(ls) for ls in [ + ["./src/example_lib/normal.py"], + ["./src/example_lib/__init__.py"], + ["./src/example_lib/__about__.py"], + ["./src/example_lib/mod_a/__init__.py"], + ["./src/example_lib/mod_a/some_defn.py", "./src/example_lib/mod_a/some_defn.py"], ["./src/example_lib/test.pyx"], ["./src/example_lib/mod_a/adds.pyx"], - ["./src/example_lib/mod_a/some_defn.py"], - ] - - rf = [ - "./src/example_lib/test.*.pyx", - "./src/example_lib/test.*.pxd", - "./src/example_lib/mod_a/adds.*.pyx", - "./src/example_lib/mod_a/adds.*.pxd", - "./src/example_lib/mod_a/some_defn.*.pyx", - "./src/example_lib/mod_a/some_defn.*.pxd", - ] - assert hook.normalized_artifact_globs == rf - - assert hook.artifact_patterns == [f"/{f}" for f in rf] + ]]) + + rf = sorted( + [ + "./src/example_lib/normal.*.py", + "./src/example_lib/normal.*.pyx", + "./src/example_lib/normal.*.pxd", + "./src/example_lib/__init__.*.py", + "./src/example_lib/__init__.*.pyx", + "./src/example_lib/__init__.*.pxd", + "./src/example_lib/__about__.*.py", + "./src/example_lib/__about__.*.pyx", + "./src/example_lib/__about__.*.pxd", + "./src/example_lib/mod_a/__init__.*.py", + "./src/example_lib/mod_a/__init__.*.pyx", + "./src/example_lib/mod_a/__init__.*.pxd", + "./src/example_lib/mod_a/some_defn.*.py", + "./src/example_lib/mod_a/some_defn.*.pyx", + "./src/example_lib/mod_a/some_defn.*.pxd", + "./src/example_lib/test.*.py", + "./src/example_lib/test.*.pyx", + "./src/example_lib/test.*.pxd", + "./src/example_lib/mod_a/adds.*.py", + "./src/example_lib/mod_a/adds.*.pyx", + "./src/example_lib/mod_a/adds.*.pxd", + "./src/example_lib/mod_a/some_defn.*.py", + "./src/example_lib/mod_a/some_defn.*.pyx", + "./src/example_lib/mod_a/some_defn.*.pxd", + ] + ) + assert sorted(hook.normalized_artifact_globs) == rf + + assert sorted(hook.artifact_patterns) == [f"/{f}" for f in rf] hook.clean([]) @@ -101,5 +136,5 @@ def test_build_hook(new_proj): assert build_data.get("infer_tag") assert not build_data.get("pure_python") - assert build_data.get("artifacts") == [f"/{f}" for f in rf] - assert len(build_data.get("force_include")) == 3 + assert sorted(build_data.get("artifacts")) == sorted([f"/{f}" for f in rf]) + assert len(build_data.get("force_include")) == 7