Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 549 fallback when scm missing #901

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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ features
* support passing log levels to SETUPTOOLS_SCM_DEBUG
* support using rich.logging as console log handler if installed
* fix #527: type annotation in default version template
* fix #549: use fallbacks when scm search raises CommandNotFoundError

bugfixes
--------
Expand Down
15 changes: 4 additions & 11 deletions src/setuptools_scm/_entrypoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from . import version

if TYPE_CHECKING:
from ._config import Configuration
from . import _types as _t
from ._config import Configuration, ParseFunction


log = _log.log.getChild("entrypoints")
Expand All @@ -27,21 +27,14 @@ def load(self) -> Any:
pass


def _version_from_entrypoints(
config: Configuration, fallback: bool = False
def version_from_entrypoint(
config: Configuration, entrypoint: str, root: _t.PathT
) -> version.ScmVersion | None:
if fallback:
entrypoint = "setuptools_scm.parse_scm_fallback"
root = config.fallback_root
else:
entrypoint = "setuptools_scm.parse_scm"
root = config.absolute_root

from .discover import iter_matching_entrypoints

log.debug("version_from_ep %s in %s", entrypoint, root)
for ep in iter_matching_entrypoints(root, entrypoint, config):
fn = ep.load()
fn: ParseFunction = ep.load()
maybe_version: version.ScmVersion | None = fn(root, config=config)
log.debug("%s found %r", ep, maybe_version)
if maybe_version is not None:
Expand Down
36 changes: 24 additions & 12 deletions src/setuptools_scm/_get_version.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import logging
import re
import warnings
from pathlib import Path
Expand All @@ -8,30 +9,41 @@
from typing import Pattern

from . import _config
from . import _entrypoints
from . import _run_cmd
from . import _types as _t
from ._config import Configuration
from ._entrypoints import _version_from_entrypoints
from ._overrides import _read_pretended_version_for
from ._version_cls import _validate_version_cls
from .version import format_version as _format_version
from .version import ScmVersion

_log = logging.getLogger(__name__)


def parse_scm_version(config: Configuration) -> ScmVersion | None:
if config.parse is not None:
parse_result = config.parse(config.absolute_root, config=config)
if parse_result is not None and not isinstance(parse_result, ScmVersion):
raise TypeError(
f"version parse result was {str!r}\n"
"please return a parsed version (ScmVersion)"
)
return parse_result
else:
return _version_from_entrypoints(config)
try:
if config.parse is not None:
parse_result = config.parse(config.absolute_root, config=config)
if parse_result is not None and not isinstance(parse_result, ScmVersion):
raise TypeError(
f"version parse result was {str!r}\n"
"please return a parsed version (ScmVersion)"
)
return parse_result
else:
entrypoint = "setuptools_scm.parse_scm"
root = config.absolute_root
return _entrypoints.version_from_entrypoint(config, entrypoint, root)
except _run_cmd.CommandNotFoundError as e:
_log.exception("command %s not found while parsing the scm, using fallbacks", e)
return None


def parse_fallback_version(config: Configuration) -> ScmVersion | None:
return _version_from_entrypoints(config, fallback=True)
entrypoint = "setuptools_scm.parse_scm_fallback"
root = config.fallback_root
return _entrypoints.version_from_entrypoint(config, entrypoint, root)


def _do_parse(config: Configuration) -> ScmVersion | None:
Expand Down
6 changes: 5 additions & 1 deletion src/setuptools_scm/_run_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ def has_command(
return res


class CommandNotFoundError(LookupError, FileNotFoundError):
pass


def require_command(name: str) -> None:
if not has_command(name, warn=False):
raise OSError(f"{name!r} was not found")
raise CommandNotFoundError(name)
9 changes: 7 additions & 2 deletions testing/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from setuptools_scm import git
from setuptools_scm import NonNormalizedVersion
from setuptools_scm._file_finders.git import git_find_files
from setuptools_scm._run_cmd import CommandNotFoundError
from setuptools_scm._run_cmd import CompletedProcess
from setuptools_scm._run_cmd import has_command
from setuptools_scm._run_cmd import run
Expand Down Expand Up @@ -93,8 +94,12 @@ def test_root_search_parent_directories(

def test_git_gone(wd: WorkDir, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("PATH", str(wd.cwd / "not-existing"))
with pytest.raises(EnvironmentError, match="'git' was not found"):
git.parse(str(wd.cwd), Configuration(), git.DEFAULT_DESCRIBE)

wd.write("pyproject.toml", "[tool.setuptools_scm]")
with pytest.raises(CommandNotFoundError, match=r"git"):
git.parse(wd.cwd, Configuration(), git.DEFAULT_DESCRIBE)

assert wd.get_version(fallback_version="1.0") == "1.0"


@pytest.mark.issue("https://github.com/pypa/setuptools_scm/issues/298")
Expand Down
8 changes: 6 additions & 2 deletions testing/test_mercurial.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import setuptools_scm._file_finders
from setuptools_scm import Configuration
from setuptools_scm._run_cmd import CommandNotFoundError
from setuptools_scm._run_cmd import has_command
from setuptools_scm.hg import archival_to_version
from setuptools_scm.hg import parse
Expand Down Expand Up @@ -55,8 +56,11 @@ def test_archival_to_version(expected: str, data: dict[str, str]) -> None:
def test_hg_gone(wd: WorkDir, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("PATH", str(wd.cwd / "not-existing"))
config = Configuration()
with pytest.raises(EnvironmentError, match="'hg' was not found"):
parse(str(wd.cwd), config=config)
wd.write("pyproject.toml", "[tool.setuptools_scm]")
with pytest.raises(CommandNotFoundError, match=r"hg"):
parse(wd.cwd, config=config)

assert wd.get_version(fallback_version="1.0") == "1.0"


def test_find_files_stop_at_root_hg(
Expand Down
Loading