typedpy 2.2.1__tar.gz → 2.2.2__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.
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__init__.py +1 -1
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/__init__.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/commons.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/fields.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/__pycache__/structures.cpython-39.pyc +0 -0
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/commons.py +7 -7
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/fields.py +6 -1
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/typedpy/structures.py +90 -60
- home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.1-py3.9.egg-info → typedpy-2.2.2-py3.9.egg-info}/PKG-INFO +2 -2
- /home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.1-py3.9.egg-info → typedpy-2.2.2-py3.9.egg-info}/SOURCES.txt +0 -0
- /home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.1-py3.9.egg-info → typedpy-2.2.2-py3.9.egg-info}/dependency_links.txt +0 -0
- /home/dannyloya/github/typedpy/venv39/lib/python3.9/site-packages/{typedpy-2.2.1-py3.9.egg-info → typedpy-2.2.2-py3.9.egg-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -4,14 +4,14 @@ def wrap_val(v):
|
|
|
4
4
|
|
|
5
5
|
def _is_dunder(name):
|
|
6
6
|
"""Returns True if a __dunder__ name, False otherwise."""
|
|
7
|
-
return (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
return (
|
|
8
|
+
len(name) > 4
|
|
9
|
+
and name[:2] == name[-2:] == "__"
|
|
10
|
+
and name[2] != "_"
|
|
11
|
+
and name[-3] != "_"
|
|
12
|
+
)
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def _is_sunder(name):
|
|
14
16
|
"""Returns True if a _sunder name, False otherwise."""
|
|
15
|
-
return
|
|
16
|
-
name[0] == '_' and
|
|
17
|
-
name[1:2] != '_' )
|
|
17
|
+
return len(name) > 2 and name[0] == "_" and name[1:2] != "_"
|
|
@@ -282,11 +282,16 @@ class Function(Field):
|
|
|
282
282
|
"""
|
|
283
283
|
A function or method. Note that this can't be any callable (it can't be a class, for example), but a real function
|
|
284
284
|
"""
|
|
285
|
+
|
|
285
286
|
_bound_method_type = type(Field().__init__)
|
|
286
287
|
|
|
287
288
|
def __set__(self, instance, value):
|
|
288
289
|
def is_function(f):
|
|
289
|
-
return type(f) in {
|
|
290
|
+
return type(f) in {
|
|
291
|
+
type(lambda x: x),
|
|
292
|
+
type(open),
|
|
293
|
+
Function._bound_method_type,
|
|
294
|
+
}
|
|
290
295
|
|
|
291
296
|
def err_prefix():
|
|
292
297
|
return (
|
|
@@ -20,6 +20,7 @@ ADDITIONAL_PROPERTIES = "_additionalProperties"
|
|
|
20
20
|
IS_IMMUTABLE = "_immutable"
|
|
21
21
|
OPTIONAL_FIELDS = "_optional"
|
|
22
22
|
MUST_BE_UNIQUE = "_must_be_unique"
|
|
23
|
+
IGNORE_NONE_VALUES = "_ignore_none"
|
|
23
24
|
MAX_NUMBER_OF_INSTANCES_TO_VERIFY_UNIQUENESS = 100000
|
|
24
25
|
|
|
25
26
|
py_version = sys.version_info[0:2]
|
|
@@ -108,9 +109,15 @@ def get_base_info(bases):
|
|
|
108
109
|
"""
|
|
109
110
|
bases_params = OrderedDict()
|
|
110
111
|
bases_required = []
|
|
111
|
-
base_structures =
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
base_structures = (
|
|
113
|
+
[
|
|
114
|
+
base
|
|
115
|
+
for base in bases
|
|
116
|
+
if issubclass(base, Structure) and base is not Structure
|
|
117
|
+
]
|
|
118
|
+
if "Structure" in globals()
|
|
119
|
+
else []
|
|
120
|
+
)
|
|
114
121
|
for base in base_structures:
|
|
115
122
|
for k, param in getattr(base, "__signature__").parameters.items():
|
|
116
123
|
if k not in bases_params:
|
|
@@ -138,7 +145,7 @@ def _check_for_final_violations(classes):
|
|
|
138
145
|
)
|
|
139
146
|
)
|
|
140
147
|
if "ImmutableStructure" in globals() and is_sub_class(
|
|
141
|
-
|
|
148
|
+
c, ImmutableStructure
|
|
142
149
|
):
|
|
143
150
|
raise TypeError(
|
|
144
151
|
"Tried to extend {}, which is an ImmutableStructure. This is forbidden".format(
|
|
@@ -202,13 +209,19 @@ class UniqueMixin:
|
|
|
202
209
|
|
|
203
210
|
def __manage_uniqueness__(self):
|
|
204
211
|
myclass = self.__class__
|
|
205
|
-
if
|
|
206
|
-
|
|
212
|
+
if (
|
|
213
|
+
getattr(myclass, MUST_BE_UNIQUE, False)
|
|
214
|
+
and len(getattr(myclass, "_ALL_INSTANCES", set()))
|
|
215
|
+
< MAX_NUMBER_OF_INSTANCES_TO_VERIFY_UNIQUENESS
|
|
216
|
+
):
|
|
207
217
|
hash_of_instance = self.__hash__()
|
|
208
218
|
if hash_of_instance in getattr(myclass, "_ALL_INSTANCES", set()):
|
|
209
219
|
classname = self.__class__.__name__
|
|
210
|
-
raise ValueError(
|
|
211
|
-
|
|
220
|
+
raise ValueError(
|
|
221
|
+
"Instance copy in {}, which is defined as unique. Instance is {}".format(
|
|
222
|
+
classname, self
|
|
223
|
+
)
|
|
224
|
+
)
|
|
212
225
|
getattr(myclass, "_ALL_INSTANCES", set()).add(hash_of_instance)
|
|
213
226
|
|
|
214
227
|
def __manage_uniqueness_for_field__(self, instance, value):
|
|
@@ -216,14 +229,27 @@ class UniqueMixin:
|
|
|
216
229
|
return
|
|
217
230
|
field_name = getattr(self, "_name")
|
|
218
231
|
structure_class_name = instance.__class__.__name__
|
|
219
|
-
all_instances_by_struct_name = getattr(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
all_instances_by_struct_name = getattr(
|
|
233
|
+
self, "_ALL_INSTANCES", defaultdict(dict)
|
|
234
|
+
)
|
|
235
|
+
instance_by_value_for_current_struct = all_instances_by_struct_name[
|
|
236
|
+
structure_class_name
|
|
237
|
+
]
|
|
238
|
+
if (
|
|
239
|
+
getattr(self, MUST_BE_UNIQUE, False)
|
|
240
|
+
and len(instance_by_value_for_current_struct)
|
|
241
|
+
< MAX_NUMBER_OF_INSTANCES_TO_VERIFY_UNIQUENESS
|
|
242
|
+
):
|
|
223
243
|
hash_of_field_val = value.__hash__()
|
|
224
|
-
if
|
|
225
|
-
|
|
226
|
-
|
|
244
|
+
if (
|
|
245
|
+
instance_by_value_for_current_struct.get(hash_of_field_val, instance)
|
|
246
|
+
!= instance
|
|
247
|
+
):
|
|
248
|
+
raise ValueError(
|
|
249
|
+
"Instance copy of field {} in {}, which is defined as unique. Instance is {}".format(
|
|
250
|
+
field_name, structure_class_name, wrap_val(value)
|
|
251
|
+
)
|
|
252
|
+
)
|
|
227
253
|
if hash_of_field_val not in instance_by_value_for_current_struct:
|
|
228
254
|
instance_by_value_for_current_struct[hash_of_field_val] = instance
|
|
229
255
|
|
|
@@ -261,12 +287,9 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
261
287
|
the field implicitly optional.
|
|
262
288
|
Default values are validated based on the field definition like any other value
|
|
263
289
|
assignment.
|
|
264
|
-
|
|
265
|
-
ignore_none: optional
|
|
266
|
-
ignore assignment to None. Default is True
|
|
267
290
|
"""
|
|
268
291
|
|
|
269
|
-
def __init__(self, name=None, immutable=None, is_unique=None, default=None
|
|
292
|
+
def __init__(self, name=None, immutable=None, is_unique=None, default=None):
|
|
270
293
|
self._name = name
|
|
271
294
|
self._default = default
|
|
272
295
|
if is_unique in [True, False]:
|
|
@@ -277,7 +300,6 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
277
300
|
self._immutable = immutable
|
|
278
301
|
if default:
|
|
279
302
|
self._try_default_value(default)
|
|
280
|
-
self._ignore_none = ignore_none
|
|
281
303
|
|
|
282
304
|
def _try_default_value(self, default):
|
|
283
305
|
try:
|
|
@@ -298,13 +320,13 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
298
320
|
else owner.__dict__[self._name]
|
|
299
321
|
)
|
|
300
322
|
is_immutable = (
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
323
|
+
instance is not None
|
|
324
|
+
and getattr(instance, IS_IMMUTABLE, False)
|
|
325
|
+
or getattr(self, IS_IMMUTABLE, False)
|
|
304
326
|
)
|
|
305
327
|
needs_defensive_copy = (
|
|
306
|
-
|
|
307
|
-
|
|
328
|
+
not isinstance(res, (ImmutableMixin, int, float, str, bool, enum.Enum))
|
|
329
|
+
or res is None
|
|
308
330
|
)
|
|
309
331
|
return deepcopy(res) if (is_immutable and needs_defensive_copy) else res
|
|
310
332
|
|
|
@@ -312,7 +334,7 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
312
334
|
if getattr(self, IS_IMMUTABLE, False) and self._name in instance.__dict__:
|
|
313
335
|
raise ValueError("{}: Field is immutable".format(self._name))
|
|
314
336
|
if getattr(self, IS_IMMUTABLE, False) and not getattr(
|
|
315
|
-
|
|
337
|
+
self, "_custom_deep_copy_implementation", False
|
|
316
338
|
):
|
|
317
339
|
try:
|
|
318
340
|
instance.__dict__[self._name] = deepcopy(value)
|
|
@@ -327,7 +349,7 @@ class Field(UniqueMixin, metaclass=_FieldMeta):
|
|
|
327
349
|
instance.__dict__[self._name] = value
|
|
328
350
|
instance.__manage__uniqueness_of_all_fields__()
|
|
329
351
|
if getattr(instance, "_instantiated", False) and not getattr(
|
|
330
|
-
|
|
352
|
+
instance, "_skip_validation", False
|
|
331
353
|
):
|
|
332
354
|
instance.__validate__()
|
|
333
355
|
|
|
@@ -391,33 +413,34 @@ def _get_all_fields_by_name(cls):
|
|
|
391
413
|
def _instantiate_fields_if_needed(cls_dict: dict, defaults: dict):
|
|
392
414
|
for key, val in cls_dict.items():
|
|
393
415
|
if (
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
416
|
+
key
|
|
417
|
+
not in {
|
|
418
|
+
REQUIRED_FIELDS,
|
|
419
|
+
ADDITIONAL_PROPERTIES,
|
|
420
|
+
IS_IMMUTABLE,
|
|
421
|
+
DEFAULTS,
|
|
422
|
+
OPTIONAL_FIELDS,
|
|
423
|
+
IGNORE_NONE_VALUES,
|
|
424
|
+
}
|
|
425
|
+
and not isinstance(val, Field)
|
|
426
|
+
and not key.startswith("__")
|
|
427
|
+
and (
|
|
405
428
|
Field in getattr(val, "__mro__", []) or is_function_returning_field(val)
|
|
406
|
-
|
|
429
|
+
)
|
|
407
430
|
):
|
|
408
431
|
new_val = val(default=defaults[key]) if key in defaults else val()
|
|
409
432
|
cls_dict[key] = new_val
|
|
410
433
|
|
|
411
434
|
|
|
412
435
|
def _apply_default_and_update_required_not_to_include_fields_with_defaults(
|
|
413
|
-
|
|
436
|
+
cls_dict: dict, defaults: dict, fields: list
|
|
414
437
|
):
|
|
415
438
|
required_fields = set(cls_dict.get(REQUIRED_FIELDS, []))
|
|
416
439
|
optional_fields = set(cls_dict.get(OPTIONAL_FIELDS, []))
|
|
417
440
|
required_fields_predefined = REQUIRED_FIELDS in cls_dict
|
|
418
441
|
for field_name in fields:
|
|
419
442
|
if field_name in defaults and not getattr(
|
|
420
|
-
|
|
443
|
+
cls_dict[field_name], "_default", None
|
|
421
444
|
):
|
|
422
445
|
cls_dict[field_name]._try_default_value(defaults[field_name])
|
|
423
446
|
cls_dict[field_name]._default = defaults[field_name]
|
|
@@ -524,15 +547,15 @@ def _type_is_generic(v):
|
|
|
524
547
|
generic_alias = getattr(typing, "_GenericAlias", Foo)
|
|
525
548
|
special_generic_alias = getattr(typing, "_SpecialGenericAlias", Foo)
|
|
526
549
|
return (
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
550
|
+
(python_ver_36 and isinstance(v, typing_base))
|
|
551
|
+
or (
|
|
552
|
+
python_ver_atleast_than_37
|
|
553
|
+
and isinstance(v, (generic_alias, special_generic_alias))
|
|
554
|
+
)
|
|
555
|
+
or (
|
|
556
|
+
python_ver_atleast_39
|
|
557
|
+
and origin in {list, dict, tuple, set, frozenset, deque, typing.Union}
|
|
558
|
+
)
|
|
536
559
|
)
|
|
537
560
|
|
|
538
561
|
|
|
@@ -591,7 +614,7 @@ def add_annotations_to_class_dict(cls_dict):
|
|
|
591
614
|
from .fields import AnyOf
|
|
592
615
|
|
|
593
616
|
if isinstance(the_type, AnyOf) and getattr(
|
|
594
|
-
|
|
617
|
+
the_type, "_is_optional", False
|
|
595
618
|
):
|
|
596
619
|
optional_fields.add(k)
|
|
597
620
|
if k in cls_dict:
|
|
@@ -665,6 +688,10 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
665
688
|
# this raises an exception:
|
|
666
689
|
Foo(id = 1, a = 2)
|
|
667
690
|
|
|
691
|
+
_ignore_none(bool): optional
|
|
692
|
+
Ignore assignment to None for any field value.
|
|
693
|
+
Default is False.
|
|
694
|
+
|
|
668
695
|
Decorating it with @unique ensures that no all instances of this structure will be unique. It
|
|
669
696
|
will raise an exception otherwise (see "Uniqueness" section).
|
|
670
697
|
"""
|
|
@@ -696,10 +723,15 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
696
723
|
if key in self.__dict__:
|
|
697
724
|
raise ValueError("Structure is immutable")
|
|
698
725
|
value = deepcopy(value)
|
|
726
|
+
if getattr(self, IGNORE_NONE_VALUES, False) and value is None:
|
|
727
|
+
return
|
|
699
728
|
super().__setattr__(key, value)
|
|
700
729
|
|
|
701
|
-
if
|
|
702
|
-
|
|
730
|
+
if (
|
|
731
|
+
getattr(self, "_instantiated", False)
|
|
732
|
+
and not _is_dunder(key)
|
|
733
|
+
and not _is_sunder(key)
|
|
734
|
+
):
|
|
703
735
|
self.__manage_uniqueness__()
|
|
704
736
|
|
|
705
737
|
def __getstate__(self):
|
|
@@ -734,7 +766,7 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
734
766
|
|
|
735
767
|
name = self.__class__.__name__
|
|
736
768
|
if name.startswith("StructureReference_") and self.__class__.__bases__ == (
|
|
737
|
-
|
|
769
|
+
Structure,
|
|
738
770
|
):
|
|
739
771
|
name = "Structure"
|
|
740
772
|
props = []
|
|
@@ -765,7 +797,7 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
765
797
|
|
|
766
798
|
def __delitem__(self, key):
|
|
767
799
|
if isinstance(getattr(self, REQUIRED_FIELDS), list) and key in getattr(
|
|
768
|
-
|
|
800
|
+
self, REQUIRED_FIELDS
|
|
769
801
|
):
|
|
770
802
|
raise ValueError("{} is mandatory".format(key))
|
|
771
803
|
del self.__dict__[key]
|
|
@@ -810,9 +842,9 @@ class Structure(UniqueMixin, metaclass=StructMeta):
|
|
|
810
842
|
required = props.get(REQUIRED_FIELDS, field_names)
|
|
811
843
|
additional_props = props.get(ADDITIONAL_PROPERTIES, True)
|
|
812
844
|
if (
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
845
|
+
len(field_names) == 1
|
|
846
|
+
and required == field_names
|
|
847
|
+
and additional_props is False
|
|
816
848
|
):
|
|
817
849
|
return item in getattr(self, field_names[0], {})
|
|
818
850
|
|
|
@@ -882,8 +914,6 @@ class TypedField(Field):
|
|
|
882
914
|
)
|
|
883
915
|
|
|
884
916
|
def __set__(self, instance, value):
|
|
885
|
-
if getattr(instance, "_ignore_none", False) and value is None:
|
|
886
|
-
return
|
|
887
917
|
if not getattr(instance, "_skip_validation", False):
|
|
888
918
|
self._validate(value)
|
|
889
919
|
super().__set__(instance, value)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: typedpy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Type-safe Python
|
|
5
5
|
Home-page: http://github.com/loyada/typedpy
|
|
6
6
|
Author: Danny Loya
|
|
7
7
|
Author-email: dan.loya@gmail.com
|
|
8
8
|
License: MIT
|
|
9
|
-
Download-URL: https://github.com/loyada/typedpy/archive/v2.2.
|
|
9
|
+
Download-URL: https://github.com/loyada/typedpy/archive/v2.2.2.tar.gz
|
|
10
10
|
Description: [![][travis img]][travis]
|
|
11
11
|
[![][docs img]][docs]
|
|
12
12
|
|
|
File without changes
|
|
File without changes
|