Skip to content

Commit dfadacc

Browse files
Refactor version inference logic to use should_infer method for dynamic version verification
- Introduced should_infer method in PyProjectData to determine if version inference should proceed based on configuration. - Updated version_inference.py to utilize should_infer for handling version inference conditions. - Modified tests to reflect changes in dynamic version verification and ensure proper error handling when dynamic=['version'] is missing.
1 parent 5413460 commit dfadacc

File tree

3 files changed

+77
-48
lines changed

3 files changed

+77
-48
lines changed

src/setuptools_scm/_integration/pyproject_reading.py

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,20 @@ def for_testing(
3333
section_present: bool = False,
3434
project_present: bool = False,
3535
project_name: str | None = None,
36+
has_dynamic_version: bool = True,
3637
) -> PyProjectData:
3738
"""Create a PyProjectData instance for testing purposes."""
39+
project: TOML_RESULT
3840
if project_name is not None:
3941
project = {"name": project_name}
4042
assert project_present
4143
else:
4244
project = {}
45+
46+
# If project is present and has_dynamic_version is True, add dynamic=['version']
47+
if project_present and has_dynamic_version:
48+
project["dynamic"] = ["version"]
49+
4350
return cls(
4451
path=Path("pyproject.toml"),
4552
tool_name="setuptools_scm",
@@ -54,22 +61,43 @@ def for_testing(
5461
def project_name(self) -> str | None:
5562
return self.project.get("name")
5663

57-
def verify_dynamic_version_when_required(self) -> None:
58-
"""Verify that dynamic=['version'] is set when setuptools-scm is used as build dependency indicator."""
59-
if self.is_required and not self.section_present:
60-
# When setuptools-scm is in build-system.requires but no tool section exists,
61-
# we need to verify that dynamic=['version'] is set in the project section
62-
# But only if there's actually a project section
63-
if not self.project_present:
64-
# No project section, so don't auto-activate setuptools_scm
65-
return
66-
dynamic = self.project.get("dynamic", [])
67-
if "version" not in dynamic:
68-
raise ValueError(
69-
f"{self.path}: setuptools-scm is present in [build-system].requires "
70-
f"but dynamic=['version'] is not set in [project]. "
71-
f"Either add dynamic=['version'] to [project] or add a [tool.{self.tool_name}] section."
72-
)
64+
def should_infer(self) -> bool:
65+
"""
66+
Determine if setuptools_scm should infer version based on configuration.
67+
68+
This method only considers the pyproject.toml configuration state.
69+
It does not consider version_keyword context (overrides always infer).
70+
71+
Returns:
72+
True if version inference should proceed based on configuration
73+
74+
Raises:
75+
ValueError: If setuptools-scm is required but dynamic=['version'] is missing
76+
"""
77+
# If there's a tool section, always infer
78+
if self.section_present:
79+
return True
80+
81+
# If not required, don't auto-activate for infer_version
82+
if not self.is_required:
83+
return False
84+
85+
# setuptools-scm is required but no tool section
86+
if not self.project_present:
87+
# No project section - don't auto-activate
88+
return False
89+
90+
# Project section exists - check for dynamic=['version']
91+
dynamic = self.project.get("dynamic", [])
92+
if "version" not in dynamic:
93+
raise ValueError(
94+
f"{self.path}: setuptools-scm is present in [build-system].requires "
95+
f"but dynamic=['version'] is not set in [project]. "
96+
f"Either add dynamic=['version'] to [project] or add a [tool.{self.tool_name}] section."
97+
)
98+
99+
# All conditions met
100+
return True
73101

74102

75103
def has_build_package(
@@ -134,9 +162,6 @@ def read_pyproject(
134162
path, tool_name, project, section, is_required, section_present, project_present
135163
)
136164

137-
# Verify dynamic version when setuptools-scm is used as build dependency indicator
138-
pyproject_data.verify_dynamic_version_when_required()
139-
140165
return pyproject_data
141166

142167

src/setuptools_scm/_integration/version_inference.py

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -152,31 +152,26 @@ def get_version_inference_config(
152152
if dist_name == "setuptools-scm":
153153
return VersionInferenceNoOp()
154154

155-
# Handle missing configuration
156-
if not pyproject_data.is_required and not pyproject_data.section_present:
157-
# If version_keyword was called (overrides is not None), activate setuptools_scm
158-
# This handles both use_scm_version=True (empty {}) and use_scm_version={config}
159-
if overrides is not None:
160-
return VersionInferenceConfig(
161-
dist_name=dist_name,
162-
pyproject_data=pyproject_data,
163-
overrides=overrides,
164-
)
165-
# If infer_version was called (overrides is None), only activate with config
166-
return VersionInferenceNoOp()
155+
# version_keyword (with overrides) always tries to infer
156+
if overrides is not None:
157+
return VersionInferenceConfig(
158+
dist_name=dist_name,
159+
pyproject_data=pyproject_data,
160+
overrides=overrides,
161+
)
167162

168-
# Handle missing project section when required
169-
if (
170-
pyproject_data.is_required
171-
and not pyproject_data.section_present
172-
and not pyproject_data.project_present
173-
and overrides is None # Only return NoOp for infer_version, not version_keyword
174-
):
163+
# infer_version (no overrides) uses pyproject configuration to decide
164+
try:
165+
should_proceed = pyproject_data.should_infer()
166+
except ValueError:
167+
# For infer_version, silently skip on configuration issues (auto-activation shouldn't error)
175168
return VersionInferenceNoOp()
176169

177-
# All conditions met - proceed with inference
178-
return VersionInferenceConfig(
179-
dist_name=dist_name,
180-
pyproject_data=pyproject_data,
181-
overrides=overrides,
182-
)
170+
if should_proceed:
171+
return VersionInferenceConfig(
172+
dist_name=dist_name,
173+
pyproject_data=pyproject_data,
174+
overrides=overrides,
175+
)
176+
else:
177+
return VersionInferenceNoOp()

testing/test_integration.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ def test_version_keyword_no_scm_dependency_works(
11811181
def test_verify_dynamic_version_when_required_missing_dynamic(
11821182
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
11831183
) -> None:
1184-
"""Test that verification fails when setuptools-scm is in build-system.requires but dynamic=['version'] is missing"""
1184+
"""Test that should_infer raises ValueError when setuptools-scm is in build-system.requires but dynamic=['version'] is missing"""
11851185
if sys.version_info < (3, 11):
11861186
pytest.importorskip("tomli")
11871187

@@ -1202,11 +1202,14 @@ def test_verify_dynamic_version_when_required_missing_dynamic(
12021202

12031203
from setuptools_scm._integration.pyproject_reading import read_pyproject
12041204

1205-
# This should raise a ValueError because dynamic=['version'] is missing
1205+
# Read pyproject data first
1206+
pyproject_data = read_pyproject(Path("pyproject.toml"), missing_section_ok=True)
1207+
1208+
# should_infer should raise a ValueError when dynamic=['version'] is missing
12061209
with pytest.raises(
12071210
ValueError, match="dynamic=\\['version'\\] is not set in \\[project\\]"
12081211
):
1209-
read_pyproject(Path("pyproject.toml"), missing_section_ok=True)
1212+
pyproject_data.should_infer()
12101213

12111214

12121215
def test_verify_dynamic_version_when_required_with_tool_section(
@@ -1240,6 +1243,9 @@ def test_verify_dynamic_version_when_required_with_tool_section(
12401243
assert pyproject_data.is_required is True
12411244
assert pyproject_data.section_present is True
12421245

1246+
# should_infer should return True because tool section exists
1247+
assert pyproject_data.should_infer() is True
1248+
12431249

12441250
def test_verify_dynamic_version_when_required_with_dynamic(
12451251
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
@@ -1270,11 +1276,14 @@ def test_verify_dynamic_version_when_required_with_dynamic(
12701276
assert pyproject_data.is_required is True
12711277
assert pyproject_data.section_present is False
12721278

1279+
# should_infer should return True because dynamic=['version'] is set
1280+
assert pyproject_data.should_infer() is True
1281+
12731282

12741283
def test_infer_version_logs_debug_when_missing_dynamic_version(
12751284
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
12761285
) -> None:
1277-
"""Test that infer_version logs debug info when setuptools-scm is in build-system.requires but dynamic=['version'] is missing"""
1286+
"""Test that infer_version gracefully handles and logs debug info when setuptools-scm is in build-system.requires but dynamic=['version'] is missing"""
12781287
if sys.version_info < (3, 11):
12791288
pytest.importorskip("tomli")
12801289

0 commit comments

Comments
 (0)