v440 2.0.0.dev182__tar.gz → 2.0.0.dev184__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.
Files changed (42) hide show
  1. {v440-2.0.0.dev182/src/v440.egg-info → v440-2.0.0.dev184}/PKG-INFO +1 -1
  2. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/pyproject.toml +1 -1
  3. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/BaseStringer.py +0 -3
  4. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/Pattern.py +4 -1
  5. v440-2.0.0.dev184/src/v440/_utils/QualStringer.py +127 -0
  6. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/SlotStringer.py +4 -1
  7. v440-2.0.0.dev184/src/v440/core/Dev.py +31 -0
  8. v440-2.0.0.dev184/src/v440/core/Post.py +32 -0
  9. v440-2.0.0.dev184/src/v440/core/Pre.py +28 -0
  10. v440-2.0.0.dev184/src/v440/core/Qual.py +124 -0
  11. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/Release.py +2 -0
  12. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/tests/test_testdata.py +4 -42
  13. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/tests/test_version.py +12 -12
  14. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/tests/testdata.toml +15 -110
  15. {v440-2.0.0.dev182 → v440-2.0.0.dev184/src/v440.egg-info}/PKG-INFO +1 -1
  16. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440.egg-info/SOURCES.txt +4 -0
  17. v440-2.0.0.dev182/src/v440/core/Qual.py +0 -225
  18. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/LICENSE.txt +0 -0
  19. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/MANIFEST.in +0 -0
  20. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/README.rst +0 -0
  21. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/setup.cfg +0 -0
  22. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/__init__.py +0 -0
  23. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/Cfg.py +0 -0
  24. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/ListStringer.py +0 -0
  25. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/__init__.py +0 -0
  26. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/cfg.toml +0 -0
  27. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/guarding.py +0 -0
  28. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/releaseparse/__init__.py +0 -0
  29. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/releaseparse/deleting.py +0 -0
  30. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/releaseparse/getting.py +0 -0
  31. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/releaseparse/ranging.py +0 -0
  32. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/_utils/releaseparse/setting.py +0 -0
  33. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/Base.py +0 -0
  34. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/Local.py +0 -0
  35. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/Public.py +0 -0
  36. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/Version.py +0 -0
  37. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/VersionError.py +0 -0
  38. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/core/__init__.py +0 -0
  39. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440/tests/__init__.py +0 -0
  40. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440.egg-info/dependency_links.txt +0 -0
  41. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/src/v440.egg-info/requires.txt +0 -0
  42. {v440-2.0.0.dev182 → v440-2.0.0.dev184}/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.dev182
3
+ Version: 2.0.0.dev184
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)
@@ -37,7 +37,7 @@ keywords = []
37
37
  name = "v440"
38
38
  readme = "README.rst"
39
39
  requires-python = ">=3.11"
40
- version = "2.0.0.dev182"
40
+ version = "2.0.0.dev184"
41
41
 
42
42
  [project.license]
43
43
  file = "LICENSE.txt"
@@ -93,9 +93,6 @@ class BaseStringer(metaclass=ABCMeta):
93
93
  @abstractmethod
94
94
  def _string_fset(self: Self, value: str) -> None: ...
95
95
 
96
- @abstractmethod
97
- def _todict(self: Self) -> dict: ...
98
-
99
96
  @setdoc.basic
100
97
  def copy(self: Self) -> Self:
101
98
  return type(self)(self)
@@ -8,7 +8,10 @@ class Pattern(enum.StrEnum):
8
8
 
9
9
  EPOCH = r"""(?:(?P<n>[0-9]+)!?)?"""
10
10
  PARSER = r"(?:\.?(?P<l>[a-z]+))?(?:\.?(?P<n>[0-9]+))?"
11
- PRE = r"\.?([a-z]+)\.?(\d*)"
11
+ PRE = r"[-_\.]?(?:alpha|a|beta|b|preview|pre|c|rc)(?:[-_\.]?[0-9]+)?"
12
+ POST = r"(?:-(?:[0-9]+))|(?:(?:[-_\.]?(?:post|rev|r))(?:[-_\.]?(?:[0-9]+))?)"
13
+ DEV = r"[-_\.]?dev(?:[-_\.]?[0-9]+)?"
14
+ QUAL = r"(?P<pre>%s)?(?P<post>%s)?(?P<dev>%s)?" % (PRE, POST, DEV)
12
15
  PUBLIC = r"(v?([0-9]+!)?[0-9]+(\.[0-9]+)*)?"
13
16
  QUALIFIERS = r"(([-_\.]?(?P<l>[a-z]+)[-_\.]?(?P<n>[0-9]*))|(-(?P<N>[0-9]+)))"
14
17
 
@@ -0,0 +1,127 @@
1
+ import operator
2
+ from abc import abstractmethod
3
+ from typing import *
4
+
5
+ import setdoc
6
+ from datarepr import datarepr
7
+ from overloadable import Overloadable
8
+
9
+ from v440._utils.BaseStringer import BaseStringer
10
+ from v440._utils.guarding import guard
11
+
12
+ __all__ = ["QualStringer"]
13
+
14
+
15
+ class QualStringer(BaseStringer):
16
+ __slots__ = ("_phase", "_num")
17
+
18
+ string: str
19
+ phase: str
20
+ num: int
21
+
22
+ @setdoc.basic
23
+ def __bool__(self: Self) -> bool:
24
+ return self.phase != ""
25
+
26
+ @Overloadable
27
+ @setdoc.basic
28
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> str:
29
+ self._phase = ""
30
+ self._num = 0
31
+ argc: int = len(args) + len(kwargs)
32
+ keys: set = set(kwargs.keys())
33
+ if argc <= 1 and keys <= {"string"}:
34
+ return "string"
35
+ return "slots"
36
+
37
+ @__init__.overload("string")
38
+ @setdoc.basic
39
+ def __init__(self: Self, string: Any = "") -> None:
40
+ self.string = string
41
+
42
+ @__init__.overload("slots")
43
+ @setdoc.basic
44
+ def __init__(
45
+ self: Self,
46
+ phase: Any = "",
47
+ num: Any = 0,
48
+ ) -> None:
49
+ self.phase = phase
50
+ self.num = num
51
+
52
+ @setdoc.basic
53
+ def __repr__(self: Self) -> str:
54
+ return datarepr(
55
+ type(self).__name__,
56
+ phase=self.phase,
57
+ num=self.num,
58
+ )
59
+
60
+ def _format(self: Self, format_spec: str) -> str:
61
+ if format_spec:
62
+ raise ValueError
63
+ if self.phase:
64
+ return self.phase + str(self.num)
65
+ else:
66
+ return ""
67
+
68
+ @classmethod
69
+ @abstractmethod
70
+ def _phase_parse(cls: type, value: str) -> str: ...
71
+
72
+ def _string_fset(self: Self, value: str) -> None:
73
+ if value == "":
74
+ self._phase = ""
75
+ self._num = 0
76
+ return
77
+ x: str = value.rstrip("0123456789")
78
+ y: str = value[len(x) :]
79
+ if x == "-":
80
+ self._string_fset_minus(y)
81
+ return
82
+ x = x.lower()
83
+ x = x.replace("-", ".")
84
+ x = x.replace("_", ".")
85
+ if x.endswith("."):
86
+ x = x[:-1]
87
+ if not y:
88
+ raise ValueError
89
+ if x.startswith("."):
90
+ x = x[1:]
91
+ if not x:
92
+ raise ValueError
93
+ self._phase = self._phase_parse(x)
94
+ self._num = int("0" + y)
95
+
96
+ @abstractmethod
97
+ def _string_fset_minus(self: Self, value: str) -> None: ...
98
+
99
+ @property
100
+ def num(self: Self) -> int:
101
+ return self._num
102
+
103
+ @num.setter
104
+ @guard
105
+ def num(self: Self, value: SupportsIndex) -> None:
106
+ y: int = operator.index(value)
107
+ if y < 0:
108
+ raise ValueError
109
+ if y and not self.phase:
110
+ self.string = y
111
+ else:
112
+ self._num = y
113
+
114
+ @property
115
+ def phase(self: Self) -> str:
116
+ return self._phase
117
+
118
+ @phase.setter
119
+ @guard
120
+ def phase(self: Self, value: Any) -> None:
121
+ x: str = str(value).lower()
122
+ if x:
123
+ self._phase = self._phase_parse(x)
124
+ elif self.num:
125
+ self.string = self.num
126
+ else:
127
+ self._phase = ""
@@ -1,4 +1,4 @@
1
- from functools import partial
1
+ from abc import abstractmethod
2
2
  from typing import *
3
3
 
4
4
  import setdoc
@@ -17,3 +17,6 @@ class SlotStringer(BaseStringer):
17
17
  @setdoc.basic
18
18
  def __repr__(self: Self) -> str:
19
19
  return datarepr(type(self).__name__, **self._todict())
20
+
21
+ @abstractmethod
22
+ def _todict(self: Self) -> dict: ...
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import *
4
+
5
+ from v440._utils.QualStringer import QualStringer
6
+
7
+ __all__ = ["Dev"]
8
+
9
+
10
+ class Dev(QualStringer):
11
+
12
+ __slots__ = ()
13
+ string: str
14
+ phase: str
15
+ num: int
16
+
17
+ def _cmp(self: Self) -> tuple:
18
+ if self.phase:
19
+ return 0, self.num
20
+ else:
21
+ return (1,)
22
+
23
+ @classmethod
24
+ def _phase_parse(cls: type, value: str) -> str:
25
+ if value == "dev":
26
+ return "dev"
27
+ else:
28
+ raise ValueError
29
+
30
+ def _string_fset_minus(self: Self, value: str) -> None:
31
+ raise ValueError
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import *
4
+
5
+ from v440._utils.QualStringer import QualStringer
6
+
7
+ __all__ = ["Post"]
8
+
9
+
10
+ class Post(QualStringer):
11
+
12
+ __slots__ = ()
13
+ string: str
14
+ phase: str
15
+ num: int
16
+
17
+ def _cmp(self: Self) -> int:
18
+ if self.phase:
19
+ return self.num
20
+ else:
21
+ return -1
22
+
23
+ @classmethod
24
+ def _phase_parse(cls: type, value: str) -> str:
25
+ if value in ("post", "r", "rev"):
26
+ return "post"
27
+ else:
28
+ raise ValueError
29
+
30
+ def _string_fset_minus(self: Self, value: str) -> None:
31
+ self._phase = "post"
32
+ self._num = int(value)
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import *
4
+
5
+ from v440._utils.Cfg import Cfg
6
+ from v440._utils.QualStringer import QualStringer
7
+
8
+ __all__ = ["Pre"]
9
+
10
+
11
+ class Pre(QualStringer):
12
+
13
+ __slots__ = ()
14
+ string: str
15
+ phase: str
16
+ num: int
17
+
18
+ def _cmp(self: Self) -> tuple:
19
+ if not self:
20
+ return frozenset("0")
21
+ return frozenset("1"), self.phase, self.num
22
+
23
+ @classmethod
24
+ def _phase_parse(cls: type, value: str) -> str:
25
+ return Cfg.cfg.data["phases"][value]
26
+
27
+ def _string_fset_minus(self: Self, value: str) -> None:
28
+ raise ValueError
@@ -0,0 +1,124 @@
1
+ from __future__ import annotations
2
+
3
+ import operator
4
+ import string as string_
5
+ from typing import *
6
+
7
+ import setdoc
8
+ from overloadable import Overloadable
9
+
10
+ from v440._utils.Cfg import Cfg
11
+ from v440._utils.guarding import guard
12
+ from v440._utils.Pattern import Pattern
13
+ from v440._utils.SlotStringer import SlotStringer
14
+ from v440.core.Dev import Dev
15
+ from v440.core.Post import Post
16
+ from v440.core.Pre import Pre
17
+
18
+ __all__ = ["Qual"]
19
+
20
+
21
+ class Qual(SlotStringer):
22
+
23
+ __slots__ = ("_pre", "_post", "_dev")
24
+ string: str
25
+ pre: Pre
26
+ post: Post
27
+ dev: Dev
28
+
29
+ @setdoc.basic
30
+ def __bool__(self: Self) -> bool:
31
+ return bool(self.pre or self.post or self.dev)
32
+
33
+ @Overloadable
34
+ @setdoc.basic
35
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> str:
36
+ self._pre = Pre()
37
+ self._post = Post()
38
+ self._dev = Dev()
39
+ argc: int = len(args) + len(kwargs)
40
+ keys: set = set(kwargs.keys())
41
+ if argc <= 1 and keys <= {"string"}:
42
+ return "string"
43
+ return "slots"
44
+
45
+ @__init__.overload("string")
46
+ @setdoc.basic
47
+ def __init__(self: Self, string: Any = "") -> None:
48
+ self.string = string
49
+
50
+ @__init__.overload("slots")
51
+ @setdoc.basic
52
+ def __init__(
53
+ self: Self,
54
+ pre: Any = "",
55
+ post: Any = "",
56
+ dev: Any = "",
57
+ ) -> None:
58
+ self.pre = pre
59
+ self.post = post
60
+ self.dev = dev
61
+
62
+ def _cmp(self: Self) -> list:
63
+ ans: tuple = ()
64
+ if self.pre:
65
+ ans += (self.pre.phase, self.pre.num)
66
+ elif self.post is not None:
67
+ ans += ("z", 0)
68
+ elif self.dev is None:
69
+ ans += ("z", 0)
70
+ else:
71
+ ans += ("", 0)
72
+ ans += (self.post, self.dev)
73
+ return ans
74
+
75
+ def _format(self: Self, format_spec: str) -> str:
76
+ if format_spec:
77
+ raise ValueError
78
+ ans: str = str(self.pre)
79
+ if self.post:
80
+ ans += "." + str(self.post)
81
+ if self.dev:
82
+ ans += "." + str(self.dev)
83
+ return ans
84
+
85
+ @classmethod
86
+ def _none_empty(cls: type, value: Optional[str]) -> str:
87
+ if value is None:
88
+ return ""
89
+ else:
90
+ return value
91
+
92
+ def _string_fset(self: Self, value: str) -> None:
93
+ m: Any = Pattern.QUAL.bound.search(value.lower())
94
+ self.pre.string = self._none_empty(m.group("pre"))
95
+ self.post.string = self._none_empty(m.group("post"))
96
+ self.dev.string = self._none_empty(m.group("dev"))
97
+
98
+ def _todict(self: Self) -> dict:
99
+ return dict(pre=self.pre, post=self.post, dev=self.dev)
100
+
101
+ @property
102
+ def dev(self: Self) -> Pre:
103
+ "This property represents the stage of development."
104
+ return self._dev
105
+
106
+ def isdevrelease(self: Self) -> bool:
107
+ "This method returns whether the current instance denotes a dev-release."
108
+ return bool(self.dev)
109
+
110
+ def isprerelease(self: Self) -> bool:
111
+ "This method returns whether the current instance denotes a pre-release."
112
+ return bool(self.pre) or bool(self.dev)
113
+
114
+ def ispostrelease(self: Self) -> bool:
115
+ "This method returns whether the current instance denotes a post-release."
116
+ return bool(self.post)
117
+
118
+ @property
119
+ def post(self: Self) -> Post:
120
+ return self._post
121
+
122
+ @property
123
+ def pre(self: Self) -> Pre:
124
+ return self._pre
@@ -124,6 +124,8 @@ class Release(ListStringer):
124
124
  if value == "":
125
125
  self.data = ()
126
126
  return
127
+ if value.strip("0123456789_-."):
128
+ raise ValueError
127
129
  v: str = value
128
130
  v = v.replace("_", ".")
129
131
  v = v.replace("-", ".")
@@ -199,56 +199,18 @@ class TestVersionRelease(unittest.TestCase):
199
199
  self.assertEqual(list(release), solution)
200
200
 
201
201
 
202
- class TestDevGo(unittest.TestCase):
203
- def test_dev_as_tuple(self: Self) -> None:
204
- self.go_key(
205
- key="test_dev_as_list_mixed_case",
206
- setup="1.2.3.dev9000",
207
- update=None,
208
- text="1.2.3",
209
- solution=None,
210
- dev_type=type(None),
211
- )
212
-
213
- def test_strings_a(self: Self) -> None:
214
- k: str
215
- v: dict
216
- for k, v in Util.util.data["devint"].items():
217
- self.go_key(**v, key=k)
218
-
219
- def go_key(self: Self, key: str, **kwargs: Any) -> None:
220
- msg: str = "dev %r" % key
221
- with self.subTest(key=key):
222
- self.go(**kwargs, msg=msg)
223
-
224
- def go(
225
- self: Self,
226
- msg: str,
227
- setup: Any,
228
- text: str,
229
- solution: Any = None,
230
- update: Any = None,
231
- dev_type: type = int,
232
- ):
233
- v: Version = Version(setup)
234
- v.public.qual.dev = update
235
- self.assertEqual(str(v), text, msg=msg)
236
- self.assertIsInstance(v.public.qual.dev, dev_type, msg=msg)
237
- self.assertEqual(v.public.qual.dev, solution, msg=msg)
238
-
239
-
240
202
  class TestVersionSpecifiersGo(unittest.TestCase):
241
203
 
242
204
  def test_spec_toml(self: Self) -> None:
243
205
  k: str
244
206
  v: dict
245
207
  for k, v in Util.util.data["spec"].items():
246
- self.go(**v, key=k)
208
+ with self.subTest(key=k):
209
+ self.go(**v)
247
210
 
248
- def go(self: Self, string_a: str, string_b: str, key: str = "") -> None:
249
- msg: str = "spec %r" % key
211
+ def go(self: Self, string_a: str, string_b: str) -> None:
250
212
  version: Version = Version(string_a)
251
- self.assertEqual(str(version), string_b, msg=msg)
213
+ self.assertEqual(str(version), string_b)
252
214
 
253
215
 
254
216
  class TestPackagingA(unittest.TestCase):
@@ -67,17 +67,17 @@ class TestPre(unittest.TestCase):
67
67
  self.assertEqual(str(v.public.qual), "a1")
68
68
 
69
69
  # Modify pre-release phase to "preview"
70
- v.public.qual.prephase = "preview"
70
+ v.public.qual.pre.phase = "preview"
71
71
  self.assertEqual(str(v), "1.2.3rc1")
72
72
  self.assertEqual(str(v.public.qual), "rc1")
73
73
 
74
74
  # Modify subphase to "42"
75
- v.public.qual.prenum = 42
75
+ v.public.qual.pre.num = 42
76
76
  self.assertEqual(str(v), "1.2.3rc42")
77
77
  self.assertEqual(str(v.public.qual), "rc42")
78
78
 
79
79
  # Change phase to a formatted string "BeTa"
80
- v.public.qual.prephase = "BeTa"
80
+ v.public.qual.pre.phase = "BeTa"
81
81
  self.assertEqual(str(v), "1.2.3b42")
82
82
  self.assertEqual(str(v.public.qual), "b42")
83
83
  self.assertEqual(v.public.qual, backup)
@@ -179,27 +179,27 @@ class TestExample(unittest.TestCase):
179
179
  def test_example_5(self: Self) -> None:
180
180
  v: Version = Version("2.0.0-alpha.1")
181
181
  self.assertEqual(str(v), "2a1") # Pre-release version
182
- v.public.qual.pre = "beta.2"
182
+ v.public.qual.pre.string = "beta.2"
183
183
  self.assertEqual(str(v), "2b2") # Modified pre-release version
184
184
  with self.assertRaises(Exception):
185
185
  v.public.qual.pre[1] = 4
186
186
  self.assertEqual(str(v), "2b2") # Further modified pre-release version
187
- v.public.qual.prephase = "PrEvIeW"
187
+ v.public.qual.pre.phase = "PrEvIeW"
188
188
  self.assertEqual(str(v), "2rc2") # Even further modified pre-release version
189
189
 
190
190
  def test_example_6(self: Self) -> None:
191
191
  v: Version = Version("1.2.3")
192
- v.public.qual.post = 1
192
+ v.public.qual.post.string = -1
193
193
  v.local.string = "local.7.dev"
194
194
  self.assertEqual(str(v), "1.2.3.post1+local.7.dev") # Post-release version
195
195
  self.assertEqual(
196
196
  format(v, "02r"), "1.2.3.post1+local.7.dev"
197
197
  ) # Formatted version
198
- v.public.qual.post = 2
198
+ v.public.qual.post.string = -2
199
199
  self.assertEqual(str(v), "1.2.3.post2+local.7.dev") # Modified version
200
- v.public.qual.post = None
200
+ v.public.qual.post.string = ""
201
201
  self.assertEqual(str(v), "1.2.3+local.7.dev") # Modified without post
202
- v.public.qual.post = 3
202
+ v.public.qual.post.string = -3
203
203
  v.local.sort()
204
204
  self.assertEqual(str(v), "1.2.3.post3+dev.local.7") # After sorting local
205
205
  v.local.append(8)
@@ -430,13 +430,13 @@ class TestDevNoGo(unittest.TestCase):
430
430
  def test_initial_none_dev(self: Self) -> None:
431
431
  v: Version = Version("1.2.3")
432
432
  self.assertEqual(str(v), "1.2.3")
433
- self.assertIsNone(v.public.qual.dev)
433
+ self.assertFalse(v.public.qual.dev)
434
434
 
435
435
  def test_dev_as_none(self: Self) -> None:
436
436
  v: Version = Version("1.2.3")
437
- v.public.qual.dev = None
437
+ v.public.qual.dev.string = ""
438
438
  self.assertEqual(str(v), "1.2.3")
439
- self.assertIsNone(v.public.qual.dev)
439
+ self.assertFalse(v.public.qual.dev)
440
440
 
441
441
 
442
442
  if __name__ == "__main__":
@@ -671,6 +671,7 @@ Post-releases = [
671
671
  "1.2.3a1.post11.dev7+sha256.abc123def456",
672
672
  "0!0.0.0a1.post9999.dev8888+local-build.0",
673
673
  "42!1.0.0rc999.post999.dev9999+exp.build.local1",
674
+ "1!1.2.3a1.post6.dev5+local",
674
675
  ]
675
676
  "Combining epochs with local versions" = [
676
677
  "2!1.0.0+local.version.1234",
@@ -716,26 +717,26 @@ Post-releases = [
716
717
  ]
717
718
  "Difficult Qualification Relations" = ['1.2.3', '1.2.3.dev0', '1.2.3.dev1', '1.2.3.dev2', '1.2.3.post0', '1.2.3.post0.dev0', '1.2.3.post0.dev1', '1.2.3.post0.dev2', '1.2.3.post10', '1.2.3.post10.dev0', '1.2.3.post10.dev1', '1.2.3.post10.dev2', '1.2.3a0', '1.2.3a0.dev0', '1.2.3a0.dev1', '1.2.3a0.dev2', '1.2.3a0.post0', '1.2.3a0.post0.dev0', '1.2.3a0.post0.dev1', '1.2.3a0.post0.dev2', '1.2.3a0.post10', '1.2.3a0.post10.dev0', '1.2.3a0.post10.dev1', '1.2.3a0.post10.dev2', '1.2.3a4', '1.2.3a4.dev0', '1.2.3a4.dev1', '1.2.3a4.dev2', '1.2.3a4.post0', '1.2.3a4.post0.dev0', '1.2.3a4.post0.dev1', '1.2.3a4.post0.dev2', '1.2.3a4.post10', '1.2.3a4.post10.dev0', '1.2.3a4.post10.dev1', '1.2.3a4.post10.dev2', '1.2.3b1', '1.2.3b1.dev0', '1.2.3b1.dev1', '1.2.3b1.dev2', '1.2.3b1.post0', '1.2.3b1.post0.dev0', '1.2.3b1.post0.dev1', '1.2.3b1.post0.dev2', '1.2.3b1.post10', '1.2.3b1.post10.dev0', '1.2.3b1.post10.dev1', '1.2.3b1.post10.dev2']
718
719
  [strings.incomp]
719
- "Increasing complexity with more combinations" = [
720
- "1!1.0.0.dev4567.post9+20190101",
721
- ]
722
720
  "Invalid cases (testing error handling for extreme cases)" = [
723
- "1.0.0alpha_beta",
724
721
  "1!2.0.0+",
725
722
  ]
723
+
724
+ [strings.exc]
726
725
  "Cases with inconsistent pre-release and post-release ordering" = [
727
726
  "1.0.0.post1a1",
728
727
  "1.0.0.dev1rc1",
729
728
  "2!1.0.0rc1.post1a1",
730
729
  "3!1.0.0a1.dev1rc1+build123",
731
730
  ]
732
-
733
- [strings.exc]
731
+ "Increasing complexity with more combinations" = [
732
+ "1!1.0.0.dev4567.post9+20190101",
733
+ ]
734
734
  "Invalid or Potentially Problematic Cases (for error handling)" = [
735
735
  "1..0",
736
736
  "1.0.0+@build",
737
737
  ]
738
738
  "Invalid cases (testing error handling for extreme cases)" = [
739
+ "1.0.0alpha_beta",
739
740
  "1.0.0...dev",
740
741
  "0.0.0a1.post0.dev0+local.build.invalid_character#",
741
742
  "1.0.0a1..post2",
@@ -746,100 +747,24 @@ Post-releases = [
746
747
  "Test version with invalid specifiers that should raise an error" = [
747
748
  "1.2.3--4",
748
749
  "1.2.3a1--4",
750
+ "1!1.2.3a1-4-dev5-6+local",
751
+ "1.2.3-dev1-dev2",
752
+ "1.2.3-4-5",
753
+ "1.2.3a1-4-5",
754
+ "2!1.2.3-4-5",
755
+ "1.2.3-4a1-dev5-6",
756
+ "1.2.3-dev1-post2-dev3",
757
+ "1.2.3-4a1",
749
758
  ]
750
759
 
751
- [devint.test_dev_as_int]
752
- setup = "1.2.3"
753
- update = 1
754
- text = "1.2.3.dev1"
755
- solution = 1
756
-
757
- [devint.test_dev_as_string_int]
758
- setup = "1.2.3"
759
- update = 42
760
- text = "1.2.3.dev42"
761
- solution = 42
762
-
763
- [devint.test_dev_as_string_with_dev_prefix]
764
- setup = "1.2.3"
765
- update = 1000
766
- text = "1.2.3.dev1000"
767
- solution = 1000
768
-
769
- [devint.test_dev_as_string_with_dev_dot_prefix]
770
- setup = "1.2.3"
771
- update = 2000
772
- text = "1.2.3.dev2000"
773
- solution = 2000
774
-
775
- [devint.test_dev_as_string_with_dot_dev_prefix]
776
- setup = "1.2.3"
777
- update = 3000
778
- text = "1.2.3.dev3000"
779
- solution = 3000
780
-
781
- [devint.test_dev_as_string_with_dot_dev_number_prefix]
782
- setup = "1.2.3"
783
- update = 4000
784
- text = "1.2.3.dev4000"
785
- solution = 4000
786
-
787
- [devint.test_dev_as_list]
788
- setup = "1.2.3"
789
- update = 6000
790
- text = "1.2.3.dev6000"
791
- solution = 6000
792
-
793
- [devint.test_dev_as_uppercase_string]
794
- setup = "1.2.3"
795
- update = 7000
796
- text = "1.2.3.dev7000"
797
- solution = 7000
798
-
799
- [devint.test_dev_as_mixed_case_string]
800
- setup = "1.2.3"
801
- update = 8000
802
- text = "1.2.3.dev8000"
803
- solution = 8000
804
-
805
- [devint.test_dev_as_list_mixed_case]
806
- setup = "1.2.3"
807
- update = 9000
808
- text = "1.2.3.dev9000"
809
- solution = 9000
810
-
811
- [devint.test_dev_as_false]
812
- setup = "1.2.3"
813
- update = false
814
- text = "1.2.3.dev0"
815
- solution = 0
816
-
817
- [devint.test_dev_as_true]
818
- setup = "1.2.3"
819
- update = true
820
- text = "1.2.3.dev1"
821
- solution = 1
822
-
823
760
  [spec.test_basic_version_with_post_specifier]
824
761
  string_a = "1.2.3-4"
825
762
  string_b = "1.2.3.post4"
826
763
 
827
- [spec.test_version_with_multiple_post_specifiers]
828
- string_a = "1.2.3-4-5"
829
- string_b = "1.2.3.post5"
830
-
831
- [spec.test_version_with_mixed_post_and_dev_specifiers]
832
- string_a = "1.2.3-dev1-post2-dev3"
833
- string_b = "1.2.3.post2.dev3"
834
-
835
764
  [spec.test_version_with_pre_release_and_post_specifiers]
836
765
  string_a = "1.2.3a1-4"
837
766
  string_b = "1.2.3a1.post4"
838
767
 
839
- [spec.test_version_with_multiple_pre_and_post_specifiers]
840
- string_a = "1.2.3a1-4-5"
841
- string_b = "1.2.3a1.post5"
842
-
843
768
  [spec.test_version_with_post_and_local_specifiers]
844
769
  string_a = "1.2.3-4+local"
845
770
  string_b = "1.2.3.post4+local"
@@ -848,14 +773,6 @@ string_b = "1.2.3.post4+local"
848
773
  string_a = "1!1.2.3-4"
849
774
  string_b = "1!1.2.3.post4"
850
775
 
851
- [spec.test_version_with_wrong_order_specifiers]
852
- string_a = "1.2.3-4a1"
853
- string_b = "1.2.3a1.post4"
854
-
855
- [spec.test_version_with_multiple_misordered_specifiers]
856
- string_a = "1.2.3-4a1-dev5-6"
857
- string_b = "1.2.3a1.post6.dev5"
858
-
859
776
  [spec.test_version_with_dev_specifier_after_post]
860
777
  string_a = "1.2.3-4-dev5"
861
778
  string_b = "1.2.3.post4.dev5"
@@ -864,22 +781,10 @@ string_b = "1.2.3.post4.dev5"
864
781
  string_a = "1!1.2.3-4-dev2"
865
782
  string_b = "1!1.2.3.post4.dev2"
866
783
 
867
- [spec.test_version_with_multiple_epoch_and_specifiers]
868
- string_a = "2!1.2.3-4-5"
869
- string_b = "2!1.2.3.post5"
870
-
871
- [spec.test_version_with_repeated_dev_specifier]
872
- string_a = "1.2.3-dev1-dev2"
873
- string_b = "1.2.3.dev2"
874
-
875
784
  [spec.test_version_with_complex_specifiers_and_local]
876
785
  string_a = "1.2.3a1-4-dev5+local"
877
786
  string_b = "1.2.3a1.post4.dev5+local"
878
787
 
879
- [spec.test_version_with_multiple_releases_and_epoch]
880
- string_a = "1!1.2.3a1-4-dev5-6+local"
881
- string_b = "1!1.2.3a1.post6.dev5+local"
882
-
883
788
  [release.test_release_basic_assignment]
884
789
  query = [
885
790
  1,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: v440
3
- Version: 2.0.0.dev182
3
+ Version: 2.0.0.dev184
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)
@@ -13,6 +13,7 @@ src/v440/_utils/BaseStringer.py
13
13
  src/v440/_utils/Cfg.py
14
14
  src/v440/_utils/ListStringer.py
15
15
  src/v440/_utils/Pattern.py
16
+ src/v440/_utils/QualStringer.py
16
17
  src/v440/_utils/SlotStringer.py
17
18
  src/v440/_utils/__init__.py
18
19
  src/v440/_utils/cfg.toml
@@ -23,7 +24,10 @@ src/v440/_utils/releaseparse/getting.py
23
24
  src/v440/_utils/releaseparse/ranging.py
24
25
  src/v440/_utils/releaseparse/setting.py
25
26
  src/v440/core/Base.py
27
+ src/v440/core/Dev.py
26
28
  src/v440/core/Local.py
29
+ src/v440/core/Post.py
30
+ src/v440/core/Pre.py
27
31
  src/v440/core/Public.py
28
32
  src/v440/core/Qual.py
29
33
  src/v440/core/Release.py
@@ -1,225 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import operator
4
- import string as string_
5
- from typing import *
6
-
7
- import setdoc
8
- from overloadable import Overloadable
9
-
10
- from v440._utils.Cfg import Cfg
11
- from v440._utils.guarding import guard
12
- from v440._utils.Pattern import Pattern
13
- from v440._utils.SlotStringer import SlotStringer
14
-
15
- __all__ = ["Qual"]
16
-
17
-
18
- class Qual(SlotStringer):
19
-
20
- __slots__ = ("_prephase", "_prenum", "_post", "_dev")
21
- string: str
22
- pre: str
23
- prephase: str
24
- prenum: int
25
- post: Optional[int]
26
- dev: Optional[int]
27
-
28
- @setdoc.basic
29
- def __bool__(self: Self) -> bool:
30
- return self.string == ""
31
-
32
- @Overloadable
33
- @setdoc.basic
34
- def __init__(self: Self, *args: Any, **kwargs: Any) -> str:
35
- self._prephase = ""
36
- self._prenum = 0
37
- self._post = None
38
- self._dev = None
39
- argc: int = len(args) + len(kwargs)
40
- keys: set = set(kwargs.keys())
41
- if argc <= 1 and keys <= {"string"}:
42
- return "string"
43
- if argc <= 3 and keys <= {"pre", "post", "dev"}:
44
- return "pre"
45
- return "slots"
46
-
47
- @__init__.overload("string")
48
- @setdoc.basic
49
- def __init__(self: Self, string: Any = "") -> None:
50
- self.string = string
51
-
52
- @__init__.overload("pre")
53
- @setdoc.basic
54
- def __init__(
55
- self: Self,
56
- pre: Any = "",
57
- post: Any = None,
58
- dev: Any = None,
59
- ) -> None:
60
- self.pre = pre
61
- self.post = post
62
- self.dev = dev
63
-
64
- @__init__.overload("slots")
65
- @setdoc.basic
66
- def __init__(
67
- self: Self,
68
- prephase: Any = "",
69
- prenum: Any = 0,
70
- post: Any = None,
71
- dev: Any = None,
72
- ) -> None:
73
- self.prephase = prephase
74
- self.prenum = prenum
75
- self.post = post
76
- self.dev = dev
77
-
78
- def _cmp(self: Self) -> list:
79
- ans: list = list()
80
- if self.prephase:
81
- ans += [self.prephase, self.prenum]
82
- elif self.post is not None:
83
- ans += ["z", float("inf")]
84
- elif self.dev is None:
85
- ans += ["z", float("inf")]
86
- else:
87
- ans += ["", -1]
88
- ans.append(-1 if self.post is None else self.post)
89
- ans.append(float("inf") if self.dev is None else self.dev)
90
- return ans
91
-
92
- def _format(self: Self, format_spec: str) -> str:
93
- if format_spec:
94
- raise ValueError
95
- ans: str = self.pre
96
- if self.post is not None:
97
- ans += ".post%s" % self.post
98
- if self.dev is not None:
99
- ans += ".dev%s" % self.dev
100
- return ans
101
-
102
- def _string_fset(self: Self, value: str) -> None:
103
- v: str = value
104
- m: Any
105
- x: Any
106
- y: Any
107
- self.dev = None
108
- self.post = None
109
- self.pre = ""
110
- while v:
111
- m = Pattern.QUALIFIERS.leftbound.search(v)
112
- v = v[m.end() :]
113
- if m.group("N"):
114
- self.post = int(m.group("N"))
115
- continue
116
- x = m.group("l")
117
- y = m.group("n")
118
- if x == "dev":
119
- self.dev = int(y)
120
- continue
121
- if x in ("post", "r", "rev"):
122
- self.post = int(y)
123
- continue
124
- self.pre = x + y
125
-
126
- def _todict(self: Self) -> dict:
127
- return dict(pre=self.pre, post=self.post, dev=self.dev)
128
-
129
- @property
130
- def dev(self: Self) -> Optional[int]:
131
- "This property represents the stage of development."
132
- return self._dev
133
-
134
- @dev.setter
135
- @guard
136
- def dev(self: Self, value: Optional[SupportsIndex]) -> None:
137
- if value is None:
138
- self._dev = None
139
- return
140
- self._dev: int = operator.index(value)
141
- if self._dev < 0:
142
- raise ValueError
143
-
144
- def isdevrelease(self: Self) -> bool:
145
- "This method returns whether the current instance denotes a dev-release."
146
- return self.dev is not None
147
-
148
- def isprerelease(self: Self) -> bool:
149
- "This method returns whether the current instance denotes a pre-release."
150
- return self.prephase != "" or self.dev is not None
151
-
152
- def ispostrelease(self: Self) -> bool:
153
- "This method returns whether the current instance denotes a post-release."
154
- return self.post is not None
155
-
156
- @property
157
- def post(self: Self) -> Optional[int]:
158
- return self._post
159
-
160
- @post.setter
161
- @guard
162
- def post(self: Self, value: Optional[SupportsIndex]) -> None:
163
- if value is None:
164
- self._post = None
165
- return
166
- self._post: int = abs(operator.index(value))
167
-
168
- @property
169
- def pre(self: Self) -> str:
170
- if "" == self.prephase:
171
- return ""
172
- return self.prephase + str(self.prenum)
173
-
174
- @pre.setter
175
- @guard
176
- def pre(self: Self, value: Any) -> None:
177
- v: str = str(value).lower()
178
- v = v.replace("_", ".")
179
- v = v.replace("-", ".")
180
- x: str = v.rstrip(string_.digits)
181
- v = v[len(x) :]
182
- q: bool = x.endswith(".")
183
- if q:
184
- if not v:
185
- raise ValueError
186
- x = x[:-1]
187
- p: bool = x.startswith(".")
188
- if p:
189
- x = x[1:]
190
- if x:
191
- self._prephase = Cfg.cfg.data["phases"][x]
192
- self._prenum = int("0" + v)
193
- elif p or v:
194
- raise ValueError
195
- else:
196
- self._prephase = ""
197
- self._prenum = 0
198
-
199
- @property
200
- def prephase(self: Self) -> str:
201
- return self._prephase
202
-
203
- @prephase.setter
204
- @guard
205
- def prephase(self: Self, value: Any) -> None:
206
- x: str = str(value).lower()
207
- if x != "":
208
- self._prephase = Cfg.cfg.data["phases"][x]
209
- elif self.prenum:
210
- self.pre = self.prenum # raises error
211
-
212
- @property
213
- def prenum(self: Self) -> Optional[int]:
214
- return self._prenum
215
-
216
- @prenum.setter
217
- @guard
218
- def prenum(self: Self, value: Any) -> None:
219
- y: int = operator.index(value)
220
- if y < 0:
221
- raise ValueError
222
- if self.prephase:
223
- self._prenum = y
224
- else:
225
- self.pre = y # raises error
File without changes
File without changes
File without changes
File without changes