Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog


## v9.0.1

### Fixed

- fix #1180: ensure version dumping works when no scm_version is given (problems in downstreams)
- fix #1181: config - reintroduce controll over when we expect a section to be present
as it turns out theres valid use cases where setuptools_scm is not direct part of the dependencies

## v9.0.0

### Breaking
Expand Down
13 changes: 12 additions & 1 deletion src/setuptools_scm/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ def from_file(
name: str | os.PathLike[str] = "pyproject.toml",
dist_name: str | None = None,
missing_file_ok: bool = False,
missing_section_ok: bool = False,
**kwargs: Any,
) -> Configuration:
"""
Expand All @@ -279,10 +280,20 @@ def from_file(
not installed or the file has invalid format or does
not contain setuptools_scm configuration (either via
_ [tool.setuptools_scm] section or build-system.requires).

Parameters:
- name: path to pyproject.toml
- dist_name: name of the distribution
- missing_file_ok: if True, do not raise an error if the file is not found
- missing_section_ok: if True, do not raise an error if the section is not found
(workaround for not walking the dependency graph when figuring out if setuptools_scm is a dependency)
- **kwargs: additional keyword arguments to pass to the Configuration constructor
"""

try:
pyproject_data = _read_pyproject(Path(name))
pyproject_data = _read_pyproject(
Path(name), missing_section_ok=missing_section_ok
)
except FileNotFoundError:
if missing_file_ok:
log.warning("File %s not found, using empty configuration", name)
Expand Down
31 changes: 23 additions & 8 deletions src/setuptools_scm/_integration/dump_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,34 @@ def _validate_template(target: Path, template: str | None) -> str:
return template


class DummyScmVersion:
@property
def short_node(self) -> str | None:
return None


def write_version_to_path(
target: Path, template: str | None, version: str, scm_version: ScmVersion | None
target: Path,
template: str | None,
version: str,
scm_version: ScmVersion | None = None,
) -> None:
final_template = _validate_template(target, template)
log.debug("dump %s into %s", version, target)
version_tuple = _version_as_tuple(version)
if scm_version is not None:
content = final_template.format(
version=version,
version_tuple=version_tuple,
scm_version=scm_version,
if scm_version is None:
warnings.warn(
"write_version_to_path called without scm_version parameter. "
"This will be required in a future version. "
"Pass scm_version=None explicitly to suppress this warning.",
DeprecationWarning,
stacklevel=2,
)
else:
content = final_template.format(version=version, version_tuple=version_tuple)

content = final_template.format(
version=version,
version_tuple=version_tuple,
scm_version=scm_version or DummyScmVersion(),
)

target.write_text(content, encoding="utf-8")
3 changes: 2 additions & 1 deletion src/setuptools_scm/_integration/pyproject_reading.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def read_pyproject(
path: Path = Path("pyproject.toml"),
tool_name: str = "setuptools_scm",
build_package_names: Sequence[str] = ("setuptools_scm", "setuptools-scm"),
missing_section_ok: bool = False,
) -> PyProjectData:
defn = read_toml_content(path)
requires: list[str] = defn.get("build-system", {}).get("requires", [])
Expand All @@ -55,7 +56,7 @@ def read_pyproject(
try:
section = defn.get("tool", {})[tool_name]
except LookupError as e:
if not is_required:
if not is_required and not missing_section_ok:
# Enhanced error message that mentions both configuration options
error = (
f"{path} does not contain a tool.{tool_name} section. "
Expand Down
1 change: 1 addition & 0 deletions src/setuptools_scm/_integration/setuptools.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def version_keyword(
config = _config.Configuration.from_file(
dist_name=dist_name,
missing_file_ok=True,
missing_section_ok=True,
**overrides,
)
_assign_version(dist, config)
Expand Down
58 changes: 58 additions & 0 deletions testing/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,61 @@ def test_has_command_logs_stderr(caplog: pytest.LogCaptureFixture) -> None:
def test_tag_to_version(tag: str, expected_version: str) -> None:
version = str(tag_to_version(tag, c))
assert version == expected_version


def test_write_version_to_path_deprecation_warning_none(tmp_path: Path) -> None:
"""Test that write_version_to_path warns when scm_version=None is passed."""
from setuptools_scm._integration.dump_version import write_version_to_path

target_file = tmp_path / "version.py"

# This should raise a deprecation warning when scm_version=None is explicitly passed
with pytest.warns(
DeprecationWarning, match="write_version_to_path called without scm_version"
):
write_version_to_path(
target=target_file,
template=None, # Use default template
version="1.2.3",
scm_version=None, # Explicitly passing None should warn
)

# Verify the file was created and contains the expected content
assert target_file.exists()
content = target_file.read_text(encoding="utf-8")

# Check that the version is correctly formatted
assert "__version__ = version = '1.2.3'" in content
assert "__version_tuple__ = version_tuple = (1, 2, 3)" in content

# Check that commit_id is set to None when scm_version is None
assert "__commit_id__ = commit_id = None" in content


def test_write_version_to_path_deprecation_warning_missing(tmp_path: Path) -> None:
"""Test that write_version_to_path warns when scm_version parameter is not provided."""
from setuptools_scm._integration.dump_version import write_version_to_path

target_file = tmp_path / "version.py"

# This should raise a deprecation warning when scm_version is not provided
with pytest.warns(
DeprecationWarning, match="write_version_to_path called without scm_version"
):
write_version_to_path(
target=target_file,
template=None, # Use default template
version="1.2.3",
# scm_version not provided - should warn
)

# Verify the file was created and contains the expected content
assert target_file.exists()
content = target_file.read_text(encoding="utf-8")

# Check that the version is correctly formatted
assert "__version__ = version = '1.2.3'" in content
assert "__version_tuple__ = version_tuple = (1, 2, 3)" in content

# Check that commit_id is set to None when scm_version is None
assert "__commit_id__ = commit_id = None" in content
32 changes: 32 additions & 0 deletions testing/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,3 +921,35 @@ def test_integration_function_call_order(
assert final_version == expected_final_version, (
f"Expected version '{expected_final_version}' but got '{final_version}'"
)


def test_version_keyword_no_scm_dependency_works(
wd: WorkDir, monkeypatch: pytest.MonkeyPatch
) -> None:
# Set up a git repository with a tag
wd.commit_testfile("test")
wd("git tag 1.0.0")
monkeypatch.chdir(wd.cwd)

# Create a pyproject.toml file WITHOUT setuptools_scm in build-system.requires
# and WITHOUT [tool.setuptools_scm] section
pyproject_content = """
[build-system]
requires = ["setuptools>=80"]
build-backend = "setuptools.build_meta"

[project]
name = "test-package-no-scm"
dynamic = ["version"]
"""
wd.write("pyproject.toml", pyproject_content)

import setuptools

from setuptools_scm._integration.setuptools import version_keyword

# Create distribution
dist = setuptools.Distribution({"name": "test-package-no-scm"})

version_keyword(dist, "use_scm_version", True)
assert dist.metadata.version == "1.0.0"
Loading