Skip to content

Commit 206742a

Browse files
return simplified activation with a extra to prevent regressions
1 parent e85f66c commit 206742a

File tree

9 files changed

+307
-35
lines changed

9 files changed

+307
-35
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Added
6+
7+
- add simplified activation via `setuptools-scm[simple]` extra
8+
9+
A new streamlined way to enable version inference without requiring a `[tool.setuptools_scm]` section.
10+
When `setuptools-scm[simple]` is in `build-system.requires` and `version` is in `project.dynamic`,
11+
version inference is automatically enabled with default settings.
12+
13+
14+
### removed
15+
- unchecked simplified activation - too many projects use setups where it would fail
16+
17+
318
## v9.1.1
419

520
### fixed

docs/config.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,23 @@
22

33
## When is configuration needed?
44

5-
Starting with setuptools-scm 9.0, explicit configuration is required to enable
6-
version inference, either via the `[tool.setuptools_scm]` section or the
7-
`use_scm_version` setup keyword. Listing `setuptools_scm` in `build-system.requires`
8-
and declaring `project.dynamic = ["version"]` no longer auto-enables inference.
5+
setuptools-scm provides flexible activation options:
6+
7+
### Simplified Activation (No Configuration Needed)
8+
9+
For basic usage, use the `simple` extra with no configuration:
10+
11+
```toml title="pyproject.toml"
12+
[build-system]
13+
requires = ["setuptools>=80", "setuptools-scm[simple]>=8"]
14+
15+
[project]
16+
dynamic = ["version"]
17+
```
18+
19+
This automatically enables version inference with default settings.
20+
21+
### Explicit Configuration (Full Control)
922

1023
Use the `[tool.setuptools_scm]` section when you need to:
1124
- Write version files (`version_file`)

docs/index.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,36 @@ Note: `setuptools-scm>=8` intentionally doesn't depend on setuptools to ease non
3030
Please ensure a recent version of setuptools is installed (minimum: >=61, recommended: >=80 for best compatibility).
3131
Support for setuptools <80 is deprecated and will be removed in a future release.
3232

33+
**Simplified setup (recommended for basic usage):**
3334

3435
```toml title="pyproject.toml"
3536
[build-system]
36-
requires = ["setuptools>=80", "setuptools-scm>=8"]
37+
requires = ["setuptools>=80", "setuptools-scm[simple]>=8"]
3738
build-backend = "setuptools.build_meta"
3839

3940
[project]
4041
name = "example"
4142
# Important: Remove any existing version declaration
4243
# version = "0.0.1"
4344
dynamic = ["version"]
44-
# more missing
45+
46+
# No additional configuration needed!
47+
```
48+
49+
**With custom configuration:**
50+
51+
```toml title="pyproject.toml"
52+
[build-system]
53+
requires = ["setuptools>=80", "setuptools-scm>=8"]
54+
build-backend = "setuptools.build_meta"
55+
56+
[project]
57+
name = "example"
58+
dynamic = ["version"]
4559

4660
[tool.setuptools_scm]
47-
´´´
61+
# Custom configuration options go here
62+
```
4863

4964

5065
!!! tip "Recommended Tag Format"

docs/usage.md

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,40 @@
77
Support for setuptools <80 is deprecated and will be removed in a future release.
88
The examples below use `setuptools>=80` as the recommended version.
99

10-
There are two ways to enable `setuptools-scm` at build time:
10+
There are three ways to enable `setuptools-scm` at build time:
1111

12-
### Explicit Configuration (required)
12+
### Simplified Activation (new)
1313

14-
Add a `tool.setuptools_scm` section to explicitly opt-in to version inference:
14+
For basic usage without custom configuration, use the `simple` extra:
15+
16+
```toml title="pyproject.toml"
17+
[build-system]
18+
requires = ["setuptools>=80", "setuptools-scm[simple]>=8"]
19+
build-backend = "setuptools.build_meta"
20+
21+
[project]
22+
# version = "0.0.1" # Remove any existing version parameter.
23+
dynamic = ["version"]
24+
25+
# No [tool.setuptools_scm] section needed for basic usage!
26+
```
27+
28+
This streamlined approach automatically enables version inference when:
29+
- `setuptools-scm[simple]` is listed in `build-system.requires`
30+
- `version` is included in `project.dynamic`
31+
32+
!!! tip "When to use simplified activation"
33+
34+
Use simplified activation when you:
35+
- Want basic SCM version inference with default settings
36+
- Don't need custom version schemes or file writing
37+
- Prefer minimal configuration
38+
39+
Upgrade to explicit configuration if you need customization.
40+
41+
### Explicit Configuration (full control)
42+
43+
Add a `tool.setuptools_scm` section for custom configuration:
1544

1645
```toml title="pyproject.toml"
1746
[build-system]
@@ -41,19 +70,16 @@ must ensure build requirements are installed.
4170
Alternatively, enable `setuptools-scm` via the `use_scm_version` keyword in `setup.py`.
4271
This also counts as an explicit opt-in and does not require a tool section.
4372

44-
!!! warning "Simplified activation removed"
45-
46-
Previous documentation described a "simplified" activation where listing
47-
`setuptools_scm` in `build-system.requires` together with `project.dynamic = ["version"]`
48-
would auto-enable version inference. This behavior has been removed due to
49-
regressions and ambiguous activation. You must explicitly opt in via either:
73+
!!! note "Legacy simplified activation"
5074

51-
- a `[tool.setuptools_scm]` section, or
52-
- the `use_scm_version` setup keyword.
75+
Previous versions had a "simplified" activation where listing `setuptools_scm`
76+
in `build-system.requires` together with `project.dynamic = ["version"]` would
77+
auto-enable version inference. This behavior was removed due to regressions and
78+
ambiguous activation.
5379

54-
The presence of `setuptools_scm` (or `setuptools-scm`) in `build-system.requires`
55-
is still recommended to ensure the dependency is available during builds, but it
56-
no longer enables version inference by itself.
80+
The new simplified activation using the `[simple]` extra provides the same
81+
convenience but with explicit opt-in, making it clear when version inference
82+
should be enabled.
5783

5884
### Version files
5985

src/setuptools_scm/_integration/pyproject_reading.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class PyProjectData:
3131
is_required: bool
3232
section_present: bool
3333
project_present: bool
34+
build_requires: list[str]
3435

3536
@classmethod
3637
def for_testing(
@@ -41,6 +42,8 @@ def for_testing(
4142
project_present: bool = False,
4243
project_name: str | None = None,
4344
has_dynamic_version: bool = True,
45+
build_requires: list[str] | None = None,
46+
local_scheme: str | None = None,
4447
) -> PyProjectData:
4548
"""Create a PyProjectData instance for testing purposes."""
4649
project: TOML_RESULT
@@ -54,14 +57,22 @@ def for_testing(
5457
if project_present and has_dynamic_version:
5558
project["dynamic"] = ["version"]
5659

60+
if build_requires is None:
61+
build_requires = []
62+
if local_scheme is not None:
63+
assert section_present
64+
section = {"local_scheme": local_scheme}
65+
else:
66+
section = {}
5767
return cls(
5868
path=DEFAULT_PYPROJECT_PATH,
5969
tool_name=DEFAULT_TOOL_NAME,
6070
project=project,
61-
section={},
71+
section=section,
6272
is_required=is_required,
6373
section_present=section_present,
6474
project_present=project_present,
75+
build_requires=build_requires,
6576
)
6677

6778
@classmethod
@@ -76,6 +87,7 @@ def empty(
7687
is_required=False,
7788
section_present=False,
7889
project_present=False,
90+
build_requires=[],
7991
)
8092

8193
@property
@@ -95,14 +107,28 @@ def should_infer(self) -> bool:
95107
"""
96108
Determine if setuptools_scm should infer version based on configuration.
97109
98-
Only infer when an explicit [tool.setuptools_scm] section is present.
99-
The presence of setuptools-scm in build-system.requires or
100-
project.dynamic does NOT auto-enable inference.
110+
Infer when:
111+
1. An explicit [tool.setuptools_scm] section is present, OR
112+
2. setuptools-scm[simple] is in build-system.requires AND
113+
version is in project.dynamic
101114
102115
Returns:
103116
True if [tool.setuptools_scm] is present, otherwise False
104117
"""
105-
return self.section_present
118+
# Original behavior: explicit tool section
119+
if self.section_present:
120+
return True
121+
122+
# New behavior: simple extra + dynamic version
123+
if self.project_present:
124+
dynamic_fields = self.project.get("dynamic", [])
125+
if "version" in dynamic_fields:
126+
if has_build_package_with_extra(
127+
self.build_requires, "setuptools-scm", "simple"
128+
):
129+
return True
130+
131+
return False
106132

107133

108134
def has_build_package(
@@ -115,6 +141,34 @@ def has_build_package(
115141
return False
116142

117143

144+
def has_build_package_with_extra(
145+
requires: Sequence[str], canonical_build_package_name: str, extra_name: str
146+
) -> bool:
147+
"""Check if a build dependency has a specific extra.
148+
149+
Args:
150+
requires: List of requirement strings from build-system.requires
151+
canonical_build_package_name: The canonical package name to look for
152+
extra_name: The extra name to check for (e.g., "simple")
153+
154+
Returns:
155+
True if the package is found with the specified extra
156+
"""
157+
from .._requirement_cls import Requirement
158+
159+
for requirement_string in requires:
160+
try:
161+
requirement = Requirement(requirement_string)
162+
package_name = extract_package_name(requirement_string)
163+
if package_name == canonical_build_package_name:
164+
if extra_name in requirement.extras:
165+
return True
166+
except Exception:
167+
# If parsing fails, continue to next requirement
168+
continue
169+
return False
170+
171+
118172
def read_pyproject(
119173
path: Path = DEFAULT_PYPROJECT_PATH,
120174
tool_name: str = DEFAULT_TOOL_NAME,
@@ -160,7 +214,14 @@ def read_pyproject(
160214
project = defn.get("project", {})
161215
project_present = "project" in defn
162216
pyproject_data = PyProjectData(
163-
path, tool_name, project, section, is_required, section_present, project_present
217+
path,
218+
tool_name,
219+
project,
220+
section,
221+
is_required,
222+
section_present,
223+
project_present,
224+
requires,
164225
)
165226

166227
return pyproject_data

src/setuptools_scm/_requirement_cls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
__all__ = ["Requirement", "extract_package_name"]
4+
35
try:
46
from packaging.requirements import Requirement
57
from packaging.utils import canonicalize_name

testing/test_integration.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -633,14 +633,12 @@ def test_integration_function_call_order(
633633

634634
# Create PyProjectData with equivalent configuration - no file I/O!
635635
project_name = "test-call-order"
636-
pyproject_data = PyProjectData(
637-
path=Path("pyproject.toml"),
638-
tool_name="setuptools_scm",
639-
project={"name": project_name, "dynamic": ["version"]},
640-
section={"local_scheme": "no-local-version"}, # [tool.setuptools_scm] config
641-
is_required=True, # setuptools_scm in build-system.requires
642-
section_present=True, # [tool.setuptools_scm] section exists
643-
project_present=True, # [project] section exists
636+
pyproject_data = PyProjectData.for_testing(
637+
project_name=project_name,
638+
has_dynamic_version=True,
639+
project_present=True,
640+
section_present=True,
641+
local_scheme="no-local-version",
644642
)
645643

646644
dist = create_clean_distribution(project_name)

0 commit comments

Comments
 (0)