Skip to content

Commit 2bfc568

Browse files
read version from setup.cfg
1 parent 10a96fb commit 2bfc568

File tree

3 files changed

+87
-15
lines changed

3 files changed

+87
-15
lines changed

src/setuptools_scm/_integration/setup_cfg.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,36 @@
22

33
import os
44

5+
from dataclasses import dataclass
6+
from pathlib import Path
7+
58
import setuptools
69

710

8-
def read_dist_name_from_setup_cfg(
9-
input: str | os.PathLike[str] = "setup.cfg",
10-
) -> str | None:
11-
# minimal effort to read dist_name off setup.cfg metadata
11+
@dataclass
12+
class SetuptoolsBasicData:
13+
path: Path
14+
name: str | None
15+
version: str | None
16+
17+
18+
def read_setup_cfg(input: str | os.PathLike[str] = "setup.cfg") -> SetuptoolsBasicData:
19+
"""Parse setup.cfg and return unified data. Does not raise if file is missing."""
1220
import configparser
1321

22+
path = Path(input)
1423
parser = configparser.ConfigParser()
1524
parser.read([input], encoding="utf-8")
16-
dist_name = parser.get("metadata", "name", fallback=None)
17-
return dist_name
25+
26+
name = parser.get("metadata", "name", fallback=None)
27+
version = parser.get("metadata", "version", fallback=None)
28+
return SetuptoolsBasicData(path=path, name=name, version=version)
1829

1930

20-
def _dist_name_from_legacy(dist: setuptools.Distribution) -> str | None:
21-
return dist.metadata.name or read_dist_name_from_setup_cfg()
31+
def extract_from_legacy(dist: setuptools.Distribution) -> SetuptoolsBasicData:
32+
base = read_setup_cfg()
33+
if base.name is None:
34+
base.name = dist.metadata.name
35+
if base.version is None:
36+
base.version = dist.metadata.version
37+
return base

src/setuptools_scm/_integration/setuptools.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from .. import _types as _t
1313
from .pyproject_reading import PyProjectData
1414
from .pyproject_reading import read_pyproject
15-
from .setup_cfg import _dist_name_from_legacy
15+
from .setup_cfg import extract_from_legacy
1616
from .toml import InvalidTomlError
1717
from .version_inference import get_version_inference_config
1818

@@ -85,7 +85,8 @@ def version_keyword(
8585
"dist_name may not be specified in the setup keyword "
8686
)
8787

88-
dist_name: str | None = _dist_name_from_legacy(dist)
88+
legacy_data = extract_from_legacy(dist)
89+
dist_name: str | None = legacy_data.name
8990

9091
was_set_by_infer = getattr(dist, "_setuptools_scm_version_set_by_infer", False)
9192

@@ -101,7 +102,7 @@ def version_keyword(
101102

102103
result = _get_version_inference_config(
103104
dist_name=dist_name,
104-
current_version=dist.metadata.version,
105+
current_version=legacy_data.version or pyproject_data.project.get("version"),
105106
pyproject_data=pyproject_data,
106107
overrides=overrides,
107108
was_set_by_infer=was_set_by_infer,
@@ -125,7 +126,8 @@ def infer_version(
125126

126127
_log_hookstart("infer_version", dist)
127128

128-
dist_name = _dist_name_from_legacy(dist)
129+
legacy_data = extract_from_legacy(dist)
130+
dist_name = legacy_data.name
129131

130132
try:
131133
pyproject_data = read_pyproject(_given_result=_given_pyproject_data)
@@ -138,7 +140,7 @@ def infer_version(
138140

139141
result = _get_version_inference_config(
140142
dist_name=dist_name,
141-
current_version=dist.metadata.version,
143+
current_version=legacy_data.version or pyproject_data.project.get("version"),
142144
pyproject_data=pyproject_data,
143145
)
144146
result.apply(dist)

testing/test_integration.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from setuptools_scm._integration import setuptools as setuptools_integration
2020
from setuptools_scm._integration.pyproject_reading import PyProjectData
21+
from setuptools_scm._integration.setup_cfg import SetuptoolsBasicData
2122
from setuptools_scm._requirement_cls import extract_package_name
2223

2324
if TYPE_CHECKING:
@@ -645,11 +646,64 @@ def test_unicode_in_setup_cfg(tmp_path: Path) -> None:
645646
),
646647
encoding="utf-8",
647648
)
648-
from setuptools_scm._integration.setup_cfg import read_dist_name_from_setup_cfg
649+
from setuptools_scm._integration.setup_cfg import read_setup_cfg
649650

650-
name = read_dist_name_from_setup_cfg(cfg)
651+
name = read_setup_cfg(cfg).name
651652
assert name == "configparser"
652653

654+
# also ensure we can parse a version if present (legacy projects)
655+
cfg.write_text(
656+
textwrap.dedent(
657+
"""
658+
[metadata]
659+
name = configparser
660+
version = 1.2.3
661+
"""
662+
),
663+
encoding="utf-8",
664+
)
665+
666+
data = read_setup_cfg(cfg)
667+
assert isinstance(data, SetuptoolsBasicData)
668+
assert data.name == "configparser"
669+
assert data.version == "1.2.3"
670+
671+
672+
def test_setup_cfg_version_prevents_inference_version_keyword(
673+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
674+
) -> None:
675+
# Legacy project with version in setup.cfg
676+
cfg = tmp_path / "setup.cfg"
677+
cfg.write_text(
678+
textwrap.dedent(
679+
"""
680+
[metadata]
681+
name = legacy-proj
682+
version = 0.9.0
683+
"""
684+
),
685+
encoding="utf-8",
686+
)
687+
688+
# No pyproject.toml
689+
monkeypatch.chdir(tmp_path)
690+
691+
dist = create_clean_distribution("legacy-proj")
692+
693+
# Using keyword should detect an existing version via setup.cfg and avoid inferring
694+
from setuptools_scm._integration import setuptools as setuptools_integration
695+
from setuptools_scm._integration.pyproject_reading import PyProjectData
696+
697+
setuptools_integration.version_keyword(
698+
dist,
699+
"use_scm_version",
700+
True,
701+
_given_pyproject_data=PyProjectData.empty(tmp_path / "pyproject.toml"),
702+
)
703+
704+
# setuptools_scm should not set a version when setup.cfg already provided one
705+
assert dist.metadata.version is None
706+
653707

654708
def test_setuptools_version_keyword_ensures_regex(
655709
wd: WorkDir,

0 commit comments

Comments
 (0)