vcs-versioning 2.0.1__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/CHANGELOG.md +12 -0
- {vcs_versioning-2.0.1/src/vcs_versioning.egg-info → vcs_versioning-2.1.0}/PKG-INFO +1 -1
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/__init__.py +9 -3
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_config.py +19 -18
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_environment.py +82 -3
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_get_version_impl.py +12 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_integrator_helpers.py +11 -5
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_overrides.py +18 -18
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_run_cmd.py +1 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_inference.py +9 -2
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_worktree_discovery.py +20 -8
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0/src/vcs_versioning.egg-info}/PKG-INFO +1 -1
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_chain_api.py +103 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_regressions.py +24 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_tag_config.py +21 -30
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_workdir_discovery.py +34 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/LICENSE.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/MANIFEST.in +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/README.md +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/pyproject.toml +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/setup.cfg +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/setup.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/__main__.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/__init__.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/_discover_vcs.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/_git.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/_hg.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/_hg_git.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/_jj.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_backends/_scm_workdir.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_cli/__init__.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_cli/_args.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_cli/git_archival_full.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_cli/git_archival_stable.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_compat.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_discover.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_dump_version.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_entrypoints.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_exceptions.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_fallback_workdir.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_fallbacks.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_file_finders/__init__.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_file_finders/_git.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_file_finders/_hg.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_file_finders/_jj.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_integration.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_legacy_parse.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_log.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_modify_version.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_node_utils.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_paths.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_project_overrides.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_protocols.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_pyproject_reading.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_requirement_cls.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_scm_metadata.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_scm_version.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_test_utils.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_toml.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_types.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_cls.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_fields.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/__init__.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/_common.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/_standard.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/_towncrier.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/overrides.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/py.typed +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/test_api.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning.egg-info/SOURCES.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning.egg-info/dependency_links.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning.egg-info/entry_points.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning.egg-info/requires.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning.egg-info/top_level.txt +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/__init__.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/conftest.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_better_root_errors.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_compat.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_config.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_expect_parse.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_file_finders.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_git.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_hg_git.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_integrator_helpers.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_internal_log_level.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_jj.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_legacy_parse.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_mercurial.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_overrides_api.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_overrides_env_reader.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_project_overrides.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_project_path.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_scm_metadata.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_version.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_version_scheme_towncrier.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_version_schemes.py +0 -0
- {vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/testing_vcs/test_workdir_api.py +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- towncrier release notes start -->
|
|
4
4
|
|
|
5
|
+
## 2.1.0 (2026-06-22)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add `VcsEnvironment.build_config_from_pyproject`, `build_config_from_data`, and `pyproject_tool_names` methods for canonical env-first configuration creation. ([#1424](https://github.com/pypa/setuptools-scm/issues/1424))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Fix DeprecationWarning leak in pretend API by ensuring all public APIs attach VcsEnvironment to Configuration before accessing env-dependent properties. ([#1424](https://github.com/pypa/setuptools-scm/issues/1424))
|
|
15
|
+
- Fix fallback discovery so an unprocessed `.git_archival.txt` no longer shadows a valid `PKG-INFO` in PyPI sdists. ([#1431](https://github.com/pypa/setuptools-scm/issues/1431))
|
|
16
|
+
|
|
5
17
|
## 2.0.1 (2026-06-22)
|
|
6
18
|
|
|
7
19
|
### Fixed
|
|
@@ -25,6 +25,7 @@ def build_configuration_from_pyproject(
|
|
|
25
25
|
pyproject_data: PyProjectData,
|
|
26
26
|
*,
|
|
27
27
|
dist_name: str | None = None,
|
|
28
|
+
env: VcsEnvironment | None = None,
|
|
28
29
|
**integrator_overrides: Any,
|
|
29
30
|
) -> Configuration:
|
|
30
31
|
"""Build Configuration from PyProjectData with full workflow.
|
|
@@ -36,7 +37,7 @@ def build_configuration_from_pyproject(
|
|
|
36
37
|
2. Determine dist_name (argument > pyproject.project_name)
|
|
37
38
|
3. Apply integrator overrides (override config file)
|
|
38
39
|
4. Apply environment TOML overrides (highest priority)
|
|
39
|
-
5. Create and validate Configuration instance
|
|
40
|
+
5. Create and validate Configuration instance with VcsEnvironment attached
|
|
40
41
|
|
|
41
42
|
Integrators create PyProjectData themselves:
|
|
42
43
|
|
|
@@ -73,6 +74,8 @@ def build_configuration_from_pyproject(
|
|
|
73
74
|
Args:
|
|
74
75
|
pyproject_data: Parsed pyproject data (integrator creates this)
|
|
75
76
|
dist_name: Distribution name (overrides pyproject_data.project_name)
|
|
77
|
+
env: Optional VcsEnvironment. If None, resolves from the active
|
|
78
|
+
GlobalOverrides context or process environment.
|
|
76
79
|
**integrator_overrides: Integrator-provided config overrides
|
|
77
80
|
(override config file, but overridden by env)
|
|
78
81
|
|
|
@@ -88,9 +91,12 @@ def build_configuration_from_pyproject(
|
|
|
88
91
|
This allows integrators to provide their own transformations
|
|
89
92
|
while still respecting user environment variable overrides.
|
|
90
93
|
"""
|
|
91
|
-
from .
|
|
94
|
+
from ._environment import resolve_runtime_env
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
if env is None:
|
|
97
|
+
env = resolve_runtime_env()
|
|
98
|
+
|
|
99
|
+
return env.build_config_from_pyproject(
|
|
94
100
|
pyproject_data=pyproject_data,
|
|
95
101
|
dist_name=dist_name,
|
|
96
102
|
**integrator_overrides,
|
|
@@ -347,27 +347,19 @@ class Configuration:
|
|
|
347
347
|
self.tag, regex=_check_tag_regex(tag_regex)
|
|
348
348
|
)
|
|
349
349
|
|
|
350
|
+
# TODO(#1429): re-introduce these warnings with non-conflicting logic
|
|
350
351
|
if self.tag.strict is None:
|
|
351
|
-
|
|
352
|
-
"tag.strict is not set
|
|
353
|
-
"tag matching). In a future major version the default will change "
|
|
354
|
-
"to True (require tags to contain a dot). "
|
|
355
|
-
"Set tag.strict = true or tag.strict = false explicitly in your "
|
|
356
|
-
"[tool.setuptools_scm] / [tool.vcs-versioning] config to silence "
|
|
357
|
-
"this warning.",
|
|
358
|
-
FutureWarning,
|
|
359
|
-
stacklevel=2,
|
|
352
|
+
log.debug(
|
|
353
|
+
"tag.strict is not set — defaults to False (permissive tag matching)"
|
|
360
354
|
)
|
|
361
355
|
|
|
362
356
|
if (
|
|
363
357
|
self.tag.prefix or self.tag.strict is not None
|
|
364
358
|
) and self.scm.git.describe_command is not None:
|
|
365
|
-
|
|
359
|
+
log.debug(
|
|
366
360
|
"Both tag.prefix/tag.strict and scm.git.describe_command are set. "
|
|
367
361
|
"The explicit describe_command takes precedence; tag.prefix and "
|
|
368
|
-
"tag.strict will have no effect on the git describe match pattern."
|
|
369
|
-
UserWarning,
|
|
370
|
-
stacklevel=2,
|
|
362
|
+
"tag.strict will have no effect on the git describe match pattern."
|
|
371
363
|
)
|
|
372
364
|
|
|
373
365
|
self._resolved_paths = resolve_paths(
|
|
@@ -450,6 +442,7 @@ class Configuration:
|
|
|
450
442
|
*,
|
|
451
443
|
tool_names: tuple[str, ...] | None = None,
|
|
452
444
|
env: Mapping[str, str] | None = None,
|
|
445
|
+
_env: VcsEnvironment | None = None,
|
|
453
446
|
**kwargs: Any,
|
|
454
447
|
) -> Configuration:
|
|
455
448
|
"""
|
|
@@ -462,6 +455,7 @@ class Configuration:
|
|
|
462
455
|
- dist_name: name of the distribution
|
|
463
456
|
- tool_names: env-var prefix order for TOML overrides
|
|
464
457
|
- env: environment mapping for TOML overrides (default: os.environ)
|
|
458
|
+
- _env: VcsEnvironment to attach to the resulting Configuration
|
|
465
459
|
- **kwargs: additional keyword arguments to pass to the Configuration constructor
|
|
466
460
|
"""
|
|
467
461
|
|
|
@@ -485,14 +479,20 @@ class Configuration:
|
|
|
485
479
|
args.update(project_overrides)
|
|
486
480
|
|
|
487
481
|
# Env overrides: highest priority
|
|
488
|
-
|
|
489
|
-
read_toml_overrides(args["dist_name"]
|
|
490
|
-
|
|
491
|
-
|
|
482
|
+
if _env is not None:
|
|
483
|
+
args.update(_env.read_toml_overrides(args["dist_name"]))
|
|
484
|
+
else:
|
|
485
|
+
args.update(
|
|
486
|
+
read_toml_overrides(args["dist_name"], tool_names=tool_names, env=env)
|
|
487
|
+
)
|
|
488
|
+
return cls.from_data(relative_to=relative_to, data=args, _env=_env)
|
|
492
489
|
|
|
493
490
|
@classmethod
|
|
494
491
|
def from_data(
|
|
495
|
-
cls,
|
|
492
|
+
cls,
|
|
493
|
+
relative_to: str | os.PathLike[str],
|
|
494
|
+
data: dict[str, Any],
|
|
495
|
+
_env: VcsEnvironment | None = None,
|
|
496
496
|
) -> Configuration:
|
|
497
497
|
"""
|
|
498
498
|
given configuration data
|
|
@@ -526,6 +526,7 @@ class Configuration:
|
|
|
526
526
|
version_cls=version_cls,
|
|
527
527
|
tag=tag_config,
|
|
528
528
|
scm=scm_config,
|
|
529
|
+
_env=_env,
|
|
529
530
|
**data,
|
|
530
531
|
)
|
|
531
532
|
|
|
@@ -22,7 +22,7 @@ from typing import TYPE_CHECKING, Any, Literal
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
23
|
from pytest import MonkeyPatch
|
|
24
24
|
|
|
25
|
-
from . import _config, overrides
|
|
25
|
+
from . import _config, _overrides, overrides
|
|
26
26
|
|
|
27
27
|
log = logging.getLogger(__name__)
|
|
28
28
|
|
|
@@ -248,7 +248,86 @@ class VcsEnvironment:
|
|
|
248
248
|
from ._config import Configuration
|
|
249
249
|
|
|
250
250
|
config = Configuration.from_file(
|
|
251
|
-
tool_names=self.tool_names, env=self._env, **kwargs
|
|
251
|
+
tool_names=self.tool_names, env=self._env, _env=self, **kwargs
|
|
252
252
|
)
|
|
253
|
-
object.__setattr__(config, "_env", self)
|
|
254
253
|
return config
|
|
254
|
+
|
|
255
|
+
def build_config_from_data(
|
|
256
|
+
self,
|
|
257
|
+
relative_to: str | os.PathLike[str],
|
|
258
|
+
data: dict[str, Any],
|
|
259
|
+
) -> _config.Configuration:
|
|
260
|
+
"""Create a ``Configuration`` from pre-assembled data dict.
|
|
261
|
+
|
|
262
|
+
Use this when you have already extracted and merged configuration
|
|
263
|
+
data (e.g. from pyproject section + overrides) and want to build
|
|
264
|
+
a validated Configuration without re-reading files.
|
|
265
|
+
"""
|
|
266
|
+
from ._config import Configuration
|
|
267
|
+
|
|
268
|
+
return Configuration.from_data(relative_to=relative_to, data=data, _env=self)
|
|
269
|
+
|
|
270
|
+
def build_config_from_pyproject(
|
|
271
|
+
self,
|
|
272
|
+
pyproject_data: Any,
|
|
273
|
+
*,
|
|
274
|
+
dist_name: str | None = None,
|
|
275
|
+
**integrator_overrides: Any,
|
|
276
|
+
) -> _config.Configuration:
|
|
277
|
+
"""Create a ``Configuration`` from PyProjectData with full workflow.
|
|
278
|
+
|
|
279
|
+
Canonical entry point for integrators. Orchestrates:
|
|
280
|
+
1. Extract config from pyproject_data.section
|
|
281
|
+
2. Determine dist_name
|
|
282
|
+
3. Apply integrator overrides
|
|
283
|
+
4. Apply environment TOML overrides
|
|
284
|
+
5. Build and validate Configuration with this env attached
|
|
285
|
+
"""
|
|
286
|
+
from ._integrator_helpers import build_configuration_from_pyproject_internal
|
|
287
|
+
|
|
288
|
+
return build_configuration_from_pyproject_internal(
|
|
289
|
+
pyproject_data=pyproject_data,
|
|
290
|
+
dist_name=dist_name,
|
|
291
|
+
env=self,
|
|
292
|
+
**integrator_overrides,
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
def pyproject_tool_names(self) -> list[str]:
|
|
296
|
+
"""Derive TOML section names from env-var prefixes.
|
|
297
|
+
|
|
298
|
+
Maps env-var prefixes to their canonical pyproject [tool.X] section
|
|
299
|
+
names. The ``VCS_VERSIONING`` prefix always maps to ``vcs-versioning``
|
|
300
|
+
(with dash). Other prefixes are lowercased with underscores preserved.
|
|
301
|
+
|
|
302
|
+
Examples:
|
|
303
|
+
- ``SETUPTOOLS_SCM`` -> ``setuptools_scm``
|
|
304
|
+
- ``VCS_VERSIONING`` -> ``vcs-versioning``
|
|
305
|
+
- ``HATCH_VCS`` -> ``hatch_vcs``
|
|
306
|
+
|
|
307
|
+
.. todo::
|
|
308
|
+
This uses special-case mapping (VCS_VERSIONING -> vcs-versioning).
|
|
309
|
+
The tool names should be made properly configurable via an explicit
|
|
310
|
+
mapping parameter on VcsEnvironment rather than guessing from
|
|
311
|
+
env-var prefix casing conventions.
|
|
312
|
+
"""
|
|
313
|
+
result: list[str] = []
|
|
314
|
+
for name in self.tool_names:
|
|
315
|
+
if name == "VCS_VERSIONING":
|
|
316
|
+
result.append("vcs-versioning")
|
|
317
|
+
else:
|
|
318
|
+
result.append(name.lower())
|
|
319
|
+
return result
|
|
320
|
+
|
|
321
|
+
def read_toml_overrides(
|
|
322
|
+
self, dist_name: str | None
|
|
323
|
+
) -> _overrides.ConfigOverridesDict:
|
|
324
|
+
"""Read TOML config overrides from environment variables.
|
|
325
|
+
|
|
326
|
+
Uses this environment's tool_names and env dict, delegating to
|
|
327
|
+
the standalone ``read_toml_overrides`` function.
|
|
328
|
+
"""
|
|
329
|
+
from ._overrides import read_toml_overrides as _read_toml_overrides
|
|
330
|
+
|
|
331
|
+
return _read_toml_overrides(
|
|
332
|
+
dist_name, tool_names=self.tool_names, env=self._env
|
|
333
|
+
)
|
|
@@ -29,6 +29,18 @@ EMPTY_TAG_REGEX_DEPRECATION = DeprecationWarning(
|
|
|
29
29
|
log = logging.getLogger(__name__)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
def parse_version(config: Configuration) -> ScmVersion | None:
|
|
33
|
+
"""Backward-compat shim for setuptools-scm <=10.0.x.
|
|
34
|
+
|
|
35
|
+
Those releases import ``parse_version`` from this module. The function
|
|
36
|
+
was inlined during the 10.1 / vcs-versioning 2.0 refactor, but we keep
|
|
37
|
+
the name importable so that older setuptools-scm pins still work with
|
|
38
|
+
newer vcs-versioning releases.
|
|
39
|
+
"""
|
|
40
|
+
scm_version = _resolve_version(config)
|
|
41
|
+
return _apply_metadata_overrides(scm_version, config)
|
|
42
|
+
|
|
43
|
+
|
|
32
44
|
def _finalize(
|
|
33
45
|
scm_version: ScmVersion,
|
|
34
46
|
config: Configuration,
|
|
@@ -13,6 +13,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from ._config import Configuration
|
|
16
|
+
from ._environment import VcsEnvironment
|
|
16
17
|
from ._pyproject_reading import PyProjectData
|
|
17
18
|
|
|
18
19
|
log = logging.getLogger(__name__)
|
|
@@ -22,6 +23,7 @@ def build_configuration_from_pyproject_internal(
|
|
|
22
23
|
pyproject_data: PyProjectData,
|
|
23
24
|
*,
|
|
24
25
|
dist_name: str | None = None,
|
|
26
|
+
env: VcsEnvironment | None = None,
|
|
25
27
|
**integrator_overrides: Any,
|
|
26
28
|
) -> Configuration:
|
|
27
29
|
"""Build Configuration with complete workflow orchestration.
|
|
@@ -34,7 +36,7 @@ def build_configuration_from_pyproject_internal(
|
|
|
34
36
|
2. Determine dist_name (argument > pyproject.project_name)
|
|
35
37
|
3. Merge integrator overrides (override config file)
|
|
36
38
|
4. Read and apply env TOML overrides (highest priority)
|
|
37
|
-
5. Build Configuration with proper validation
|
|
39
|
+
5. Build Configuration with proper validation and VcsEnvironment attached
|
|
38
40
|
|
|
39
41
|
Priority order (highest to lowest):
|
|
40
42
|
1. Environment TOML overrides (TOOL_OVERRIDES_FOR_DIST, TOOL_OVERRIDES)
|
|
@@ -45,6 +47,8 @@ def build_configuration_from_pyproject_internal(
|
|
|
45
47
|
Args:
|
|
46
48
|
pyproject_data: Parsed pyproject data from PyProjectData.from_file() or manual composition
|
|
47
49
|
dist_name: Distribution name for env var lookups (overrides pyproject_data.project_name)
|
|
50
|
+
env: Optional VcsEnvironment. If None, resolves from the active
|
|
51
|
+
GlobalOverrides context or process environment.
|
|
48
52
|
**integrator_overrides: Integrator-provided config overrides
|
|
49
53
|
(override config file, but overridden by env)
|
|
50
54
|
|
|
@@ -67,9 +71,12 @@ def build_configuration_from_pyproject_internal(
|
|
|
67
71
|
"""
|
|
68
72
|
# Import here to avoid circular dependencies
|
|
69
73
|
from ._config import Configuration
|
|
70
|
-
from .
|
|
74
|
+
from ._environment import resolve_runtime_env
|
|
71
75
|
from ._pyproject_reading import get_args_for_pyproject
|
|
72
76
|
|
|
77
|
+
if env is None:
|
|
78
|
+
env = resolve_runtime_env()
|
|
79
|
+
|
|
73
80
|
# Step 1: Get base config from pyproject section
|
|
74
81
|
# This also handles dist_name resolution
|
|
75
82
|
log.debug(
|
|
@@ -96,8 +103,7 @@ def build_configuration_from_pyproject_internal(
|
|
|
96
103
|
config_data.update(integrator_overrides)
|
|
97
104
|
|
|
98
105
|
# Step 4: Apply environment TOML overrides (highest priority)
|
|
99
|
-
|
|
100
|
-
env_overrides = read_toml_overrides(actual_dist_name, tool_names=tool_names)
|
|
106
|
+
env_overrides = env.read_toml_overrides(actual_dist_name)
|
|
101
107
|
if env_overrides:
|
|
102
108
|
log.debug("Applying environment TOML overrides: %s", list(env_overrides.keys()))
|
|
103
109
|
config_data.update(env_overrides)
|
|
@@ -106,7 +112,7 @@ def build_configuration_from_pyproject_internal(
|
|
|
106
112
|
relative_to = pyproject_data.path
|
|
107
113
|
log.debug("Building Configuration with relative_to=%s", relative_to)
|
|
108
114
|
|
|
109
|
-
return Configuration.from_data(relative_to=relative_to, data=config_data)
|
|
115
|
+
return Configuration.from_data(relative_to=relative_to, data=config_data, _env=env)
|
|
110
116
|
|
|
111
117
|
|
|
112
118
|
__all__ = [
|
|
@@ -153,18 +153,18 @@ def _read_pretended_metadata_for(
|
|
|
153
153
|
Returns a dictionary with metadata field overrides like:
|
|
154
154
|
{"node": "g1337beef", "distance": 4}
|
|
155
155
|
"""
|
|
156
|
-
|
|
156
|
+
log.debug("dist name: %s", config.dist_name)
|
|
157
157
|
|
|
158
158
|
if env is None:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
reader = config.env.make_reader(config.dist_name)
|
|
160
|
+
else:
|
|
161
|
+
from .overrides import EnvReader
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
reader = EnvReader(
|
|
164
|
+
tools_names=config.env.tool_names,
|
|
165
|
+
env=env,
|
|
166
|
+
dist_name=config.dist_name,
|
|
167
|
+
)
|
|
168
168
|
|
|
169
169
|
try:
|
|
170
170
|
metadata_overrides = reader.read_toml(
|
|
@@ -259,18 +259,18 @@ def _read_pretended_version_for(
|
|
|
259
259
|
tries ``SETUPTOOLS_SCM_PRETEND_VERSION``
|
|
260
260
|
and ``SETUPTOOLS_SCM_PRETEND_VERSION_FOR_$UPPERCASE_DIST_NAME``
|
|
261
261
|
"""
|
|
262
|
-
|
|
262
|
+
log.debug("dist name: %s", config.dist_name)
|
|
263
263
|
|
|
264
264
|
if env is None:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
reader = config.env.make_reader(config.dist_name)
|
|
266
|
+
else:
|
|
267
|
+
from .overrides import EnvReader
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
269
|
+
reader = EnvReader(
|
|
270
|
+
tools_names=config.env.tool_names,
|
|
271
|
+
env=env,
|
|
272
|
+
dist_name=config.dist_name,
|
|
273
|
+
)
|
|
274
274
|
pretended = reader.read("PRETEND_VERSION")
|
|
275
275
|
|
|
276
276
|
if pretended:
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
|
+
from ._environment import VcsEnvironment
|
|
8
9
|
from ._pyproject_reading import PyProjectData
|
|
9
10
|
|
|
10
11
|
|
|
@@ -14,6 +15,7 @@ def infer_version_string(
|
|
|
14
15
|
overrides: dict[str, Any] | None = None,
|
|
15
16
|
*,
|
|
16
17
|
force_write_version_files: bool = False,
|
|
18
|
+
env: VcsEnvironment | None = None,
|
|
17
19
|
) -> str:
|
|
18
20
|
"""
|
|
19
21
|
Compute the inferred version string from the given inputs.
|
|
@@ -27,6 +29,8 @@ def infer_version_string(
|
|
|
27
29
|
pyproject_data: Parsed PyProjectData (may be constructed via for_testing())
|
|
28
30
|
overrides: Optional override configuration (same keys as [tool.setuptools_scm])
|
|
29
31
|
force_write_version_files: When True, apply write_to/version_file effects
|
|
32
|
+
env: Optional VcsEnvironment. If None, resolves from the active
|
|
33
|
+
GlobalOverrides context or process environment.
|
|
30
34
|
|
|
31
35
|
Returns:
|
|
32
36
|
The computed version string.
|
|
@@ -34,10 +38,13 @@ def infer_version_string(
|
|
|
34
38
|
Raises:
|
|
35
39
|
SystemExit: If version cannot be determined (via _version_missing)
|
|
36
40
|
"""
|
|
37
|
-
from .
|
|
41
|
+
from ._environment import resolve_runtime_env
|
|
38
42
|
from ._get_version_impl import _get_version, _version_missing
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
if env is None:
|
|
45
|
+
env = resolve_runtime_env()
|
|
46
|
+
|
|
47
|
+
config = env.build_config(
|
|
41
48
|
dist_name=dist_name, pyproject_data=pyproject_data, **(overrides or {})
|
|
42
49
|
)
|
|
43
50
|
|
|
@@ -70,7 +70,10 @@ def discover_workdir(config: Configuration) -> AnyWorkdir | None:
|
|
|
70
70
|
- ScmWorkdir result: verify project_path, return immediately.
|
|
71
71
|
- FallbackWorkdir result: stash as candidate, keep probing for SCM.
|
|
72
72
|
2. Fallback phase: probe ``project_dir`` (if different from scm root).
|
|
73
|
-
3.
|
|
73
|
+
3. Try each stashed FallbackWorkdir in discovery order; return the first
|
|
74
|
+
whose ``get_scm_version()`` is not None. This prevents an
|
|
75
|
+
unprocessed ``.git_archival.txt`` from shadowing a valid ``PKG-INFO``
|
|
76
|
+
(see :issue:`1431`).
|
|
74
77
|
4. Try StaticWorkdir from config.fallback_version / parentdir_prefix_version.
|
|
75
78
|
5. Return None.
|
|
76
79
|
"""
|
|
@@ -92,7 +95,7 @@ def discover_workdir(config: Configuration) -> AnyWorkdir | None:
|
|
|
92
95
|
project_dir = config._resolved_paths.project_dir
|
|
93
96
|
scm_root_hint = config._resolved_paths.scm_probe_root
|
|
94
97
|
|
|
95
|
-
|
|
98
|
+
fallback_candidates: list[FallbackWorkdir] = []
|
|
96
99
|
|
|
97
100
|
def _accept_scm(result: ScmWorkdir, ep_name: str) -> ScmWorkdir:
|
|
98
101
|
result.project_root = project_dir
|
|
@@ -109,7 +112,6 @@ def discover_workdir(config: Configuration) -> AnyWorkdir | None:
|
|
|
109
112
|
return result
|
|
110
113
|
|
|
111
114
|
def _probe_dir(current_dir: Path, *, accept_scm: bool) -> ScmWorkdir | None:
|
|
112
|
-
nonlocal fallback_candidate
|
|
113
115
|
for ep_name, factory in factories:
|
|
114
116
|
try:
|
|
115
117
|
result = factory(current_dir, config=config)
|
|
@@ -122,7 +124,7 @@ def discover_workdir(config: Configuration) -> AnyWorkdir | None:
|
|
|
122
124
|
continue
|
|
123
125
|
if accept_scm and isinstance(result, ScmWorkdir):
|
|
124
126
|
return _accept_scm(result, ep_name)
|
|
125
|
-
if isinstance(result, FallbackWorkdir)
|
|
127
|
+
if isinstance(result, FallbackWorkdir):
|
|
126
128
|
result._config = config
|
|
127
129
|
log.debug(
|
|
128
130
|
"stashed fallback workdir %s from factory %s at %s",
|
|
@@ -130,7 +132,7 @@ def discover_workdir(config: Configuration) -> AnyWorkdir | None:
|
|
|
130
132
|
ep_name,
|
|
131
133
|
current_dir,
|
|
132
134
|
)
|
|
133
|
-
|
|
135
|
+
fallback_candidates.append(result)
|
|
134
136
|
return None
|
|
135
137
|
|
|
136
138
|
# Phase 1: SCM probes at scm_root_hint (the declared root) and optionally parents.
|
|
@@ -146,9 +148,19 @@ def discover_workdir(config: Configuration) -> AnyWorkdir | None:
|
|
|
146
148
|
if project_dir != scm_root_hint:
|
|
147
149
|
_probe_dir(project_dir, accept_scm=False)
|
|
148
150
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
# Try each fallback candidate until one can provide a version (#1431).
|
|
152
|
+
# Earlier discovery code stashed all matching fallback workdirs; an
|
|
153
|
+
# unprocessed .git_archival.txt (raw $Format placeholders) would
|
|
154
|
+
# shadow a valid PKG-INFO if we only kept the first candidate.
|
|
155
|
+
for candidate in fallback_candidates:
|
|
156
|
+
if candidate.get_scm_version() is not None:
|
|
157
|
+
log.info("using fallback workdir %s", type(candidate).__name__)
|
|
158
|
+
return candidate
|
|
159
|
+
if fallback_candidates:
|
|
160
|
+
log.debug(
|
|
161
|
+
"all %d fallback candidates returned None for get_scm_version",
|
|
162
|
+
len(fallback_candidates),
|
|
163
|
+
)
|
|
152
164
|
|
|
153
165
|
static = StaticWorkdir(path=project_dir, _config=config)
|
|
154
166
|
if static.get_scm_version() is not None:
|
|
@@ -304,3 +304,106 @@ class TestFrozenLegacyConfig:
|
|
|
304
304
|
frozen = FrozenLegacyConfig(config)
|
|
305
305
|
with pytest.raises((AttributeError, dataclasses.FrozenInstanceError)):
|
|
306
306
|
frozen.version_scheme = "something" # type: ignore[attr-defined]
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class TestInferVersionStringEnv:
|
|
310
|
+
"""Tests that infer_version_string properly resolves and attaches VcsEnvironment."""
|
|
311
|
+
|
|
312
|
+
def _pyproject(self) -> PyProjectData:
|
|
313
|
+
return PyProjectData.for_testing(
|
|
314
|
+
tool_name="vcs-versioning",
|
|
315
|
+
is_required=True,
|
|
316
|
+
section_present=True,
|
|
317
|
+
project_present=True,
|
|
318
|
+
project_name="test-pkg",
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def test_no_deprecation_warning_with_pretend_version(
|
|
322
|
+
self, monkeypatch: pytest.MonkeyPatch
|
|
323
|
+
) -> None:
|
|
324
|
+
"""infer_version_string must not leak DeprecationWarning for missing env."""
|
|
325
|
+
import warnings
|
|
326
|
+
|
|
327
|
+
from vcs_versioning._version_inference import infer_version_string
|
|
328
|
+
|
|
329
|
+
monkeypatch.setenv("SETUPTOOLS_SCM_PRETEND_VERSION", "1.2.3")
|
|
330
|
+
|
|
331
|
+
with warnings.catch_warnings():
|
|
332
|
+
warnings.filterwarnings("error", category=DeprecationWarning)
|
|
333
|
+
result = infer_version_string("test-pkg", self._pyproject())
|
|
334
|
+
|
|
335
|
+
assert result == "1.2.3"
|
|
336
|
+
|
|
337
|
+
def test_resolves_env_from_global_overrides_context(
|
|
338
|
+
self, monkeypatch: pytest.MonkeyPatch
|
|
339
|
+
) -> None:
|
|
340
|
+
"""infer_version_string respects the active GlobalOverrides context."""
|
|
341
|
+
from vcs_versioning._version_inference import infer_version_string
|
|
342
|
+
|
|
343
|
+
monkeypatch.setenv("MYTOOL_PRETEND_VERSION", "9.8.7")
|
|
344
|
+
|
|
345
|
+
with GlobalOverrides.from_env("MYTOOL"):
|
|
346
|
+
result = infer_version_string("test-pkg", self._pyproject())
|
|
347
|
+
|
|
348
|
+
assert result == "9.8.7"
|
|
349
|
+
|
|
350
|
+
def test_accepts_explicit_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
351
|
+
"""infer_version_string uses an explicitly passed VcsEnvironment."""
|
|
352
|
+
from vcs_versioning._version_inference import infer_version_string
|
|
353
|
+
|
|
354
|
+
env_mapping = {"VCS_VERSIONING_PRETEND_VERSION": "4.5.6"}
|
|
355
|
+
env = VcsEnvironment.from_env(env=env_mapping)
|
|
356
|
+
|
|
357
|
+
result = infer_version_string("test-pkg", self._pyproject(), env=env)
|
|
358
|
+
assert result == "4.5.6"
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class TestBuildConfigurationFromPyprojectEnv:
|
|
362
|
+
"""Tests that build_configuration_from_pyproject attaches VcsEnvironment."""
|
|
363
|
+
|
|
364
|
+
def _pyproject(self) -> PyProjectData:
|
|
365
|
+
return PyProjectData.for_testing(
|
|
366
|
+
tool_name="vcs-versioning",
|
|
367
|
+
is_required=True,
|
|
368
|
+
section_present=True,
|
|
369
|
+
project_present=True,
|
|
370
|
+
project_name="test-pkg",
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
def test_no_deprecation_warning(self) -> None:
|
|
374
|
+
"""build_configuration_from_pyproject must not leak DeprecationWarning."""
|
|
375
|
+
import warnings
|
|
376
|
+
|
|
377
|
+
from vcs_versioning import build_configuration_from_pyproject
|
|
378
|
+
|
|
379
|
+
with warnings.catch_warnings():
|
|
380
|
+
warnings.filterwarnings("error", category=DeprecationWarning)
|
|
381
|
+
config = build_configuration_from_pyproject(
|
|
382
|
+
self._pyproject(), dist_name="test-pkg"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
assert config._env is not None
|
|
386
|
+
|
|
387
|
+
def test_resolves_env_from_global_overrides_context(self) -> None:
|
|
388
|
+
"""build_configuration_from_pyproject uses active GlobalOverrides."""
|
|
389
|
+
from vcs_versioning import build_configuration_from_pyproject
|
|
390
|
+
|
|
391
|
+
with GlobalOverrides.from_env("MYTOOL", env={}):
|
|
392
|
+
config = build_configuration_from_pyproject(
|
|
393
|
+
self._pyproject(), dist_name="test-pkg"
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
assert config._env is not None
|
|
397
|
+
assert "MYTOOL" in config._env.tool_names
|
|
398
|
+
|
|
399
|
+
def test_accepts_explicit_env(self) -> None:
|
|
400
|
+
"""build_configuration_from_pyproject passes explicit env through."""
|
|
401
|
+
from vcs_versioning import build_configuration_from_pyproject
|
|
402
|
+
|
|
403
|
+
env = VcsEnvironment.from_env("CUSTOM", env={})
|
|
404
|
+
|
|
405
|
+
config = build_configuration_from_pyproject(
|
|
406
|
+
self._pyproject(), dist_name="test-pkg", env=env
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
assert config._env is env
|
|
@@ -138,6 +138,30 @@ def test_no_warn_when_version_file_not_tracked(tmp_path: Path, scm: str) -> None
|
|
|
138
138
|
assert tracked_warnings == []
|
|
139
139
|
|
|
140
140
|
|
|
141
|
+
@pytest.mark.issue(1423)
|
|
142
|
+
def test_parse_version_importable_from_get_version_impl() -> None:
|
|
143
|
+
"""setuptools-scm <=10.0.x imports parse_version from this module."""
|
|
144
|
+
from vcs_versioning._get_version_impl import parse_version
|
|
145
|
+
|
|
146
|
+
assert callable(parse_version)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@pytest.mark.issue(1423)
|
|
150
|
+
def test_parse_version_shim_returns_version(tmp_path: Path) -> None:
|
|
151
|
+
"""The compat shim should resolve and return a ScmVersion."""
|
|
152
|
+
wd = WorkDir(tmp_path).setup_git()
|
|
153
|
+
wd.add_and_commit("initial")
|
|
154
|
+
wd("git tag -a v1.0.0 -m v1.0.0")
|
|
155
|
+
|
|
156
|
+
c = Configuration(root=tmp_path)
|
|
157
|
+
|
|
158
|
+
from vcs_versioning._get_version_impl import parse_version
|
|
159
|
+
from vcs_versioning._scm_version import ScmVersion
|
|
160
|
+
|
|
161
|
+
result = parse_version(c)
|
|
162
|
+
assert isinstance(result, ScmVersion)
|
|
163
|
+
|
|
164
|
+
|
|
141
165
|
@pytest.mark.parametrize(
|
|
142
166
|
("input", "expected"),
|
|
143
167
|
[
|
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import warnings
|
|
6
6
|
|
|
7
|
-
import pytest
|
|
8
7
|
from vcs_versioning import Configuration
|
|
9
8
|
from vcs_versioning._config import TagConfiguration
|
|
10
9
|
from vcs_versioning._scm_version import tag_to_version
|
|
@@ -59,8 +58,10 @@ class TestDescribeMatchGlob:
|
|
|
59
58
|
|
|
60
59
|
|
|
61
60
|
class TestTagStrictWarning:
|
|
62
|
-
def
|
|
63
|
-
|
|
61
|
+
def test_none_strict_no_warning(self) -> None:
|
|
62
|
+
"""tag.strict=None no longer warns (suppressed per #1422, see #1429)."""
|
|
63
|
+
with warnings.catch_warnings():
|
|
64
|
+
warnings.simplefilter("error", FutureWarning)
|
|
64
65
|
Configuration(tag=TagConfiguration(strict=None))
|
|
65
66
|
|
|
66
67
|
def test_true_strict_no_warning(self) -> None:
|
|
@@ -78,17 +79,13 @@ class TestTagPrefixStripping:
|
|
|
78
79
|
"""Test that tag.prefix is stripped before tag_regex matching."""
|
|
79
80
|
|
|
80
81
|
def test_prefix_stripped_from_tag(self) -> None:
|
|
81
|
-
|
|
82
|
-
warnings.simplefilter("ignore", FutureWarning)
|
|
83
|
-
config = Configuration(tag=TagConfiguration(prefix="hatchling-v"))
|
|
82
|
+
config = Configuration(tag=TagConfiguration(prefix="hatchling-v"))
|
|
84
83
|
version = tag_to_version("hatchling-v1.0.0", config)
|
|
85
84
|
assert version is not None
|
|
86
85
|
assert str(version) == "1.0.0"
|
|
87
86
|
|
|
88
87
|
def test_no_prefix_no_stripping(self) -> None:
|
|
89
|
-
|
|
90
|
-
warnings.simplefilter("ignore", FutureWarning)
|
|
91
|
-
config = Configuration(tag=TagConfiguration(prefix=""))
|
|
88
|
+
config = Configuration(tag=TagConfiguration(prefix=""))
|
|
92
89
|
version = tag_to_version("v1.0.0", config)
|
|
93
90
|
assert version is not None
|
|
94
91
|
assert str(version) == "1.0.0"
|
|
@@ -100,17 +97,13 @@ class TestTagPrefixStripping:
|
|
|
100
97
|
may still parse -- but the prefix is NOT stripped, meaning
|
|
101
98
|
git describe --match would have already filtered it out in practice.
|
|
102
99
|
"""
|
|
103
|
-
|
|
104
|
-
warnings.simplefilter("ignore", FutureWarning)
|
|
105
|
-
config = Configuration(tag=TagConfiguration(prefix="other-"))
|
|
100
|
+
config = Configuration(tag=TagConfiguration(prefix="other-"))
|
|
106
101
|
version = tag_to_version("hatchling-v1.0.0", config)
|
|
107
102
|
# Default tag_regex matches and extracts "v1.0.0" from dashed prefix
|
|
108
103
|
assert version is not None
|
|
109
104
|
|
|
110
105
|
def test_prefix_v_strips_v(self) -> None:
|
|
111
|
-
|
|
112
|
-
warnings.simplefilter("ignore", FutureWarning)
|
|
113
|
-
config = Configuration(tag=TagConfiguration(prefix="v"))
|
|
106
|
+
config = Configuration(tag=TagConfiguration(prefix="v"))
|
|
114
107
|
version = tag_to_version("v1.2.3", config)
|
|
115
108
|
assert version is not None
|
|
116
109
|
assert str(version) == "1.2.3"
|
|
@@ -120,20 +113,19 @@ class TestConfigFromData:
|
|
|
120
113
|
"""Test that Configuration.from_data correctly parses tag config."""
|
|
121
114
|
|
|
122
115
|
def test_tag_in_from_data(self) -> None:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
},
|
|
131
|
-
)
|
|
116
|
+
config = Configuration.from_data(
|
|
117
|
+
relative_to=".",
|
|
118
|
+
data={
|
|
119
|
+
"dist_name": "test",
|
|
120
|
+
"tag": {"prefix": "mylib-", "strict": True},
|
|
121
|
+
},
|
|
122
|
+
)
|
|
132
123
|
assert config.tag.prefix == "mylib-"
|
|
133
124
|
assert config.tag.strict is True
|
|
134
125
|
|
|
135
126
|
def test_no_tag_in_from_data(self) -> None:
|
|
136
|
-
with
|
|
127
|
+
with warnings.catch_warnings():
|
|
128
|
+
warnings.simplefilter("error", FutureWarning)
|
|
137
129
|
config = Configuration.from_data(
|
|
138
130
|
relative_to=".",
|
|
139
131
|
data={"dist_name": "test"},
|
|
@@ -143,13 +135,12 @@ class TestConfigFromData:
|
|
|
143
135
|
|
|
144
136
|
|
|
145
137
|
class TestDescribeCommandConflictWarning:
|
|
146
|
-
def
|
|
138
|
+
def test_no_warning_when_prefix_and_describe_command_both_set(self) -> None:
|
|
139
|
+
"""Suppressed per #1422, see #1429 for follow-up."""
|
|
147
140
|
from vcs_versioning._config import GitConfiguration, ScmConfiguration
|
|
148
141
|
|
|
149
|
-
with
|
|
150
|
-
UserWarning
|
|
151
|
-
match="Both tag.prefix/tag.strict and scm.git.describe_command are set",
|
|
152
|
-
):
|
|
142
|
+
with warnings.catch_warnings():
|
|
143
|
+
warnings.simplefilter("error", UserWarning)
|
|
153
144
|
Configuration(
|
|
154
145
|
tag=TagConfiguration(prefix="v", strict=True),
|
|
155
146
|
scm=ScmConfiguration(
|
|
@@ -177,6 +177,40 @@ class TestProjectPathVerificationInDiscovery:
|
|
|
177
177
|
discover_workdir(config)
|
|
178
178
|
|
|
179
179
|
|
|
180
|
+
class TestFallbackPriority:
|
|
181
|
+
@pytest.mark.issue(1431)
|
|
182
|
+
def test_unprocessed_archival_falls_through_to_pkginfo(
|
|
183
|
+
self, tmp_path: Path
|
|
184
|
+
) -> None:
|
|
185
|
+
"""Unprocessed .git_archival.txt must not shadow a valid PKG-INFO.
|
|
186
|
+
|
|
187
|
+
PyPI sdists contain both files: a .git_archival.txt with raw
|
|
188
|
+
``$Format:...`` placeholders (never substituted because the sdist
|
|
189
|
+
was built by setuptools, not ``git archive``) and a PKG-INFO with
|
|
190
|
+
the correct version. Before the fix, the archival fallback was
|
|
191
|
+
stashed as the sole candidate and its ``get_scm_version()`` returned
|
|
192
|
+
None, causing a LookupError.
|
|
193
|
+
"""
|
|
194
|
+
(tmp_path / ".git_archival.txt").write_text(
|
|
195
|
+
"node: $Format:%H$\n"
|
|
196
|
+
"node-date: $Format:%cI$\n"
|
|
197
|
+
"describe-name: $Format:%(describe:tags=true)$\n"
|
|
198
|
+
"ref-names: $Format:%D$\n",
|
|
199
|
+
encoding="utf-8",
|
|
200
|
+
)
|
|
201
|
+
(tmp_path / "PKG-INFO").write_text(
|
|
202
|
+
"Metadata-Version: 2.1\nName: my-pkg\nVersion: 1.2.3\n",
|
|
203
|
+
encoding="utf-8",
|
|
204
|
+
)
|
|
205
|
+
config = Configuration(relative_to=str(tmp_path / "pyproject.toml"))
|
|
206
|
+
result = discover_workdir(config)
|
|
207
|
+
assert result is not None
|
|
208
|
+
assert isinstance(result, PkgInfoWorkdir)
|
|
209
|
+
version = result.get_scm_version()
|
|
210
|
+
assert version is not None
|
|
211
|
+
assert str(version.tag) == "1.2.3"
|
|
212
|
+
|
|
213
|
+
|
|
180
214
|
class TestFallbackWorkdirDiscoveryFactories:
|
|
181
215
|
def test_discover_archival_git(self, tmp_path: Path) -> None:
|
|
182
216
|
from vcs_versioning._fallback_workdir import discover_archival
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_cli/git_archival_stable.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/__init__.py
RENAMED
|
File without changes
|
{vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/_common.py
RENAMED
|
File without changes
|
{vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/_standard.py
RENAMED
|
File without changes
|
{vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning/_version_schemes/_towncrier.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vcs_versioning-2.0.1 → vcs_versioning-2.1.0}/src/vcs_versioning.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|