value-object-pattern 0.1.0__py3-none-any.whl

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 (73) hide show
  1. value_object_pattern/__init__.py +10 -0
  2. value_object_pattern/decorators/__init__.py +7 -0
  3. value_object_pattern/decorators/value_object_process.py +83 -0
  4. value_object_pattern/decorators/value_object_validation.py +78 -0
  5. value_object_pattern/models/__init__.py +3 -0
  6. value_object_pattern/models/value_object.py +383 -0
  7. value_object_pattern/py.typed +0 -0
  8. value_object_pattern/usables/__init__.py +54 -0
  9. value_object_pattern/usables/dates/__init__.py +9 -0
  10. value_object_pattern/usables/dates/date/__init__.py +7 -0
  11. value_object_pattern/usables/dates/date/date_value_object.py +162 -0
  12. value_object_pattern/usables/dates/date/string_date_value_object.py +201 -0
  13. value_object_pattern/usables/dates/datetime/__init__.py +7 -0
  14. value_object_pattern/usables/dates/datetime/datetime_value_object.py +193 -0
  15. value_object_pattern/usables/dates/datetime/string_datetime_value_object.py +237 -0
  16. value_object_pattern/usables/identifiers/__init__.py +7 -0
  17. value_object_pattern/usables/identifiers/country_ids/__init__.py +3 -0
  18. value_object_pattern/usables/identifiers/country_ids/spain/__init__.py +3 -0
  19. value_object_pattern/usables/identifiers/country_ids/spain/dni_value_object.py +63 -0
  20. value_object_pattern/usables/identifiers/string_uuid_value_object.py +56 -0
  21. value_object_pattern/usables/identifiers/uuid_value_object.py +40 -0
  22. value_object_pattern/usables/internet/__init__.py +38 -0
  23. value_object_pattern/usables/internet/api_keys/__init__.py +13 -0
  24. value_object_pattern/usables/internet/api_keys/aws_access_key_id_value_object.py +40 -0
  25. value_object_pattern/usables/internet/api_keys/aws_secret_access_key_value_object.py +40 -0
  26. value_object_pattern/usables/internet/api_keys/github_personal_access_token_value_object.py +41 -0
  27. value_object_pattern/usables/internet/api_keys/openai_api_key_value_object.py +40 -0
  28. value_object_pattern/usables/internet/api_keys/resend_api_key_value_object.py +40 -0
  29. value_object_pattern/usables/internet/aws_cloud_region_value_object.py +77 -0
  30. value_object_pattern/usables/internet/domain_value_object.py +149 -0
  31. value_object_pattern/usables/internet/host_value_object.py +143 -0
  32. value_object_pattern/usables/internet/ipv4_address_value_object.py +305 -0
  33. value_object_pattern/usables/internet/ipv4_network_value_object.py +165 -0
  34. value_object_pattern/usables/internet/ipv6_address_value_object.py +288 -0
  35. value_object_pattern/usables/internet/ipv6_network_value_object.py +145 -0
  36. value_object_pattern/usables/internet/mac_address_value_object.py +390 -0
  37. value_object_pattern/usables/internet/port_value_object.py +682 -0
  38. value_object_pattern/usables/internet/uri/__init__.py +11 -0
  39. value_object_pattern/usables/internet/uri/http_https_url_value_object.py +39 -0
  40. value_object_pattern/usables/internet/uri/http_url_value_object.py +39 -0
  41. value_object_pattern/usables/internet/uri/https_url_value_object.py +39 -0
  42. value_object_pattern/usables/internet/uri/url_value_object.py +396 -0
  43. value_object_pattern/usables/primitives/__init__.py +45 -0
  44. value_object_pattern/usables/primitives/boolean/__init__.py +9 -0
  45. value_object_pattern/usables/primitives/boolean/boolean_value_object.py +36 -0
  46. value_object_pattern/usables/primitives/boolean/false_value_object.py +37 -0
  47. value_object_pattern/usables/primitives/boolean/true_value_object.py +37 -0
  48. value_object_pattern/usables/primitives/bytes/__init__.py +3 -0
  49. value_object_pattern/usables/primitives/bytes/bytes_value_object.py +36 -0
  50. value_object_pattern/usables/primitives/float/__init__.py +9 -0
  51. value_object_pattern/usables/primitives/float/float_value_object.py +36 -0
  52. value_object_pattern/usables/primitives/float/negative_float_value_object.py +37 -0
  53. value_object_pattern/usables/primitives/float/positive_float_value_object.py +37 -0
  54. value_object_pattern/usables/primitives/integer/__init__.py +13 -0
  55. value_object_pattern/usables/primitives/integer/even_integer_value_object.py +37 -0
  56. value_object_pattern/usables/primitives/integer/integer_value_object.py +36 -0
  57. value_object_pattern/usables/primitives/integer/negative_integer_value_object.py +37 -0
  58. value_object_pattern/usables/primitives/integer/odd_integer_value_object.py +37 -0
  59. value_object_pattern/usables/primitives/integer/positive_integer_value_object.py +37 -0
  60. value_object_pattern/usables/primitives/string/__init__.py +21 -0
  61. value_object_pattern/usables/primitives/string/alpha_value_object.py +37 -0
  62. value_object_pattern/usables/primitives/string/alphanumeric_value_object.py +37 -0
  63. value_object_pattern/usables/primitives/string/digit_value_object.py +37 -0
  64. value_object_pattern/usables/primitives/string/lowercase_string_value_object.py +37 -0
  65. value_object_pattern/usables/primitives/string/non_empty_string_value_object.py +37 -0
  66. value_object_pattern/usables/primitives/string/printable_string_value_object.py +37 -0
  67. value_object_pattern/usables/primitives/string/string_value_object.py +36 -0
  68. value_object_pattern/usables/primitives/string/trimmed_string_value_object.py +37 -0
  69. value_object_pattern/usables/primitives/string/uppercase_string_value_object.py +37 -0
  70. value_object_pattern-0.1.0.dist-info/METADATA +95 -0
  71. value_object_pattern-0.1.0.dist-info/RECORD +73 -0
  72. value_object_pattern-0.1.0.dist-info/WHEEL +4 -0
  73. value_object_pattern-0.1.0.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,39 @@
1
+ """
2
+ HttpHttpsUrlValueObject value object.
3
+ """
4
+
5
+ from value_object_pattern import validation
6
+
7
+ from .url_value_object import UrlValueObject, split_url
8
+
9
+
10
+ class HttpHttpsUrlValueObject(UrlValueObject):
11
+ """
12
+ HttpHttpsUrlValueObject value object ensures the provided value is a valid HTTP or HTTPS URL.
13
+
14
+ Example:
15
+ ```python
16
+ from value_object_pattern.usables.internet import HttpHttpsUrlValueObject
17
+
18
+ url = HttpHttpsUrlValueObject(value='https://github.com/adriamontoto/value-object-pattern')
19
+
20
+ print(repr(url))
21
+ # >>> HttpHttpsUrlValueObject(value=https://github.com/adriamontoto/value-object-pattern)
22
+ ```
23
+ """
24
+
25
+ @validation(order=0)
26
+ def _validate_url_is_http_https(self, value: str) -> None:
27
+ """
28
+ Validate url scheme is HTTP or HTTPS.
29
+
30
+ Args:
31
+ value (str): The url value.
32
+
33
+ Raises:
34
+ ValueError: If the url scheme is not HTTP or HTTPS.
35
+ """
36
+ scheme, *_ = split_url(value=value)
37
+
38
+ if scheme not in ('http', 'https'):
39
+ raise ValueError(f'HttpHttpsUrlValueObject value <<<{value}>>> scheme is not HTTP or HTTPS')
@@ -0,0 +1,39 @@
1
+ """
2
+ HttpUrlValueObject value object.
3
+ """
4
+
5
+ from value_object_pattern import validation
6
+
7
+ from .url_value_object import UrlValueObject, split_url
8
+
9
+
10
+ class HttpUrlValueObject(UrlValueObject):
11
+ """
12
+ HttpUrlValueObject value object ensures the provided value is a valid HTTP URL.
13
+
14
+ Example:
15
+ ```python
16
+ from value_object_pattern.usables.internet import HttpUrlValueObject
17
+
18
+ url = HttpUrlValueObject(value='http://github.com/adriamontoto/value-object-pattern')
19
+
20
+ print(repr(url))
21
+ # >>> HttpUrlValueObject(value=http://github.com/adriamontoto/value-object-pattern)
22
+ ```
23
+ """
24
+
25
+ @validation(order=0)
26
+ def _validate_url_is_http(self, value: str) -> None:
27
+ """
28
+ Validate url scheme is HTTP.
29
+
30
+ Args:
31
+ value (str): The url value.
32
+
33
+ Raises:
34
+ ValueError: If the url scheme is not HTTP.
35
+ """
36
+ scheme, *_ = split_url(value=value)
37
+
38
+ if scheme != 'http':
39
+ raise ValueError(f'HttpUrlValueObject value <<<{value}>>> scheme is not HTTP')
@@ -0,0 +1,39 @@
1
+ """
2
+ HttpsUrlValueObject value object.
3
+ """
4
+
5
+ from value_object_pattern import validation
6
+
7
+ from .url_value_object import UrlValueObject, split_url
8
+
9
+
10
+ class HttpsUrlValueObject(UrlValueObject):
11
+ """
12
+ HttpsUrlValueObject value object ensures the provided value is a valid HTTPS URL.
13
+
14
+ Example:
15
+ ```python
16
+ from value_object_pattern.usables.internet import HttpsUrlValueObject
17
+
18
+ url = HttpsUrlValueObject(value='https://github.com/adriamontoto/value-object-pattern')
19
+
20
+ print(repr(url))
21
+ # >>> HttpsUrlValueObject(value=https://github.com/adriamontoto/value-object-pattern)
22
+ ```
23
+ """
24
+
25
+ @validation(order=0)
26
+ def _validate_url_is_https(self, value: str) -> None:
27
+ """
28
+ Validate url scheme is HTTPS.
29
+
30
+ Args:
31
+ value (str): The url value.
32
+
33
+ Raises:
34
+ ValueError: If the url scheme is not HTTPS.
35
+ """
36
+ scheme, *_ = split_url(value=value)
37
+
38
+ if scheme != 'https':
39
+ raise ValueError(f'HttpsUrlValueObject value <<<{value}>>> scheme is not HTTPS')
@@ -0,0 +1,396 @@
1
+ """
2
+ UrlValueObject value object.
3
+ """
4
+
5
+ from functools import lru_cache
6
+ from re import Pattern, compile as re_compile
7
+ from urllib.parse import parse_qs, urlsplit
8
+
9
+ from value_object_pattern import process, validation
10
+ from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
11
+ from value_object_pattern.usables.internet.host_value_object import HostValueObject
12
+ from value_object_pattern.usables.internet.port_value_object import PortValueObject
13
+
14
+
15
+ @lru_cache(maxsize=16)
16
+ def join_url(
17
+ scheme: str,
18
+ host: str,
19
+ port: int | None = None,
20
+ user_information: str | None = None,
21
+ path: str | None = None,
22
+ query: str | None = None,
23
+ fragment: str | None = None,
24
+ ) -> str:
25
+ """
26
+ Join the URL parts.
27
+
28
+ Args:
29
+ scheme (str): The URL scheme.
30
+ host (str): The URL host.
31
+ port (int | None, optional): The URL port. Defaults to None.
32
+ user_information (str | None, optional): The URL user information. Defaults to None.
33
+ path (str | None, optional): The URL path. Defaults to None.
34
+ query (str | None, optional): The URL query. Defaults to None.
35
+ fragment (str | None, optional): The URL fragment. Defaults to None.
36
+
37
+ Returns:
38
+ str: The URL joined.
39
+ """
40
+ netloc = host
41
+ if user_information:
42
+ netloc = f'{user_information}@{netloc}'
43
+
44
+ if port is not None:
45
+ netloc = f'{netloc}:{port}'
46
+
47
+ if path and not path.startswith('/'):
48
+ path = f'/{path}'
49
+
50
+ if query:
51
+ query = f'?{query}'
52
+
53
+ if fragment:
54
+ fragment = f'#{fragment}'
55
+
56
+ return f'{scheme}://{netloc}{path}{query}{fragment}'
57
+
58
+
59
+ @lru_cache(maxsize=16)
60
+ def split_url(value: str) -> tuple[str, str, str, str, str]:
61
+ """
62
+ Split the URL in scheme, netloc, path, query and fragment.
63
+
64
+ Args:
65
+ value (str): The URL value.
66
+
67
+ Returns:
68
+ tuple[str, str, str, str, str]: The URL splitted in scheme, netloc, path, query and fragment.
69
+ """
70
+ return urlsplit(url=value)
71
+
72
+
73
+ @lru_cache(maxsize=16)
74
+ def split_netloc(value: str) -> tuple[str | None, str, int | None]:
75
+ """
76
+ Split the netloc in user_information, host and port.
77
+
78
+ Args:
79
+ value (str): The netloc value.
80
+
81
+ Returns:
82
+ tuple[str | None, str, int | None]: The netloc splitted in user_information, host and port.
83
+ """
84
+ user_information, port = None, None
85
+
86
+ host_port = value
87
+ if '@' in value:
88
+ # prevent splitting passwords with @
89
+ user_information, host_port = value.rsplit(sep='@', maxsplit=1)
90
+
91
+ host = host_port
92
+ if ':' in host_port and host_port.count(':') == 1:
93
+ # prevent splitting IPv6 addresses
94
+ host, port_string = host_port.rsplit(sep=':', maxsplit=1)
95
+ port = int(port_string)
96
+
97
+ return user_information, host, port
98
+
99
+
100
+ class UrlValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
101
+ """
102
+ UrlValueObject value object ensures the provided value is a valid URL.
103
+
104
+ References:
105
+ https://www.rfc-editor.org/rfc/rfc3986
106
+
107
+ Example:
108
+ ```python
109
+ from value_object_pattern.usables.internet import UrlValueObject
110
+
111
+ url = UrlValueObject(value='https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents')
112
+
113
+ print(repr(url))
114
+ # >>> UrlValueObject(value=https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents)
115
+ ```
116
+ """
117
+
118
+ __URL_VALUE_OBJECT_SCHEME_REGEX: Pattern[str] = re_compile(pattern=r'^[a-zA-Z][a-zA-Z0-9\+\-\.]+$')
119
+ __URL_VALUE_OBJECT_USER_INFORMATION_REGEX: Pattern[str] = re_compile(pattern=r'^[a-zA-Z0-9\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=\:\@]+$') # noqa: E501 # fmt: skip
120
+ __URL_VALUE_OBJECT_PATH_REGEX: Pattern[str] = re_compile(pattern=r'^\/(?:[a-zA-Z0-9\/\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[a-fA-F0-9]{2})*$') # noqa: E501 # fmt: skip
121
+ __URL_VALUE_OBJECT_QUERY_REGEX: Pattern[str] = re_compile(pattern=r'^(?:[a-zA-Z0-9\/\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[a-fA-F0-9]{2})*$') # noqa: E501 # fmt: skip
122
+ __URL_VALUE_OBJECT_FRAGMENT_REGEX: Pattern[str] = re_compile(pattern=r'^(?:[a-zA-Z0-9\/\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[a-fA-F0-9]{2})*$') # noqa: E501 # fmt: skip
123
+
124
+ @process(order=0)
125
+ def _ensure_url_is_lower(self, value: str) -> str:
126
+ """
127
+ Ensure scheme and domain are in lower case.
128
+
129
+ Args:
130
+ value (str): The url value.
131
+
132
+ Returns:
133
+ str: The url value with scheme and domain in lower case.
134
+ """
135
+ scheme, netloc, path, query, fragment = split_url(value=value)
136
+ user_information, host, port = split_netloc(value=netloc)
137
+
138
+ return join_url(
139
+ scheme=scheme.lower(),
140
+ user_information=user_information,
141
+ host=host.lower(),
142
+ port=port,
143
+ path=path,
144
+ query=query,
145
+ fragment=fragment,
146
+ )
147
+
148
+ @validation(order=0)
149
+ def _validate_url(self, value: str) -> None:
150
+ """
151
+ Validate url.
152
+
153
+ Args:
154
+ value (str): The url value.
155
+
156
+ Raises:
157
+ ValueError: If value is not a valid url.
158
+
159
+ References:
160
+ https://www.rfc-editor.org/rfc/rfc3986
161
+ """
162
+ try:
163
+ scheme, netloc, path, query, fragment = split_url(value=value)
164
+
165
+ except ValueError as error:
166
+ raise ValueError(f'UrlValueObject value <<<{value}>>> is not a valid url.') from error
167
+
168
+ if not scheme and not netloc and not path and not query and not fragment:
169
+ raise ValueError(f'UrlValueObject value <<<{value}>>> is not a valid url.')
170
+
171
+ @validation(order=1)
172
+ def _validate_url_scheme(self, value: str) -> None:
173
+ """
174
+ Validate url scheme.
175
+
176
+ Args:
177
+ value (str): The url value.
178
+
179
+ Raises:
180
+ ValueError: If the url value has not a valid scheme.
181
+
182
+ References:
183
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.1
184
+ """
185
+ scheme, *_ = split_url(value=value)
186
+ if not self.__URL_VALUE_OBJECT_SCHEME_REGEX.match(string=scheme):
187
+ raise ValueError(f'UrlValueObject value <<<{value}>>> contains an invalid scheme <<<{scheme}>>>.')
188
+
189
+ @validation(order=2)
190
+ def _validate_url_netloc(self, value: str) -> None:
191
+ """
192
+ Validate url netloc.
193
+
194
+ Args:
195
+ value (str): The url value.
196
+
197
+ Raises:
198
+ ValueError: If url value has not a valid netloc.
199
+
200
+ References:
201
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.2.1
202
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2
203
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.2.3
204
+ """
205
+ _, netloc, *_ = split_url(value=value)
206
+ user_information, host, port = split_netloc(value=netloc)
207
+
208
+ if user_information is not None and not self.__URL_VALUE_OBJECT_USER_INFORMATION_REGEX.match(string=user_information): # noqa: E501 # fmt: skip
209
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid user information <<<{user_information}>>>.') # noqa: E501 # fmt: skip
210
+
211
+ try:
212
+ HostValueObject(value=host)
213
+
214
+ except ValueError as error:
215
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid host <<<{host}>>>.') from error
216
+
217
+ try:
218
+ if port is not None:
219
+ PortValueObject(value=port)
220
+
221
+ except ValueError as error:
222
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid port <<<{port}>>>.') from error
223
+
224
+ @validation(order=3)
225
+ def _validate_url_path(self, value: str) -> None:
226
+ """
227
+ Validate url path.
228
+
229
+ Args:
230
+ value (str): The url value.
231
+
232
+ Raises:
233
+ ValueError: If url value has not a valid path.
234
+
235
+ References:
236
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.3
237
+ """
238
+ _, _, path, *_ = split_url(value=value)
239
+ if not path:
240
+ return
241
+
242
+ if not self.__URL_VALUE_OBJECT_PATH_REGEX.match(string=path):
243
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid path <<<{path}>>>.')
244
+
245
+ @validation(order=4)
246
+ def _validate_url_query(self, value: str) -> None:
247
+ """
248
+ Validate url query.
249
+
250
+ Args:
251
+ value (str): The url value.
252
+
253
+ Raises:
254
+ ValueError: If url value has not a valid query.
255
+
256
+ References:
257
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.4
258
+ """
259
+ _, _, _, query, *_ = split_url(value=value)
260
+ if not query:
261
+ return
262
+
263
+ try:
264
+ parse_qs(qs=query)
265
+
266
+ except ValueError as error:
267
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid query <<<{query}>>>.') from error
268
+
269
+ if not self.__URL_VALUE_OBJECT_QUERY_REGEX.match(string=query):
270
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid query <<<{query}>>>.')
271
+
272
+ @validation(order=5)
273
+ def _validate_url_fragment(self, value: str) -> None:
274
+ """
275
+ Validate url fragment.
276
+
277
+ Args:
278
+ value (str): The url value.
279
+
280
+ Raises:
281
+ ValueError: If url value has not a valid fragment.
282
+
283
+ References:
284
+ https://www.rfc-editor.org/rfc/rfc3986#section-3.5
285
+ """
286
+ _, _, _, _, fragment = split_url(value=value)
287
+ if not fragment:
288
+ return
289
+
290
+ if not self.__URL_VALUE_OBJECT_FRAGMENT_REGEX.match(string=fragment):
291
+ raise ValueError(f'UrlValueObject value <<<{value}>>> has not a valid fragment <<<{fragment}>>>.')
292
+
293
+ @property
294
+ def scheme(self) -> str:
295
+ """
296
+ Get the URL scheme.
297
+
298
+ Returns:
299
+ str: The URL scheme.
300
+
301
+ Example:
302
+ ```python
303
+ from value_object_pattern.usables.internet import UrlValueObject
304
+
305
+ url = UrlValueObject(value='https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents')
306
+
307
+ print(url.scheme)
308
+ # >>> https
309
+ ```
310
+ """
311
+ scheme, *_ = split_url(value=self.value)
312
+ return scheme
313
+
314
+ @property
315
+ def netloc(self) -> str:
316
+ """
317
+ Get the URL netloc.
318
+
319
+ Returns:
320
+ str: The URL netloc.
321
+
322
+ Example:
323
+ ```python
324
+ from value_object_pattern.usables.internet import UrlValueObject
325
+
326
+ url = UrlValueObject(value='https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents')
327
+
328
+ print(url.netloc)
329
+ # >>> github.com
330
+ ```
331
+ """
332
+ _, netloc, *_ = split_url(value=self.value)
333
+ return netloc
334
+
335
+ @property
336
+ def path(self) -> str | None:
337
+ """
338
+ Get the URL path.
339
+
340
+ Returns:
341
+ str | None: The URL path if exists, otherwise None.
342
+
343
+ Example:
344
+ ```python
345
+ from value_object_pattern.usables.internet import UrlValueObject
346
+
347
+ url = UrlValueObject(value='https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents')
348
+
349
+ print(url.path)
350
+ # >>> /adriamontoto/value-object-pattern
351
+ ```
352
+ """
353
+ _, _, path, *_ = split_url(value=self.value)
354
+ return path if path else None
355
+
356
+ @property
357
+ def query(self) -> str | None:
358
+ """
359
+ Get the URL query.
360
+
361
+ Returns:
362
+ str | None: The URL query if exists, otherwise None.
363
+
364
+ Example:
365
+ ```python
366
+ from value_object_pattern.usables.internet import UrlValueObject
367
+
368
+ url = UrlValueObject(value='https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents')
369
+
370
+ print(url.query)
371
+ # >>> tab=readme-ov-file
372
+ ```
373
+ """
374
+ _, _, _, query, *_ = split_url(value=self.value)
375
+ return query if query else None
376
+
377
+ @property
378
+ def fragment(self) -> str | None:
379
+ """
380
+ Get the URL fragment.
381
+
382
+ Returns:
383
+ str | None: The URL fragment if exists, otherwise None.
384
+
385
+ Example:
386
+ ```python
387
+ from value_object_pattern.usables.internet import UrlValueObject
388
+
389
+ url = UrlValueObject(value='https://github.com/adriamontoto/value-object-pattern?tab=readme-ov-file#table-of-contents')
390
+
391
+ print(url.fragment)
392
+ # >>> table-of-contents
393
+ ```
394
+ """
395
+ _, _, _, _, fragment = split_url(value=self.value)
396
+ return fragment if fragment else None
@@ -0,0 +1,45 @@
1
+ from .boolean import BooleanValueObject, FalseValueObject, TrueValueObject
2
+ from .bytes import BytesValueObject
3
+ from .float import FloatValueObject, NegativeFloatValueObject, PositiveFloatValueObject
4
+ from .integer import (
5
+ EvenIntegerValueObject,
6
+ IntegerValueObject,
7
+ NegativeIntegerValueObject,
8
+ OddIntegerValueObject,
9
+ PositiveIntegerValueObject,
10
+ )
11
+ from .string import (
12
+ AlphaStringValueObject,
13
+ AlphanumericStringValueObject,
14
+ DigitStringValueObject,
15
+ LowercaseStringValueObject,
16
+ NotEmptyStringValueObject,
17
+ PrintableStringValueObject,
18
+ StringValueObject,
19
+ TrimmedStringValueObject,
20
+ UppercaseStringValueObject,
21
+ )
22
+
23
+ __all__ = (
24
+ 'AlphaStringValueObject',
25
+ 'AlphanumericStringValueObject',
26
+ 'BooleanValueObject',
27
+ 'BytesValueObject',
28
+ 'DigitStringValueObject',
29
+ 'EvenIntegerValueObject',
30
+ 'FalseValueObject',
31
+ 'FloatValueObject',
32
+ 'IntegerValueObject',
33
+ 'LowercaseStringValueObject',
34
+ 'NegativeFloatValueObject',
35
+ 'NegativeIntegerValueObject',
36
+ 'NotEmptyStringValueObject',
37
+ 'OddIntegerValueObject',
38
+ 'PositiveFloatValueObject',
39
+ 'PositiveIntegerValueObject',
40
+ 'PrintableStringValueObject',
41
+ 'StringValueObject',
42
+ 'TrimmedStringValueObject',
43
+ 'TrueValueObject',
44
+ 'UppercaseStringValueObject',
45
+ )
@@ -0,0 +1,9 @@
1
+ from .boolean_value_object import BooleanValueObject
2
+ from .false_value_object import FalseValueObject
3
+ from .true_value_object import TrueValueObject
4
+
5
+ __all__ = (
6
+ 'BooleanValueObject',
7
+ 'FalseValueObject',
8
+ 'TrueValueObject',
9
+ )
@@ -0,0 +1,36 @@
1
+ """
2
+ BooleanValueObject value object.
3
+ """
4
+
5
+ from value_object_pattern.decorators import validation
6
+ from value_object_pattern.models import ValueObject
7
+
8
+
9
+ class BooleanValueObject(ValueObject[bool]):
10
+ """
11
+ BooleanValueObject value object ensures the provided value is a boolean.
12
+
13
+ Example:
14
+ ```python
15
+ from value_object_pattern.usables import BooleanValueObject
16
+
17
+ boolean = BooleanValueObject(value=True)
18
+
19
+ print(repr(boolean))
20
+ # >>> BooleanValueObject(value=True)
21
+ ```
22
+ """
23
+
24
+ @validation(order=0)
25
+ def _ensure_value_is_boolean(self, value: bool) -> None:
26
+ """
27
+ Ensures the value object `value` is a boolean.
28
+
29
+ Args:
30
+ value (bool): The provided value.
31
+
32
+ Raises:
33
+ TypeError: If the `value` is not a boolean.
34
+ """
35
+ if type(value) is not bool:
36
+ raise TypeError(f'BooleanValueObject value <<<{value}>>> must be a boolean. Got <<<{type(value).__name__}>>> type.') # noqa: E501 # fmt: skip
@@ -0,0 +1,37 @@
1
+ """
2
+ FalseValueObject value object.
3
+ """
4
+
5
+ from value_object_pattern.decorators import validation
6
+
7
+ from .boolean_value_object import BooleanValueObject
8
+
9
+
10
+ class FalseValueObject(BooleanValueObject):
11
+ """
12
+ FalseValueObject value object ensures the provided value is false.
13
+
14
+ Example:
15
+ ```python
16
+ from value_object_pattern.usables import BooleanValueObject
17
+
18
+ boolean = BooleanValueObject(value=False)
19
+
20
+ print(repr(boolean))
21
+ # >>> BooleanValueObject(value=False)
22
+ ```
23
+ """
24
+
25
+ @validation(order=0)
26
+ def _ensure_value_is_false(self, value: bool) -> None:
27
+ """
28
+ Ensures the value object `value` is false.
29
+
30
+ Args:
31
+ value (bool): The provided value.
32
+
33
+ Raises:
34
+ ValueError: If the `value` is not false.
35
+ """
36
+ if value:
37
+ raise ValueError(f'FalseValueObject value <<<{value}>>> must be false.')
@@ -0,0 +1,37 @@
1
+ """
2
+ TrueValueObject value object.
3
+ """
4
+
5
+ from value_object_pattern.decorators import validation
6
+
7
+ from .boolean_value_object import BooleanValueObject
8
+
9
+
10
+ class TrueValueObject(BooleanValueObject):
11
+ """
12
+ TrueValueObject value object ensures the provided value is true.
13
+
14
+ Example:
15
+ ```python
16
+ from value_object_pattern.usables import BooleanValueObject
17
+
18
+ boolean = BooleanValueObject(value=True)
19
+
20
+ print(repr(boolean))
21
+ # >>> BooleanValueObject(value=True)
22
+ ```
23
+ """
24
+
25
+ @validation(order=0)
26
+ def _ensure_value_is_true(self, value: bool) -> None:
27
+ """
28
+ Ensures the value object `value` is true.
29
+
30
+ Args:
31
+ value (bool): The provided value.
32
+
33
+ Raises:
34
+ ValueError: If the `value` is not true.
35
+ """
36
+ if not value:
37
+ raise ValueError(f'TrueValueObject value <<<{value}>>> must be true.')
@@ -0,0 +1,3 @@
1
+ from .bytes_value_object import BytesValueObject
2
+
3
+ __all__ = ('BytesValueObject',)