Skip to content

Split usethis._tool.impl into impl/spec and impl/base submodules#1373

Merged
nathanjmcdougall merged 5 commits intomainfrom
copilot/split-usethis-tool-impl
Mar 12, 2026
Merged

Split usethis._tool.impl into impl/spec and impl/base submodules#1373
nathanjmcdougall merged 5 commits intomainfrom
copilot/split-usethis-tool-impl

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 11, 2026

The flat usethis._tool.impl module mixed ToolSpec subclasses (declarative metadata) and Tool subclasses (runtime behaviour) in the same files. This splits them into parallel submodule structures to separate concerns.

Structure

Each tool now has two dedicated modules:

  • usethis._tool.impl.spec.*ToolSpec subclasses: meta, dev_deps, pre_commit_config, preferred_file_manager, etc.
  • usethis._tool.impl.base.*Tool subclasses: config_spec, print_how_to_use, get_bitbucket_steps, selected_rules, etc.
src/usethis/_tool/impl/
├── spec/
│   ├── codespell.py    # CodespellToolSpec
│   ├── ruff.py         # RuffToolSpec
│   └── ...
└── base/
    ├── codespell.py    # CodespellTool
    ├── ruff.py         # RuffTool
    └── ...

The test directory mirrors the src structure:

tests/usethis/_tool/impl/
└── base/
    ├── test_codespell.py
    ├── test_ruff.py
    └── ...

Notable decisions

  • test_deps() moved to base/ for pytest and coverage_py: these methods call .is_used() on sibling Tool instances, making them runtime behaviour rather than declarative spec. Moving them to base/ eliminates the spec → base import cycle and enforces the clean base → spec dependency direction.
  • Import-linter contracts updated: the old tool_impl contract is replaced with three — tool_impl (base above spec), tool_impl_base, and tool_impl_spec — each with the same internal layer ordering as before.
  • All external consumers (_core/, _tool/all_.py, _toolset/, _ui/, tests) updated to the new paths.
  • Test suite restructured: all tests/usethis/_tool/impl/test_*.py files moved to tests/usethis/_tool/impl/base/ to match the src layout.
Original prompt

This section details on the original issue you should resolve

<issue_title>Split the usethis._tool.impl layer into usethis._tool.impl.spec and usethis._tool.impl.base layers</issue_title>
<issue_description>Current dir structure looks like this:

src\usethis_tool\impl
src\usethis_tool\impl_init_.py
src\usethis_tool\impl\codespell.py
src\usethis_tool\impl\coverage_py.py
src\usethis_tool\impl\deptry.py
src\usethis_tool\impl\import_linter.py
src\usethis_tool\impl\mkdocs.py
src\usethis_tool\impl\pre_commit.py
src\usethis_tool\impl\pyproject_fmt.py
src\usethis_tool\impl\pyproject_toml.py
src\usethis_tool\impl\pytest.py
src\usethis_tool\impl\requirements_txt.py
src\usethis_tool\impl\ruff.py

Each module contains the implementation for a ToolSpec and a Tool subclass.

We should create a submodule in the impl module for spec and base separately with parallel submodule structures.

This helps us work toward #1311 </issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits March 11, 2026 03:47
Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
…nces

Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Copilot AI changed the title [WIP] Split the usethis._tool.impl layer into spec and base layers Split usethis._tool.impl into impl/spec and impl/base submodules Mar 11, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 11, 2026

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing copilot/split-usethis-tool-impl (320fbd9) with main (4bd7e97)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (00e11d3) during the generation of this report, so 4bd7e97 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@nathanjmcdougall
Copy link
Copy Markdown
Collaborator

@copilot I have updated the usethis-python-module-layout-modify skill to explain how you also need to restructure the test suite to match the src directory.

…tructure

Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 12, 2026

@copilot I have updated the usethis-python-module-layout-modify skill to explain how you also need to restructure the test suite to match the src directory.

Done in 320fbd9 — moved all 11 test files from tests/usethis/_tool/impl/test_*.py to tests/usethis/_tool/impl/base/test_*.py to mirror the src/usethis/_tool/impl/base/ structure.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 98.26087% with 6 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/usethis/_tool/impl/base/requirements_txt.py 90.90% 2 Missing ⚠️
src/usethis/_tool/impl/spec/coverage_py.py 93.33% 1 Missing ⚠️
src/usethis/_tool/impl/spec/import_linter.py 98.43% 1 Missing ⚠️
src/usethis/_tool/impl/spec/pytest.py 94.44% 1 Missing ⚠️
src/usethis/_tool/impl/spec/ruff.py 94.44% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@nathanjmcdougall nathanjmcdougall marked this pull request as ready for review March 12, 2026 19:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the usethis._tool.impl layer by splitting each tool’s implementation into two parallel subpackages: impl/spec for declarative ToolSpec metadata and impl/base for runtime Tool behavior, updating all internal imports and tests accordingly.

Changes:

  • Introduces src/usethis/_tool/impl/spec/* modules containing ToolSpec subclasses (metadata, deps, pre-commit config, preferred config file selection).
  • Introduces/updates src/usethis/_tool/impl/base/* modules containing Tool subclasses (runtime behavior like config management and how-to-use output) that depend on their corresponding spec modules.
  • Updates import paths across core/toolset/UI code, tests, and .importlinter contracts to reflect the new structure.

Reviewed changes

Copilot reviewed 46 out of 48 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.importlinter Updates import-linter contracts to model impl as base above spec, plus adds dedicated contracts for each subpackage.
src/usethis/_core/ci.py Updates tool imports to the new usethis._tool.impl.base.* paths.
src/usethis/_core/docstyle.py Updates Ruff tool import path to impl.base.
src/usethis/_core/list.py Updates Ruff tool import path to impl.base.
src/usethis/_core/rule.py Updates Deptry/Ruff tool import paths to impl.base.
src/usethis/_core/tool.py Updates all tool imports to impl.base.
src/usethis/tool/all.py Updates ALL_TOOLS imports to impl.base tool classes.
src/usethis/_tool/impl/base/codespell.py Moves runtime CodespellTool behavior into impl/base and imports CodespellToolSpec from impl/spec.
src/usethis/_tool/impl/base/coverage_py.py Moves runtime CoveragePyTool behavior into impl/base and imports CoveragePyToolSpec from impl/spec; updates circular imports to new paths.
src/usethis/_tool/impl/base/deptry.py Moves runtime DeptryTool behavior into impl/base and imports DeptryToolSpec from impl/spec.
src/usethis/_tool/impl/base/import_linter.py Moves runtime ImportLinterTool behavior into impl/base and imports ImportLinterToolSpec from impl/spec; removes spec-only helpers.
src/usethis/_tool/impl/base/mkdocs.py Moves runtime MkDocsTool behavior into impl/base and imports MkDocsToolSpec from impl/spec.
src/usethis/_tool/impl/base/pre_commit.py Moves runtime PreCommitTool behavior into impl/base and imports PreCommitToolSpec from impl/spec.
src/usethis/_tool/impl/base/pyproject_fmt.py Moves runtime PyprojectFmtTool behavior into impl/base and imports PyprojectFmtToolSpec from impl/spec.
src/usethis/_tool/impl/base/pyproject_toml.py Updates tool aggregation imports to impl.base.* and imports PyprojectTOMLToolSpec from impl/spec.
src/usethis/_tool/impl/base/pytest.py Moves runtime PytestTool behavior into impl/base and imports PytestToolSpec from impl/spec; updates circular imports to new paths.
src/usethis/_tool/impl/base/requirements_txt.py Moves runtime RequirementsTxtTool behavior into impl/base and imports RequirementsTxtToolSpec from impl/spec.
src/usethis/_tool/impl/base/ruff.py Removes embedded RuffToolSpec and imports it from impl/spec, keeping runtime logic in impl/base.
src/usethis/_tool/impl/pyproject_fmt.py Deletes the old combined (spec+base) module in favor of split impl/spec + impl/base.
src/usethis/_tool/impl/spec/codespell.py Adds CodespellToolSpec module (metadata/deps/pre-commit config).
src/usethis/_tool/impl/spec/coverage_py.py Adds CoveragePyToolSpec module (metadata + preferred config file selection).
src/usethis/_tool/impl/spec/deptry.py Adds DeptryToolSpec module (metadata/deps/pre-commit config).
src/usethis/_tool/impl/spec/import_linter.py Adds ImportLinterToolSpec module (metadata/deps/pre-commit config + layered-architecture helpers + warning helper).
src/usethis/_tool/impl/spec/mkdocs.py Adds MkDocsToolSpec module (metadata/doc deps/preferred config file).
src/usethis/_tool/impl/spec/pre_commit.py Adds PreCommitToolSpec module (metadata/deps/pre-commit config + version constant).
src/usethis/_tool/impl/spec/pyproject_fmt.py Adds PyprojectFmtToolSpec module (metadata/deps/pre-commit config + version constant).
src/usethis/_tool/impl/spec/pyproject_toml.py Adds PyprojectTOMLToolSpec module (metadata).
src/usethis/_tool/impl/spec/pytest.py Adds PytestToolSpec module (metadata/raw cmd/preferred config file + RuleConfig).
src/usethis/_tool/impl/spec/requirements_txt.py Removes runtime RequirementsTxtTool from spec module (leaving spec-only behavior).
src/usethis/_tool/impl/spec/ruff.py Adds RuffToolSpec module (metadata/dev deps/preferred config file).
src/usethis/toolset/format.py Updates PyprojectTOMLTool import path to impl.base.
src/usethis/_ui/interface/readme.py Updates PreCommitTool/RuffTool import paths to impl.base.
tests/conftest.py Updates import of _importlinter_warn_no_packages_found to impl.spec.import_linter.
tests/usethis/_core/test_core_tool.py Updates imports: Ruff from impl.base, _SYNC_WITH_UV_VERSION from impl.spec.pre_commit.
tests/usethis/_core/test_rule.py Updates Deptry/Ruff imports to impl.base.
tests/usethis/_tool/impl/base/test_codespell.py Updates CodespellTool import to impl.base.
tests/usethis/_tool/impl/base/test_coverage_py.py Updates CoveragePyTool import to impl.base.
tests/usethis/_tool/impl/base/test_deptry.py Updates DeptryTool import to impl.base.
tests/usethis/_tool/impl/base/test_import_linter.py Updates ImportLinterTool import to impl.base.
tests/usethis/_tool/impl/base/test_mkdocs.py Updates MkDocsTool import to impl.base.
tests/usethis/_tool/impl/base/test_pre_commit.py Updates PreCommitTool import to impl.base.
tests/usethis/_tool/impl/base/test_pyproject_fmt.py Updates PyprojectFmtTool import to impl.base.
tests/usethis/_tool/impl/base/test_pyproject_toml.py Updates PyprojectTOMLTool import to impl.base.
tests/usethis/_tool/impl/base/test_pytest.py Updates module/class imports and monkeypatch target to impl.base.pytest.
tests/usethis/_tool/impl/base/test_requirements_txt.py Updates RequirementsTxtTool import to impl.base.
tests/usethis/_tool/impl/base/test_ruff.py Updates RuffTool import to impl.base.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@nathanjmcdougall nathanjmcdougall merged commit b9a60b2 into main Mar 12, 2026
24 checks passed
@nathanjmcdougall nathanjmcdougall deleted the copilot/split-usethis-tool-impl branch March 12, 2026 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Split the usethis._tool.impl layer into usethis._tool.impl.spec and usethis._tool.impl.base layers

3 participants