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.
- value_object_pattern/__init__.py +10 -0
- value_object_pattern/decorators/__init__.py +7 -0
- value_object_pattern/decorators/value_object_process.py +83 -0
- value_object_pattern/decorators/value_object_validation.py +78 -0
- value_object_pattern/models/__init__.py +3 -0
- value_object_pattern/models/value_object.py +383 -0
- value_object_pattern/py.typed +0 -0
- value_object_pattern/usables/__init__.py +54 -0
- value_object_pattern/usables/dates/__init__.py +9 -0
- value_object_pattern/usables/dates/date/__init__.py +7 -0
- value_object_pattern/usables/dates/date/date_value_object.py +162 -0
- value_object_pattern/usables/dates/date/string_date_value_object.py +201 -0
- value_object_pattern/usables/dates/datetime/__init__.py +7 -0
- value_object_pattern/usables/dates/datetime/datetime_value_object.py +193 -0
- value_object_pattern/usables/dates/datetime/string_datetime_value_object.py +237 -0
- value_object_pattern/usables/identifiers/__init__.py +7 -0
- value_object_pattern/usables/identifiers/country_ids/__init__.py +3 -0
- value_object_pattern/usables/identifiers/country_ids/spain/__init__.py +3 -0
- value_object_pattern/usables/identifiers/country_ids/spain/dni_value_object.py +63 -0
- value_object_pattern/usables/identifiers/string_uuid_value_object.py +56 -0
- value_object_pattern/usables/identifiers/uuid_value_object.py +40 -0
- value_object_pattern/usables/internet/__init__.py +38 -0
- value_object_pattern/usables/internet/api_keys/__init__.py +13 -0
- value_object_pattern/usables/internet/api_keys/aws_access_key_id_value_object.py +40 -0
- value_object_pattern/usables/internet/api_keys/aws_secret_access_key_value_object.py +40 -0
- value_object_pattern/usables/internet/api_keys/github_personal_access_token_value_object.py +41 -0
- value_object_pattern/usables/internet/api_keys/openai_api_key_value_object.py +40 -0
- value_object_pattern/usables/internet/api_keys/resend_api_key_value_object.py +40 -0
- value_object_pattern/usables/internet/aws_cloud_region_value_object.py +77 -0
- value_object_pattern/usables/internet/domain_value_object.py +149 -0
- value_object_pattern/usables/internet/host_value_object.py +143 -0
- value_object_pattern/usables/internet/ipv4_address_value_object.py +305 -0
- value_object_pattern/usables/internet/ipv4_network_value_object.py +165 -0
- value_object_pattern/usables/internet/ipv6_address_value_object.py +288 -0
- value_object_pattern/usables/internet/ipv6_network_value_object.py +145 -0
- value_object_pattern/usables/internet/mac_address_value_object.py +390 -0
- value_object_pattern/usables/internet/port_value_object.py +682 -0
- value_object_pattern/usables/internet/uri/__init__.py +11 -0
- value_object_pattern/usables/internet/uri/http_https_url_value_object.py +39 -0
- value_object_pattern/usables/internet/uri/http_url_value_object.py +39 -0
- value_object_pattern/usables/internet/uri/https_url_value_object.py +39 -0
- value_object_pattern/usables/internet/uri/url_value_object.py +396 -0
- value_object_pattern/usables/primitives/__init__.py +45 -0
- value_object_pattern/usables/primitives/boolean/__init__.py +9 -0
- value_object_pattern/usables/primitives/boolean/boolean_value_object.py +36 -0
- value_object_pattern/usables/primitives/boolean/false_value_object.py +37 -0
- value_object_pattern/usables/primitives/boolean/true_value_object.py +37 -0
- value_object_pattern/usables/primitives/bytes/__init__.py +3 -0
- value_object_pattern/usables/primitives/bytes/bytes_value_object.py +36 -0
- value_object_pattern/usables/primitives/float/__init__.py +9 -0
- value_object_pattern/usables/primitives/float/float_value_object.py +36 -0
- value_object_pattern/usables/primitives/float/negative_float_value_object.py +37 -0
- value_object_pattern/usables/primitives/float/positive_float_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/__init__.py +13 -0
- value_object_pattern/usables/primitives/integer/even_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/integer_value_object.py +36 -0
- value_object_pattern/usables/primitives/integer/negative_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/odd_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/positive_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/__init__.py +21 -0
- value_object_pattern/usables/primitives/string/alpha_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/alphanumeric_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/digit_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/lowercase_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/non_empty_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/printable_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/string_value_object.py +36 -0
- value_object_pattern/usables/primitives/string/trimmed_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/uppercase_string_value_object.py +37 -0
- value_object_pattern-0.1.0.dist-info/METADATA +95 -0
- value_object_pattern-0.1.0.dist-info/RECORD +73 -0
- value_object_pattern-0.1.0.dist-info/WHEEL +4 -0
- value_object_pattern-0.1.0.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
"""
|
2
|
+
AwsCloudRegionValueObject value object.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from functools import lru_cache
|
6
|
+
from re import DOTALL, findall
|
7
|
+
from urllib.request import urlopen
|
8
|
+
|
9
|
+
from value_object_pattern import process, validation
|
10
|
+
from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
|
11
|
+
|
12
|
+
|
13
|
+
@lru_cache(maxsize=1)
|
14
|
+
def get_aws_cloud_regions() -> set[str]:
|
15
|
+
"""
|
16
|
+
Get AWS cloud regions.
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
set[str]: The AWS cloud regions.
|
20
|
+
|
21
|
+
References:
|
22
|
+
AWS Regions: https://docs.aws.amazon.com/global-infrastructure/latest/regions/aws-regions.html#available-regions
|
23
|
+
"""
|
24
|
+
url = 'https://docs.aws.amazon.com/global-infrastructure/latest/regions/aws-regions.html#available-regions'
|
25
|
+
with urlopen(url=url) as response: # noqa: S310
|
26
|
+
content = response.read().decode('utf-8')
|
27
|
+
|
28
|
+
pattern = r'<tr>\s*<td[^>]*tabindex="-1">(.*?)</td>\s*<td[^>]*tabindex="-1">.*?</td>\s*<td[^>]*tabindex="-1">.*?</td>\s*</tr>' # noqa: E501
|
29
|
+
region_codes = findall(pattern=pattern, string=content, flags=DOTALL)
|
30
|
+
|
31
|
+
return {region_code.lower() for region_code in region_codes}
|
32
|
+
|
33
|
+
|
34
|
+
class AwsCloudRegionValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
|
35
|
+
"""
|
36
|
+
AwsCloudRegionValueObject value object ensures the provided value is a valid AWS cloud region.
|
37
|
+
|
38
|
+
References:
|
39
|
+
AWS Regions: https://docs.aws.amazon.com/global-infrastructure/latest/regions/aws-regions.html#available-regions
|
40
|
+
|
41
|
+
Example:
|
42
|
+
```python
|
43
|
+
from value_object_pattern.usables.internet import AwsCloudRegionValueObject
|
44
|
+
|
45
|
+
key = AwsCloudRegionValueObject(value='us-east-1')
|
46
|
+
|
47
|
+
print(repr(key))
|
48
|
+
# >>> AwsCloudRegionValueObject(value=us-east-1)
|
49
|
+
```
|
50
|
+
"""
|
51
|
+
|
52
|
+
@process(order=0)
|
53
|
+
def _ensure_region_is_in_lowercase(self, value: str) -> str:
|
54
|
+
"""
|
55
|
+
Ensure AWS region is in lowercase.
|
56
|
+
|
57
|
+
Args:
|
58
|
+
value (str): The region value.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
str: The region value in lowercase.
|
62
|
+
"""
|
63
|
+
return value.lower()
|
64
|
+
|
65
|
+
@validation(order=0)
|
66
|
+
def _validate_region(self, value: str) -> None:
|
67
|
+
"""
|
68
|
+
Validate AWS region.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
value (str): The region value.
|
72
|
+
|
73
|
+
Raises:
|
74
|
+
ValueError: If the region does not exist.
|
75
|
+
"""
|
76
|
+
if value.lower() not in get_aws_cloud_regions():
|
77
|
+
raise ValueError(f'AwsCloudRegionValueObject value <<<{value}>>> does not exist.')
|
@@ -0,0 +1,149 @@
|
|
1
|
+
"""
|
2
|
+
DomainValueObject value object.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from functools import lru_cache
|
6
|
+
from re import Pattern, compile as re_compile
|
7
|
+
from urllib.request import urlopen
|
8
|
+
|
9
|
+
from value_object_pattern import process, validation
|
10
|
+
from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
|
11
|
+
|
12
|
+
|
13
|
+
@lru_cache(maxsize=1)
|
14
|
+
def get_top_level_domains() -> set[str]:
|
15
|
+
"""
|
16
|
+
Get top level domains from IANA.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
url (str): The URL to get the top level domains.
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
set[str]: The top level domains in lower case.
|
23
|
+
|
24
|
+
References:
|
25
|
+
https://data.iana.org/TLD/tlds-alpha-by-domain.txt
|
26
|
+
"""
|
27
|
+
url = 'https://data.iana.org/TLD/tlds-alpha-by-domain.txt'
|
28
|
+
with urlopen(url=url) as response: # noqa: S310
|
29
|
+
content = response.read().decode('utf-8')
|
30
|
+
|
31
|
+
return {line.strip().lower() for line in content.splitlines() if line and not line.startswith('#')}
|
32
|
+
|
33
|
+
|
34
|
+
class DomainValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
|
35
|
+
"""
|
36
|
+
DomainValueObject value object ensures the provided value is a valid domain.
|
37
|
+
|
38
|
+
References:
|
39
|
+
https://data.iana.org/TLD/tlds-alpha-by-domain.txt
|
40
|
+
|
41
|
+
Example:
|
42
|
+
```python
|
43
|
+
from value_object_pattern.usables.internet import DomainValueObject
|
44
|
+
|
45
|
+
key = DomainValueObject(value='github.com')
|
46
|
+
|
47
|
+
print(repr(key))
|
48
|
+
# >>> DomainValueObject(value=github.com)
|
49
|
+
```
|
50
|
+
"""
|
51
|
+
|
52
|
+
__DOMAIN_VALUE_OBJECT_MIN_LABEL_LENGTH: int = 1
|
53
|
+
__DOMAIN_VALUE_OBJECT_MAX_LABEL_LENGTH: int = 63
|
54
|
+
__DOMAIN_VALUE_OBJECT_MAX_DOMAIN_LENGTH: int = 253
|
55
|
+
__DOMAIN_VALUE_OBJECT_REGEX: Pattern[str] = re_compile(pattern=r'^[a-zA-Z0-9-]+$')
|
56
|
+
|
57
|
+
@process(order=0)
|
58
|
+
def _ensure_domain_is_in_lowercase(self, value: str) -> str:
|
59
|
+
"""
|
60
|
+
Ensure domain is in lowercase.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
value (str): The domain value.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
str: The domain value in lowercase.
|
67
|
+
"""
|
68
|
+
return value.lower()
|
69
|
+
|
70
|
+
@process(order=1)
|
71
|
+
def _ensure_domain_has_not_trailing_dot(self, value: str) -> str:
|
72
|
+
"""
|
73
|
+
Ensure domain has not trailing dot.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
value (str): The domain value.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
str: The domain value without trailing dot.
|
80
|
+
"""
|
81
|
+
return value.rstrip('.')
|
82
|
+
|
83
|
+
@validation(order=0)
|
84
|
+
def _validate_top_level_domain(self, value: str) -> None:
|
85
|
+
"""
|
86
|
+
Validate top level domain.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
value (str): The domain value.
|
90
|
+
|
91
|
+
Raises:
|
92
|
+
ValueError: If domain value has not a valid top level domain.
|
93
|
+
"""
|
94
|
+
if '.' not in value:
|
95
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has not a valid top level domain.')
|
96
|
+
|
97
|
+
tdl = value.lower().rstrip('.').split(sep='.')[-1]
|
98
|
+
if tdl not in get_top_level_domains():
|
99
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has not a valid top level domain <<<{tdl}>>>.')
|
100
|
+
|
101
|
+
@validation(order=1)
|
102
|
+
def _validate_domain_length(self, value: str) -> None:
|
103
|
+
"""
|
104
|
+
Validate domain length.
|
105
|
+
|
106
|
+
Args:
|
107
|
+
value (str): The domain value.
|
108
|
+
|
109
|
+
Raises:
|
110
|
+
ValueError: If value length is longer than the maximum domain length.
|
111
|
+
"""
|
112
|
+
if len(value) > self.__DOMAIN_VALUE_OBJECT_MAX_DOMAIN_LENGTH:
|
113
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> length is longer than <<<{self.__DOMAIN_VALUE_OBJECT_MAX_DOMAIN_LENGTH}>>> characters.') # noqa: E501 # fmt: skip
|
114
|
+
|
115
|
+
@validation(order=2)
|
116
|
+
def _validate_domain_labels(self, value: str) -> None:
|
117
|
+
"""
|
118
|
+
Validate each label (label) according to standard DNS rules.
|
119
|
+
- Label must be between 1 and 63 characters long.
|
120
|
+
- Label must only contain letters, digits, or hyphens.
|
121
|
+
- Label must not start or end with a hyphen.
|
122
|
+
|
123
|
+
Args:
|
124
|
+
value (str): The domain value.
|
125
|
+
|
126
|
+
Raises:
|
127
|
+
ValueError: If value has a label shorter than the minimum length.
|
128
|
+
ValueError: If value has a label longer than the maximum length.
|
129
|
+
ValueError: If value has a label starting with a hyphen.
|
130
|
+
ValueError: If value has a label ending with a hyphen.
|
131
|
+
ValueError: If value has a label containing invalid characters.
|
132
|
+
"""
|
133
|
+
labels = value.lower().rstrip('.').split(sep='.')
|
134
|
+
labels = labels[:-1] if len(labels) > 1 else labels # remove top level domain
|
135
|
+
for label in labels:
|
136
|
+
if len(label) < self.__DOMAIN_VALUE_OBJECT_MIN_LABEL_LENGTH:
|
137
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has a label <<<{label}>>> shorter than <<<{self.__DOMAIN_VALUE_OBJECT_MIN_LABEL_LENGTH}>>> characters.') # noqa: E501 # fmt: skip
|
138
|
+
|
139
|
+
if len(label) > self.__DOMAIN_VALUE_OBJECT_MAX_LABEL_LENGTH:
|
140
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has a label <<<{label}>>> longer than <<<{self.__DOMAIN_VALUE_OBJECT_MAX_LABEL_LENGTH}>>> characters.') # noqa: E501 # fmt: skip
|
141
|
+
|
142
|
+
if label[0] == '-':
|
143
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has a label <<<{label}>>> that starts with a hyphen.') # noqa: E501 # fmt: skip
|
144
|
+
|
145
|
+
if label[-1] == '-':
|
146
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has a label <<<{label}>>> that ends with a hyphen.') # noqa: E501 # fmt: skip
|
147
|
+
|
148
|
+
if not self.__DOMAIN_VALUE_OBJECT_REGEX.fullmatch(string=label.encode(encoding='idna').decode(encoding='utf-8')): # noqa: E501 # fmt: skip
|
149
|
+
raise ValueError(f'DomainValueObject value <<<{value}>>> has a label <<<{label}>>> containing invalid characters. Only letters, digits, and hyphens are allowed.') # noqa: E501 # fmt: skip
|
@@ -0,0 +1,143 @@
|
|
1
|
+
"""
|
2
|
+
HostValueObject value object.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from value_object_pattern import process, validation
|
6
|
+
from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
|
7
|
+
|
8
|
+
from .domain_value_object import DomainValueObject
|
9
|
+
from .ipv4_address_value_object import Ipv4AddressValueObject
|
10
|
+
from .ipv6_address_value_object import Ipv6AddressValueObject
|
11
|
+
|
12
|
+
|
13
|
+
class HostValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
|
14
|
+
"""
|
15
|
+
HostValueObject value object ensures the provided value is a valid host.
|
16
|
+
|
17
|
+
Example:
|
18
|
+
```python
|
19
|
+
from value_object_pattern.usables.internet import HostValueObject
|
20
|
+
|
21
|
+
key = HostValueObject(value='github.com')
|
22
|
+
|
23
|
+
print(repr(key))
|
24
|
+
# >>> HostValueObject(value=github.com)
|
25
|
+
```
|
26
|
+
"""
|
27
|
+
|
28
|
+
@process(order=0)
|
29
|
+
def _ensure_host_stored_respective_format(self, value: str) -> str:
|
30
|
+
"""
|
31
|
+
Ensure host is stored in respective format, domain, IPv4 or IPv6 address.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
value (str): The host value.
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
str: The host value stored in respective format.
|
38
|
+
"""
|
39
|
+
if self.is_domain(value=value):
|
40
|
+
return DomainValueObject(value=value).value
|
41
|
+
|
42
|
+
if self.is_ipv4_address(value=value):
|
43
|
+
return Ipv4AddressValueObject(value=value).value
|
44
|
+
|
45
|
+
return Ipv6AddressValueObject(value=value).value
|
46
|
+
|
47
|
+
@validation(order=0)
|
48
|
+
def _validate_host(self, value: str) -> None:
|
49
|
+
"""
|
50
|
+
Validate that the host is a domain or an IPv4 or IPv6 address.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
value (str): The host value.
|
54
|
+
|
55
|
+
Raises:
|
56
|
+
ValueError: If the host is not a domain or an IPv4 or IPv6 address.
|
57
|
+
"""
|
58
|
+
if not (self.is_domain(value=value) or self.is_ipv4_address(value=value) or self.is_ipv6_address(value=value)):
|
59
|
+
raise ValueError(f'HostValueObject value <<<{value}>>> must be a domain or an IPv4 or IPv6 address.')
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def is_domain(cls, *, value: str) -> bool:
|
63
|
+
"""
|
64
|
+
Checks if a value is a domain.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
value (str): Value.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
bool: True if the value is a host, False otherwise.
|
71
|
+
|
72
|
+
Example:
|
73
|
+
```python
|
74
|
+
from value_object_pattern.usables.internet import HostValueObject
|
75
|
+
|
76
|
+
is_domain = HostValueObject.is_domain(value='github.com')
|
77
|
+
|
78
|
+
print(is_domain)
|
79
|
+
# >>> True
|
80
|
+
```
|
81
|
+
"""
|
82
|
+
try:
|
83
|
+
DomainValueObject(value=value)
|
84
|
+
return True
|
85
|
+
|
86
|
+
except (TypeError, ValueError):
|
87
|
+
return False
|
88
|
+
|
89
|
+
@classmethod
|
90
|
+
def is_ipv4_address(cls, *, value: str) -> bool:
|
91
|
+
"""
|
92
|
+
Checks if a value is an IPv4 host.
|
93
|
+
|
94
|
+
Args:
|
95
|
+
value (str): Value.
|
96
|
+
|
97
|
+
Returns:
|
98
|
+
bool: True if the value is an IPv4 host, False otherwise.
|
99
|
+
|
100
|
+
Example:
|
101
|
+
```python
|
102
|
+
from value_object_pattern.usables.internet import HostValueObject
|
103
|
+
|
104
|
+
is_ipv4 = HostValueObject.is_ipv4_address(value='1.1.1.1')
|
105
|
+
|
106
|
+
print(is_ipv4)
|
107
|
+
# >>> True
|
108
|
+
```
|
109
|
+
"""
|
110
|
+
try:
|
111
|
+
Ipv4AddressValueObject(value=value)
|
112
|
+
return True
|
113
|
+
|
114
|
+
except (TypeError, ValueError):
|
115
|
+
return False
|
116
|
+
|
117
|
+
@classmethod
|
118
|
+
def is_ipv6_address(cls, *, value: str) -> bool:
|
119
|
+
"""
|
120
|
+
Checks if a value is an IPv6 host.
|
121
|
+
|
122
|
+
Args:
|
123
|
+
value (str): Value.
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
bool: True if the value is an IPv6 host, False otherwise.
|
127
|
+
|
128
|
+
Example:
|
129
|
+
```python
|
130
|
+
from value_object_pattern.usables.internet import HostValueObject
|
131
|
+
|
132
|
+
is_ipv6 = HostValueObject.is_ipv6_address(value='a1c4:c052:a98e:8da4:301a:bd2a:3b36:36b4')
|
133
|
+
|
134
|
+
print(is_ipv6)
|
135
|
+
# >>> True
|
136
|
+
```
|
137
|
+
"""
|
138
|
+
try:
|
139
|
+
Ipv6AddressValueObject(value=value)
|
140
|
+
return True
|
141
|
+
|
142
|
+
except (TypeError, ValueError):
|
143
|
+
return False
|
@@ -0,0 +1,305 @@
|
|
1
|
+
# ruff: noqa: N802
|
2
|
+
"""
|
3
|
+
Ipv4AddressValueObject value object.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from __future__ import annotations
|
7
|
+
|
8
|
+
from ipaddress import AddressValueError, IPv4Address
|
9
|
+
|
10
|
+
from value_object_pattern.decorators import process, validation
|
11
|
+
from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
|
12
|
+
|
13
|
+
|
14
|
+
class Ipv4AddressValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
|
15
|
+
"""
|
16
|
+
Ipv4AddressValueObject value object ensures the provided value is a valid IPv4 address.
|
17
|
+
|
18
|
+
Example:
|
19
|
+
```python
|
20
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
21
|
+
|
22
|
+
ip = Ipv4AddressValueObject(value='66.162.207.81')
|
23
|
+
|
24
|
+
print(repr(ip))
|
25
|
+
# >>> Ipv4AddressValueObject(value=66.162.207.81)
|
26
|
+
```
|
27
|
+
"""
|
28
|
+
|
29
|
+
@process(order=0)
|
30
|
+
def _ensure_value_is_normalized(self, value: str) -> str:
|
31
|
+
"""
|
32
|
+
Ensures the value object value is normalized IPv4 address.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
value (str): Value.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
str: Value with the normalized IPv4 address.
|
39
|
+
"""
|
40
|
+
value = self._ipv4_address_normalize(value=value)
|
41
|
+
return str(object=IPv4Address(address=value))
|
42
|
+
|
43
|
+
@validation(order=0)
|
44
|
+
def _ensure_value_is_valid_ipv4_address(self, value: str) -> None:
|
45
|
+
"""
|
46
|
+
Ensures the value object value is a valid IPv4 address.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
value (str): Value.
|
50
|
+
|
51
|
+
Raises:
|
52
|
+
ValueError: If the value is not a valid IPv4 address.
|
53
|
+
"""
|
54
|
+
value = self._ipv4_address_normalize(value=value)
|
55
|
+
self._ipv4_address_validate(value=value)
|
56
|
+
|
57
|
+
@classmethod
|
58
|
+
def _ipv4_address_normalize(cls, value: str) -> str:
|
59
|
+
"""
|
60
|
+
Normalizes the given IPv4 address.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
value (str): IPv4 address.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
str: Normalized IPv4 address.
|
67
|
+
"""
|
68
|
+
if '/' in value and value.endswith('/32'):
|
69
|
+
value = value[:-3]
|
70
|
+
|
71
|
+
return value
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def _ipv4_address_validate(cls, value: str) -> IPv4Address:
|
75
|
+
"""
|
76
|
+
Validates the given IPv4 address.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
value (str): IPv4 address.
|
80
|
+
|
81
|
+
Raises:
|
82
|
+
ValueError: If the value is not a valid IPv4 address.
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
IPv4Address: IPv4 address.
|
86
|
+
"""
|
87
|
+
try:
|
88
|
+
return IPv4Address(address=value)
|
89
|
+
|
90
|
+
except AddressValueError as error:
|
91
|
+
raise ValueError(f'Ipv4AddressValueObject value <<<{value}>>> is not a valid IPv4 address.') from error
|
92
|
+
|
93
|
+
def is_reserved(self) -> bool:
|
94
|
+
"""
|
95
|
+
Checks if the given IPv4 address is reserved.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
value (str): IPv4 address.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
bool: True if the given IPv4 address is reserved, False otherwise.
|
102
|
+
|
103
|
+
Example:
|
104
|
+
```python
|
105
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
106
|
+
|
107
|
+
is_reserved = Ipv4AddressValueObject(value='240.0.0.0').is_reserved()
|
108
|
+
|
109
|
+
print(is_reserved)
|
110
|
+
# >>> True
|
111
|
+
```
|
112
|
+
"""
|
113
|
+
return self._ipv4_address_validate(value=self.value).is_reserved
|
114
|
+
|
115
|
+
def is_private(self) -> bool:
|
116
|
+
"""
|
117
|
+
Checks if the given IPv4 address is private.
|
118
|
+
|
119
|
+
Args:
|
120
|
+
value (str): IPv4 address.
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
bool: True if the given IPv4 address is private, False otherwise.
|
124
|
+
|
125
|
+
Example:
|
126
|
+
```python
|
127
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
128
|
+
|
129
|
+
is_private = Ipv4AddressValueObject(value='192.168.10.4').is_private()
|
130
|
+
|
131
|
+
print(is_private)
|
132
|
+
# >>> True
|
133
|
+
```
|
134
|
+
"""
|
135
|
+
return self._ipv4_address_validate(value=self.value).is_private
|
136
|
+
|
137
|
+
def is_global(self) -> bool:
|
138
|
+
"""
|
139
|
+
Checks if the given IPv4 address is global.
|
140
|
+
|
141
|
+
Args:
|
142
|
+
value (str): IPv4 address.
|
143
|
+
|
144
|
+
Returns:
|
145
|
+
bool: True if the given IPv4 address is global, False otherwise.
|
146
|
+
|
147
|
+
Example:
|
148
|
+
```python
|
149
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
150
|
+
|
151
|
+
is_global = Ipv4AddressValueObject(value='66.162.207.81').is_global()
|
152
|
+
|
153
|
+
print(is_global)
|
154
|
+
# >>> True
|
155
|
+
```
|
156
|
+
"""
|
157
|
+
return self._ipv4_address_validate(value=self.value).is_global
|
158
|
+
|
159
|
+
def is_multicast(self) -> bool:
|
160
|
+
"""
|
161
|
+
Checks if the given IPv4 address is multicast.
|
162
|
+
|
163
|
+
Args:
|
164
|
+
value (str): IPv4 address.
|
165
|
+
|
166
|
+
Returns:
|
167
|
+
bool: True if the given IPv4 address is multicast, False otherwise.
|
168
|
+
|
169
|
+
Example:
|
170
|
+
```python
|
171
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
172
|
+
|
173
|
+
is_multicast = Ipv4AddressValueObject(value='224.0.0.1').is_multicast()
|
174
|
+
|
175
|
+
print(is_multicast)
|
176
|
+
# >>> True
|
177
|
+
```
|
178
|
+
"""
|
179
|
+
return self._ipv4_address_validate(value=self.value).is_multicast
|
180
|
+
|
181
|
+
def is_unspecified(self) -> bool:
|
182
|
+
"""
|
183
|
+
Checks if the given IPv4 address is unspecified.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
value (str): IPv4 address.
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
bool: True if the given IPv4 address is unspecified, False otherwise.
|
190
|
+
|
191
|
+
Example:
|
192
|
+
```python
|
193
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
194
|
+
|
195
|
+
is_unspecified = Ipv4AddressValueObject(value='0.0.0.0').is_unspecified()
|
196
|
+
|
197
|
+
print(is_unspecified)
|
198
|
+
# >>> True
|
199
|
+
```
|
200
|
+
"""
|
201
|
+
return self._ipv4_address_validate(value=self.value).is_unspecified
|
202
|
+
|
203
|
+
def is_loopback(self) -> bool:
|
204
|
+
"""
|
205
|
+
Checks if the given IPv4 address is loopback.
|
206
|
+
|
207
|
+
Args:
|
208
|
+
value (str): IPv4 address.
|
209
|
+
|
210
|
+
Returns:
|
211
|
+
bool: True if the given IPv4 address is loopback, False otherwise.
|
212
|
+
|
213
|
+
Example:
|
214
|
+
```python
|
215
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
216
|
+
|
217
|
+
is_loopback = Ipv4AddressValueObject(value='127.0.0.1').is_loopback()
|
218
|
+
|
219
|
+
print(is_loopback)
|
220
|
+
# >>> True
|
221
|
+
```
|
222
|
+
"""
|
223
|
+
return self._ipv4_address_validate(value=self.value).is_loopback
|
224
|
+
|
225
|
+
def is_link_local(self) -> bool:
|
226
|
+
"""
|
227
|
+
Checks if the given IPv4 address is link-local.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
value (str): IPv4 address.
|
231
|
+
|
232
|
+
Returns:
|
233
|
+
bool: True if the given IPv4 address is link-local, False otherwise.
|
234
|
+
|
235
|
+
Example:
|
236
|
+
```python
|
237
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
238
|
+
|
239
|
+
is_link_local = Ipv4AddressValueObject(value='169.254.0.0').is_link_local()
|
240
|
+
|
241
|
+
print(is_link_local)
|
242
|
+
# >>> True
|
243
|
+
```
|
244
|
+
"""
|
245
|
+
return self._ipv4_address_validate(value=self.value).is_link_local
|
246
|
+
|
247
|
+
@classmethod
|
248
|
+
def UNSPECIFIED(cls) -> Ipv4AddressValueObject:
|
249
|
+
"""
|
250
|
+
Returns the unspecified IPv4 address (0.0.0.0).
|
251
|
+
|
252
|
+
Returns:
|
253
|
+
Ipv4AddressValueObject: Unspecified IPv4 address.
|
254
|
+
|
255
|
+
Example:
|
256
|
+
```python
|
257
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
258
|
+
|
259
|
+
ip = Ipv4AddressValueObject.UNSPECIFIED()
|
260
|
+
|
261
|
+
print(repr(ip))
|
262
|
+
# >>> Ipv4AddressValueObject(value=0.0.0.0)
|
263
|
+
```
|
264
|
+
"""
|
265
|
+
return cls(value='0.0.0.0') # noqa: S104
|
266
|
+
|
267
|
+
@classmethod
|
268
|
+
def LOOPBACK(cls) -> Ipv4AddressValueObject:
|
269
|
+
"""
|
270
|
+
Returns the loopback IPv4 address (127.0.0.1).
|
271
|
+
|
272
|
+
Returns:
|
273
|
+
Ipv4AddressValueObject: Loopback IPv4 address.
|
274
|
+
|
275
|
+
Example:
|
276
|
+
```python
|
277
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
278
|
+
|
279
|
+
ip = Ipv4AddressValueObject.LOOPBACK()
|
280
|
+
|
281
|
+
print(repr(ip))
|
282
|
+
# >>> Ipv4AddressValueObject(value=127.0.0.1)
|
283
|
+
```
|
284
|
+
"""
|
285
|
+
return cls(value='127.0.0.1')
|
286
|
+
|
287
|
+
@classmethod
|
288
|
+
def BROADCAST(cls) -> Ipv4AddressValueObject:
|
289
|
+
"""
|
290
|
+
Returns the broadcast IPv4 address (255.255.255.255).
|
291
|
+
|
292
|
+
Returns:
|
293
|
+
Ipv4AddressValueObject: Broadcast IPv4 address.
|
294
|
+
|
295
|
+
Example:
|
296
|
+
```python
|
297
|
+
from value_object_pattern.usables.internet import Ipv4AddressValueObject
|
298
|
+
|
299
|
+
ip = Ipv4AddressValueObject.BROADCAST()
|
300
|
+
|
301
|
+
print(repr(ip))
|
302
|
+
# >>> Ipv4AddressValueObject(value=255.255.255.255)
|
303
|
+
```
|
304
|
+
"""
|
305
|
+
return cls(value='255.255.255.255')
|