1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
""" configuration """
from __future__ import annotations
import dataclasses
import os
import re
import warnings
from typing import Any
from typing import Callable
from typing import Pattern
from . import _log
from . import _types as _t
from ._integration.pyproject_reading import (
get_args_for_pyproject as _get_args_for_pyproject,
)
from ._integration.pyproject_reading import read_pyproject as _read_pyproject
from ._overrides import read_toml_overrides
from ._version_cls import _validate_version_cls
from ._version_cls import _VersionT
from ._version_cls import Version as _Version
log = _log.log.getChild("config")
DEFAULT_TAG_REGEX = re.compile(
r"^(?:[\w-]+-)?(?P<version>[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$"
)
DEFAULT_VERSION_SCHEME = "guess-next-dev"
DEFAULT_LOCAL_SCHEME = "node-and-date"
def _check_tag_regex(value: str | Pattern[str] | None) -> Pattern[str]:
if not value:
regex = DEFAULT_TAG_REGEX
else:
regex = re.compile(value)
group_names = regex.groupindex.keys()
if regex.groups == 0 or (regex.groups > 1 and "version" not in group_names):
warnings.warn(
"Expected tag_regex to contain a single match group or a group named"
" 'version' to identify the version part of any tag."
)
return regex
def _check_absolute_root(root: _t.PathT, relative_to: _t.PathT | None) -> str:
log.debug("check absolute root=%s relative_to=%s", root, relative_to)
if relative_to:
if (
os.path.isabs(root)
and os.path.isabs(relative_to)
and not os.path.commonpath([root, relative_to]) == root
):
warnings.warn(
"absolute root path '%s' overrides relative_to '%s'"
% (root, relative_to)
)
if os.path.isdir(relative_to):
warnings.warn(
"relative_to is expected to be a file,"
" its the directory %r\n"
"assuming the parent directory was passed" % (relative_to,)
)
log.debug("dir %s", relative_to)
root = os.path.join(relative_to, root)
else:
log.debug("file %s", relative_to)
root = os.path.join(os.path.dirname(relative_to), root)
return os.path.abspath(root)
@dataclasses.dataclass
class Configuration:
"""Global configuration model"""
relative_to: _t.PathT | None = None
root: _t.PathT = "."
version_scheme: _t.VERSION_SCHEME = DEFAULT_VERSION_SCHEME
local_scheme: _t.VERSION_SCHEME = DEFAULT_LOCAL_SCHEME
tag_regex: Pattern[str] = DEFAULT_TAG_REGEX
parentdir_prefix_version: str | None = None
fallback_version: str | None = None
fallback_root: _t.PathT = "."
write_to: _t.PathT | None = None
write_to_template: str | None = None
parse: Any | None = None
git_describe_command: _t.CMD_TYPE | None = None
dist_name: str | None = None
version_cls: type[_VersionT] = _Version
search_parent_directories: bool = False
parent: _t.PathT | None = None
@property
def absolute_root(self) -> str:
return _check_absolute_root(self.root, self.relative_to)
@classmethod
def from_file(
cls,
name: str | os.PathLike[str] = "pyproject.toml",
dist_name: str | None = None,
_load_toml: Callable[[str], dict[str, Any]] | None = None,
**kwargs: Any,
) -> Configuration:
"""
Read Configuration from pyproject.toml (or similar).
Raises exceptions when file is not found or toml is
not installed or the file has invalid format or does
not contain the [tool.setuptools_scm] section.
"""
pyproject_data = _read_pyproject(name, _load_toml=_load_toml)
args = _get_args_for_pyproject(pyproject_data, dist_name, kwargs)
args.update(read_toml_overrides(args["dist_name"]))
return cls.from_data(relative_to=name, data=args)
@classmethod
def from_data(
cls, relative_to: str | os.PathLike[str], data: dict[str, Any]
) -> Configuration:
tag_regex = _check_tag_regex(data.pop("tag_regex", None))
version_cls = _validate_version_cls(
data.pop("version_cls", None), data.pop("normalize", True)
)
return cls(
relative_to,
version_cls=version_cls,
tag_regex=tag_regex,
**data,
)
|