v440 2.0.0.dev59__tar.gz → 2.0.0.dev61__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 (36) hide show
  1. {v440-2.0.0.dev59/src/v440.egg-info → v440-2.0.0.dev61}/PKG-INFO +1 -1
  2. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/pyproject.toml +1 -1
  3. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/BaseList.py +29 -41
  4. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/SlotList.py +13 -5
  5. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/VList.py +96 -1
  6. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/qualparse.py +0 -45
  7. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/utils.py +3 -16
  8. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/core/Base.py +44 -38
  9. v440-2.0.0.dev61/src/v440/core/Local.py +45 -0
  10. v440-2.0.0.dev61/src/v440/core/Public.py +86 -0
  11. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/core/Qual.py +62 -15
  12. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/core/Release.py +14 -17
  13. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/core/Version.py +42 -39
  14. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/tests/test_testdata.py +1 -1
  15. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/tests/test_version.py +38 -24
  16. {v440-2.0.0.dev59 → v440-2.0.0.dev61/src/v440.egg-info}/PKG-INFO +1 -1
  17. v440-2.0.0.dev59/src/v440/core/Local.py +0 -75
  18. v440-2.0.0.dev59/src/v440/core/Public.py +0 -86
  19. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/LICENSE.txt +0 -0
  20. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/MANIFEST.in +0 -0
  21. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/README.rst +0 -0
  22. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/setup.cfg +0 -0
  23. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/__init__.py +0 -0
  24. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/Cfg.py +0 -0
  25. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/Digest.py +0 -0
  26. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/Pattern.py +0 -0
  27. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/__init__.py +0 -0
  28. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/_utils/cfg.toml +0 -0
  29. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/core/VersionError.py +0 -0
  30. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/core/__init__.py +0 -0
  31. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/tests/__init__.py +0 -0
  32. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440/tests/testdata.toml +0 -0
  33. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440.egg-info/SOURCES.txt +0 -0
  34. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440.egg-info/dependency_links.txt +0 -0
  35. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/src/v440.egg-info/requires.txt +0 -0
  36. {v440-2.0.0.dev59 → v440-2.0.0.dev61}/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.dev59
3
+ Version: 2.0.0.dev61
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)
@@ -36,7 +36,7 @@ keywords = []
36
36
  name = "v440"
37
37
  readme = "README.rst"
38
38
  requires-python = ">=3.11"
39
- version = "2.0.0.dev59"
39
+ version = "2.0.0.dev61"
40
40
 
41
41
  [project.license]
42
42
  file = "LICENSE.txt"
@@ -1,34 +1,32 @@
1
1
  import collections
2
- from abc import abstractmethod
2
+ from abc import ABCMeta, abstractmethod
3
3
  from typing import *
4
4
 
5
5
  import scaevola
6
6
  import setdoc
7
7
  import unhash
8
- from datarepr import datarepr
9
8
 
9
+ from v440._utils.utils import guard
10
10
  from v440.core.VersionError import VersionError
11
11
 
12
12
 
13
13
  @scaevola.auto
14
- class BaseList(collections.abc.Collection):
14
+ class BaseList(metaclass=ABCMeta):
15
15
  __slots__ = ()
16
16
 
17
+ string: str
18
+
17
19
  @abstractmethod
18
20
  @setdoc.basic
19
21
  def __bool__(self: Self) -> bool: ...
20
22
 
21
- @setdoc.basic
22
- def __contains__(self: Self, other: Any) -> bool:
23
- return other in self.data
24
-
25
23
  @setdoc.basic
26
24
  def __eq__(self: Self, other: Any) -> bool:
27
25
  try:
28
26
  alt: Self = type(self)(other)
29
27
  except VersionError:
30
28
  return False
31
- return self.data == alt.data
29
+ return self.string == alt.string
32
30
 
33
31
  @setdoc.basic
34
32
  def __format__(self: Self, format_spec: Any) -> str:
@@ -37,7 +35,7 @@ class BaseList(collections.abc.Collection):
37
35
  except Exception:
38
36
  msg: str = "unsupported format string passed to %s.__format__"
39
37
  msg %= type(self).__name__
40
- raise TypeError(msg) from None
38
+ raise TypeError(msg) # from None
41
39
 
42
40
  @setdoc.basic
43
41
  def __ge__(self: Self, other: Any) -> bool:
@@ -48,10 +46,6 @@ class BaseList(collections.abc.Collection):
48
46
  return NotImplemented
49
47
  return self._cmp() >= alt._cmp()
50
48
 
51
- @setdoc.basic
52
- def __getitem__(self: Self, key: Any) -> Any:
53
- return self.data[key]
54
-
55
49
  @setdoc.basic
56
50
  def __gt__(self: Self, other: Any) -> bool:
57
51
  alt: Self
@@ -63,13 +57,9 @@ class BaseList(collections.abc.Collection):
63
57
 
64
58
  __hash__ = unhash
65
59
 
60
+ @abstractmethod
66
61
  @setdoc.basic
67
- def __init__(self: Self, data: Any = None) -> None:
68
- self.data = data
69
-
70
- @setdoc.basic
71
- def __iter__(self: Self) -> Iterator:
72
- return iter(self.data)
62
+ def __init__(self: Self, string: Any) -> None: ...
73
63
 
74
64
  @setdoc.basic
75
65
  def __le__(self: Self, other: Any) -> bool:
@@ -93,19 +83,9 @@ class BaseList(collections.abc.Collection):
93
83
  def __ne__(self: Self, other: Any) -> bool:
94
84
  return not (self == other)
95
85
 
86
+ @abstractmethod
96
87
  @setdoc.basic
97
- def __repr__(self: Self) -> str:
98
- return datarepr(type(self).__name__, self.data)
99
-
100
- @setdoc.basic
101
- def __reversed__(self: Self) -> reversed:
102
- return reversed(self.data)
103
-
104
- @setdoc.basic
105
- def __setitem__(self: Self, key: Any, value: Any) -> None:
106
- data: list = list(self.data)
107
- data[key] = value
108
- self.data = data
88
+ def __repr__(self: Self) -> str: ...
109
89
 
110
90
  @classmethod
111
91
  def __subclasshook__(cls: type, other: type, /) -> bool:
@@ -122,19 +102,27 @@ class BaseList(collections.abc.Collection):
122
102
  @abstractmethod
123
103
  def _format(self: Self, format_spec: str) -> str: ...
124
104
 
105
+ @abstractmethod
106
+ def _set(self: Self, value: Any) -> None: ...
107
+
108
+ @abstractmethod
109
+ def _string_fset(self: Self, value: str) -> None: ...
110
+
111
+ @abstractmethod
112
+ def _todict(self: Self) -> dict: ...
113
+
125
114
  @setdoc.basic
126
115
  def copy(self: Self) -> Self:
127
116
  return type(self)(self)
128
117
 
129
118
  @property
130
- @abstractmethod
131
- @setdoc.basic
132
- def data(self: Self) -> tuple: ...
133
-
134
- def count(self: Self, value: Any) -> int:
135
- "This method counts the occurences of value."
136
- return self.data.count(value)
119
+ def string(self: Self) -> str:
120
+ return self._format("")
137
121
 
138
- def index(self: Self, *args: Any) -> None:
139
- "This method returns the index of the first occurence."
140
- return self.data.index(*args)
122
+ @string.setter
123
+ @guard
124
+ def string(self: Self, value: Any) -> None:
125
+ if value is None:
126
+ self._string_fset("")
127
+ else:
128
+ self._string_fset(str(value))
@@ -1,7 +1,9 @@
1
+ from abc import abstractmethod
1
2
  from functools import partial
2
3
  from typing import *
3
4
 
4
5
  import setdoc
6
+ from datarepr import datarepr
5
7
 
6
8
  from v440._utils.BaseList import BaseList
7
9
 
@@ -11,15 +13,21 @@ __all__ = ["SlotList"]
11
13
  class SlotList(BaseList):
12
14
  __slots__ = ()
13
15
 
14
- data: tuple
15
-
16
- @setdoc.basic
17
- def __bool__(self: Self) -> bool:
18
- return any(self.data)
16
+ string: str
19
17
 
20
18
  @setdoc.basic
21
19
  def __len__(self: Self) -> int:
22
20
  return len(type(self).__slots__)
23
21
 
22
+ @setdoc.basic
23
+ def __repr__(self: Self) -> str:
24
+ return datarepr(type(self).__name__, **self._todict())
25
+
24
26
  def _cmp(self: Self) -> tuple:
25
27
  return tuple(map(partial(getattr, self), type(self).__slots__))
28
+
29
+ def _set(self: Self, value: Any) -> None:
30
+ if value is None:
31
+ self.string = ""
32
+ else:
33
+ self.string = value
@@ -1,17 +1,22 @@
1
+ import collections
1
2
  from abc import abstractmethod
2
3
  from typing import *
3
4
 
4
5
  import setdoc
6
+ from datarepr import datarepr
7
+ from overloadable import Overloadable
5
8
 
6
9
  from v440._utils.BaseList import BaseList
10
+ from v440._utils.utils import guard
7
11
 
8
12
  __all__ = ["VList"]
9
13
 
10
14
 
11
- class VList(BaseList):
15
+ class VList(BaseList, collections.abc.MutableSequence):
12
16
 
13
17
  __slots__ = ("_data",)
14
18
  data: tuple
19
+ string: str
15
20
 
16
21
  @setdoc.basic
17
22
  def __add__(self: Self, other: Any) -> Self:
@@ -56,6 +61,9 @@ class VList(BaseList):
56
61
  @abstractmethod
57
62
  def _sort(cls: type, value: Any): ...
58
63
 
64
+ def _todict(self: Self) -> dict:
65
+ return dict(data=self.data)
66
+
59
67
  def append(self: Self, value: Self, /) -> None:
60
68
  "This method appends value to self."
61
69
  data: list = list(self.data)
@@ -109,3 +117,90 @@ class VList(BaseList):
109
117
  r: bool = bool(reverse)
110
118
  data.sort(key=k, reverse=r)
111
119
  self.data = data
120
+
121
+ # data-associated
122
+ @setdoc.basic
123
+ def __contains__(self: Self, other: Any) -> bool:
124
+ return other in self.data
125
+
126
+ @setdoc.basic
127
+ def __getitem__(self: Self, key: Any) -> Any:
128
+ return self.data[key]
129
+
130
+ @Overloadable
131
+ @setdoc.basic
132
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> bool:
133
+ if len(args) == 0 and "string" in kwargs.keys():
134
+ return True
135
+ if len(args) == 1 and len(kwargs) == 0:
136
+ if isinstance(args[0], str):
137
+ return True
138
+ if hasattr(args[0], "__iter__"):
139
+ return False
140
+ return True
141
+ return False
142
+
143
+ @__init__.overload(True)
144
+ @setdoc.basic
145
+ def __init__(self: Self, string: Any) -> None:
146
+ self._init_setup()
147
+ self.string = string
148
+
149
+ @__init__.overload(False)
150
+ @setdoc.basic
151
+ def __init__(self: Self, data: Iterable = ()) -> None:
152
+ self._init_setup()
153
+ self.data = data
154
+
155
+ @setdoc.basic
156
+ def __iter__(self: Self) -> Iterator:
157
+ return iter(self.data)
158
+
159
+ @setdoc.basic
160
+ def __repr__(self: Self) -> str:
161
+ return datarepr(type(self).__name__, *self.data)
162
+
163
+ @setdoc.basic
164
+ def __reversed__(self: Self) -> reversed:
165
+ return reversed(self.data)
166
+
167
+ @setdoc.basic
168
+ def __setitem__(self: Self, key: Any, value: Any) -> None:
169
+ data: list = list(self.data)
170
+ data[key] = value
171
+ self.data = data
172
+
173
+ @classmethod
174
+ @abstractmethod
175
+ def _data_parse(cls: type, value: list) -> Iterable: ...
176
+
177
+ def _init_setup(self: Self) -> None:
178
+ self._data = ()
179
+
180
+ def _set(self: Self, value: Any) -> None:
181
+ if value is None:
182
+ self.data = ()
183
+ elif isinstance(value, str):
184
+ self.string = value
185
+ elif hasattr(value, "__iter__"):
186
+ self.data = value
187
+ else:
188
+ self.string = value
189
+
190
+ @property
191
+ @setdoc.basic
192
+ def data(self: Self) -> tuple:
193
+ return self._data
194
+
195
+ @data.setter
196
+ @guard
197
+ def data(self: Self, value: Iterable) -> None:
198
+ self._data = tuple(self._data_parse(list(value)))
199
+
200
+ def count(self: Self, value: Any) -> int:
201
+ "This method counts the occurences of value."
202
+ return self.data.count(value)
203
+
204
+ def index(self: Self, *args: Any) -> None:
205
+ "This method returns the index of the first occurence."
206
+ return self.data.index(*args)
@@ -7,51 +7,6 @@ from v440._utils.Cfg import Cfg
7
7
  from v440._utils.Digest import Digest
8
8
  from v440._utils.Pattern import Pattern
9
9
 
10
- parse_leg: Digest = Digest("parse_leg")
11
-
12
-
13
- @parse_leg.overload()
14
- def parse_leg() -> tuple:
15
- return None, None, None
16
-
17
-
18
- @parse_leg.overload(int)
19
- def parse_leg(value: int) -> tuple:
20
- return None, abs(value), None
21
-
22
-
23
- @parse_leg.overload(list)
24
- def parse_leg(value: list) -> tuple:
25
- return tuple([value[:2]] + value[2:])
26
-
27
-
28
- @parse_leg.overload(str)
29
- def parse_leg(value: str) -> tuple:
30
- v = value
31
- pre: tuple = None, None
32
- post: Optional[str] = None
33
- dev: Optional[str] = None
34
- m: Any
35
- x: Any
36
- y: Any
37
- while v:
38
- m = Pattern.QUALIFIERS.leftbound.search(v)
39
- v = v[m.end() :]
40
- if m.group("N"):
41
- post = m.group("N")
42
- continue
43
- x = m.group("l")
44
- y = m.group("n")
45
- if x == "dev":
46
- dev = y
47
- continue
48
- if x in ("post", "r", "rev"):
49
- post = y
50
- continue
51
- pre = x, y
52
- return pre, post, dev
53
-
54
-
55
10
  parse_dev: Digest = Digest("parse_dev")
56
11
 
57
12
 
@@ -74,30 +74,17 @@ def ishashable(value: Any) -> bool:
74
74
  def guard(old: Any) -> Any:
75
75
  @functools.wraps(old)
76
76
  def new(self: Self, value: Any) -> None:
77
- backup: dict = dict()
78
- x: Any
79
- y: Any
80
- for x in type(self).__slots__:
81
- y = getattr(self, x)
82
- backup[x] = y if ishashable(y) else y.copy()
77
+ backup: str = str(getattr(self, old.__name__))
83
78
  try:
84
79
  old(self, value)
85
80
  except VersionError:
86
- restore(obj=self, backup=backup)
81
+ setattr(self, old.__name__, backup)
87
82
  raise
88
83
  except Exception:
89
- restore(obj=self, backup=backup)
84
+ setattr(self, old.__name__, backup)
90
85
  msg: str = "%r is an invalid value for %r"
91
86
  target: str = type(self).__name__ + "." + old.__name__
92
87
  msg %= (value, target)
93
88
  raise VersionError(msg)
94
89
 
95
90
  return new
96
-
97
-
98
- def restore(obj: Any, backup: dict) -> None:
99
- for x in type(obj).__slots__:
100
- if ishashable(backup[x]):
101
- setattr(obj, x, backup[x])
102
- else:
103
- getattr(obj, x).data = backup[x]
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import *
4
4
 
5
5
  import setdoc
6
+ from overloadable import Overloadable
6
7
 
7
8
  from v440._utils.Digest import Digest
8
9
  from v440._utils.SlotList import SlotList
@@ -12,32 +13,6 @@ from v440.core.Release import Release
12
13
  __all__ = ["Base"]
13
14
 
14
15
 
15
- parse_data: Digest = Digest("parse_data")
16
-
17
-
18
- @parse_data.overload()
19
- def parse_data() -> tuple:
20
- return None, None
21
-
22
-
23
- @parse_data.overload(int)
24
- def parse_data(value: int) -> tuple:
25
- return None, value
26
-
27
-
28
- @parse_data.overload(list)
29
- def parse_data(value: list) -> tuple:
30
- return tuple(value)
31
-
32
-
33
- @parse_data.overload(str)
34
- def parse_data(value: str) -> tuple:
35
- if "!" in value:
36
- return tuple(value.split("!"))
37
- else:
38
- return 0, value
39
-
40
-
41
16
  parse_epoch: Digest = Digest("parse_epoch")
42
17
 
43
18
 
@@ -70,15 +45,42 @@ class Base(SlotList):
70
45
 
71
46
  __slots__ = ("_epoch", "_release")
72
47
 
73
- data: tuple
48
+ string: str
74
49
  epoch: int
75
50
  release: Release
76
51
 
52
+ def __bool__(self: Self) -> bool:
53
+ return bool(self.epoch or self.release)
54
+
55
+ @Overloadable
56
+ @setdoc.basic
57
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> bool:
58
+ if len(args) == 0 and "string" in kwargs.keys():
59
+ return True
60
+ if len(args) == 1 and len(kwargs) == 0:
61
+ return True
62
+ return False
63
+
64
+ @__init__.overload(True)
65
+ @setdoc.basic
66
+ def __init__(self: Self, string: Any) -> None:
67
+ self._init_setup()
68
+ self.string = string
69
+
70
+ @__init__.overload(False)
77
71
  @setdoc.basic
78
- def __init__(self: Self, data: Any = None) -> None:
72
+ def __init__(
73
+ self: Self,
74
+ epoch: Any = "0",
75
+ release: Any = "0",
76
+ ) -> None:
77
+ self._init_setup()
78
+ self.epoch = epoch
79
+ self.release = release
80
+
81
+ def _init_setup(self: Self) -> None:
79
82
  self._epoch = 0
80
83
  self._release = Release()
81
- self.data = data
82
84
 
83
85
  def _format(self: Self, format_spec: str) -> str:
84
86
  ans: str = ""
@@ -87,15 +89,19 @@ class Base(SlotList):
87
89
  ans += format(self.release, format_spec)
88
90
  return ans
89
91
 
90
- @property
91
- @setdoc.basic
92
- def data(self: Self) -> tuple:
93
- return self.epoch, self.release
92
+ def _string_fset(self: Self, value: str) -> None:
93
+ v: str = value
94
+ if v.startswith("v"):
95
+ v = v[1:]
96
+ parsed: Iterable
97
+ if "!" in v:
98
+ parsed = v.split("!")
99
+ else:
100
+ parsed = 0, v
101
+ self.epoch, self.release.string = parsed
94
102
 
95
- @data.setter
96
- @guard
97
- def data(self: Self, value: Any) -> None:
98
- self.epoch, self.release = parse_data(value)
103
+ def _todict(self: Self) -> dict:
104
+ return dict(epoch=self.epoch, release=self.release)
99
105
 
100
106
  @property
101
107
  def epoch(self: Self) -> int:
@@ -115,4 +121,4 @@ class Base(SlotList):
115
121
  @release.setter
116
122
  @guard
117
123
  def release(self: Self, value: Any) -> None:
118
- self._release.data = value
124
+ self.release._set(value)
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import *
4
+
5
+ import setdoc
6
+
7
+ from v440._utils import utils
8
+ from v440._utils.Digest import Digest
9
+ from v440._utils.utils import guard
10
+ from v440._utils.VList import VList
11
+
12
+ __all__ = ["Local"]
13
+
14
+
15
+ class Local(VList):
16
+ __slots__ = ()
17
+
18
+ data: tuple[int | str]
19
+ string: str
20
+
21
+ @classmethod
22
+ def _data_parse(cls: type, value: list) -> Iterable:
23
+ ans: tuple = tuple(map(utils.segment, value))
24
+ if None in ans:
25
+ raise ValueError
26
+ return ans
27
+
28
+ def _format(self: Self, format_spec: str) -> str:
29
+ if format_spec:
30
+ raise ValueError
31
+ return ".".join(map(str, self))
32
+
33
+ @classmethod
34
+ def _sort(cls: type, value: Any) -> tuple[bool, int | str]:
35
+ return type(value) is int, value
36
+
37
+ def _string_fset(self: Self, value: str) -> None:
38
+ if value == "":
39
+ return ()
40
+ v: str = value
41
+ if v.startswith("+"):
42
+ v = v[1:]
43
+ v = v.replace("_", ".")
44
+ v = v.replace("-", ".")
45
+ self.data = v.split(".")
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import *
4
+
5
+ import setdoc
6
+ from overloadable import Overloadable
7
+
8
+ from v440._utils.Digest import Digest
9
+ from v440._utils.Pattern import Pattern
10
+ from v440._utils.SlotList import SlotList
11
+ from v440._utils.utils import guard
12
+ from v440.core.Base import Base
13
+ from v440.core.Qual import Qual
14
+
15
+ __all__ = ["Public"]
16
+
17
+
18
+ class Public(SlotList):
19
+
20
+ __slots__ = ("_base", "_qual")
21
+
22
+ string: str
23
+ base: Base
24
+ qual: Qual
25
+
26
+ def __bool__(self: Self) -> bool:
27
+ return bool(self.base or self.qual)
28
+
29
+ @Overloadable
30
+ @setdoc.basic
31
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> bool:
32
+ if len(args) == 0 and "string" in kwargs.keys():
33
+ return True
34
+ if len(args) == 1 and len(kwargs) == 0:
35
+ return True
36
+ return False
37
+
38
+ @__init__.overload(True)
39
+ @setdoc.basic
40
+ def __init__(self: Self, string: Any) -> None:
41
+ self._init_setup()
42
+ self.string = string
43
+
44
+ @__init__.overload(False)
45
+ @setdoc.basic
46
+ def __init__(
47
+ self: Self,
48
+ base: Any = "0",
49
+ qual: Any = "",
50
+ ) -> None:
51
+ self._init_setup()
52
+ self.base = base
53
+ self.qual = qual
54
+
55
+ def _init_setup(self: Self) -> None:
56
+ self._base = Base()
57
+ self._qual = Qual()
58
+
59
+ def _format(self: Self, format_spec: str) -> str:
60
+ return format(self.base, format_spec) + format(self.qual)
61
+
62
+ def _string_fset(self: Self, value: str) -> None:
63
+ match: Any = Pattern.PUBLIC.leftbound.search(value)
64
+ self.base.string = value[: match.end()]
65
+ self.qual.string = value[match.end() :]
66
+
67
+ def _todict(self: Self) -> dict:
68
+ return dict(base=self.base, qual=self.qual)
69
+
70
+ @property
71
+ def base(self: Self) -> Base:
72
+ "This property represents the version base."
73
+ return self._base
74
+
75
+ @base.setter
76
+ def base(self: Self, value: Any) -> None:
77
+ self.base._set(value)
78
+
79
+ @property
80
+ def qual(self: Self) -> Qual:
81
+ "This property represents the qualification."
82
+ return self._qual
83
+
84
+ @qual.setter
85
+ def qual(self: Self, value: Any) -> None:
86
+ self.qual._set(value)
@@ -3,8 +3,10 @@ from __future__ import annotations
3
3
  from typing import *
4
4
 
5
5
  import setdoc
6
+ from overloadable import Overloadable
6
7
 
7
- from v440._utils import qualparse
8
+ from v440._utils import qualparse, utils
9
+ from v440._utils.Pattern import Pattern
8
10
  from v440._utils.SlotList import SlotList
9
11
  from v440._utils.utils import guard
10
12
 
@@ -15,24 +17,49 @@ class Qual(SlotList):
15
17
 
16
18
  __slots__ = ("_prephase", "_presubphase", "_post", "_dev")
17
19
 
18
- data: tuple
20
+ string: str
19
21
  pre: tuple
20
22
  prephase: Optional[str]
21
23
  presubphase: Optional[int]
22
24
  post: Optional[int]
23
25
  dev: Optional[int]
24
26
 
25
- @setdoc.basic
26
27
  def __bool__(self: Self) -> bool:
27
- return set(self.data) != {None}
28
+ return self.string == ""
29
+
30
+ @Overloadable
31
+ @setdoc.basic
32
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> bool:
33
+ if len(args) == 0 and "string" in kwargs.keys():
34
+ return True
35
+ if len(args) == 1 and len(kwargs) == 0:
36
+ return True
37
+ return False
38
+
39
+ @__init__.overload(True)
40
+ @setdoc.basic
41
+ def __init__(self: Self, string: Any) -> None:
42
+ self._init_setup()
43
+ self.string = string
28
44
 
45
+ @__init__.overload(False)
29
46
  @setdoc.basic
30
- def __init__(self: Self, data: Any = None) -> None:
47
+ def __init__(
48
+ self: Self,
49
+ pre: Any = None,
50
+ post: Any = None,
51
+ dev: Any = None,
52
+ ) -> None:
53
+ self._init_setup()
54
+ self.pre = pre
55
+ self.post = post
56
+ self.dev = dev
57
+
58
+ def _init_setup(self: Self) -> None:
31
59
  self._prephase = None
32
60
  self._presubphase = None
33
61
  self._post = None
34
62
  self._dev = None
35
- self.data = data
36
63
 
37
64
  def _cmp(self: Self) -> list:
38
65
  ans: list = list()
@@ -62,15 +89,35 @@ class Qual(SlotList):
62
89
  ans += ".dev%s" % self.dev
63
90
  return ans
64
91
 
65
- @property
66
- @setdoc.basic
67
- def data(self: Self) -> tuple:
68
- return self.prephase, self.presubphase, self.post, self.dev
69
-
70
- @data.setter
71
- @guard
72
- def data(self: Self, value: Any) -> None:
73
- self.pre, self.post, self.dev = qualparse.parse_leg(value)
92
+ def _string_fset(self: Self, value: str) -> None:
93
+ v: str = value
94
+ m: Any
95
+ x: Any
96
+ y: Any
97
+ pre: Any = (None, None)
98
+ post: Any = None
99
+ dev: Any = None
100
+ while v:
101
+ m = Pattern.QUALIFIERS.leftbound.search(v)
102
+ v = v[m.end() :]
103
+ if m.group("N"):
104
+ post = m.group("N")
105
+ continue
106
+ x = m.group("l")
107
+ y = m.group("n")
108
+ if x == "dev":
109
+ dev = y
110
+ continue
111
+ if x in ("post", "r", "rev"):
112
+ post = y
113
+ continue
114
+ pre = x, y
115
+ self.pre = pre
116
+ self.post = post
117
+ self.dev = dev
118
+
119
+ def _todict(self: Self) -> dict:
120
+ return dict(pre=self.pre, post=self.post, dev=self.dev)
74
121
 
75
122
  @property
76
123
  def dev(self: Self) -> Optional[int]:
@@ -104,6 +104,7 @@ class Release(VList):
104
104
  __slots__ = ()
105
105
 
106
106
  data: tuple[int]
107
+ string: str
107
108
  major: int
108
109
  minor: int
109
110
  micro: int
@@ -156,10 +157,6 @@ class Release(VList):
156
157
  ans: list = list(m)
157
158
  return ans
158
159
 
159
- @setdoc.basic
160
- def __init__(self: Any, data: Any = None) -> None:
161
- self.data = data
162
-
163
160
  @Overloadable
164
161
  @setdoc.basic
165
162
  def __setitem__(self: Self, key: Any, value: Any) -> bool:
@@ -177,6 +174,13 @@ class Release(VList):
177
174
  k: range = torange(key, len(self))
178
175
  self._setitem_range(k, value)
179
176
 
177
+ @classmethod
178
+ def _data_parse(cls: type, value: list) -> Iterable:
179
+ v: list = tolist(value, slicing="always")
180
+ while v and v[-1] == 0:
181
+ v.pop()
182
+ return v
183
+
180
184
  def _format(self: Self, format_spec: str) -> str:
181
185
  i: Optional[int]
182
186
  if format_spec:
@@ -240,6 +244,12 @@ class Release(VList):
240
244
  def _sort(cls: type, value: int) -> int:
241
245
  return value
242
246
 
247
+ def _string_fset(self: Self, value: str) -> None:
248
+ v: str = value
249
+ v = v.replace("_", ".")
250
+ v = v.replace("-", ".")
251
+ self.data = v.split(".")
252
+
243
253
  def bump(self: Self, index: SupportsIndex = -1, amount: SupportsIndex = 1) -> None:
244
254
  i: int = operator.index(index)
245
255
  a: int = operator.index(amount)
@@ -247,16 +257,3 @@ class Release(VList):
247
257
  self._setitem_int(i, x)
248
258
  if i != -1:
249
259
  self.data = self.data[: i + 1]
250
-
251
- @property
252
- @setdoc.basic
253
- def data(self: Self) -> tuple:
254
- return self._data
255
-
256
- @data.setter
257
- @guard
258
- def data(self: Self, value: Any) -> None:
259
- v: list = tolist(value, slicing="always")
260
- while v and v[-1] == 0:
261
- v.pop()
262
- self._data = tuple(v)
@@ -4,8 +4,8 @@ from typing import *
4
4
 
5
5
  import packaging.version
6
6
  import setdoc
7
+ from overloadable import Overloadable
7
8
 
8
- from v440._utils.Digest import Digest
9
9
  from v440._utils.SlotList import SlotList
10
10
  from v440._utils.utils import guard
11
11
  from v440.core.Local import Local
@@ -13,44 +13,46 @@ from v440.core.Public import Public
13
13
 
14
14
  __all__ = ["Version"]
15
15
 
16
- parse_data: Digest = Digest("parse_data")
17
-
18
-
19
- @parse_data.overload()
20
- def parse_data() -> tuple:
21
- return None, None
22
-
23
-
24
- @parse_data.overload(int)
25
- def parse_data(value: int) -> tuple:
26
- return value, None
27
-
28
-
29
- @parse_data.overload(list)
30
- def parse_data(value: list) -> tuple:
31
- return tuple(value)
32
-
33
-
34
- @parse_data.overload(str)
35
- def parse_data(value: str) -> tuple:
36
- if "+" in value:
37
- return tuple(value.split("+"))
38
- else:
39
- return value, None
40
-
41
16
 
42
17
  class Version(SlotList):
43
18
  __slots__ = ("_public", "_local")
44
19
 
45
- data: tuple
20
+ string: str
46
21
  local: Local
47
22
  public: Public
48
23
 
24
+ def __bool__(self: Self) -> bool:
25
+ return bool(self.local or self.public)
26
+
27
+ @Overloadable
28
+ @setdoc.basic
29
+ def __init__(self: Self, *args: Any, **kwargs: Any) -> bool:
30
+ if len(args) == 0 and "string" in kwargs.keys():
31
+ return True
32
+ if len(args) == 1 and len(kwargs) == 0:
33
+ return True
34
+ return False
35
+
36
+ @__init__.overload(True)
37
+ @setdoc.basic
38
+ def __init__(self: Self, string: Any) -> None:
39
+ self._init_setup()
40
+ self.string = string
41
+
42
+ @__init__.overload(False)
49
43
  @setdoc.basic
50
- def __init__(self: Self, data: Any = None) -> None:
44
+ def __init__(
45
+ self: Self,
46
+ public: Any = "0",
47
+ local: Any = "",
48
+ ) -> None:
49
+ self._init_setup()
50
+ self.public = public
51
+ self.local = local
52
+
53
+ def _init_setup(self: Self) -> None:
51
54
  self._public = Public()
52
55
  self._local = Local()
53
- self.data = data
54
56
 
55
57
  def _format(self: Self, format_spec: str) -> str:
56
58
  ans: str = format(self.public, format_spec)
@@ -58,15 +60,16 @@ class Version(SlotList):
58
60
  ans += "+" + format(self.local)
59
61
  return ans
60
62
 
61
- @property
62
- @setdoc.basic
63
- def data(self: Self) -> tuple:
64
- return self.public, self.local
63
+ def _string_fset(self: Self, value: str) -> None:
64
+ parsed: Iterable
65
+ if "+" in value:
66
+ parsed = value.split("+")
67
+ else:
68
+ parsed = value, ""
69
+ self.public.string, self.local.string = parsed
65
70
 
66
- @data.setter
67
- @guard
68
- def data(self: Self, value: Any) -> None:
69
- self.public, self.local = parse_data(value)
71
+ def _todict(self: Self) -> dict:
72
+ return dict(public=self.public, local=self.local)
70
73
 
71
74
  @property
72
75
  def local(self: Self) -> Local:
@@ -76,7 +79,7 @@ class Version(SlotList):
76
79
  @local.setter
77
80
  @guard
78
81
  def local(self: Self, value: Any) -> None:
79
- self.local.data = value
82
+ self.local._set(value)
80
83
 
81
84
  def packaging(self: Self) -> packaging.version.Version:
82
85
  "This method returns an eqivalent packaging.version.Version object."
@@ -90,4 +93,4 @@ class Version(SlotList):
90
93
  @public.setter
91
94
  @guard
92
95
  def public(self: Self, value: Any) -> None:
93
- self.public.data = value
96
+ self.public._set(value)
@@ -177,7 +177,7 @@ class TestDataProperty(unittest.TestCase):
177
177
  ) -> None:
178
178
  msg: str = "data-property %r" % key
179
179
  version: Version = Version()
180
- version.data = query
180
+ version.string = query
181
181
  self.assertEqual(solution, str(version), msg=msg)
182
182
 
183
183
 
@@ -59,7 +59,7 @@ class TestPre(unittest.TestCase):
59
59
 
60
60
  # Initial version, no pre-release version
61
61
  self.assertEqual(str(v), "1.2.3")
62
- self.assertEqual(v.public.qual, [None, None, None, None])
62
+ self.assertEqual(v.public.qual.string, "")
63
63
 
64
64
  # Set pre-release version to "a1"
65
65
  v.public.qual = "a1"
@@ -88,7 +88,7 @@ class TestPre(unittest.TestCase):
88
88
  # Set pre-release to None
89
89
  v.public.qual = None
90
90
  self.assertEqual(str(v), "1.2.3")
91
- self.assertEqual(v.public.qual, [None, None, None, None])
91
+ self.assertEqual(str(v.public.qual), "")
92
92
 
93
93
 
94
94
  class TestExample(unittest.TestCase):
@@ -105,27 +105,41 @@ class TestExample(unittest.TestCase):
105
105
  v.public.base.release.micro = 4
106
106
  self.assertEqual(str(v), "2.64.4") # Further modified version
107
107
 
108
- def test_example_3(self: Self) -> None:
109
- t: list = [
110
- [Version, str],
111
- [str, Version],
112
- [Version, Version],
113
- ]
114
- X: type
115
- Y: type
116
- x: Any
117
- y: Any
118
- for X, Y in t:
119
- x = X("1.6.3")
120
- y = Y("1.6.3")
121
- self.assertEqual(str(x), "1.6.3") # x
122
- self.assertEqual(str(y), "1.6.4") # y
123
- self.assertFalse(x == y) # x == y gives False
124
- self.assertTrue(x != y) # x != y gives True
125
- self.assertFalse(x >= y) # x >= y gives False
126
- self.assertTrue(x <= y) # x <= y gives True
127
- self.assertFalse(x > y) # x > y gives False
128
- self.assertTrue(x < y) # x < y gives True
108
+ def test_example_3a(self: Self) -> None:
109
+ v1: Version = Version("1.6.3")
110
+ v2: str = "1.6.4"
111
+ self.assertEqual(str(v1), "1.6.3") # v1
112
+ self.assertEqual(str(v2), "1.6.4") # v2
113
+ self.assertFalse(v1 == v2) # v1 == v2 gives False
114
+ self.assertTrue(v1 != v2) # v1 != v2 gives True
115
+ self.assertFalse(v1 >= v2) # v1 >= v2 gives False
116
+ self.assertTrue(v1 <= v2) # v1 <= v2 gives True
117
+ self.assertFalse(v1 > v2) # v1 > v2 gives False
118
+ self.assertTrue(v1 < v2) # v1 < v2 gives True
119
+
120
+ def test_example_3b(self: Self) -> None:
121
+ v1: str = "1.6.3"
122
+ v2: Version = Version("1.6.4")
123
+ self.assertEqual(str(v1), "1.6.3") # v1
124
+ self.assertEqual(str(v2), "1.6.4") # v2
125
+ self.assertFalse(v1 == v2) # v1 == v2 gives False
126
+ self.assertTrue(v1 != v2) # v1 != v2 gives True
127
+ self.assertFalse(v1 >= v2) # v1 >= v2 gives False
128
+ self.assertTrue(v1 <= v2) # v1 <= v2 gives True
129
+ self.assertFalse(v1 > v2) # v1 > v2 gives False
130
+ self.assertTrue(v1 < v2) # v1 < v2 gives True
131
+
132
+ def test_example_3c(self: Self) -> None:
133
+ v1: Version = Version("1.6.3")
134
+ v2: Version = Version("1.6.4")
135
+ self.assertEqual(str(v1), "1.6.3") # v1
136
+ self.assertEqual(str(v2), "1.6.4") # v2
137
+ self.assertFalse(v1 == v2) # v1 == v2 gives False
138
+ self.assertTrue(v1 != v2) # v1 != v2 gives True
139
+ self.assertFalse(v1 >= v2) # v1 >= v2 gives False
140
+ self.assertTrue(v1 <= v2) # v1 <= v2 gives True
141
+ self.assertFalse(v1 > v2) # v1 > v2 gives False
142
+ self.assertTrue(v1 < v2) # v1 < v2 gives True
129
143
 
130
144
  def test_example_4(self: Self) -> None:
131
145
  v: Version = Version("2.5.3.9")
@@ -165,7 +179,7 @@ class TestExample(unittest.TestCase):
165
179
  def test_example_7(self: Self) -> None:
166
180
  v: Version = Version("5.0.0")
167
181
  self.assertEqual(str(v), "5") # Original version
168
- v.data = None
182
+ v.string = ""
169
183
  self.assertEqual(str(v), "0") # After reset
170
184
  v.public.base = "4!5.0.1"
171
185
  self.assertEqual(str(v), "4!5.0.1") # Before error
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: v440
3
- Version: 2.0.0.dev59
3
+ Version: 2.0.0.dev61
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)
@@ -1,75 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import *
4
-
5
- import setdoc
6
-
7
- from v440._utils import utils
8
- from v440._utils.Digest import Digest
9
- from v440._utils.utils import guard
10
- from v440._utils.VList import VList
11
-
12
- __all__ = ["Local"]
13
-
14
- parse_data: Digest = Digest("parse_data")
15
-
16
-
17
- @parse_data.overload()
18
- def parse_data() -> tuple:
19
- return ()
20
-
21
-
22
- @parse_data.overload(int)
23
- def parse_data(value: int) -> list:
24
- return (value,)
25
-
26
-
27
- @parse_data.overload(list)
28
- def parse_data(value: list) -> list:
29
- ans: tuple = tuple(map(utils.segment, value))
30
- if None in ans:
31
- raise ValueError
32
- return ans
33
-
34
-
35
- @parse_data.overload(str)
36
- def parse_data(value: str) -> tuple:
37
- v: str = value
38
- if v.startswith("+"):
39
- v = v[1:]
40
- v = v.replace("_", ".")
41
- v = v.replace("-", ".")
42
- ans: tuple = v.split(".")
43
- ans = tuple(map(utils.segment, ans))
44
- if None in ans:
45
- raise ValueError
46
- return ans
47
-
48
-
49
- class Local(VList):
50
- __slots__ = ()
51
-
52
- data: tuple[int | str]
53
-
54
- @setdoc.basic
55
- def __init__(self: Any, data: Any = None) -> None:
56
- self.data = data
57
-
58
- def _format(self: Self, format_spec: str) -> str:
59
- if format_spec:
60
- raise ValueError
61
- return ".".join(map(str, self))
62
-
63
- @classmethod
64
- def _sort(cls: type, value: Any) -> tuple[bool, int | str]:
65
- return type(value) is int, value
66
-
67
- @property
68
- @setdoc.basic
69
- def data(self: Self) -> tuple[int | str]:
70
- return self._data
71
-
72
- @data.setter
73
- @guard
74
- def data(self: Self, value: Any) -> None:
75
- self._data = parse_data(value)
@@ -1,86 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import *
4
-
5
- import setdoc
6
-
7
- from v440._utils.Digest import Digest
8
- from v440._utils.Pattern import Pattern
9
- from v440._utils.SlotList import SlotList
10
- from v440._utils.utils import guard
11
- from v440.core.Base import Base
12
- from v440.core.Qual import Qual
13
-
14
- __all__ = ["Public"]
15
-
16
-
17
- parse_data: Digest = Digest("parse_data")
18
-
19
-
20
- @parse_data.overload()
21
- def parse_data() -> tuple:
22
- return None, None
23
-
24
-
25
- @parse_data.overload(int)
26
- def parse_data(value: int) -> tuple:
27
- return value, None
28
-
29
-
30
- @parse_data.overload(list)
31
- def parse_data(value: list) -> tuple:
32
- return tuple(value)
33
-
34
-
35
- @parse_data.overload(str)
36
- def parse_data(value: str) -> tuple:
37
- match: Any = Pattern.PUBLIC.leftbound.search(value)
38
- return value[: match.end()], value[match.end() :]
39
-
40
-
41
- class Public(SlotList):
42
-
43
- __slots__ = ("_base", "_qual")
44
-
45
- data: tuple
46
- base: Base
47
- qual: Qual
48
-
49
- @setdoc.basic
50
- def __init__(self: Self, data: Any = None) -> None:
51
- self._base = Base()
52
- self._qual = Qual()
53
- self.data = data
54
-
55
- def _format(self: Self, format_spec: str) -> str:
56
- return format(self.base, format_spec) + format(self.qual)
57
-
58
- @property
59
- def base(self: Self) -> Base:
60
- "This property represents the version base."
61
- return self._base
62
-
63
- @base.setter
64
- @guard
65
- def base(self: Self, value: Any) -> None:
66
- self.base.data = value
67
-
68
- @property
69
- @setdoc.basic
70
- def data(self: Self) -> list:
71
- return self.base, self.qual
72
-
73
- @data.setter
74
- @guard
75
- def data(self: Self, value: Any) -> None:
76
- self.base, self.qual = parse_data(value)
77
-
78
- @property
79
- def qual(self: Self) -> Qual:
80
- "This property represents the qualification."
81
- return self._qual
82
-
83
- @qual.setter
84
- @guard
85
- def qual(self: Self, value: Any) -> None:
86
- self.qual.data = value
File without changes
File without changes
File without changes
File without changes