Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The following checks run automatically via prek (pre-commit framework). All must

**To run all checks manually:**
```bash
uv run prek run --all-files
uv run prek run -a
```

**Individual validation commands:**
Expand Down Expand Up @@ -217,7 +217,7 @@ See CONTRIBUTING.md Architecture section for detailed documentation and examples
```bash
uv run pytest # Tests
uv run pytest --cov # Coverage
uv run prek run --all-files # All pre-commit checks
uv run prek run -a # All pre-commit checks
```

7. **Build documentation** (optional):
Expand Down Expand Up @@ -273,7 +273,7 @@ These instructions have been validated by running actual commands and inspecting
| Install git hooks | `uv run prek install` |
| Run tests | `uv run pytest` |
| Run tests with coverage | `uv run pytest --cov` |
| Run all checks | `uv run prek run --all-files` |
| Run all checks | `uv run prek run -a` |
| Format code | `uv run ruff format` |
| Lint code | `uv run ruff check --fix` |
| Check types | `uv run ty check` |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Run checks
if: ${{ matrix.checks == null || matrix.checks == 'true' }}
run: |
uv run --frozen prek run --all-files
uv run --frozen prek run -a
uv run --frozen basedpyright

- name: Run pytest
Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ Tool implementations are defined in classes in the `usethis._tool.impl` module.
- Name the classes based on the filename of the configuration file, following the pattern of the other classes in the module.
- Register the file in the `files_manager` function in the `usethis._config_file` module.

#### Create the `Tool` subclass
#### Create the `Tool` and `ToolSpec` subclasses

- Create a submodule in `usethis._tool.impl` for your tool, e.g. for a tool named Xyz name it `usethis._tool.impl.xyz`.
- Declare this new submodule in the `.importlinter` configuration to architecturally describe its dependency relationships with other tools' submodules. For example, does your tool integrate with pre-commit? It should be in a higher layer module than the `pre-commit` submodule.
- Define a `usethis._tool.base.Tool` subclass, e.g. for a tool named Xyz, define a class `XyzTool(Tool)`.
- Start by implementing its `name` property method, then work through the other methods. Most method have default implementations, but even in those cases you will need to consider them individually and determine an appropriate implementation. For example, methods which specify the tool's dependencies default to empty dependencies, but you shouldn't rely on this. In the future, it is planned to make it easier for you to distinguish methods which are essential to consider overriding versus those which are usually not necessary to override, see <https://github.com/usethis-python/usethis-python/issues/1316>
- Define a `usethis._tool.base.ToolSpec` subclass, e.g. for a tool named Xyz, define a class `XyzToolSpec(ToolSpec)`.
- Start by implementing its `name` property method, then work through the other methods. Most method have default implementations, but even in those cases you will need to consider them individually and determine an appropriate implementation. For example, methods which specify the tool's dependencies default to empty dependencies, but you shouldn't rely on this.
- Then, define a subclass of the `ToolSpec` subclass you just created, which also subclasses `usethis._tool.base.Tool`, e.g. for a tool named Xyz, define a class `XyzTool(XyzToolSpec, Tool)`. The only method this usually requires a non-default implementation for is `config_spec` to specify which configuration sections should be set up for the tool (and which sections the tool manages). However, you may find it helpful to provide custom implementations for other methods as well, e.g. `print_how_to_use`.
- Include a comment with a URL linking to the tool's source repo for reference.

#### Register your `Tool` subclass
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_backend/uv/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from usethis._backend.uv.call import call_uv_subprocess
from usethis._backend.uv.errors import UVSubprocessFailedError

FALLBACK_UV_VERSION = "0.10.0"
FALLBACK_UV_VERSION = "0.10.8"


def get_uv_version() -> str:
Expand Down
27 changes: 10 additions & 17 deletions src/usethis/_core/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,13 @@ def use_import_linter(*, remove: bool = False, how: bool = False) -> None:
tool.print_how_to_use()
return

rule_config = tool.get_rule_config()

if not remove:
ensure_dep_declaration_file()

tool.add_dev_deps()
tool.add_configs()
if RuffTool().is_used():
RuffTool().apply_rule_config(rule_config)
RuffTool().apply_rule_config(tool.rule_config)
tool.update_bitbucket_steps()
tool.add_pre_commit_config()

Expand All @@ -147,7 +145,7 @@ def use_import_linter(*, remove: bool = False, how: bool = False) -> None:
tool.remove_pre_commit_repo_configs()
tool.remove_bitbucket_steps()
if RuffTool().is_used():
RuffTool().remove_rule_config(rule_config)
RuffTool().remove_rule_config(tool.rule_config)
tool.remove_configs()
tool.remove_dev_deps()
tool.remove_managed_files()
Expand Down Expand Up @@ -313,16 +311,14 @@ def use_pytest(*, remove: bool = False, how: bool = False) -> None:
# https://github.com/fpgmaas/deptry/issues/302
add_pytest_dir()

rule_config = tool.get_rule_config()
rule_config = tool.rule_config

for _tool in ALL_TOOLS:
if isinstance(_tool, PytestTool):
continue

config = _tool.get_rule_config()

if config.is_related_to_tests and _tool.is_used():
rule_config |= config.subset_related_to_tests()
if _tool.rule_config.is_related_to_tests and _tool.is_used():
rule_config |= _tool.rule_config.subset_related_to_tests()

if RuffTool().is_used():
RuffTool().apply_rule_config(rule_config)
Expand All @@ -334,12 +330,10 @@ def use_pytest(*, remove: bool = False, how: bool = False) -> None:
if CoveragePyTool().is_used():
CoveragePyTool().print_how_to_use()
else:
rule_config = tool.get_rule_config()

PytestTool().remove_bitbucket_steps()

if RuffTool().is_used():
RuffTool().remove_rule_config(rule_config)
RuffTool().remove_rule_config(tool.rule_config)
tool.remove_configs()
tool.remove_test_deps()
remove_pytest_dir() # Last, since this is a manual step
Expand Down Expand Up @@ -446,16 +440,15 @@ def use_ruff(
# See docstring. Basically, `usethis docstyle` manages the pydocstyle rules,
# so we want to allow the user to subsequently call `usethis tool ruff` and
# still get non-minimal default rules.
all(tool._is_pydocstyle_rule(rule) for rule in tool.get_selected_rules())
all(tool._is_pydocstyle_rule(rule) for rule in tool.selected_rules())
# Another situation where we add default rules is when there are no rules
# selected yet (and we haven't explicitly been requested to add minimal config).
or not tool.get_selected_rules()
or not tool.selected_rules()
):
rule_config = _get_basic_rule_config()
for _tool in ALL_TOOLS:
tool_rule_config = _tool.get_rule_config()
if not tool_rule_config.empty and _tool.is_used():
rule_config |= tool_rule_config
if not _tool.rule_config.empty and _tool.is_used():
rule_config |= _tool.rule_config
else:
rule_config = RuleConfig()

Expand Down
1 change: 1 addition & 0 deletions src/usethis/_integrations/pre_commit/cmd_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pre_commit_raw_cmd = "pre-commit run -a"
Loading