value-object-pattern 0.3.0__tar.gz → 0.5.0__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 (72) hide show
  1. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/PKG-INFO +1 -1
  2. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/pyproject.toml +1 -1
  3. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/__init__.py +1 -1
  4. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/models/enumeration_value_object.py +1 -1
  5. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/models/value_object.py +54 -5
  6. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/__init__.py +3 -0
  7. value_object_pattern-0.5.0/value_object_pattern/usables/dates/timezone/__init__.py +7 -0
  8. value_object_pattern-0.5.0/value_object_pattern/usables/dates/timezone/string_timezone_value_object.py +66 -0
  9. value_object_pattern-0.5.0/value_object_pattern/usables/dates/timezone/timezone_value_object.py +53 -0
  10. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/.gitignore +0 -0
  11. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/LICENSE.md +0 -0
  12. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/README.md +0 -0
  13. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/decorators/__init__.py +0 -0
  14. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/decorators/value_object_process.py +0 -0
  15. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/decorators/value_object_validation.py +0 -0
  16. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/models/__init__.py +0 -0
  17. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/py.typed +0 -0
  18. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/__init__.py +0 -0
  19. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/date/__init__.py +0 -0
  20. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/date/date_value_object.py +0 -0
  21. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/date/string_date_value_object.py +0 -0
  22. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/datetime/__init__.py +0 -0
  23. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/datetime/datetime_value_object.py +0 -0
  24. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/dates/datetime/string_datetime_value_object.py +0 -0
  25. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/identifiers/__init__.py +0 -0
  26. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/identifiers/countries/__init__.py +0 -0
  27. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/identifiers/countries/spain/__init__.py +0 -0
  28. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/identifiers/countries/spain/dni_value_object.py +0 -0
  29. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/identifiers/string_uuid_value_object.py +0 -0
  30. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/identifiers/uuid_value_object.py +0 -0
  31. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/__init__.py +0 -0
  32. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/aws_cloud_region_value_object.py +0 -0
  33. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/domain_value_object.py +0 -0
  34. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/host_value_object.py +0 -0
  35. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/ipv4_address_value_object.py +0 -0
  36. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/ipv4_network_value_object.py +0 -0
  37. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/ipv6_address_value_object.py +0 -0
  38. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/ipv6_network_value_object.py +0 -0
  39. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/mac_address_value_object.py +0 -0
  40. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/port_value_object.py +0 -0
  41. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/uri/__init__.py +0 -0
  42. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/uri/http_https_url_value_object.py +0 -0
  43. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/uri/http_url_value_object.py +0 -0
  44. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/uri/https_url_value_object.py +0 -0
  45. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/internet/uri/url_value_object.py +0 -0
  46. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/__init__.py +0 -0
  47. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/boolean/__init__.py +0 -0
  48. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/boolean/boolean_value_object.py +0 -0
  49. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/boolean/false_value_object.py +0 -0
  50. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/boolean/true_value_object.py +0 -0
  51. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/bytes/__init__.py +0 -0
  52. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/bytes/bytes_value_object.py +0 -0
  53. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/float/__init__.py +0 -0
  54. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/float/float_value_object.py +0 -0
  55. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/float/negative_float_value_object.py +0 -0
  56. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/float/positive_float_value_object.py +0 -0
  57. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/integer/__init__.py +0 -0
  58. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/integer/even_integer_value_object.py +0 -0
  59. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/integer/integer_value_object.py +0 -0
  60. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/integer/negative_integer_value_object.py +0 -0
  61. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/integer/odd_integer_value_object.py +0 -0
  62. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/integer/positive_integer_value_object.py +0 -0
  63. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/__init__.py +0 -0
  64. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/alpha_value_object.py +0 -0
  65. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/alphanumeric_value_object.py +0 -0
  66. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/digit_value_object.py +0 -0
  67. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/lowercase_string_value_object.py +0 -0
  68. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/non_empty_string_value_object.py +0 -0
  69. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/printable_string_value_object.py +0 -0
  70. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/string_value_object.py +0 -0
  71. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/trimmed_string_value_object.py +0 -0
  72. {value_object_pattern-0.3.0 → value_object_pattern-0.5.0}/value_object_pattern/usables/primitives/string/uppercase_string_value_object.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: value-object-pattern
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: The Value Object Pattern is a Python package that streamlines the creation and management of value objects in your projects.
5
5
  Project-URL: Homepage, https://github.com/adriamontoto/value-object-pattern
6
6
  Project-URL: Repository, https://github.com/adriamontoto/value-object-pattern
@@ -63,7 +63,7 @@ release = ['build>=1.2.2', 'python-semantic-release>=10.0.2']
63
63
  test = [
64
64
  'pytest>=8.0.0',
65
65
  'pytest-randomly>=3.0.0',
66
- 'object-mother-pattern>=1.0.0',
66
+ 'object-mother-pattern>=2.1.0',
67
67
  { include-group = 'coverage' },
68
68
  ]
69
69
  types = ['types-python-dateutil>=2.9.0.20241206']
@@ -1,4 +1,4 @@
1
- __version__ = '0.3.0'
1
+ __version__ = '0.5.0'
2
2
 
3
3
  from .decorators import process, validation
4
4
  from .models import EnumerationValueObject, ValueObject
@@ -18,7 +18,7 @@ from value_object_pattern.models.value_object import ValueObject
18
18
  E = TypeVar('E', bound=Enum)
19
19
 
20
20
 
21
- class EnumerationValueObject(ValueObject[str | E], Generic[E]):
21
+ class EnumerationValueObject(ValueObject[str | E], Generic[E]): # noqa: UP046
22
22
  """
23
23
  EnumerationValueObject is a value object that ensures the provided value is from an enumeration.
24
24
 
@@ -15,7 +15,7 @@ else:
15
15
  T = TypeVar('T')
16
16
 
17
17
 
18
- class ValueObject(ABC, Generic[T]):
18
+ class ValueObject(ABC, Generic[T]): # noqa: UP046
19
19
  """
20
20
  ValueObject generic type.
21
21
 
@@ -34,13 +34,14 @@ class ValueObject(ABC, Generic[T]):
34
34
  ```
35
35
  """
36
36
 
37
- __slots__ = ('_title', '_value')
38
- __match_args__ = ('_title', '_value')
37
+ __slots__ = ('_parameter', '_title', '_value')
38
+ __match_args__ = ('_parameter', '_title', '_value')
39
39
 
40
40
  _value: T
41
41
  _title: str
42
+ _parameter: str
42
43
 
43
- def __init__(self, *, value: T, title: str | None = None) -> None:
44
+ def __init__(self, *, value: T, title: str | None = None, parameter: str | None = None) -> None:
44
45
  """
45
46
  ValueObject value object constructor.
46
47
 
@@ -48,10 +49,16 @@ class ValueObject(ABC, Generic[T]):
48
49
  value (T): The value to store in the value object.
49
50
  title (str | None, optional): The title of the value object when raising exceptions, if title is None, the
50
51
  class name is used instead. Defaults to None.
52
+ parameter (str | None, optional): The parameter name of the value object when raising exceptions, if
53
+ parameter is None, the string "value" is used instead. Defaults to None.
51
54
 
52
55
  Raises:
53
56
  TypeError: If the title is not a string.
57
+ ValueError: If the title is an empty string.
54
58
  ValueError: If the title contains leading or trailing whitespaces.
59
+ TypeError: If the parameter is not a string.
60
+ ValueError: If the parameter is an empty string.
61
+ ValueError: If the parameter contains leading or trailing whitespaces.
55
62
 
56
63
  Example:
57
64
  ```python
@@ -71,12 +78,28 @@ class ValueObject(ABC, Generic[T]):
71
78
  title = self.__class__.__name__
72
79
 
73
80
  if type(title) is not str:
74
- raise TypeError(f'ValueObject value <<<{title}>>> must be a string. Got <<<{type(title).__name__}>>> instead.') # noqa: E501 # fmt: skip
81
+ raise TypeError(f'ValueObject title <<<{title}>>> must be a string. Got <<<{type(title).__name__}>>> instead.') # noqa: E501 # fmt: skip
82
+
83
+ if title == '':
84
+ raise ValueError(f'ValueObject title <<<{title}>>> must not be an empty string.') # noqa: E501 # fmt: skip
75
85
 
76
86
  if title.strip() != title:
77
87
  raise ValueError(f'ValueObject title <<<{title}>>> contains leading or trailing whitespaces. Only trimmed values are allowed.') # noqa: E501 # fmt: skip
78
88
 
89
+ if parameter is None:
90
+ parameter = 'value'
91
+
92
+ if type(parameter) is not str:
93
+ raise TypeError(f'ValueObject parameter <<<{parameter}>>> must be a string. Got <<<{type(parameter).__name__}>>> instead.') # noqa: E501 # fmt: skip
94
+
95
+ if parameter == '':
96
+ raise ValueError(f'ValueObject parameter <<<{parameter}>>> must not be an empty string.') # noqa: E501 # fmt: skip
97
+
98
+ if parameter.strip() != parameter:
99
+ raise ValueError(f'ValueObject parameter <<<{parameter}>>> contains leading or trailing whitespaces. Only trimmed values are allowed.') # noqa: E501 # fmt: skip
100
+
79
101
  object.__setattr__(self, '_title', title)
102
+ object.__setattr__(self, '_parameter', parameter)
80
103
 
81
104
  self._validate(value=value)
82
105
  value = self._process(value=value)
@@ -247,6 +270,8 @@ class ValueObject(ABC, Generic[T]):
247
270
  for class_name in {cls.__name__ for cls in classes}:
248
271
  error.args = (str(object=error.args[0]).replace(class_name, self.title),)
249
272
 
273
+ error.args = (str(object=error.args[0]).replace('value', self.parameter, 1),)
274
+
250
275
  raise error
251
276
 
252
277
  def _post_order_dfs_mro(self, cls: type, visited: set[type] | None = None, cut_off: type = object) -> list[type]:
@@ -381,3 +406,27 @@ class ValueObject(ABC, Generic[T]):
381
406
  ```
382
407
  """
383
408
  return self._title
409
+
410
+ @property
411
+ def parameter(self) -> str:
412
+ """
413
+ Returns the value object parameter name.
414
+
415
+ Returns:
416
+ str: The value object parameter name.
417
+
418
+ Example:
419
+ ```python
420
+ from value_object_pattern import ValueObject
421
+
422
+
423
+ class IntegerValueObject(ValueObject[int]):
424
+ pass
425
+
426
+
427
+ integer = IntegerValueObject(value=10)
428
+ print(integer.parameter)
429
+ # >>> value
430
+ ```
431
+ """
432
+ return self._parameter
@@ -1,9 +1,12 @@
1
1
  from .date import DateValueObject, StringDateValueObject
2
2
  from .datetime import DatetimeValueObject, StringDatetimeValueObject
3
+ from .timezone import StringTimezoneValueObject, TimezoneValueObject
3
4
 
4
5
  __all__ = (
5
6
  'DateValueObject',
6
7
  'DatetimeValueObject',
7
8
  'StringDateValueObject',
8
9
  'StringDatetimeValueObject',
10
+ 'StringTimezoneValueObject',
11
+ 'TimezoneValueObject',
9
12
  )
@@ -0,0 +1,7 @@
1
+ from .string_timezone_value_object import StringTimezoneValueObject
2
+ from .timezone_value_object import TimezoneValueObject
3
+
4
+ __all__ = (
5
+ 'StringTimezoneValueObject',
6
+ 'TimezoneValueObject',
7
+ )
@@ -0,0 +1,66 @@
1
+ """
2
+ StringTimezoneValueObject value object.
3
+ """
4
+
5
+ from typing import Any, NoReturn
6
+ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
7
+
8
+ from value_object_pattern.decorators import process, validation
9
+ from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
10
+
11
+
12
+ class StringTimezoneValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
13
+ """
14
+ StringTimezoneValueObject value object ensures the provided value is a string timezone.
15
+
16
+ Example:
17
+ ```python
18
+ from value_object_pattern.usables.dates import StringTimezoneValueObject
19
+
20
+ timezone = StringTimezoneValueObject(value='UTC')
21
+
22
+ print(repr(timezone))
23
+ # >>> StringTimezoneValueObject(value='UTC')
24
+ ```
25
+ """
26
+
27
+ @process(order=0)
28
+ def _ensure_value_is_normalized(self, value: str) -> str:
29
+ """
30
+ Ensures the value object `value` is normalized timezone string (uppercase).
31
+
32
+ Args:
33
+ value (str): The provided value.
34
+
35
+ Returns:
36
+ str: The normalized timezone string.
37
+ """
38
+ return value.upper()
39
+
40
+ @validation(order=0)
41
+ def _ensure_value_is_timezone(self, value: str) -> None:
42
+ """
43
+ Ensures the value object `value` is a string timezone.
44
+
45
+ Args:
46
+ value (str): The provided value.
47
+
48
+ Raises:
49
+ ValueError: If the `value` is not a timezone.
50
+ """
51
+ try:
52
+ ZoneInfo(value)
53
+ except ZoneInfoNotFoundError:
54
+ self._raise_value_is_not_timezone(value=value)
55
+
56
+ def _raise_value_is_not_timezone(self, value: Any) -> NoReturn:
57
+ """
58
+ Raises a ValueError if the value object `value` is not a timezone.
59
+
60
+ Args:
61
+ value (Any): The provided value.
62
+
63
+ Raises:
64
+ ValueError: If the `value` is not a timezone.
65
+ """
66
+ raise ValueError(f'StringTimezoneValueObject value <<<{value}>>> must be a timezone.')
@@ -0,0 +1,53 @@
1
+ """
2
+ TimezoneValueObject value object.
3
+ """
4
+
5
+ from datetime import tzinfo
6
+ from typing import Any, NoReturn
7
+
8
+ from value_object_pattern.decorators import validation
9
+ from value_object_pattern.models import ValueObject
10
+
11
+
12
+ class TimezoneValueObject(ValueObject[tzinfo]):
13
+ """
14
+ TimezoneValueObject value object ensures the provided value is a timezone.
15
+
16
+ Example:
17
+ ```python
18
+ from datetime import UTC
19
+
20
+ from value_object_pattern.usables import TimezoneValueObject
21
+
22
+ timezone = TimezoneValueObject(value=UTC)
23
+
24
+ print(repr(timezone))
25
+ # >>> TimezoneValueObject(value=UTC)
26
+ ```
27
+ """
28
+
29
+ @validation(order=0)
30
+ def _ensure_value_is_timezone(self, value: tzinfo) -> None:
31
+ """
32
+ Ensures the value object `value` is a timezone.
33
+
34
+ Args:
35
+ value (tzinfo): The provided value.
36
+
37
+ Raises:
38
+ TypeError: If the `value` is not a timezone.
39
+ """
40
+ if not isinstance(value, tzinfo):
41
+ self._raise_value_is_not_timezone(value=value)
42
+
43
+ def _raise_value_is_not_timezone(self, value: Any) -> NoReturn:
44
+ """
45
+ Raises a TypeError if the value object `value` is not a timezone.
46
+
47
+ Args:
48
+ value (Any): The provided value.
49
+
50
+ Raises:
51
+ TypeError: If the `value` is not a timezone.
52
+ """
53
+ raise TypeError(f'TimezoneValueObject value <<<{value}>>> must be a timezone. Got <<<{type(value).__name__}>>> type.') # noqa: E501 # fmt: skip