Skip to content

Commit c753fba

Browse files
Use lazy definitions for config values (#504)
1 parent b7fbc12 commit c753fba

File tree

2 files changed

+108
-41
lines changed

2 files changed

+108
-41
lines changed

src/usethis/_tool.py

Lines changed: 105 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import re
44
from abc import abstractmethod
5+
from collections.abc import Callable
56
from pathlib import Path
67
from typing import Any, Literal, Protocol, TypeAlias
78

@@ -104,6 +105,10 @@ class _NoConfigValue:
104105
pass
105106

106107

108+
def _get_no_config_value() -> _NoConfigValue:
109+
return _NoConfigValue()
110+
111+
107112
class ConfigEntry(BaseModel):
108113
"""A configuration entry in a config file associated with a tool.
109114
@@ -117,7 +122,7 @@ class ConfigEntry(BaseModel):
117122
"""
118123

119124
keys: list[str]
120-
value: Any | InstanceOf[_NoConfigValue] = _NoConfigValue()
125+
get_value: Callable[[], Any] = _get_no_config_value
121126

122127

123128
class ConfigItem(BaseModel):
@@ -390,7 +395,7 @@ def add_configs(self) -> None:
390395

391396
(entry,) = config_entries
392397

393-
if isinstance(entry.value, _NoConfigValue):
398+
if isinstance(entry.get_value(), _NoConfigValue):
394399
# No value to add, so skip this config item.
395400
continue
396401

@@ -413,7 +418,7 @@ def add_configs(self) -> None:
413418
f"Adding {self.name} config to '{used_file_manager.relative_path}'."
414419
)
415420
first_addition = False
416-
used_file_manager[entry.keys] = entry.value
421+
used_file_manager[entry.keys] = entry.get_value()
417422

418423
def remove_configs(self) -> None:
419424
"""Remove the tool's configuration sections.
@@ -587,15 +592,15 @@ def get_config_spec(self) -> ConfigSpec:
587592
root={
588593
Path(".codespellrc"): ConfigEntry(
589594
keys=["codespell", "ignore-regex"],
590-
value="[A-Za-z0-9+/]{100,}",
595+
get_value=lambda: "[A-Za-z0-9+/]{100,}",
591596
),
592597
Path("setup.cfg"): ConfigEntry(
593598
keys=["codespell", "ignore-regex"],
594-
value="[A-Za-z0-9+/]{100,}",
599+
get_value=lambda: "[A-Za-z0-9+/]{100,}",
595600
),
596601
Path("pyproject.toml"): ConfigEntry(
597602
keys=["tool", "codespell", "ignore-regex"],
598-
value=["[A-Za-z0-9+/]{100,}"],
603+
get_value=lambda: ["[A-Za-z0-9+/]{100,}"],
599604
),
600605
},
601606
),
@@ -658,18 +663,18 @@ def get_test_deps(self, *, unconditional: bool = False) -> list[Dependency]:
658663
def get_config_spec(self) -> ConfigSpec:
659664
# https://coverage.readthedocs.io/en/latest/config.html#configuration-reference
660665

661-
run = {"source": [get_source_dir_str()]}
662-
report = {
663-
"exclude_also": [
664-
"if TYPE_CHECKING:",
665-
"raise AssertionError",
666-
"raise NotImplementedError",
667-
"assert_never(.*)",
668-
"class .*\\bProtocol\\):",
669-
"@(abc\\.)?abstractmethod",
670-
],
671-
"omit": ["*/pytest-of-*/*"],
672-
}
666+
exclude_also = [
667+
"if TYPE_CHECKING:",
668+
"raise AssertionError",
669+
"raise NotImplementedError",
670+
"assert_never(.*)",
671+
"class .*\\bProtocol\\):",
672+
"@(abc\\.)?abstractmethod",
673+
]
674+
omit = ["*/pytest-of-*/*"]
675+
676+
def _get_source():
677+
return [get_source_dir_str()]
673678

674679
return ConfigSpec.from_flat(
675680
file_managers=[
@@ -693,28 +698,79 @@ def get_config_spec(self) -> ConfigSpec:
693698
ConfigItem(
694699
description="Run Configuration",
695700
root={
696-
Path(".coveragerc"): ConfigEntry(keys=["run"], value=run),
701+
Path(".coveragerc"): ConfigEntry(keys=["run"]),
702+
Path("setup.cfg"): ConfigEntry(keys=["coverage:run"]),
703+
Path("tox.ini"): ConfigEntry(keys=["coverage:run"]),
704+
Path("pyproject.toml"): ConfigEntry(
705+
keys=["tool", "coverage", "run"]
706+
),
707+
},
708+
),
709+
ConfigItem(
710+
description="Source Configuration",
711+
root={
712+
Path(".coveragerc"): ConfigEntry(
713+
keys=["run", "source"], get_value=_get_source
714+
),
697715
Path("setup.cfg"): ConfigEntry(
698-
keys=["coverage:run"], value=run
716+
keys=["coverage:run", "source"], get_value=_get_source
717+
),
718+
Path("tox.ini"): ConfigEntry(
719+
keys=["coverage:run", "source"], get_value=_get_source
699720
),
700-
Path("tox.ini"): ConfigEntry(keys=["coverage:run"], value=run),
701721
Path("pyproject.toml"): ConfigEntry(
702-
keys=["tool", "coverage", "run"], value=run
722+
keys=["tool", "coverage", "run", "source"],
723+
get_value=_get_source,
703724
),
704725
},
705726
),
706727
ConfigItem(
707728
description="Report Configuration",
708729
root={
709-
Path(".coveragerc"): ConfigEntry(keys=["report"], value=report),
730+
Path(".coveragerc"): ConfigEntry(keys=["report"]),
731+
Path("setup.cfg"): ConfigEntry(keys=["coverage:report"]),
732+
Path("tox.ini"): ConfigEntry(keys=["coverage:report"]),
733+
Path("pyproject.toml"): ConfigEntry(
734+
keys=["tool", "coverage", "report"]
735+
),
736+
},
737+
),
738+
ConfigItem(
739+
description="Exclude Also Configuration",
740+
root={
741+
Path(".coveragerc"): ConfigEntry(
742+
keys=["report", "exclude_also"],
743+
get_value=lambda: exclude_also,
744+
),
710745
Path("setup.cfg"): ConfigEntry(
711-
keys=["coverage:report"], value=report
746+
keys=["coverage:report", "exclude_also"],
747+
get_value=lambda: exclude_also,
712748
),
713749
Path("tox.ini"): ConfigEntry(
714-
keys=["coverage:report"], value=report
750+
keys=["coverage:report", "exclude_also"],
751+
get_value=lambda: exclude_also,
715752
),
716753
Path("pyproject.toml"): ConfigEntry(
717-
keys=["tool", "coverage", "report"], value=report
754+
keys=["tool", "coverage", "report", "exclude_also"],
755+
get_value=lambda: exclude_also,
756+
),
757+
},
758+
),
759+
ConfigItem(
760+
description="Omit Configuration",
761+
root={
762+
Path(".coveragerc"): ConfigEntry(
763+
keys=["report", "omit"], get_value=lambda: omit
764+
),
765+
Path("setup.cfg"): ConfigEntry(
766+
keys=["coverage:report", "omit"], get_value=lambda: omit
767+
),
768+
Path("tox.ini"): ConfigEntry(
769+
keys=["coverage:report", "omit"], get_value=lambda: omit
770+
),
771+
Path("pyproject.toml"): ConfigEntry(
772+
keys=["tool", "coverage", "report", "omit"],
773+
get_value=lambda: omit,
718774
),
719775
},
720776
),
@@ -964,14 +1020,22 @@ def get_config_spec(self) -> ConfigSpec:
9641020
resolution="first",
9651021
config_items=[
9661022
ConfigItem(
967-
description="Overall config",
1023+
description="Overall Config",
9681024
root={
9691025
Path("pyproject.toml"): ConfigEntry(
970-
keys=["tool", "pyproject-fmt"],
971-
value={"keep_full_version": True},
1026+
keys=["tool", "pyproject-fmt"]
9721027
)
9731028
},
974-
)
1029+
),
1030+
ConfigItem(
1031+
description="Keep Full Version",
1032+
root={
1033+
Path("pyproject.toml"): ConfigEntry(
1034+
keys=["tool", "pyproject-fmt", "keep_full_version"],
1035+
get_value=lambda: True,
1036+
)
1037+
},
1038+
),
9751039
],
9761040
)
9771041

@@ -1114,17 +1178,20 @@ def get_config_spec(self) -> ConfigSpec:
11141178
description="INI-Style Options",
11151179
root={
11161180
Path("pytest.ini"): ConfigEntry(
1117-
keys=["pytest"], value=value_ini
1181+
keys=["pytest"], get_value=lambda: value_ini
11181182
),
11191183
Path(".pytest.ini"): ConfigEntry(
1120-
keys=["pytest"], value=value_ini
1184+
keys=["pytest"], get_value=lambda: value_ini
11211185
),
11221186
Path("pyproject.toml"): ConfigEntry(
1123-
keys=["tool", "pytest", "ini_options"], value=value
1187+
keys=["tool", "pytest", "ini_options"],
1188+
get_value=lambda: value,
1189+
),
1190+
Path("tox.ini"): ConfigEntry(
1191+
keys=["pytest"], get_value=lambda: value_ini
11241192
),
1125-
Path("tox.ini"): ConfigEntry(keys=["pytest"], value=value_ini),
11261193
Path("setup.cfg"): ConfigEntry(
1127-
keys=["tool:pytest"], value=value_ini
1194+
keys=["tool:pytest"], get_value=lambda: value_ini
11281195
),
11291196
},
11301197
),
@@ -1316,14 +1383,14 @@ def get_config_spec(self) -> ConfigSpec:
13161383
description="Line length",
13171384
root={
13181385
Path(".ruff.toml"): ConfigEntry(
1319-
keys=["line-length"], value=line_length
1386+
keys=["line-length"], get_value=lambda: line_length
13201387
),
13211388
Path("ruff.toml"): ConfigEntry(
1322-
keys=["line-length"], value=line_length
1389+
keys=["line-length"], get_value=lambda: line_length
13231390
),
13241391
Path("pyproject.toml"): ConfigEntry(
13251392
keys=["tool", "ruff", "line-length"],
1326-
value=line_length,
1393+
get_value=lambda: line_length,
13271394
),
13281395
},
13291396
),

tests/usethis/test_usethis_tool.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def get_config_spec(self) -> ConfigSpec:
7878
ConfigItem(
7979
root={
8080
Path("pyproject.toml"): ConfigEntry(
81-
keys=["tool", self.name], value={"key": "value"}
81+
keys=["tool", self.name], get_value=lambda: {"key": "value"}
8282
)
8383
}
8484
)
@@ -737,7 +737,7 @@ def get_config_spec(self) -> ConfigSpec:
737737
root={
738738
Path("pyproject.toml"): ConfigEntry(
739739
keys=["tool", self.name],
740-
value={"key": "value"},
740+
get_value=lambda: {"key": "value"},
741741
)
742742
}
743743
)
@@ -787,7 +787,7 @@ def get_config_spec(self) -> ConfigSpec:
787787
root={
788788
Path("pyproject.toml"): ConfigEntry(
789789
keys=["tool", self.name],
790-
value={
790+
get_value=lambda: {
791791
"name": "Modular Design",
792792
"root_packages": ["example"],
793793
},

0 commit comments

Comments
 (0)