Skip to content

Commit 777e8d3

Browse files
committed
refactor: extract model filling mechanism in its own file
1 parent 0154145 commit 777e8d3

File tree

2 files changed

+126
-119
lines changed

2 files changed

+126
-119
lines changed

scim2_tester/filling.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import base64
2+
import random
3+
import uuid
4+
from enum import Enum
5+
from inspect import isclass
6+
from typing import Annotated
7+
from typing import Any
8+
from typing import get_args
9+
from typing import get_origin
10+
11+
from scim2_models import ComplexAttribute
12+
from scim2_models import Extension
13+
from scim2_models import ExternalReference
14+
from scim2_models import Meta
15+
from scim2_models import Reference
16+
from scim2_models import Required
17+
from scim2_models import Resource
18+
from scim2_models import URIReference
19+
from scim2_models.utils import UNION_TYPES
20+
21+
from scim2_tester.utils import CheckConfig
22+
23+
24+
def create_minimal_object(
25+
conf: CheckConfig, model: type[Resource]
26+
) -> tuple[Resource, list[Resource]]:
27+
"""Create an object filling with the minimum required field set."""
28+
field_names = [
29+
field_name
30+
for field_name in model.model_fields
31+
if model.get_field_annotation(field_name, Required) == Required.true
32+
]
33+
obj, garbages = fill_with_random_values(conf, model(), field_names)
34+
obj = conf.client.create(obj)
35+
return obj, garbages
36+
37+
38+
def model_from_ref_type(
39+
conf: CheckConfig, ref_type: type, different_than: Resource
40+
) -> type[Resource]:
41+
"""Return "User" from "Union[Literal['User'], Literal['Group']]"."""
42+
43+
def model_from_ref_type_(ref_type):
44+
if get_origin(ref_type) in UNION_TYPES:
45+
return [
46+
model_from_ref_type_(sub_ref_type)
47+
for sub_ref_type in get_args(ref_type)
48+
]
49+
50+
model_name = get_args(ref_type)[0]
51+
model = conf.client.get_resource_model(model_name)
52+
return model
53+
54+
models = model_from_ref_type_(ref_type)
55+
models = models if isinstance(models, list) else [models]
56+
acceptable_models = [model for model in models if model != different_than]
57+
return acceptable_models[0]
58+
59+
60+
def fill_with_random_values(
61+
conf: CheckConfig, obj: Resource, field_names: list[str] | None = None
62+
) -> Resource:
63+
"""Fill an object with random values generated according the attribute types."""
64+
garbages = []
65+
for field_name in field_names or obj.model_fields.keys():
66+
field = obj.model_fields[field_name]
67+
if field.default:
68+
continue
69+
70+
is_multiple = obj.get_field_multiplicity(field_name)
71+
field_type = obj.get_field_root_type(field_name)
72+
if get_origin(field_type) == Annotated:
73+
field_type = get_args(field_type)[0]
74+
75+
value: Any
76+
if field_type is Meta:
77+
value = None
78+
79+
elif field.examples:
80+
value = random.choice(field.examples)
81+
82+
elif field_type is int:
83+
value = uuid.uuid4().int
84+
85+
elif field_type is bool:
86+
value = random.choice([True, False])
87+
88+
elif field_type is bytes:
89+
value = base64.b64encode(str(uuid.uuid4()).encode("utf-8"))
90+
91+
elif get_origin(field_type) is Reference:
92+
ref_type = get_args(field_type)[0]
93+
if ref_type not in (ExternalReference, URIReference):
94+
model = model_from_ref_type(
95+
conf, ref_type, different_than=obj.__class__
96+
)
97+
ref_obj, sub_garbages = create_minimal_object(conf, model)
98+
value = ref_obj.meta.location
99+
garbages += sub_garbages
100+
101+
else:
102+
value = f"https://{str(uuid.uuid4())}.test"
103+
104+
elif isclass(field_type) and issubclass(field_type, Enum):
105+
value = random.choice(list(field_type))
106+
107+
elif isclass(field_type) and issubclass(field_type, ComplexAttribute):
108+
value, sub_garbages = fill_with_random_values(conf, field_type())
109+
garbages += sub_garbages
110+
111+
elif isclass(field_type) and issubclass(field_type, Extension):
112+
value, sub_garbages = fill_with_random_values(conf, field_type())
113+
garbages += sub_garbages
114+
115+
else:
116+
# Put emails so this will be accepted by EmailStr too
117+
value = f"{uuid.uuid4()}@{uuid.uuid4()}.com"
118+
119+
if is_multiple:
120+
setattr(obj, field_name, [value])
121+
122+
else:
123+
setattr(obj, field_name, value)
124+
125+
return obj, garbages

scim2_tester/resource.py

Lines changed: 1 addition & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,8 @@
1-
import base64
2-
import random
3-
import uuid
4-
from enum import Enum
5-
from inspect import isclass
6-
from typing import Annotated
7-
from typing import Any
8-
from typing import get_args
9-
from typing import get_origin
10-
11-
from scim2_models import ComplexAttribute
12-
from scim2_models import Extension
13-
from scim2_models import ExternalReference
14-
from scim2_models import Meta
151
from scim2_models import Mutability
16-
from scim2_models import Reference
17-
from scim2_models import Required
182
from scim2_models import Resource
193
from scim2_models import ResourceType
20-
from scim2_models import URIReference
21-
from scim2_models.utils import UNION_TYPES
224

5+
from scim2_tester.filling import fill_with_random_values
236
from scim2_tester.utils import CheckConfig
247
from scim2_tester.utils import CheckResult
258
from scim2_tester.utils import Status
@@ -36,107 +19,6 @@ def model_from_resource_type(
3619
return None
3720

3821

39-
def create_minimal_object(
40-
conf: CheckConfig, model: type[Resource]
41-
) -> tuple[Resource, list[Resource]]:
42-
"""Create an object filling with the minimum required field set."""
43-
field_names = [
44-
field_name
45-
for field_name in model.model_fields.keys()
46-
if model.get_field_annotation(field_name, Required) == Required.true
47-
]
48-
obj, garbages = fill_with_random_values(conf, model(), field_names)
49-
obj = conf.client.create(obj)
50-
return obj, garbages
51-
52-
53-
def model_from_ref_type(
54-
conf: CheckConfig, ref_type: type, different_than: Resource
55-
) -> type[Resource]:
56-
def model_from_ref_type_(ref_type):
57-
if get_origin(ref_type) in UNION_TYPES:
58-
return [
59-
model_from_ref_type_(sub_ref_type)
60-
for sub_ref_type in get_args(ref_type)
61-
]
62-
63-
model_name = get_args(ref_type)[0]
64-
model = conf.client.get_resource_model(model_name)
65-
return model
66-
67-
models = model_from_ref_type_(ref_type)
68-
models = models if isinstance(models, list) else [models]
69-
acceptable_models = [model for model in models if model != different_than]
70-
return acceptable_models[0]
71-
72-
73-
def fill_with_random_values(
74-
conf: CheckConfig, obj: Resource, field_names: list[str] | None = None
75-
) -> Resource:
76-
garbages = []
77-
for field_name in field_names or obj.model_fields.keys():
78-
field = obj.model_fields[field_name]
79-
if field.default:
80-
continue
81-
82-
is_multiple = obj.get_field_multiplicity(field_name)
83-
field_type = obj.get_field_root_type(field_name)
84-
if get_origin(field_type) == Annotated:
85-
field_type = get_args(field_type)[0]
86-
87-
value: Any
88-
if field_type is Meta:
89-
value = None
90-
91-
elif field.examples:
92-
value = random.choice(field.examples)
93-
94-
elif field_type is int:
95-
value = uuid.uuid4().int
96-
97-
elif field_type is bool:
98-
value = random.choice([True, False])
99-
100-
elif field_type is bytes:
101-
value = base64.b64encode(str(uuid.uuid4()).encode("utf-8"))
102-
103-
elif get_origin(field_type) is Reference:
104-
ref_type = get_args(field_type)[0]
105-
if ref_type not in (ExternalReference, URIReference):
106-
model = model_from_ref_type(
107-
conf, ref_type, different_than=obj.__class__
108-
)
109-
ref_obj, sub_garbages = create_minimal_object(conf, model)
110-
value = ref_obj.meta.location
111-
garbages += sub_garbages
112-
113-
else:
114-
value = f"https://{str(uuid.uuid4())}.test"
115-
116-
elif isclass(field_type) and issubclass(field_type, Enum):
117-
value = random.choice(list(field_type))
118-
119-
elif isclass(field_type) and issubclass(field_type, ComplexAttribute):
120-
value, sub_garbages = fill_with_random_values(conf, field_type())
121-
garbages += sub_garbages
122-
123-
elif isclass(field_type) and issubclass(field_type, Extension):
124-
value, sub_garbages = fill_with_random_values(conf, field_type())
125-
garbages += sub_garbages
126-
127-
else:
128-
# Put emails so this will be accepted by EmailStr too
129-
value = f"{uuid.uuid4()}@{uuid.uuid4()}.com"
130-
131-
if is_multiple:
132-
setattr(obj, field_name, [value])
133-
134-
else:
135-
setattr(obj, field_name, value)
136-
137-
return obj, garbages
138-
139-
14022
@checker
14123
def check_object_creation(conf: CheckConfig, obj: type[Resource]) -> CheckResult:
14224
"""Perform an object creation.

0 commit comments

Comments
 (0)