Skip to content

Commit f9992ed

Browse files
Merge pull request #245 from phenobarbital/new-exports
New exports
2 parents e5e4bd3 + 03cffad commit f9992ed

File tree

6 files changed

+133
-10
lines changed

6 files changed

+133
-10
lines changed

datamodel/converters.pyx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ cdef object _parse_union_type(
882882
non_none_arg = arg
883883
break
884884
is_typing = hasattr(non_none_arg, '__module__') and non_none_arg.__module__ == 'typing'
885+
885886
if non_none_arg is not None and is_typing is True:
886887
# Invoke the parse_typing_type
887888
field.args = get_args(non_none_arg)
@@ -899,6 +900,14 @@ cdef object _parse_union_type(
899900
for arg_type in targs:
900901
try:
901902
if isinstance(data, list):
903+
if arg_type is str:
904+
# Ensure all elements in the list are strings
905+
if all(isinstance(item, str) for item in data):
906+
return data
907+
else:
908+
raise ValueError(
909+
f"Expected List[str], but found invalid element type in {data}"
910+
)
902911
result = _parse_list_type(field, arg_type, data, encoder, targs)
903912
else:
904913
# fallback to builtin parse
@@ -1271,9 +1280,9 @@ cpdef dict processing_fields(object obj, list columns):
12711280
obj.__dict__[name] = value
12721281
if _default is not None:
12731282
value = _handle_default_value(obj, name, value, _default, f._default_callable)
1274-
12751283
try:
12761284
_encoder = metadata.get('encoder')
1285+
newval = value
12771286
if f.parser is not None:
12781287
# If a custom parser is attached to Field, use it
12791288
try:
@@ -1358,6 +1367,16 @@ cpdef dict processing_fields(object obj, list columns):
13581367
None, name, value, f._inner_type, as_objects, None
13591368
)
13601369
obj.__dict__[name] = newval
1370+
else:
1371+
newval = _parse_typing(
1372+
f,
1373+
_type,
1374+
value,
1375+
_encoder,
1376+
as_objects,
1377+
obj
1378+
)
1379+
obj.__dict__[name] = newval
13611380
else:
13621381
try:
13631382
newval = _parse_typing(

datamodel/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
'simple library based on python +3.8 to use Dataclass-syntax'
77
'for interacting with Data'
88
)
9-
__version__ = '0.10.4'
9+
__version__ = '0.10.5'
1010
__copyright__ = 'Copyright (c) 2020-2024 Jesus Lara'
1111
__author__ = 'Jesus Lara'
1212
__author_email__ = '[email protected]'

examples/test_qsmodel.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class QueryModel(BaseModel):
7171
dwh_driver: str = Field(required=False, default=None)
7272
dwh_info: Optional[dict] = Field(required=False, db_type='jsonb')
7373
dwh_scheduler: Optional[dict] = Field(required=False, db_type='jsonb')
74-
host_info: Tuple[str, int] = Field(required=True)
74+
host_info: Tuple[str, int] = Field(required=False)
7575
# Creation Information:
7676
created_at: datetime = Field(
7777
required=False,
@@ -100,5 +100,55 @@ class Meta:
100100
try:
101101
slug = QueryModel(**data)
102102
print(slug)
103+
print('MAPPING > ', slug.more_nested, type(slug.more_nested))
103104
except ValidationError as e:
104105
print(e.payload)
106+
107+
108+
data_new = {
109+
"query_slug": "vision_form_data",
110+
"description": None,
111+
"source": None,
112+
"params": None,
113+
"attributes": None,
114+
"conditions": {
115+
"orgid": "106",
116+
"formid": "2681",
117+
"lastdate": "CURRENT_DATE",
118+
"firstdate": "CURRENT_DATE"
119+
},
120+
"cond_definition": {
121+
"orgid": "integer",
122+
"formid": "integer",
123+
"lastdate": "date",
124+
"firstdate": "date"
125+
},
126+
"fields": [],
127+
"filtering": None,
128+
"ordering": [],
129+
"grouping": [],
130+
"qry_options": None,
131+
"h_filtering": False,
132+
"query_raw": "-- Insert New query_slug:vision_form_date\nSELECT fd.*, fv.FormId, f.OrgId, fv.FormVisitId, VV.VisitDateLocal AS VisitDateLocal --in store TZ\nFROM dbo._FormView_{formid}({orgid},16558) fd\nINNER JOIN dbo.FormVisit fv on fv.FormVisitId = fd.FormVisitId\nINNER JOIN vwVisitView VV ON FV.FormVisitId = VV.FormVisitId\nINNER JOIN forms f on fv.FormId = f.FormId\nWHERE ISNULL([000_055],[000_003]) BETWEEN {firstdate} and {lastdate}\n--- end form data",
133+
"is_raw": False,
134+
"is_cached": False,
135+
"cache_timeout": 3600,
136+
"cache_refresh": None,
137+
"cache_options": None,
138+
"program_id": 1,
139+
"program_slug": "troc",
140+
"provider": "sqlserver",
141+
"parser": "SQLParser",
142+
"dwh": False,
143+
"dwh_driver": None,
144+
"dwh_info": None,
145+
"dwh_scheduler": None,
146+
"created_at": "2021-08-28 15:09:00",
147+
"created_by": None,
148+
"updated_at": "2023-01-05 11:26:00",
149+
"updated_by": None
150+
}
151+
152+
if __name__ == '__main__':
153+
slug = QueryModel(**data_new)
154+
print(slug)

examples/test_validations.py

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import uuid
33
from datetime import datetime
44
from datamodel import BaseModel, Column
5+
from datamodel.exceptions import ValidationError
56

67

78
def auto_uuid(*args, **kwargs):
@@ -25,7 +26,7 @@ class Account(BaseModel):
2526
provider: str = Column(required=True, default='dummy')
2627
enabled: bool = Column(required=True, default=True)
2728
address: Union[str, list] = Column(required=False, default='')
28-
phone: Union[str, list] = Column(required=False, default='')
29+
phone: Union[str, List[str]] = Column(required=False, default='')
2930

3031
def set_address(self, address: str):
3132
self.address = address
@@ -36,7 +37,7 @@ class Actor(BaseModel):
3637
"""
3738
userid: uuid.UUID = Column(required=True, primary_key=True, default=auto_uuid)
3839
age: int = Column(default=def_age)
39-
name: str
40+
name: str = Column(required=True)
4041
account: Union[Account, List[Account]]
4142
is_employee: str = Column(required=True, default='F', encoder=is_employee)
4243
created_at: datetime = Column(required=False, default=datetime.now)
@@ -63,6 +64,59 @@ def __str__(self) -> str:
6364
}
6465
]
6566
}
66-
user = Actor(**user)
67-
print(f"User: ID: {user.userid}, Name: {user.name}, age: {user.age}, accounts: {user.account!r}, created: {user.created_at}")
68-
print(f'Types: {type(user.created_at)}')
67+
68+
69+
if __name__ == '__main__':
70+
user = Actor(**user)
71+
print(f"User: ID: {user.userid}, Name: {user.name}, age: {user.age}, accounts: {user.account!r}, created: {user.created_at}")
72+
print(f'Types: {type(user.created_at)}')
73+
try:
74+
# Test if name is required:
75+
missing_data = {
76+
"userid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
77+
"account": [
78+
{"provider": "twilio", "phone": "+343317871"},
79+
]
80+
}
81+
user = Actor(**missing_data)
82+
except (ValueError, AttributeError) as ex:
83+
print(f"Error: {ex}", type(ex))
84+
except ValidationError as ex:
85+
print(f"Error: {ex}", type(ex))
86+
print(f"ValidationError: {ex.payload}")
87+
# Test Account for Invalid Data:
88+
invalid_data = {
89+
"userid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
90+
"name": "Invalid User",
91+
"account": [
92+
{"provider": "twilio", "phone": {"phone": 343317871}}, # Expecting a string for `phone`
93+
]
94+
}
95+
try:
96+
Account(**invalid_data["account"][0])
97+
except (ValueError, AttributeError) as ex:
98+
print(
99+
f"Error: {ex}", type(ex)
100+
)
101+
except ValidationError as ex:
102+
print(
103+
f"Error: {ex}", type(ex)
104+
)
105+
print(
106+
f"ValidationError: {ex.payload}"
107+
)
108+
# Test for Invalid Data:
109+
try:
110+
user = Actor(**invalid_data)
111+
print(user.account, type(user.account[0]['phone']))
112+
except (ValueError, AttributeError) as ex:
113+
print(
114+
f"Error: {ex}", type(ex)
115+
)
116+
except ValidationError as ex:
117+
print(
118+
f"Error: {ex}", type(ex)
119+
)
120+
print(
121+
f"ValidationError: {ex.payload}"
122+
)

tests/test_data.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from typing import Optional, List, Union
22
from datetime import datetime, date
3-
from pendulum.date import Date as PDate
43
from dataclasses import dataclass
54
import pytest
65
from datamodel import BaseModel, Field

tests/test_validations.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def test_actor_with_accounts_validation(as_objects):
212212
"userid": pgproto.UUID("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
213213
"name": "Invalid User",
214214
"account": [
215-
{"provider": "twilio", "phone": {"phone": "343317871"}}, # Expecting a string for `phone`
215+
{"provider": "twilio", "phone": {"phone": 343317871}}, # Expecting a string for `phone`
216216
]
217217
}
218218
with pytest.raises(ValueError, match="Invalid type.*phone"):
@@ -238,6 +238,7 @@ def test_actor_with_accounts_validation(as_objects):
238238
{"provider": "email", "address": "[email protected]"},
239239
]
240240
}
241+
# Validate an Account:
241242
actor = Actor(**valid_data)
242243
assert actor.name == "Valid User"
243244
assert isinstance(actor.account, list)

0 commit comments

Comments
 (0)