Skip to content

Commit 882ef63

Browse files
Enhance testing capabilities for pyproject reading and version inference
- Introduced `_given_result` parameter in `read_pyproject` - expand the setuptools integration points with it - Improved error handling by allowing direct injection of `PyProjectData`, `InvalidTomlError`, or `FileNotFoundError` for better testability.
1 parent b3c34c0 commit 882ef63

File tree

3 files changed

+52
-27
lines changed

3 files changed

+52
-27
lines changed

src/setuptools_scm/_integration/pyproject_reading.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
from typing import Sequence
88

99
from .. import _log
10+
from .. import _types as _t
1011
from .._requirement_cls import extract_package_name
1112
from .toml import TOML_RESULT
13+
from .toml import InvalidTomlError
1214
from .toml import read_toml_content
1315

1416
log = _log.log.getChild("pyproject_reading")
@@ -126,7 +128,28 @@ def read_pyproject(
126128
path: Path = Path("pyproject.toml"),
127129
tool_name: str = "setuptools_scm",
128130
canonical_build_package_name: str = "setuptools-scm",
131+
_given_result: _t.GivenPyProjectResult = None,
129132
) -> PyProjectData:
133+
"""Read and parse pyproject configuration.
134+
135+
This function supports dependency injection for tests via `_given_result`.
136+
137+
Parameters:
138+
- path: Path to the pyproject file
139+
- tool_name: The tool section name (default: `setuptools_scm`)
140+
- canonical_build_package_name: Normalized build requirement name
141+
- _given_result: Optional testing hook. Can be:
142+
- PyProjectData: returned directly
143+
- InvalidTomlError | FileNotFoundError: raised directly
144+
- None: read from filesystem
145+
"""
146+
147+
if _given_result is not None:
148+
if isinstance(_given_result, PyProjectData):
149+
return _given_result
150+
if isinstance(_given_result, (InvalidTomlError, FileNotFoundError)):
151+
raise _given_result
152+
130153
defn = read_toml_content(path)
131154

132155
requires: list[str] = defn.get("build-system", {}).get("requires", [])

src/setuptools_scm/_integration/setuptools.py

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import setuptools
1111

12+
from .. import _types as _t
1213
from .pyproject_reading import PyProjectData
1314
from .pyproject_reading import read_pyproject
1415
from .setup_cfg import _dist_name_from_legacy
@@ -68,7 +69,7 @@ def version_keyword(
6869
keyword: str,
6970
value: bool | dict[str, Any] | Callable[[], dict[str, Any]],
7071
*,
71-
_given_pyproject_data: PyProjectData | None = None,
72+
_given_pyproject_data: _t.GivenPyProjectResult = None,
7273
) -> None:
7374
"""apply version infernce when setup(use_scm_version=...) is used
7475
this takes priority over the finalize_options based version
@@ -87,20 +88,15 @@ def version_keyword(
8788

8889
was_set_by_infer = getattr(dist, "_setuptools_scm_version_set_by_infer", False)
8990

90-
# Get pyproject data
91-
if _given_pyproject_data is not None:
92-
pyproject_data = _given_pyproject_data
93-
else:
94-
try:
95-
pyproject_data = read_pyproject()
96-
except FileNotFoundError:
97-
log.debug("pyproject.toml not found, proceeding with empty configuration")
98-
pyproject_data = PyProjectData.empty(
99-
Path("pyproject.toml"), "setuptools_scm"
100-
)
101-
except InvalidTomlError as e:
102-
log.debug("Configuration issue in pyproject.toml: %s", e)
103-
return
91+
# Get pyproject data (support direct injection for tests)
92+
try:
93+
pyproject_data = read_pyproject(_given_result=_given_pyproject_data)
94+
except FileNotFoundError:
95+
log.debug("pyproject.toml not found, proceeding with empty configuration")
96+
pyproject_data = PyProjectData.empty(Path("pyproject.toml"), "setuptools_scm")
97+
except InvalidTomlError as e:
98+
log.debug("Configuration issue in pyproject.toml: %s", e)
99+
return
104100

105101
result = get_version_inference_config(
106102
dist_name=dist_name,
@@ -114,7 +110,9 @@ def version_keyword(
114110

115111

116112
def infer_version(
117-
dist: setuptools.Distribution, *, _given_pyproject_data: PyProjectData | None = None
113+
dist: setuptools.Distribution,
114+
*,
115+
_given_pyproject_data: _t.GivenPyProjectResult = None,
118116
) -> None:
119117
"""apply version inference from the finalize_options hook
120118
this is the default for pyproject.toml based projects that don't use the use_scm_version keyword
@@ -127,17 +125,14 @@ def infer_version(
127125

128126
dist_name = _dist_name_from_legacy(dist)
129127

130-
if _given_pyproject_data is not None:
131-
pyproject_data = _given_pyproject_data
132-
else:
133-
try:
134-
pyproject_data = read_pyproject()
135-
except FileNotFoundError:
136-
log.debug("pyproject.toml not found, skipping infer_version")
137-
return
138-
except InvalidTomlError as e:
139-
log.debug("Configuration issue in pyproject.toml: %s", e)
140-
return
128+
try:
129+
pyproject_data = read_pyproject(_given_result=_given_pyproject_data)
130+
except FileNotFoundError:
131+
log.debug("pyproject.toml not found, skipping infer_version")
132+
return
133+
except InvalidTomlError as e:
134+
log.debug("Configuration issue in pyproject.toml: %s", e)
135+
return
141136

142137
result = get_version_inference_config(
143138
dist_name=dist_name,

src/setuptools_scm/_types.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from typing_extensions import TypeAlias
1919

2020
from . import version
21+
from ._integration.pyproject_reading import PyProjectData
22+
from ._integration.toml import InvalidTomlError
2123

2224
PathT: TypeAlias = Union["os.PathLike[str]", str]
2325

@@ -29,3 +31,8 @@
2931

3032
# Git pre-parse function types
3133
GIT_PRE_PARSE: TypeAlias = Union[str, None]
34+
35+
# Testing injection types for configuration reading
36+
GivenPyProjectResult: TypeAlias = Union[
37+
"PyProjectData", "InvalidTomlError", FileNotFoundError, None
38+
]

0 commit comments

Comments
 (0)