datavalue 0.1.5__py3-none-any.whl → 0.1.6__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.
- datavalue/__init__.py +2 -1
- datavalue/classes/complex_data.py +130 -0
- datavalue/classes/primitive_data.py +13 -0
- {datavalue-0.1.5.dist-info → datavalue-0.1.6.dist-info}/METADATA +1 -1
- datavalue-0.1.6.dist-info/RECORD +9 -0
- {datavalue-0.1.5.dist-info → datavalue-0.1.6.dist-info}/top_level.txt +0 -1
- datavalue-0.1.5.dist-info/RECORD +0 -9
- tests/test.py +0 -62
- {datavalue-0.1.5.dist-info → datavalue-0.1.6.dist-info}/WHEEL +0 -0
datavalue/__init__.py
CHANGED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Library import
|
|
2
|
+
from typing import Type, Optional, Any, Iterable
|
|
3
|
+
from .. import exceptions
|
|
4
|
+
from .primitive_data import PrimitiveData
|
|
5
|
+
|
|
6
|
+
# Classes definition
|
|
7
|
+
class ComplexData:
|
|
8
|
+
def __init__(self,
|
|
9
|
+
data_type: Type[list] | Type[tuple] | Type[set] | Type[frozenset] | Type[dict],
|
|
10
|
+
value: Any,
|
|
11
|
+
maximum_length: Optional[int] = None, minimum_length: Optional[int] = None,
|
|
12
|
+
possible_values: Optional[Iterable] = None,
|
|
13
|
+
|
|
14
|
+
data_class: Optional[bool] = False
|
|
15
|
+
) -> None:
|
|
16
|
+
# Instance properties assignment
|
|
17
|
+
self.data_type = data_type
|
|
18
|
+
self.value = value
|
|
19
|
+
self.maximum_length = maximum_length; self.minimum_length = minimum_length
|
|
20
|
+
self.possible_values = possible_values
|
|
21
|
+
self.data_class = data_class
|
|
22
|
+
|
|
23
|
+
# Validate constructor parameters
|
|
24
|
+
if self.possible_values:
|
|
25
|
+
# Base validation: it has to be a collection
|
|
26
|
+
if not isinstance(self.possible_values, (list, tuple)):
|
|
27
|
+
raise ValueError(f"The possible values has to be a list/tuple. Received: {type(self.possible_values).__name__}")
|
|
28
|
+
|
|
29
|
+
# Validation to collections (list, tuple, set, frozenset)
|
|
30
|
+
if self.data_type != dict:
|
|
31
|
+
if not isinstance(self.possible_values, (list, tuple)):
|
|
32
|
+
raise ValueError(f"Possible values for {self.data_type.__name__} must be exactly one list/tuple containing the options.")
|
|
33
|
+
|
|
34
|
+
# Specific validation for dicts
|
|
35
|
+
else: # self.data_type == dict
|
|
36
|
+
if len(self.possible_values) not in (1, 2):
|
|
37
|
+
raise ValueError("Possible values for dict must be 1 (keys) or 2 (keys, values) list/tuples.")
|
|
38
|
+
|
|
39
|
+
# Validate the first element
|
|
40
|
+
if not isinstance(self.possible_values[0], (list, tuple)):
|
|
41
|
+
raise ValueError("The first element of possible_values for dict must be a list/tuple of keys.")
|
|
42
|
+
|
|
43
|
+
# Validate the second element
|
|
44
|
+
if len(self.possible_values) == 2 and not isinstance(self.possible_values[1], (list, tuple)):
|
|
45
|
+
raise ValueError("The second element of possible_values for dict must be a list/tuple of value validators.")
|
|
46
|
+
|
|
47
|
+
# Execute instance data validation
|
|
48
|
+
if not self.data_class:
|
|
49
|
+
self.validate()
|
|
50
|
+
|
|
51
|
+
# Private methods
|
|
52
|
+
def _is_match(self, element: Any, schema: Any) -> bool:
|
|
53
|
+
# Validate data types
|
|
54
|
+
if isinstance(schema, (PrimitiveData, ComplexData)):
|
|
55
|
+
try:
|
|
56
|
+
return schema.validate(element)
|
|
57
|
+
except:
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
# Validate class data types
|
|
61
|
+
if isinstance(schema, type):
|
|
62
|
+
return isinstance(element, schema)
|
|
63
|
+
|
|
64
|
+
# Validate literal values
|
|
65
|
+
return element == schema
|
|
66
|
+
|
|
67
|
+
def _validate_collection(self, data: Any) -> bool:
|
|
68
|
+
element_index: int = 0
|
|
69
|
+
for element in data:
|
|
70
|
+
if not any(self._is_match(element, validator) for validator in self.possible_values):
|
|
71
|
+
raise ValueError(f"[ComplexData] Element: {element}, on index: {element_index} is not allowed.")
|
|
72
|
+
element_index += 1
|
|
73
|
+
|
|
74
|
+
# Return results
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
def _validate_dictionary(self, data: Any) -> bool:
|
|
78
|
+
# Validate keys and (if applies) values
|
|
79
|
+
if not isinstance(self.possible_values, (list, tuple)) or len(self.possible_values) != 2:
|
|
80
|
+
keys_schema = self.possible_values
|
|
81
|
+
values_schema = None
|
|
82
|
+
else:
|
|
83
|
+
keys_schema, values_schema = self.possible_values
|
|
84
|
+
|
|
85
|
+
for key, value in data.items():
|
|
86
|
+
# Validación de Claves (Debe ser un iterable de opciones)
|
|
87
|
+
if keys_schema:
|
|
88
|
+
if not any(self._is_match(key, validator) for validator in keys_schema):
|
|
89
|
+
raise ValueError(f"[ComplexData] Invalid key: {key}")
|
|
90
|
+
|
|
91
|
+
# Validación de Valores
|
|
92
|
+
if values_schema:
|
|
93
|
+
if not any(self._is_match(value, validator) for validator in values_schema):
|
|
94
|
+
raise ValueError(f"[ComplexData] Invalid value '{value}' for key '{key}'")
|
|
95
|
+
|
|
96
|
+
return True
|
|
97
|
+
|
|
98
|
+
# Public methods
|
|
99
|
+
def validate(self, data: Any = None) -> bool:
|
|
100
|
+
# Determine objective data
|
|
101
|
+
if data is None:
|
|
102
|
+
objective_data = self.value
|
|
103
|
+
else:
|
|
104
|
+
objective_data = data
|
|
105
|
+
|
|
106
|
+
# Data type validation
|
|
107
|
+
if not isinstance(objective_data, self.data_type):
|
|
108
|
+
raise exceptions.DataTypeException(
|
|
109
|
+
f"Incorrect data type.\nExpected: {self.data_type.__name__} - Received: {type(objective_data).__name__}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Length validation
|
|
113
|
+
current_length = len(objective_data)
|
|
114
|
+
|
|
115
|
+
if self.minimum_length is not None and current_length < self.minimum_length:
|
|
116
|
+
raise ValueError(f"Minimum length not reached: {current_length} < {self.minimum_length}")
|
|
117
|
+
|
|
118
|
+
if self.maximum_length is not None and current_length > self.maximum_length:
|
|
119
|
+
raise ValueError(f"Maximum length reached: {current_length} > {self.maximum_length}")
|
|
120
|
+
|
|
121
|
+
# Content validation and recurse
|
|
122
|
+
if self.possible_values:
|
|
123
|
+
# Validate dictionaries
|
|
124
|
+
if isinstance(objective_data, dict):
|
|
125
|
+
self._validate_dictionary(objective_data)
|
|
126
|
+
else:
|
|
127
|
+
self._validate_collection(objective_data)
|
|
128
|
+
|
|
129
|
+
# Return results
|
|
130
|
+
return True
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import re
|
|
3
3
|
from typing import Type, Optional, Any, Iterable, Union
|
|
4
4
|
from .. import exceptions
|
|
5
|
+
import json
|
|
5
6
|
|
|
6
7
|
# Classes definition
|
|
7
8
|
class PrimitiveData:
|
|
@@ -54,6 +55,18 @@ class PrimitiveData:
|
|
|
54
55
|
"REGULAR_EXPRESSION":self.regular_expression,
|
|
55
56
|
"DATA_CLASS":self.data_class
|
|
56
57
|
}
|
|
58
|
+
|
|
59
|
+
def to_json(self) -> str:
|
|
60
|
+
return json.dumps(self.to_dict(), indent=4)
|
|
61
|
+
|
|
62
|
+
def from_json(self, text_content: str) -> dict:
|
|
63
|
+
data_table = json.loads(text_content)
|
|
64
|
+
local_table = self.to_dict()
|
|
65
|
+
|
|
66
|
+
for element in data_table:
|
|
67
|
+
if element not in local_table: raise ValueError(f"The loaded table has a unknown value: {element}")
|
|
68
|
+
|
|
69
|
+
return data_table
|
|
57
70
|
|
|
58
71
|
def validate(self, data: Optional[Any] = None) -> bool:
|
|
59
72
|
# Define the data to validate
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
datavalue/__init__.py,sha256=-JBKpLEehjnezX3sTbpnB2px3izjHxZ_IEL_40iRHMM,112
|
|
2
|
+
datavalue/classes/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
|
+
datavalue/classes/complex_data.py,sha256=Z6LjGqjXyGLjzrAVs09M4NfQz9P7H-ZIrijR1s-Mg_0,5581
|
|
4
|
+
datavalue/classes/primitive_data.py,sha256=2IPScXGKuam32jdx1hbk0VxKS3mowwSBdM45Iigir3k,5691
|
|
5
|
+
datavalue/exceptions/__init__.py,sha256=T9X1N0kAv6RNTuTNQR7aTAxxvF25ihMsrtZGD-QZrBI,361
|
|
6
|
+
datavalue-0.1.6.dist-info/METADATA,sha256=rSve4eGV5Wh8RpQRvp5Ig-wWH2RZjHkYMj93C-qNSrY,1597
|
|
7
|
+
datavalue-0.1.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
+
datavalue-0.1.6.dist-info/top_level.txt,sha256=tVZ_--yYzvlZ2XTCkdORn4KKL7BwXPZUOVpL6PBJaRY,10
|
|
9
|
+
datavalue-0.1.6.dist-info/RECORD,,
|
datavalue-0.1.5.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
datavalue/__init__.py,sha256=QHthd6CQaDPqpvS3ay1r_Z7WvIleUXbTAottuML8nPA,66
|
|
2
|
-
datavalue/classes/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
|
-
datavalue/classes/primitive_data.py,sha256=qsKlds33RqR0bIGjy-5kgZdNBcrBMITbrvVx4HqeO-M,5281
|
|
4
|
-
datavalue/exceptions/__init__.py,sha256=T9X1N0kAv6RNTuTNQR7aTAxxvF25ihMsrtZGD-QZrBI,361
|
|
5
|
-
tests/test.py,sha256=8-AhuPJk0Yxt49MmbbdqGamhWM87T9mkbfmIU3BZZJk,1845
|
|
6
|
-
datavalue-0.1.5.dist-info/METADATA,sha256=71CLQrhr8mhSMINt4ha0p1PxHdOtOcPRIKGWss2LvD0,1597
|
|
7
|
-
datavalue-0.1.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
-
datavalue-0.1.5.dist-info/top_level.txt,sha256=zlD2cuGB4gcH2hf8HIBij-0hqp_7e-c2e5nn6-A9j1Y,16
|
|
9
|
-
datavalue-0.1.5.dist-info/RECORD,,
|
tests/test.py
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Library import
|
|
2
|
-
from datavalue import PrimitiveData
|
|
3
|
-
|
|
4
|
-
# Phone number validation
|
|
5
|
-
print("="*10)
|
|
6
|
-
print("Validating phone number...")
|
|
7
|
-
phone_number = PrimitiveData(
|
|
8
|
-
data_type=str,
|
|
9
|
-
value="+34600111222",
|
|
10
|
-
minimum_length=7, # Minimum character length
|
|
11
|
-
maximum_length=15, # Maximum character length
|
|
12
|
-
minimum_size=None, # Not validate the minimum number
|
|
13
|
-
maximum_size=None, # Not validate the maximum number,
|
|
14
|
-
possible_values=None, # Not specify obligatory possible values
|
|
15
|
-
regular_expression=r"^\+[1-9]\d{6,14}$"
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
print("Phone number validated sucessfully:", phone_number.value)
|
|
19
|
-
|
|
20
|
-
# Connection port validation
|
|
21
|
-
print("="*10)
|
|
22
|
-
print("Validating connection port...")
|
|
23
|
-
connection_port = PrimitiveData(
|
|
24
|
-
data_type=int,
|
|
25
|
-
value=45321,
|
|
26
|
-
minimum_length=1, # Maximum digits
|
|
27
|
-
maximum_length=5, # Minimum digits
|
|
28
|
-
minimum_size=1, # Minimum numerical value
|
|
29
|
-
maximum_size=65535, # Maximum numerical value
|
|
30
|
-
possible_values=None, # Possible options
|
|
31
|
-
regular_expression=None # Regular expression applied
|
|
32
|
-
)
|
|
33
|
-
print("Connection port validated:", connection_port.value)
|
|
34
|
-
|
|
35
|
-
# Transport protocol validation
|
|
36
|
-
print("="*10)
|
|
37
|
-
print("Validating transport protocol...")
|
|
38
|
-
transport_protocol = PrimitiveData(
|
|
39
|
-
data_type=str,
|
|
40
|
-
value="TCP",
|
|
41
|
-
maximum_length=None,
|
|
42
|
-
minimum_length=None,
|
|
43
|
-
minimum_size=None,
|
|
44
|
-
maximum_size=None,
|
|
45
|
-
possible_values=("TCP", "UDP"),
|
|
46
|
-
regular_expression=None
|
|
47
|
-
)
|
|
48
|
-
print("Transport protocol validated:", transport_protocol.value)
|
|
49
|
-
|
|
50
|
-
# Validating IPv4 address
|
|
51
|
-
print("="*10)
|
|
52
|
-
print("Validating IPv4 address...")
|
|
53
|
-
ip_address = PrimitiveData(
|
|
54
|
-
data_type=str,
|
|
55
|
-
value="192.168.0.1",
|
|
56
|
-
maximum_length=15,
|
|
57
|
-
minimum_length=7,
|
|
58
|
-
maximum_size=None, minimum_size=None,
|
|
59
|
-
possible_values=None,
|
|
60
|
-
regular_expression=r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
|
|
61
|
-
)
|
|
62
|
-
print("IPv4 address validated:", ip_address.value)
|
|
File without changes
|