Skip to content

Commit ae24f0f

Browse files
219 properly handle other ruff configuration files (#398)
* Rename `pyproject` -> `pyproject_toml` for clarity * Start TOML integration abstraction Rename `PyProject` -> `Pyproject` for consistency * Pass the tests while offline * Bring `set_config_value` into a dedicated TOML integration layer * Move more functions into the TOML layer * Move do-keys-exist check to TOML layer * Rename pyproject_toml layer core functions * Refactor the way Tools define pyproject.toml configuration to make it more generalized * First draft of major refactor in the way file config is handled * Temporarily skip failing test * Rename id_keys -> keys * do_keys_exist -> contains * Update docstring * Update docstring * Add setitem and delitem methods to the KeyValueFileManager * Addressing various TODOs * Migrate tests into correct file * Migrate tests into the correct file * Uncomment tests * Refactor tests for new structure * Fix a few bugs * Re-enable temporarily disabled ruff rules * Add edge case tests for toml file manager * Test the UsethisFileManager setter * Support alternative ruff config files * Fix bug in remove_configs logic for non-pyproject.toml files * Test dunder methods for TestUsethisFileManager * Add tests for various edge cases * Remove unused method * Fix test which doesn't test what is intended
1 parent ba7f9ea commit ae24f0f

33 files changed

Lines changed: 1976 additions & 1489 deletions

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ layers = [
162162
"_interface",
163163
"_core",
164164
"_tool | _ci",
165+
"_config_file",
165166
"_integrations",
166167
"_console",
167168
"_config | _io",
@@ -186,7 +187,7 @@ name = "Integrations Modular Design"
186187
type = "layers"
187188
layers = [
188189
"ci | pre_commit",
189-
"uv | pytest | ruff | pydantic | sonarqube",
190+
"uv | pytest | pydantic | sonarqube",
190191
"project | file | python",
191192
]
192193
containers = [ "usethis._integrations" ]

src/usethis/_config_file.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from __future__ import annotations
2+
3+
import contextlib
4+
from pathlib import Path
5+
from typing import TYPE_CHECKING
6+
7+
from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager
8+
from usethis._integrations.file.toml.io_ import TOMLFileManager
9+
10+
if TYPE_CHECKING:
11+
from collections.abc import Iterator
12+
13+
14+
@contextlib.contextmanager
15+
def files_manager() -> Iterator[None]:
16+
with (
17+
PyprojectTOMLManager(),
18+
DotRuffTOMLManager(),
19+
RuffTOMLManager(),
20+
):
21+
yield
22+
23+
24+
class DotRuffTOMLManager(TOMLFileManager):
25+
"""Class to manage the .ruff.toml file."""
26+
27+
@property
28+
def relative_path(self) -> Path:
29+
return Path(".ruff.toml")
30+
31+
32+
class RuffTOMLManager(TOMLFileManager):
33+
"""Class to manage the ruff.toml file."""
34+
35+
@property
36+
def relative_path(self) -> Path:
37+
return Path("ruff.toml")

src/usethis/_core/tool.py

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@
2525
get_hook_names,
2626
)
2727
from usethis._integrations.pytest.core import add_pytest_dir, remove_pytest_dir
28-
from usethis._integrations.ruff.rules import (
29-
deselect_ruff_rules,
30-
ignore_ruff_rules,
31-
select_ruff_rules,
32-
)
3328
from usethis._integrations.uv.call import call_uv_subprocess
3429
from usethis._integrations.uv.init import ensure_pyproject_toml
3530
from usethis._tool import (
@@ -62,11 +57,11 @@ def use_codespell(*, remove: bool = False) -> None:
6257
else:
6358
tool.add_pre_commit_repo_configs()
6459

65-
tool.add_pyproject_configs()
60+
tool.add_configs()
6661
tool.print_how_to_use()
6762
else:
6863
remove_bitbucket_steps_from_default(tool.get_bitbucket_steps())
69-
tool.remove_pyproject_configs()
64+
tool.remove_configs()
7065
tool.remove_pre_commit_repo_configs()
7166
tool.remove_dev_deps()
7267
tool.remove_managed_files()
@@ -79,10 +74,10 @@ def use_coverage(*, remove: bool = False) -> None:
7974

8075
if not remove:
8176
tool.add_test_deps()
82-
tool.add_pyproject_configs()
77+
tool.add_configs()
8378
tool.print_how_to_use()
8479
else:
85-
tool.remove_pyproject_configs()
80+
tool.remove_configs()
8681
tool.remove_test_deps()
8782
tool.remove_managed_files()
8883

@@ -102,7 +97,7 @@ def use_deptry(*, remove: bool = False) -> None:
10297
tool.print_how_to_use()
10398
else:
10499
tool.remove_pre_commit_repo_configs()
105-
tool.remove_pyproject_configs()
100+
tool.remove_configs()
106101
remove_bitbucket_steps_from_default(tool.get_bitbucket_steps())
107102
tool.remove_dev_deps()
108103
tool.remove_managed_files()
@@ -123,11 +118,11 @@ def use_pre_commit(*, remove: bool = False) -> None:
123118
# We will use pre-commit instead of project-installed dependencies:
124119
if pyproject_fmt_tool.is_used():
125120
pyproject_fmt_tool.remove_dev_deps()
126-
pyproject_fmt_tool.add_pyproject_configs()
121+
pyproject_fmt_tool.add_configs()
127122
pyproject_fmt_tool.print_how_to_use()
128123
if codespell_tool.is_used():
129124
codespell_tool.remove_dev_deps()
130-
codespell_tool.add_pyproject_configs()
125+
codespell_tool.add_configs()
131126
codespell_tool.print_how_to_use()
132127

133128
if requirements_txt_tool.is_used():
@@ -206,11 +201,11 @@ def use_pyproject_fmt(*, remove: bool = False) -> None:
206201
else:
207202
tool.add_pre_commit_repo_configs()
208203

209-
tool.add_pyproject_configs()
204+
tool.add_configs()
210205
tool.print_how_to_use()
211206
else:
212207
remove_bitbucket_steps_from_default(tool.get_bitbucket_steps())
213-
tool.remove_pyproject_configs()
208+
tool.remove_configs()
214209
tool.remove_pre_commit_repo_configs()
215210
tool.remove_dev_deps()
216211
tool.remove_managed_files()
@@ -236,9 +231,9 @@ def use_pytest(*, remove: bool = False) -> None:
236231

237232
if not remove:
238233
tool.add_test_deps()
239-
tool.add_pyproject_configs()
234+
tool.add_configs()
240235
if RuffTool().is_used():
241-
select_ruff_rules(tool.get_associated_ruff_rules())
236+
RuffTool().select_rules(tool.get_associated_ruff_rules())
242237

243238
# deptry currently can't scan the tests folder for dev deps
244239
# https://github.com/fpgmaas/deptry/issues/302
@@ -256,8 +251,8 @@ def use_pytest(*, remove: bool = False) -> None:
256251
remove_bitbucket_pytest_steps()
257252

258253
if RuffTool().is_used():
259-
deselect_ruff_rules(tool.get_associated_ruff_rules())
260-
tool.remove_pyproject_configs()
254+
RuffTool().deselect_rules(tool.get_associated_ruff_rules())
255+
tool.remove_configs()
261256
tool.remove_test_deps()
262257
remove_pytest_dir() # Last, since this is a manual step
263258

@@ -335,9 +330,9 @@ def use_ruff(*, remove: bool = False) -> None:
335330

336331
if not remove:
337332
tool.add_dev_deps()
338-
tool.add_pyproject_configs()
339-
select_ruff_rules(rules)
340-
ignore_ruff_rules(ignored_rules)
333+
tool.add_configs()
334+
tool.select_rules(rules)
335+
tool.ignore_rules(ignored_rules)
341336
if PreCommitTool().is_used():
342337
tool.add_pre_commit_repo_configs()
343338
elif is_bitbucket_used():
@@ -347,6 +342,6 @@ def use_ruff(*, remove: bool = False) -> None:
347342
else:
348343
tool.remove_pre_commit_repo_configs()
349344
remove_bitbucket_steps_from_default(tool.get_bitbucket_steps())
350-
tool.remove_pyproject_configs()
345+
tool.remove_configs()
351346
tool.remove_dev_deps()
352347
tool.remove_managed_files()

src/usethis/_integrations/file/pyproject_toml/config.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/usethis/_integrations/file/pyproject_toml/core.py

Lines changed: 0 additions & 101 deletions
This file was deleted.

src/usethis/_integrations/file/pyproject_toml/io_.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,24 @@
66
from usethis._integrations.file.pyproject_toml.errors import (
77
PyprojectTOMLDecodeError,
88
PyprojectTOMLNotFoundError,
9+
PyprojectTOMLValueAlreadySetError,
10+
PyprojectTOMLValueMissingError,
911
UnexpectedPyprojectTOMLIOError,
1012
UnexpectedPyprojectTOMLOpenError,
1113
)
1214
from usethis._integrations.file.toml.errors import (
1315
TOMLDecodeError,
1416
TOMLNotFoundError,
17+
TOMLValueAlreadySetError,
18+
TOMLValueMissingError,
1519
UnexpectedTOMLIOError,
1620
UnexpectedTOMLOpenError,
1721
)
1822
from usethis._integrations.file.toml.io_ import TOMLFileManager
1923

2024
if TYPE_CHECKING:
25+
from typing import Any
26+
2127
from typing_extensions import Self
2228

2329

@@ -49,3 +55,19 @@ def _validate_lock(self) -> None:
4955
super()._validate_lock()
5056
except UnexpectedTOMLIOError as err:
5157
raise UnexpectedPyprojectTOMLIOError(err) from None
58+
59+
def set_value(
60+
self, *, keys: list[str], value: Any, exists_ok: bool = False
61+
) -> None:
62+
"""Set a value in the pyproject.toml configuration file."""
63+
try:
64+
super().set_value(keys=keys, value=value, exists_ok=exists_ok)
65+
except TOMLValueAlreadySetError as err:
66+
raise PyprojectTOMLValueAlreadySetError(err) from None
67+
68+
def __delitem__(self, keys: list[str]) -> None:
69+
"""Remove a value from the pyproject.toml configuration file."""
70+
try:
71+
super().__delitem__(keys)
72+
except TOMLValueMissingError as err:
73+
raise PyprojectTOMLValueMissingError(err) from None

0 commit comments

Comments
 (0)