Skip to content

Commit b9a60b2

Browse files
Split usethis._tool.impl into impl/spec and impl/base submodules (#1373)
* Initial plan * Split usethis._tool.impl into impl/spec and impl/base submodules Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com> * Fix: move test_deps to base classes, fix test_pytest.py module references Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com> * Move impl test files to tests/usethis/_tool/impl/base/ to match src structure Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com> Co-authored-by: Nathan McDougall <nathan.j.mcdougall@gmail.com>
1 parent ae6381e commit b9a60b2

48 files changed

Lines changed: 712 additions & 598 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.importlinter

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,29 @@ name = usethis._tool.impl
6868
type = layers
6969
containers =
7070
usethis._tool.impl
71+
layers =
72+
base
73+
spec
74+
exhaustive = true
75+
76+
[importlinter:contract:tool_impl_base]
77+
name = usethis._tool.impl.base
78+
type = layers
79+
containers =
80+
usethis._tool.impl.base
81+
layers =
82+
pyproject_toml
83+
codespell | deptry | import_linter | mkdocs | pyproject_fmt | requirements_txt
84+
ruff
85+
pytest : coverage_py
86+
pre_commit
87+
exhaustive = true
88+
89+
[importlinter:contract:tool_impl_spec]
90+
name = usethis._tool.impl.spec
91+
type = layers
92+
containers =
93+
usethis._tool.impl.spec
7194
layers =
7295
pyproject_toml
7396
codespell | deptry | import_linter | mkdocs | pyproject_fmt | requirements_txt

src/usethis/_core/ci.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
remove_bitbucket_pipelines_config,
77
)
88
from usethis._tool.all_ import ALL_TOOLS
9-
from usethis._tool.impl.codespell import CodespellTool
10-
from usethis._tool.impl.deptry import DeptryTool
11-
from usethis._tool.impl.import_linter import ImportLinterTool
12-
from usethis._tool.impl.pre_commit import PreCommitTool
13-
from usethis._tool.impl.pyproject_fmt import PyprojectFmtTool
14-
from usethis._tool.impl.pytest import PytestTool
15-
from usethis._tool.impl.ruff import RuffTool
9+
from usethis._tool.impl.base.codespell import CodespellTool
10+
from usethis._tool.impl.base.deptry import DeptryTool
11+
from usethis._tool.impl.base.import_linter import ImportLinterTool
12+
from usethis._tool.impl.base.pre_commit import PreCommitTool
13+
from usethis._tool.impl.base.pyproject_fmt import PyprojectFmtTool
14+
from usethis._tool.impl.base.pytest import PytestTool
15+
from usethis._tool.impl.base.ruff import RuffTool
1616

1717
# Ordered list of QA tools that should run in CI (matches canonical step order)
1818
# These tools run via pre-commit if available, otherwise directly in CI

src/usethis/_core/docstyle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import TYPE_CHECKING
44

55
from usethis._core.tool import use_ruff
6-
from usethis._tool.impl.ruff import RuffTool
6+
from usethis._tool.impl.base.ruff import RuffTool
77

88
if TYPE_CHECKING:
99
from usethis._types.docstyle import DocStyleEnum

src/usethis/_core/list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from usethis._detect.ci.bitbucket import is_bitbucket_used
99
from usethis._detect.readme import is_readme_used
1010
from usethis._tool.all_ import ALL_TOOLS
11-
from usethis._tool.impl.ruff import RuffTool
11+
from usethis._tool.impl.base.ruff import RuffTool
1212

1313

1414
class UsageRow(BaseModel):

src/usethis/_core/rule.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from pydantic import BaseModel
22

33
from usethis._core.tool import use_deptry, use_ruff
4-
from usethis._tool.impl.deptry import DeptryTool
5-
from usethis._tool.impl.ruff import RuffTool
4+
from usethis._tool.impl.base.deptry import DeptryTool
5+
from usethis._tool.impl.base.ruff import RuffTool
66

77

88
class RulesMapping(BaseModel):

src/usethis/_core/tool.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@
2424
from usethis._integrations.pre_commit.hooks import add_placeholder_hook, get_hook_ids
2525
from usethis._integrations.pytest.core import add_pytest_dir, remove_pytest_dir
2626
from usethis._tool.all_ import ALL_TOOLS
27-
from usethis._tool.impl.codespell import CodespellTool
28-
from usethis._tool.impl.coverage_py import CoveragePyTool
29-
from usethis._tool.impl.deptry import DeptryTool
30-
from usethis._tool.impl.import_linter import ImportLinterTool
31-
from usethis._tool.impl.mkdocs import MkDocsTool
32-
from usethis._tool.impl.pre_commit import PreCommitTool
33-
from usethis._tool.impl.pyproject_fmt import PyprojectFmtTool
34-
from usethis._tool.impl.pyproject_toml import PyprojectTOMLTool
35-
from usethis._tool.impl.pytest import PytestTool
36-
from usethis._tool.impl.requirements_txt import RequirementsTxtTool
37-
from usethis._tool.impl.ruff import RuffTool
27+
from usethis._tool.impl.base.codespell import CodespellTool
28+
from usethis._tool.impl.base.coverage_py import CoveragePyTool
29+
from usethis._tool.impl.base.deptry import DeptryTool
30+
from usethis._tool.impl.base.import_linter import ImportLinterTool
31+
from usethis._tool.impl.base.mkdocs import MkDocsTool
32+
from usethis._tool.impl.base.pre_commit import PreCommitTool
33+
from usethis._tool.impl.base.pyproject_fmt import PyprojectFmtTool
34+
from usethis._tool.impl.base.pyproject_toml import PyprojectTOMLTool
35+
from usethis._tool.impl.base.pytest import PytestTool
36+
from usethis._tool.impl.base.requirements_txt import RequirementsTxtTool
37+
from usethis._tool.impl.base.ruff import RuffTool
3838
from usethis._tool.rule import RuleConfig
3939
from usethis._types.backend import BackendEnum
4040

src/usethis/_tool/all_.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
from typing import TypeAlias
44

5-
from usethis._tool.impl.codespell import CodespellTool
6-
from usethis._tool.impl.coverage_py import CoveragePyTool
7-
from usethis._tool.impl.deptry import DeptryTool
8-
from usethis._tool.impl.import_linter import ImportLinterTool
9-
from usethis._tool.impl.mkdocs import MkDocsTool
10-
from usethis._tool.impl.pre_commit import PreCommitTool
11-
from usethis._tool.impl.pyproject_fmt import PyprojectFmtTool
12-
from usethis._tool.impl.pyproject_toml import PyprojectTOMLTool
13-
from usethis._tool.impl.pytest import PytestTool
14-
from usethis._tool.impl.requirements_txt import RequirementsTxtTool
15-
from usethis._tool.impl.ruff import RuffTool
5+
from usethis._tool.impl.base.codespell import CodespellTool
6+
from usethis._tool.impl.base.coverage_py import CoveragePyTool
7+
from usethis._tool.impl.base.deptry import DeptryTool
8+
from usethis._tool.impl.base.import_linter import ImportLinterTool
9+
from usethis._tool.impl.base.mkdocs import MkDocsTool
10+
from usethis._tool.impl.base.pre_commit import PreCommitTool
11+
from usethis._tool.impl.base.pyproject_fmt import PyprojectFmtTool
12+
from usethis._tool.impl.base.pyproject_toml import PyprojectTOMLTool
13+
from usethis._tool.impl.base.pytest import PytestTool
14+
from usethis._tool.impl.base.requirements_txt import RequirementsTxtTool
15+
from usethis._tool.impl.base.ruff import RuffTool
1616

1717
SupportedToolType: TypeAlias = (
1818
CodespellTool

src/usethis/_tool/impl/base/__init__.py

Whitespace-only changes.
Lines changed: 2 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,14 @@
11
from __future__ import annotations
22

33
from pathlib import Path
4-
from typing import TYPE_CHECKING
54

6-
from usethis._config import usethis_config
75
from usethis._config_file import DotCodespellRCManager
86
from usethis._console import how_print
9-
from usethis._file.pyproject_toml.errors import PyprojectTOMLNotFoundError
107
from usethis._file.pyproject_toml.io_ import PyprojectTOMLManager
11-
from usethis._file.pyproject_toml.requires_python import (
12-
MissingRequiresPythonError,
13-
get_required_minor_python_versions,
14-
)
158
from usethis._file.setup_cfg.io_ import SetupCFGManager
16-
from usethis._integrations.pre_commit import schema as pre_commit_schema
17-
from usethis._python.version import PythonVersion
18-
from usethis._tool.base import Tool, ToolMeta, ToolSpec
9+
from usethis._tool.base import Tool
1910
from usethis._tool.config import ConfigEntry, ConfigItem, ConfigSpec
20-
from usethis._tool.pre_commit import PreCommitConfig
21-
from usethis._types.deps import Dependency
22-
23-
if TYPE_CHECKING:
24-
from usethis._io import KeyValueFileManager
25-
26-
_CODESPELL_VERSION = "v2.4.1" # Manually bump this version when necessary
27-
28-
29-
class CodespellToolSpec(ToolSpec):
30-
@property
31-
def meta(self) -> ToolMeta:
32-
return ToolMeta(
33-
name="Codespell",
34-
url="https://github.com/codespell-project/codespell",
35-
managed_files=[Path(".codespellrc")],
36-
)
37-
38-
def preferred_file_manager(self) -> KeyValueFileManager:
39-
if (usethis_config.cpd() / "pyproject.toml").exists():
40-
return PyprojectTOMLManager()
41-
return DotCodespellRCManager()
42-
43-
def raw_cmd(self) -> str:
44-
return "codespell"
45-
46-
def dev_deps(self, *, unconditional: bool = False) -> list[Dependency]:
47-
deps = [Dependency(name="codespell")]
48-
49-
# Python < 3.11 needs tomli (instead of the stdlib tomllib) to read
50-
# pyproject.toml files
51-
if unconditional:
52-
needs_tomli = True
53-
else:
54-
try:
55-
versions = get_required_minor_python_versions()
56-
except (MissingRequiresPythonError, PyprojectTOMLNotFoundError):
57-
versions = [PythonVersion.from_interpreter()]
58-
59-
needs_tomli = any(v.to_short_tuple() < (3, 11) for v in versions)
60-
if needs_tomli:
61-
deps.append(Dependency(name="tomli"))
62-
63-
return deps
64-
65-
def pre_commit_config(self) -> PreCommitConfig:
66-
return PreCommitConfig.from_single_repo(
67-
pre_commit_schema.UriRepo(
68-
repo="https://github.com/codespell-project/codespell",
69-
rev=_CODESPELL_VERSION,
70-
hooks=[
71-
pre_commit_schema.HookDefinition(
72-
id="codespell", additional_dependencies=["tomli"]
73-
)
74-
],
75-
),
76-
requires_venv=False,
77-
)
11+
from usethis._tool.impl.spec.codespell import CodespellToolSpec
7812

7913

8014
class CodespellTool(CodespellToolSpec, Tool):

src/usethis/_tool/impl/coverage_py.py renamed to src/usethis/_tool/impl/base/coverage_py.py

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
from __future__ import annotations
22

33
from pathlib import Path
4-
from typing import TYPE_CHECKING
54

65
from typing_extensions import assert_never
76

87
from usethis._backend.dispatch import get_backend
98
from usethis._backend.uv.detect import is_uv_used
10-
from usethis._config import usethis_config
119
from usethis._config_file import (
1210
DotCoverageRCManager,
1311
DotCoverageRCTOMLManager,
@@ -17,26 +15,16 @@
1715
from usethis._file.pyproject_toml.io_ import PyprojectTOMLManager
1816
from usethis._file.setup_cfg.io_ import SetupCFGManager
1917
from usethis._integrations.project.layout import get_source_dir_str
20-
from usethis._tool.base import Tool, ToolMeta, ToolSpec
18+
from usethis._tool.base import Tool
2119
from usethis._tool.config import ConfigEntry, ConfigItem, ConfigSpec
20+
from usethis._tool.impl.spec.coverage_py import CoveragePyToolSpec
2221
from usethis._types.backend import BackendEnum
2322
from usethis._types.deps import Dependency
2423

25-
if TYPE_CHECKING:
26-
from usethis._io import KeyValueFileManager
27-
28-
29-
class CoveragePyToolSpec(ToolSpec):
30-
@property
31-
def meta(self) -> ToolMeta:
32-
return ToolMeta(
33-
name="Coverage.py",
34-
url="https://github.com/nedbat/coveragepy",
35-
managed_files=[Path(".coveragerc"), Path(".coveragerc.toml")],
36-
)
3724

25+
class CoveragePyTool(CoveragePyToolSpec, Tool):
3826
def test_deps(self, *, unconditional: bool = False) -> list[Dependency]:
39-
from usethis._tool.impl.pytest import ( # to avoid circularity; # noqa: PLC0415
27+
from usethis._tool.impl.base.pytest import ( # to avoid circularity; # noqa: PLC0415
4028
PytestTool,
4129
)
4230

@@ -45,13 +33,6 @@ def test_deps(self, *, unconditional: bool = False) -> list[Dependency]:
4533
deps += [Dependency(name="pytest-cov")]
4634
return deps
4735

48-
def preferred_file_manager(self) -> KeyValueFileManager:
49-
if (usethis_config.cpd() / "pyproject.toml").exists():
50-
return PyprojectTOMLManager()
51-
return DotCoverageRCManager()
52-
53-
54-
class CoveragePyTool(CoveragePyToolSpec, Tool):
5536
def config_spec(self) -> ConfigSpec:
5637
# https://coverage.readthedocs.io/en/latest/config.html#configuration-reference
5738
# But the `latest` link doesn't yet include some latest changes regarding
@@ -275,7 +256,7 @@ def _get_source():
275256
)
276257

277258
def print_how_to_use(self) -> None:
278-
from usethis._tool.impl.pytest import ( # to avoid circularity; # noqa: PLC0415
259+
from usethis._tool.impl.base.pytest import ( # to avoid circularity; # noqa: PLC0415
279260
PytestTool,
280261
)
281262

0 commit comments

Comments
 (0)