v440 2.0.0.dev196__tar.gz → 2.0.0.dev200__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.
- {v440-2.0.0.dev196/src/v440.egg-info → v440-2.0.0.dev200}/PKG-INFO +5 -6
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/pyproject.toml +6 -7
- {v440-2.0.0.dev196/src/v440/core → v440-2.0.0.dev200/src/v440}/__init__.py +1 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/BaseStringer.py +40 -6
- v440-2.0.0.dev200/src/v440/_utils/Cfg.py +41 -0
- v440-2.0.0.dev200/src/v440/_utils/Clue.py +114 -0
- v440-2.0.0.dev200/src/v440/_utils/ListStringer.py +90 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/QualStringer.py +27 -31
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/SlotStringer.py +3 -0
- v440-2.0.0.dev200/src/v440/_utils/cfg.toml +51 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/guarding.py +7 -4
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/releaseparse/getting.py +2 -2
- v440-2.0.0.dev200/src/v440/core/Base.py +130 -0
- v440-2.0.0.dev200/src/v440/core/Dev.py +79 -0
- v440-2.0.0.dev200/src/v440/core/Local.py +208 -0
- v440-2.0.0.dev200/src/v440/core/Post.py +78 -0
- v440-2.0.0.dev200/src/v440/core/Pre.py +106 -0
- v440-2.0.0.dev200/src/v440/core/Public.py +93 -0
- v440-2.0.0.dev200/src/v440/core/Qual.py +150 -0
- v440-2.0.0.dev200/src/v440/core/Release.py +153 -0
- v440-2.0.0.dev200/src/v440/core/Version.py +105 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/core/VersionError.py +3 -0
- v440-2.0.0.dev200/src/v440/core/__init__.py +0 -0
- v440-2.0.0.dev200/src/v440/tests/test_testdata.py +471 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/tests/test_version.py +8 -28
- v440-2.0.0.dev200/src/v440/tests/testdata.toml +2600 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200/src/v440.egg-info}/PKG-INFO +5 -6
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440.egg-info/SOURCES.txt +1 -1
- v440-2.0.0.dev200/src/v440.egg-info/requires.txt +9 -0
- v440-2.0.0.dev196/src/v440/__init__.py +0 -2
- v440-2.0.0.dev196/src/v440/_utils/Cfg.py +0 -18
- v440-2.0.0.dev196/src/v440/_utils/ListStringer.py +0 -183
- v440-2.0.0.dev196/src/v440/_utils/Pattern.py +0 -33
- v440-2.0.0.dev196/src/v440/_utils/cfg.toml +0 -9
- v440-2.0.0.dev196/src/v440/core/Base.py +0 -70
- v440-2.0.0.dev196/src/v440/core/Dev.py +0 -31
- v440-2.0.0.dev196/src/v440/core/Local.py +0 -63
- v440-2.0.0.dev196/src/v440/core/Post.py +0 -32
- v440-2.0.0.dev196/src/v440/core/Pre.py +0 -28
- v440-2.0.0.dev196/src/v440/core/Public.py +0 -51
- v440-2.0.0.dev196/src/v440/core/Qual.py +0 -93
- v440-2.0.0.dev196/src/v440/core/Release.py +0 -122
- v440-2.0.0.dev196/src/v440/core/Version.py +0 -62
- v440-2.0.0.dev196/src/v440/tests/test_testdata.py +0 -422
- v440-2.0.0.dev196/src/v440/tests/testdata.toml +0 -967
- v440-2.0.0.dev196/src/v440.egg-info/requires.txt +0 -10
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/LICENSE.txt +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/MANIFEST.in +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/README.rst +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/setup.cfg +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/__init__.py +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/releaseparse/__init__.py +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/releaseparse/deleting.py +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/releaseparse/ranging.py +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/_utils/releaseparse/setting.py +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440/tests/__init__.py +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440.egg-info/dependency_links.txt +0 -0
- {v440-2.0.0.dev196 → v440-2.0.0.dev200}/src/v440.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: v440
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev200
|
|
4
4
|
Summary: This project provides mutable version objects in accordance with PEP440.
|
|
5
5
|
Author-email: Johannes <johannes.programming@gmail.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -40,15 +40,14 @@ Classifier: Typing :: Typed
|
|
|
40
40
|
Requires-Python: >=3.11
|
|
41
41
|
Description-Content-Type: text/x-rst
|
|
42
42
|
License-File: LICENSE.txt
|
|
43
|
-
Requires-Dist:
|
|
44
|
-
Requires-Dist: datarepr<2,>=1.
|
|
43
|
+
Requires-Dist: datahold<3,>=2.0
|
|
44
|
+
Requires-Dist: datarepr<2,>=1.1
|
|
45
|
+
Requires-Dist: iterflat<2,>=0.1.3
|
|
45
46
|
Requires-Dist: iterprod<2.0,>=1.0
|
|
46
47
|
Requires-Dist: keyalias<2.0,>=1.0.3
|
|
47
|
-
Requires-Dist: packaging
|
|
48
|
-
Requires-Dist: scaevola<2.0,>=1.1
|
|
48
|
+
Requires-Dist: packaging<26,>=25.0
|
|
49
49
|
Requires-Dist: setdoc<2,>=1.2.6
|
|
50
50
|
Requires-Dist: setsig<2,>=1.0
|
|
51
|
-
Requires-Dist: tofunc<2,>=1.0.0
|
|
52
51
|
Requires-Dist: unhash<2,>=1.0.1
|
|
53
52
|
Dynamic: license-file
|
|
54
53
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
build-backend = "setuptools.build_meta"
|
|
3
3
|
requires = [
|
|
4
|
-
"setuptools>=
|
|
4
|
+
"setuptools>=64.0",
|
|
5
5
|
]
|
|
6
6
|
|
|
7
7
|
[project]
|
|
@@ -20,15 +20,14 @@ classifiers = [
|
|
|
20
20
|
"Typing :: Typed",
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
|
-
"
|
|
24
|
-
"datarepr>=1.
|
|
23
|
+
"datahold>=2.0,<3",
|
|
24
|
+
"datarepr>=1.1,<2",
|
|
25
|
+
"iterflat>=0.1.3,<2",
|
|
25
26
|
"iterprod>=1.0,<2.0",
|
|
26
27
|
"keyalias>=1.0.3,<2.0",
|
|
27
|
-
"packaging>=
|
|
28
|
-
"scaevola>=1.1,<2.0",
|
|
28
|
+
"packaging>=25.0,<26",
|
|
29
29
|
"setdoc>=1.2.6,<2",
|
|
30
30
|
"setsig>=1.0,<2",
|
|
31
|
-
"tofunc>=1.0.0,<2",
|
|
32
31
|
"unhash>=1.0.1,<2",
|
|
33
32
|
]
|
|
34
33
|
description = "This project provides mutable version objects in accordance with PEP440."
|
|
@@ -36,7 +35,7 @@ keywords = []
|
|
|
36
35
|
name = "v440"
|
|
37
36
|
readme = "README.rst"
|
|
38
37
|
requires-python = ">=3.11"
|
|
39
|
-
version = "2.0.0.
|
|
38
|
+
version = "2.0.0.dev200"
|
|
40
39
|
|
|
41
40
|
[project.license]
|
|
42
41
|
file = "LICENSE.txt"
|
|
@@ -3,8 +3,11 @@ from typing import *
|
|
|
3
3
|
|
|
4
4
|
import setdoc
|
|
5
5
|
import unhash
|
|
6
|
+
from datarepr import oxford
|
|
6
7
|
|
|
8
|
+
from v440._utils.Cfg import Cfg
|
|
7
9
|
from v440._utils.guarding import guard
|
|
10
|
+
from v440.core.VersionError import VersionError
|
|
8
11
|
|
|
9
12
|
__all__ = ["BaseStringer"]
|
|
10
13
|
|
|
@@ -13,6 +16,7 @@ class BaseStringer(metaclass=ABCMeta):
|
|
|
13
16
|
__slots__ = ()
|
|
14
17
|
|
|
15
18
|
string: str
|
|
19
|
+
packaging: Any
|
|
16
20
|
|
|
17
21
|
@abstractmethod
|
|
18
22
|
@setdoc.basic
|
|
@@ -27,12 +31,17 @@ class BaseStringer(metaclass=ABCMeta):
|
|
|
27
31
|
|
|
28
32
|
@setdoc.basic
|
|
29
33
|
def __format__(self: Self, format_spec: Any) -> str:
|
|
34
|
+
parsed: dict
|
|
35
|
+
ans: str
|
|
36
|
+
msg: str
|
|
30
37
|
try:
|
|
31
|
-
|
|
38
|
+
parsed = self._format_parse(str(format_spec))
|
|
32
39
|
except Exception:
|
|
33
|
-
msg
|
|
40
|
+
msg = Cfg.cfg.data["consts"]["errors"]["format"]
|
|
34
41
|
msg %= (format_spec, type(self).__name__)
|
|
35
|
-
raise
|
|
42
|
+
raise VersionError(msg) # from None
|
|
43
|
+
ans = str(self._format_parsed(**parsed))
|
|
44
|
+
return ans
|
|
36
45
|
|
|
37
46
|
@setdoc.basic
|
|
38
47
|
def __ge__(self: Self, other: Any) -> bool:
|
|
@@ -83,13 +92,21 @@ class BaseStringer(metaclass=ABCMeta):
|
|
|
83
92
|
|
|
84
93
|
@setdoc.basic
|
|
85
94
|
def __str__(self: Self) -> str:
|
|
86
|
-
return self
|
|
95
|
+
return format(self, "")
|
|
87
96
|
|
|
88
97
|
@abstractmethod
|
|
89
98
|
def _cmp(self: Self) -> Any: ...
|
|
90
99
|
|
|
100
|
+
@classmethod
|
|
101
|
+
@abstractmethod
|
|
102
|
+
def _deformat(cls: type, info: dict[str, Self], /) -> Any: ...
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
91
105
|
@abstractmethod
|
|
92
|
-
def
|
|
106
|
+
def _format_parse(self: Self, spec: str, /) -> dict: ...
|
|
107
|
+
|
|
108
|
+
@abstractmethod
|
|
109
|
+
def _format_parsed(self: Self, **kwargs: Any) -> Any: ...
|
|
93
110
|
|
|
94
111
|
@abstractmethod
|
|
95
112
|
def _string_fset(self: Self, value: str) -> None: ...
|
|
@@ -98,10 +115,27 @@ class BaseStringer(metaclass=ABCMeta):
|
|
|
98
115
|
def copy(self: Self) -> Self:
|
|
99
116
|
return type(self)(self)
|
|
100
117
|
|
|
118
|
+
@classmethod
|
|
119
|
+
def deformat(cls: type, *strings: Any) -> str:
|
|
120
|
+
keys: tuple = tuple(map(str, strings))
|
|
121
|
+
values: tuple = tuple(map(cls, keys))
|
|
122
|
+
info: dict = dict(zip(keys, values))
|
|
123
|
+
try:
|
|
124
|
+
ans: str = cls._deformat(info)
|
|
125
|
+
except Exception:
|
|
126
|
+
msg: str = Cfg.cfg.data["consts"]["errors"]["deformat"]
|
|
127
|
+
msg %= oxford(*strings)
|
|
128
|
+
raise TypeError(msg)
|
|
129
|
+
return ans
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
@abstractmethod
|
|
133
|
+
def packaging(self: Self) -> Any: ...
|
|
134
|
+
|
|
101
135
|
@property
|
|
102
136
|
def string(self: Self) -> str:
|
|
103
137
|
"This property represents self as str."
|
|
104
|
-
return self
|
|
138
|
+
return format(self, "")
|
|
105
139
|
|
|
106
140
|
@string.setter
|
|
107
141
|
@guard
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import functools
|
|
3
|
+
import re
|
|
4
|
+
import tomllib
|
|
5
|
+
from importlib import resources
|
|
6
|
+
from typing import *
|
|
7
|
+
|
|
8
|
+
__all__ = ["Cfg"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Cfg(enum.Enum):
|
|
12
|
+
cfg = None
|
|
13
|
+
|
|
14
|
+
@functools.cached_property
|
|
15
|
+
def data(self: Self) -> dict:
|
|
16
|
+
"This cached property holds the cfg data."
|
|
17
|
+
text: str = resources.read_text("v440._utils", "cfg.toml")
|
|
18
|
+
ans: dict = tomllib.loads(text)
|
|
19
|
+
return ans
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def fullmatches(cls: type, key: str, value: str) -> dict[str, str]:
|
|
23
|
+
ans: dict = cls.cfg.patterns[key].fullmatch(value).groupdict()
|
|
24
|
+
x: str
|
|
25
|
+
for x in ans.keys():
|
|
26
|
+
if ans[x] is None:
|
|
27
|
+
ans[x] = ""
|
|
28
|
+
return ans
|
|
29
|
+
|
|
30
|
+
@functools.cached_property
|
|
31
|
+
def patterns(self: Self) -> dict[str, re.Pattern]:
|
|
32
|
+
ans: dict = dict()
|
|
33
|
+
parts: dict = dict()
|
|
34
|
+
x: str
|
|
35
|
+
y: str
|
|
36
|
+
z: str
|
|
37
|
+
for x, y in self.data["patterns"].items():
|
|
38
|
+
z = y.format(**parts)
|
|
39
|
+
parts[x] = f"(?P<{x}>{z})"
|
|
40
|
+
ans[x] = re.compile(z, re.IGNORECASE | re.VERBOSE)
|
|
41
|
+
return ans
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import string as string_
|
|
2
|
+
from typing import *
|
|
3
|
+
|
|
4
|
+
from v440._utils.Cfg import Cfg
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Clue(NamedTuple):
|
|
8
|
+
head: str = ""
|
|
9
|
+
sep: str = "?"
|
|
10
|
+
mag: int = 0
|
|
11
|
+
|
|
12
|
+
def __and__(self: Self, other: Self) -> Self:
|
|
13
|
+
s: str
|
|
14
|
+
m: int
|
|
15
|
+
if self.head == "":
|
|
16
|
+
return other
|
|
17
|
+
if other.head == "":
|
|
18
|
+
return self
|
|
19
|
+
if self.head != other.head:
|
|
20
|
+
raise ValueError
|
|
21
|
+
if self.sep == "?":
|
|
22
|
+
s = other.sep
|
|
23
|
+
elif other.sep == "?":
|
|
24
|
+
s = self.sep
|
|
25
|
+
elif self.sep == other.sep:
|
|
26
|
+
s = self.sep
|
|
27
|
+
else:
|
|
28
|
+
raise ValueError
|
|
29
|
+
if self.mag < 0 and other.mag < 0:
|
|
30
|
+
m = max(self.mag, other.mag)
|
|
31
|
+
elif self.mag < 0 or other.mag < 0:
|
|
32
|
+
if 0 < self.mag + other.mag:
|
|
33
|
+
raise ValueError
|
|
34
|
+
m = max(self.mag, other.mag)
|
|
35
|
+
else:
|
|
36
|
+
if self.mag != other.mag:
|
|
37
|
+
raise ValueError
|
|
38
|
+
m = self.mag
|
|
39
|
+
return type(self)(self.head, s, m)
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def by_example(cls: type, value: str, /) -> Self:
|
|
43
|
+
sep: str
|
|
44
|
+
mag: int
|
|
45
|
+
matches: dict[str, str]
|
|
46
|
+
if value == "-0":
|
|
47
|
+
return cls("-", "", -1)
|
|
48
|
+
matches = Cfg.fullmatches("clue", value)
|
|
49
|
+
if matches["sep"] or matches["num"]:
|
|
50
|
+
sep = matches["sep"]
|
|
51
|
+
else:
|
|
52
|
+
sep = "?"
|
|
53
|
+
if matches["num"].startswith("0"):
|
|
54
|
+
mag = len(matches["num"])
|
|
55
|
+
else:
|
|
56
|
+
mag = -len(matches["num"])
|
|
57
|
+
return cls(matches["head"], sep, mag)
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def by_examples(cls: type, *values: str) -> Self:
|
|
61
|
+
ans: Self = cls()
|
|
62
|
+
s: str
|
|
63
|
+
for s in values:
|
|
64
|
+
ans &= cls.by_string(s)
|
|
65
|
+
return ans
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def by_spec(cls: type, value: str, /) -> Self:
|
|
69
|
+
matches: dict[str, str]
|
|
70
|
+
matches = Cfg.fullmatches("clue_f", value)
|
|
71
|
+
return cls(matches["head_f"], matches["sep_f"], len(matches["num_f"]))
|
|
72
|
+
|
|
73
|
+
def seal(self: Self) -> Self:
|
|
74
|
+
mag: int
|
|
75
|
+
mag = self.mag if self.mag >= -1 else -1
|
|
76
|
+
return type(self)(self.head, self.sep, mag)
|
|
77
|
+
|
|
78
|
+
def solo(self: Self, hollow: str) -> str:
|
|
79
|
+
sep: str
|
|
80
|
+
mag: int
|
|
81
|
+
if self.head == "":
|
|
82
|
+
return ""
|
|
83
|
+
mag = self.mag if self.mag >= -1 else -1
|
|
84
|
+
sep = self.sep.replace("?", "")
|
|
85
|
+
if self.head == hollow and sep == "" and mag in (-1, 1):
|
|
86
|
+
return ""
|
|
87
|
+
return self.head + sep + max(0, mag) * "#"
|
|
88
|
+
|
|
89
|
+
def possible(self: Self, *, hollow: str, short: str) -> set:
|
|
90
|
+
s: str
|
|
91
|
+
n: str
|
|
92
|
+
seps: set[str]
|
|
93
|
+
nums: set[str]
|
|
94
|
+
ans: set
|
|
95
|
+
ans = set()
|
|
96
|
+
if self.head == "":
|
|
97
|
+
ans.add("")
|
|
98
|
+
ans.add(short + "#")
|
|
99
|
+
return ans
|
|
100
|
+
if self.sep != "?":
|
|
101
|
+
seps = {self.sep}
|
|
102
|
+
else:
|
|
103
|
+
seps = {"", "."}
|
|
104
|
+
if self.mag < 0:
|
|
105
|
+
nums = {"", "#"}
|
|
106
|
+
else:
|
|
107
|
+
nums = {"#" * self.mag}
|
|
108
|
+
ans = set()
|
|
109
|
+
for s in seps:
|
|
110
|
+
for n in nums:
|
|
111
|
+
ans.add(self.head + s + n)
|
|
112
|
+
if (hollow + "#") in ans:
|
|
113
|
+
ans.add("")
|
|
114
|
+
return ans
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import *
|
|
3
|
+
|
|
4
|
+
import setdoc
|
|
5
|
+
from datahold import OkayList
|
|
6
|
+
from datarepr import datarepr
|
|
7
|
+
|
|
8
|
+
from v440._utils.BaseStringer import BaseStringer
|
|
9
|
+
from v440._utils.guarding import guard
|
|
10
|
+
|
|
11
|
+
__all__ = ["ListStringer"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ListStringer(BaseStringer, OkayList):
|
|
15
|
+
|
|
16
|
+
__slots__ = ()
|
|
17
|
+
string: str
|
|
18
|
+
packaging: Any
|
|
19
|
+
data: tuple
|
|
20
|
+
|
|
21
|
+
@setdoc.basic
|
|
22
|
+
def __add__(self: Self, other: Any) -> Self:
|
|
23
|
+
alt: tuple
|
|
24
|
+
ans: Self
|
|
25
|
+
try:
|
|
26
|
+
alt = tuple(other)
|
|
27
|
+
except Exception:
|
|
28
|
+
return NotImplemented
|
|
29
|
+
ans = type(self)()
|
|
30
|
+
ans.data = self.data + alt
|
|
31
|
+
return ans
|
|
32
|
+
|
|
33
|
+
@setdoc.basic
|
|
34
|
+
def __bool__(self: Self) -> bool:
|
|
35
|
+
return bool(self.data)
|
|
36
|
+
|
|
37
|
+
@setdoc.basic
|
|
38
|
+
def __mul__(self: Self, other: Any) -> Self:
|
|
39
|
+
ans: Self
|
|
40
|
+
ans = type(self)()
|
|
41
|
+
ans.data = self.data * other
|
|
42
|
+
return ans
|
|
43
|
+
|
|
44
|
+
@setdoc.basic
|
|
45
|
+
def __radd__(self: Self, other: Any) -> Self:
|
|
46
|
+
alt: tuple
|
|
47
|
+
ans: Self
|
|
48
|
+
try:
|
|
49
|
+
alt = tuple(other)
|
|
50
|
+
except Exception:
|
|
51
|
+
return NotImplemented
|
|
52
|
+
ans = type(self)()
|
|
53
|
+
ans.data = alt + self.data
|
|
54
|
+
return ans
|
|
55
|
+
|
|
56
|
+
@setdoc.basic
|
|
57
|
+
def __repr__(self: Self) -> str:
|
|
58
|
+
return datarepr(type(self).__name__, list(self))
|
|
59
|
+
|
|
60
|
+
def _cmp(self: Self) -> tuple:
|
|
61
|
+
return tuple(map(self._sort, self.data))
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def _data_parse(cls: type, value: list) -> Iterable: ...
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def _sort(cls: type, value: Any): ...
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
@setdoc.basic
|
|
73
|
+
def data(self: Self) -> tuple:
|
|
74
|
+
return self._data
|
|
75
|
+
|
|
76
|
+
@data.setter
|
|
77
|
+
@guard
|
|
78
|
+
def data(self: Self, value: Iterable) -> None:
|
|
79
|
+
self._data = tuple(self._data_parse(list(value)))
|
|
80
|
+
|
|
81
|
+
def sort(self: Self, *, key: Any = None, reverse: Any = False) -> None:
|
|
82
|
+
"This method sorts the data."
|
|
83
|
+
data: list
|
|
84
|
+
k: Any
|
|
85
|
+
r: bool
|
|
86
|
+
data = list(self.data)
|
|
87
|
+
k = self._sort if key is None else key
|
|
88
|
+
r = bool(reverse)
|
|
89
|
+
data.sort(key=k, reverse=r)
|
|
90
|
+
self.data = data
|
|
@@ -15,12 +15,13 @@ class QualStringer(BaseStringer):
|
|
|
15
15
|
__slots__ = ("_lit", "_num")
|
|
16
16
|
|
|
17
17
|
string: str
|
|
18
|
+
packaging: Any
|
|
18
19
|
lit: str
|
|
19
20
|
num: int
|
|
20
21
|
|
|
21
22
|
@setdoc.basic
|
|
22
23
|
def __bool__(self: Self) -> bool:
|
|
23
|
-
return self.lit
|
|
24
|
+
return bool(self.lit)
|
|
24
25
|
|
|
25
26
|
@setdoc.basic
|
|
26
27
|
def __init__(self: Self, string: Any = "") -> None:
|
|
@@ -36,29 +37,25 @@ class QualStringer(BaseStringer):
|
|
|
36
37
|
num=self.num,
|
|
37
38
|
)
|
|
38
39
|
|
|
39
|
-
def _format(self: Self, format_spec: str) -> str:
|
|
40
|
-
if format_spec:
|
|
41
|
-
raise ValueError
|
|
42
|
-
if self.lit:
|
|
43
|
-
return self.lit + str(self.num)
|
|
44
|
-
else:
|
|
45
|
-
return ""
|
|
46
|
-
|
|
47
40
|
@classmethod
|
|
48
41
|
@abstractmethod
|
|
49
42
|
def _lit_parse(cls: type, value: str) -> str: ...
|
|
50
43
|
|
|
51
44
|
def _string_fset(self: Self, value: str) -> None:
|
|
45
|
+
x: str
|
|
46
|
+
y: str
|
|
52
47
|
if value == "":
|
|
53
48
|
self._lit = ""
|
|
54
49
|
self._num = 0
|
|
55
50
|
return
|
|
56
|
-
x
|
|
57
|
-
y
|
|
51
|
+
x = value.rstrip("0123456789")
|
|
52
|
+
y = value[len(x) :]
|
|
58
53
|
if x == "-":
|
|
59
|
-
|
|
54
|
+
if not y:
|
|
55
|
+
raise ValueError
|
|
56
|
+
self._lit = self._lit_parse("-")
|
|
57
|
+
self._num = int(y)
|
|
60
58
|
return
|
|
61
|
-
x = x.lower()
|
|
62
59
|
x = x.replace("-", ".")
|
|
63
60
|
x = x.replace("_", ".")
|
|
64
61
|
if x.endswith("."):
|
|
@@ -72,8 +69,21 @@ class QualStringer(BaseStringer):
|
|
|
72
69
|
self._lit = self._lit_parse(x)
|
|
73
70
|
self._num = int("0" + y)
|
|
74
71
|
|
|
75
|
-
@
|
|
76
|
-
def
|
|
72
|
+
@property
|
|
73
|
+
def lit(self: Self) -> str:
|
|
74
|
+
return self._lit
|
|
75
|
+
|
|
76
|
+
@lit.setter
|
|
77
|
+
@guard
|
|
78
|
+
def lit(self: Self, value: Any) -> None:
|
|
79
|
+
x: str
|
|
80
|
+
x = str(value).lower()
|
|
81
|
+
if x:
|
|
82
|
+
self._lit = self._lit_parse(x)
|
|
83
|
+
elif self.num:
|
|
84
|
+
self.string = self.num
|
|
85
|
+
else:
|
|
86
|
+
self._lit = ""
|
|
77
87
|
|
|
78
88
|
@property
|
|
79
89
|
def num(self: Self) -> int:
|
|
@@ -82,25 +92,11 @@ class QualStringer(BaseStringer):
|
|
|
82
92
|
@num.setter
|
|
83
93
|
@guard
|
|
84
94
|
def num(self: Self, value: SupportsIndex) -> None:
|
|
85
|
-
y: int
|
|
95
|
+
y: int
|
|
96
|
+
y = operator.index(value)
|
|
86
97
|
if y < 0:
|
|
87
98
|
raise ValueError
|
|
88
99
|
if y and not self.lit:
|
|
89
100
|
self.string = y
|
|
90
101
|
else:
|
|
91
102
|
self._num = y
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def lit(self: Self) -> str:
|
|
95
|
-
return self._lit
|
|
96
|
-
|
|
97
|
-
@lit.setter
|
|
98
|
-
@guard
|
|
99
|
-
def lit(self: Self, value: Any) -> None:
|
|
100
|
-
x: str = str(value).lower()
|
|
101
|
-
if x:
|
|
102
|
-
self._lit = self._lit_parse(x)
|
|
103
|
-
elif self.num:
|
|
104
|
-
self.string = self.num
|
|
105
|
-
else:
|
|
106
|
-
self._lit = ""
|
|
@@ -13,6 +13,7 @@ class SlotStringer(BaseStringer):
|
|
|
13
13
|
__slots__ = ()
|
|
14
14
|
|
|
15
15
|
string: str
|
|
16
|
+
packaging: str
|
|
16
17
|
|
|
17
18
|
@setdoc.basic
|
|
18
19
|
def __bool__(self: Self) -> bool:
|
|
@@ -24,3 +25,5 @@ class SlotStringer(BaseStringer):
|
|
|
24
25
|
|
|
25
26
|
@abstractmethod
|
|
26
27
|
def _todict(self: Self) -> dict: ...
|
|
28
|
+
|
|
29
|
+
packaging = BaseStringer.string
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[consts.errors]
|
|
2
|
+
deformat = "No common format specifier for %s."
|
|
3
|
+
format = "Invalid format specifier %r for object of type %r."
|
|
4
|
+
|
|
5
|
+
[consts.phases]
|
|
6
|
+
alpha = "a"
|
|
7
|
+
a = "a"
|
|
8
|
+
beta = "b"
|
|
9
|
+
b = "b"
|
|
10
|
+
preview = "rc"
|
|
11
|
+
pre = "rc"
|
|
12
|
+
c = "rc"
|
|
13
|
+
rc = "rc"
|
|
14
|
+
|
|
15
|
+
[patterns]
|
|
16
|
+
basev_f = "V?"
|
|
17
|
+
epoch_f = "\\#*"
|
|
18
|
+
release_f = "[\\#\\.]*"
|
|
19
|
+
base_f = "{basev_f}({epoch_f}!)?{release_f}"
|
|
20
|
+
a_f = "[-_\\.]?(ALPHA|A)[-_\\.]?\\#*"
|
|
21
|
+
b_f = "[-_\\.]?(BETA|B)[-_\\.]?\\#*"
|
|
22
|
+
rc_f = "[-_\\.]?(PREVIEW|PRE|C|RC)[-_\\.]?\\#*"
|
|
23
|
+
pre_f = "{a_f}?{b_f}?{rc_f}?"
|
|
24
|
+
post_hyphen_f = "-"
|
|
25
|
+
post_head_f = "[-_\\.]?(POST|REV|R)"
|
|
26
|
+
post_sep_f = "[-_\\.]?"
|
|
27
|
+
post_lit_f = "({post_hyphen_f}|({post_head_f}{post_sep_f}))"
|
|
28
|
+
post_num_f = "\\#*"
|
|
29
|
+
post_f = "({post_lit_f}{post_num_f})?"
|
|
30
|
+
dev_head_f = "[-_\\.]?DEV"
|
|
31
|
+
dev_sep_f = "[-_\\.]?"
|
|
32
|
+
dev_num_f = "\\#*"
|
|
33
|
+
dev_f = "({dev_head_f}{dev_sep_f}{dev_num_f})?"
|
|
34
|
+
qual_f = "{pre_f}{post_f}{dev_f}"
|
|
35
|
+
basev = "V"
|
|
36
|
+
epoch = "[0-9]+"
|
|
37
|
+
release = "[0-9]+(\\.[0-9]+)*"
|
|
38
|
+
base = "{basev}?({epoch}!)?{release}"
|
|
39
|
+
pre = "[-_\\.]?(ALPHA|A|BETA|B|PREVIEW|PRE|C|RC)([-_\\.]?[0-9]+)?"
|
|
40
|
+
post = "(-([0-9]+))|(([-_\\.]?(POST|REV|R))([-_\\.]?([0-9]+))?)"
|
|
41
|
+
dev = "[-_\\.]?DEV([-_\\.]?[0-9]+)?"
|
|
42
|
+
qual = "{pre}?{post}?{dev}?"
|
|
43
|
+
local_splitter = "([-_\\.])"
|
|
44
|
+
head = "[-_\\.]?[A-Z]*"
|
|
45
|
+
sep = "[-_\\.]?"
|
|
46
|
+
num = "[0-9]*"
|
|
47
|
+
clue = "{head}?{sep}?{num}?"
|
|
48
|
+
head_f = "[-_\\.]?[A-Z]*"
|
|
49
|
+
sep_f = "[-_\\.]?"
|
|
50
|
+
num_f = "\\#*"
|
|
51
|
+
clue_f = "{head_f}?{sep_f}?{num_f}?"
|
|
@@ -11,16 +11,19 @@ __all__ = ["guard"]
|
|
|
11
11
|
def guard(old: Any) -> Any:
|
|
12
12
|
@functools.wraps(old)
|
|
13
13
|
def new(self: Self, value: Any) -> None:
|
|
14
|
-
backup: str
|
|
14
|
+
backup: str
|
|
15
|
+
msg: str
|
|
16
|
+
target: str
|
|
17
|
+
backup = str(self)
|
|
15
18
|
try:
|
|
16
19
|
old(self, value)
|
|
17
20
|
except VersionError:
|
|
18
21
|
self.string = backup
|
|
19
22
|
raise
|
|
20
23
|
except Exception:
|
|
21
|
-
self.
|
|
22
|
-
msg
|
|
23
|
-
target
|
|
24
|
+
self._string_fset(backup.lower())
|
|
25
|
+
msg = "%r is an invalid value for %r"
|
|
26
|
+
target = type(self).__name__ + "." + old.__name__
|
|
24
27
|
msg %= (value, target)
|
|
25
28
|
raise VersionError(msg)
|
|
26
29
|
|
|
@@ -7,8 +7,8 @@ from typing import *
|
|
|
7
7
|
from v440._utils.releaseparse import ranging
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def getitem(data: tuple, key: SupportsIndex | slice) -> list:
|
|
11
|
-
ans: int |
|
|
10
|
+
def getitem(data: tuple, key: SupportsIndex | slice) -> int | list:
|
|
11
|
+
ans: int | list
|
|
12
12
|
if type(key) is slice:
|
|
13
13
|
r: range = ranging.torange(key, len(data))
|
|
14
14
|
f: partial = partial(getitem_int, data)
|