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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ As another example, to use pytest, run:
$ uvx usethis tool pytest
✔ Adding dependency 'pytest' to the 'test' group in 'pyproject.toml'.
✔ Adding pytest config to 'pyproject.toml'.
✔ Selecting Ruff rule 'PT' in 'pyproject.toml'.
✔ Creating '/tests'.
✔ Writing '/tests/conftest.py'.
✔ Selecting Ruff rule 'PT' in 'pyproject.toml'.
☐ Add test files to the '/tests' directory with the format 'test_*.py'.
☐ Add test functions with the format 'test_*()'.
☐ Run 'uv run pytest' to run the tests.
Expand Down
2 changes: 1 addition & 1 deletion docs/start/example-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ As another example, to use pytest, run:
$ uvx usethis tool pytest
✔ Adding dependency 'pytest' to the 'test' group in 'pyproject.toml'.
✔ Adding pytest config to 'pyproject.toml'.
✔ Selecting Ruff rule 'PT' in 'pyproject.toml'.
✔ Creating '/tests'.
✔ Writing '/tests/conftest.py'.
✔ Selecting Ruff rule 'PT' in 'pyproject.toml'.
☐ Add test files to the '/tests' directory with the format 'test_*.py'.
☐ Add test functions with the format 'test_*()'.
☐ Run 'uv run pytest' to run the tests.
Expand Down
20 changes: 16 additions & 4 deletions src/usethis/_core/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,27 +311,39 @@ def use_pytest(*, 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_test_deps()
tool.add_configs()
if RuffTool().is_used():
RuffTool().apply_rule_config(rule_config)

# deptry currently can't scan the tests folder for dev deps
# https://github.com/fpgmaas/deptry/issues/302
add_pytest_dir()

rule_config = tool.get_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 RuffTool().is_used():
RuffTool().apply_rule_config(rule_config)

PytestTool().update_bitbucket_steps()

tool.print_how_to_use()

if CoveragePyTool().is_used():
CoveragePyTool().print_how_to_use()
else:
rule_config = tool.get_rule_config()

PytestTool().remove_bitbucket_steps()

if RuffTool().is_used():
Expand Down
18 changes: 18 additions & 0 deletions src/usethis/_tool/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ def get_all_ignored(self) -> list[Rule]:
"""Get all (project-scope) ignored rules."""
return self.ignored + self.unmanaged_ignored

def subset_related_to_tests(self) -> Self:
"""Get a RuleConfig with only rules relating to tests configuration.

This is useful for cases where we are introducing pytest into a project, and
then we want to introduce specifically this subset of rules.
"""
self = self.model_copy()
self.selected = []
self.ignored = []
self.unmanaged_selected = []
self.unmanaged_ignored = []
return self

@property
def empty(self) -> bool:
"""Check if the rule config is empty."""
Expand All @@ -57,6 +70,11 @@ def empty(self) -> bool:
and not self.tests_unmanaged_ignored
)

@property
def is_related_to_tests(self) -> bool:
"""Check if the rule config has any tests-related rules."""
return bool(self.tests_unmanaged_ignored)

def __repr__(self) -> str:
"""Representation which omits empty-list fields."""
args = []
Expand Down
16 changes: 16 additions & 0 deletions tests/usethis/_core/test_core_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2630,6 +2630,22 @@ def test_ruff_integration(self, uv_init_dir: Path):
# Assert
assert "PT" in RuffTool().get_selected_rules()

@pytest.mark.usefixtures("_vary_network_conn")
def test_ruff_import_linter_integration_adds_test_dir_ignores(
self, uv_init_dir: Path
):
with change_cwd(uv_init_dir), files_manager():
# Arrange
use_ruff()
use_import_linter()

# Act
use_pytest()

# Assert
# Verify that INP rules are ignored in tests/** after pytest creates tests/
assert "INP" in RuffTool().get_ignored_rules_in_glob("tests/**")

@pytest.mark.usefixtures("_vary_network_conn")
def test_pytest_ini_priority(self, uv_init_dir: Path):
# Arrange
Expand Down
2 changes: 1 addition & 1 deletion tests/usethis/_ui/interface/test_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,9 @@ def test_readme_example(self, tmp_path: Path):
== """\
✔ Adding dependency 'pytest' to the 'test' group in 'pyproject.toml'.
✔ Adding pytest config to 'pyproject.toml'.
✔ Selecting Ruff rule 'PT' in 'pyproject.toml'.
✔ Creating '/tests'.
✔ Writing '/tests/conftest.py'.
✔ Selecting Ruff rule 'PT' in 'pyproject.toml'.
☐ Add test files to the '/tests' directory with the format 'test_*.py'.
☐ Add test functions with the format 'test_*()'.
☐ Run 'uv run pytest' to run the tests.
Expand Down