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
9 changes: 9 additions & 0 deletions src/usethis/_config_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def files_manager() -> Iterator[None]:
SetupCFGManager(),
CodespellRCManager(),
CoverageRCManager(),
CoverageRCTOMLManager(),
DotRuffTOMLManager(),
DotPytestINIManager(),
DotImportLinterManager(),
Expand Down Expand Up @@ -50,6 +51,14 @@ def relative_path(self) -> Path:
return Path(".coveragerc")


class CoverageRCTOMLManager(TOMLFileManager):
"""Class to manage the .coveragerc.toml file."""

@property
def relative_path(self) -> Path:
return Path(".coveragerc.toml")


class DotImportLinterManager(INIFileManager):
"""Class to manage the .importlinter file."""

Expand Down
27 changes: 26 additions & 1 deletion src/usethis/_tool/impl/coverage_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from usethis._config import usethis_config
from usethis._config_file import (
CoverageRCManager,
CoverageRCTOMLManager,
ToxINIManager,
)
from usethis._console import how_print
Expand Down Expand Up @@ -74,6 +75,9 @@ def preferred_file_manager(self) -> KeyValueFileManager:

def get_config_spec(self) -> ConfigSpec:
# https://coverage.readthedocs.io/en/latest/config.html#configuration-reference
# But the `latest` link doesn't yet include some latest changes regarding
# `.coveragerc.toml`, which are available here:
# https://coverage.readthedocs.io/en/7.13.0/config.html#configuration-reference

exclude_also = [
"if TYPE_CHECKING:",
Expand All @@ -91,6 +95,7 @@ def _get_source():
return ConfigSpec.from_flat(
file_managers=[
CoverageRCManager(),
CoverageRCTOMLManager(),
SetupCFGManager(),
ToxINIManager(),
PyprojectTOMLManager(),
Expand All @@ -101,6 +106,7 @@ def _get_source():
description="Overall Config",
root={
Path(".coveragerc"): ConfigEntry(keys=[]),
Path(".coveragerc.toml"): ConfigEntry(keys=[]),
# N.B. other ini files use a "coverage:" prefix so there's no
# section corresponding to overall config
Path("pyproject.toml"): ConfigEntry(keys=["tool", "coverage"]),
Expand All @@ -111,6 +117,7 @@ def _get_source():
description="Run Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["run"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["run"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:run"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:run"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -124,6 +131,10 @@ def _get_source():
Path(".coveragerc"): ConfigEntry(
keys=["run", "source"], get_value=_get_source
),
Path(".coveragerc.toml"): ConfigEntry(
keys=["run", "source"],
get_value=_get_source,
),
Path("setup.cfg"): ConfigEntry(
keys=["coverage:run", "source"], get_value=_get_source
),
Expand All @@ -140,6 +151,7 @@ def _get_source():
description="Report Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["report"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["report"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:report"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:report"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -154,6 +166,10 @@ def _get_source():
keys=["report", "exclude_also"],
get_value=lambda: exclude_also,
),
Path(".coveragerc.toml"): ConfigEntry(
keys=["report", "exclude_also"],
get_value=lambda: exclude_also,
),
Path("setup.cfg"): ConfigEntry(
keys=["coverage:report", "exclude_also"],
get_value=lambda: exclude_also,
Expand All @@ -174,6 +190,10 @@ def _get_source():
Path(".coveragerc"): ConfigEntry(
keys=["report", "omit"], get_value=lambda: omit
),
Path(".coveragerc.toml"): ConfigEntry(
keys=["report", "omit"],
get_value=lambda: omit,
),
Path("setup.cfg"): ConfigEntry(
keys=["coverage:report", "omit"], get_value=lambda: omit
),
Expand All @@ -190,6 +210,7 @@ def _get_source():
description="Paths Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["paths"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["paths"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:paths"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:paths"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -201,6 +222,7 @@ def _get_source():
description="HTML Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["html"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["html"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:html"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:html"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -212,6 +234,7 @@ def _get_source():
description="XML Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["xml"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["xml"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:xml"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:xml"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -223,6 +246,7 @@ def _get_source():
description="JSON Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["json"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["json"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:json"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:json"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -234,6 +258,7 @@ def _get_source():
description="LCOV Configuration",
root={
Path(".coveragerc"): ConfigEntry(keys=["lcov"]),
Path(".coveragerc.toml"): ConfigEntry(keys=["lcov"]),
Path("setup.cfg"): ConfigEntry(keys=["coverage:lcov"]),
Path("tox.ini"): ConfigEntry(keys=["coverage:lcov"]),
Path("pyproject.toml"): ConfigEntry(
Expand All @@ -245,4 +270,4 @@ def _get_source():
)

def get_managed_files(self) -> list[Path]:
return [Path(".coveragerc")]
return [Path(".coveragerc"), Path(".coveragerc.toml")]
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/ruff.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from usethis._io import KeyValueFileManager
from usethis._tool.rule import Rule, RuleConfig

_RUFF_VERSION = "v0.14.9" # Manually bump this version when necessary
_RUFF_VERSION = "v0.14.10" # Manually bump this version when necessary


class RuffTool(Tool):
Expand Down
49 changes: 48 additions & 1 deletion tests/usethis/_tool/impl/test_coverage_py.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from usethis._config_file import files_manager
from usethis._config_file import CoverageRCTOMLManager, files_manager
from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager
from usethis._test import change_cwd
from usethis._tool.impl.coverage_py import CoveragePyTool
Expand Down Expand Up @@ -60,3 +60,50 @@ def test_pyproject_toml_exists(self, tmp_path: Path):
# Assert
assert not (tmp_path / ".coveragerc").exists()
assert (tmp_path / "pyproject.toml").exists()

def test_coveragerc_toml_exists(self, tmp_path: Path):
# Arrange
(tmp_path / ".coveragerc.toml").touch()

# Act
with change_cwd(tmp_path), files_manager():
CoveragePyTool().add_configs()

# Assert
assert not (tmp_path / ".coveragerc").exists()
assert (tmp_path / ".coveragerc.toml").exists()
assert not (tmp_path / "pyproject.toml").exists()

def test_coveragerc_toml_preferred_over_pyproject_toml(self, tmp_path: Path):
# Arrange - both files exist, .coveragerc.toml should be used
(tmp_path / "pyproject.toml").touch()
(tmp_path / ".coveragerc.toml").touch()

# Act
with change_cwd(tmp_path), files_manager():
CoveragePyTool().add_configs()

# Assert - config should be added to .coveragerc.toml
with change_cwd(tmp_path), files_manager():
assert ["run"] in CoverageRCTOMLManager()
content = (tmp_path / ".coveragerc.toml").read_text()
assert "[run]" in content
assert "[report]" in content
assert (tmp_path / "pyproject.toml").read_text() == ""

def test_coveragerc_preferred_over_coveragerc_toml(self, tmp_path: Path):
# Arrange - both .coveragerc and .coveragerc.toml exist
(tmp_path / ".coveragerc").write_text("[run]\nsource = existing\n")
(tmp_path / ".coveragerc.toml").write_text('[run]\nsource = ["existing"]\n')

# Act
with change_cwd(tmp_path), files_manager():
CoveragePyTool().add_configs()

# Assert - .coveragerc should take priority
coveragerc_content = (tmp_path / ".coveragerc").read_text()
assert "[run]" in coveragerc_content
# Verify .coveragerc.toml was not modified
assert (tmp_path / ".coveragerc.toml").read_text() == (
'[run]\nsource = ["existing"]\n'
)