partis-pyproj 0.1.4__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.
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/__init__.py +9 -1
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/_legacy_setup.py +11 -11
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/_nonprintable.py +4 -3
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/backend.py +44 -37
- partis_pyproj-0.1.6.data/purelib/partis/pyproj/builder/builder.py +351 -0
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/builder/cargo.py +2 -2
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/builder/cmake.py +9 -15
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/builder/meson.py +5 -13
- partis_pyproj-0.1.6.data/purelib/partis/pyproj/builder/process.py +42 -0
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/__init__.py +1 -1
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/dist_base.py +75 -86
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/dist_binary.py +6 -24
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/dist_copy.py +7 -18
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/dist_source.py +4 -21
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/dist_targz.py +5 -12
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/dist_file/dist_zip.py +5 -14
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/file.py +2 -1
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/legacy.py +3 -2
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/load_module.py +7 -6
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/norms.py +35 -31
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/path/__init__.py +2 -1
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/path/match.py +42 -35
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/path/pattern.py +60 -54
- partis_pyproj-0.1.6.data/purelib/partis/pyproj/path/utils.py +94 -0
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/pep.py +36 -35
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/pkginfo.py +7 -16
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/pptoml.py +125 -120
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/pyproj.py +47 -36
- partis_pyproj-0.1.6.data/purelib/partis/pyproj/template.py +229 -0
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/validate.py +273 -268
- partis_pyproj-0.1.6.dist-info/METADATA +500 -0
- partis_pyproj-0.1.6.dist-info/RECORD +37 -0
- partis_pyproj-0.1.4.data/purelib/partis/pyproj/builder/builder.py +0 -267
- partis_pyproj-0.1.4.data/purelib/partis/pyproj/builder/process.py +0 -75
- partis_pyproj-0.1.4.data/purelib/partis/pyproj/path/utils.py +0 -40
- partis_pyproj-0.1.4.dist-info/METADATA +0 -51
- partis_pyproj-0.1.4.dist-info/RECORD +0 -36
- {partis_pyproj-0.1.4.data → partis_pyproj-0.1.6.data}/purelib/partis/pyproj/builder/__init__.py +0 -0
- {partis_pyproj-0.1.4.dist-info → partis_pyproj-0.1.6.dist-info}/LICENSE.txt +0 -0
- {partis_pyproj-0.1.4.dist-info → partis_pyproj-0.1.6.dist-info}/WHEEL +0 -0
- {partis_pyproj-0.1.4.dist-info → partis_pyproj-0.1.6.dist-info}/entry_points.txt +0 -0
- {partis_pyproj-0.1.4.dist-info → partis_pyproj-0.1.6.dist-info}/top_level.txt +0 -0
@@ -1,25 +1,23 @@
|
|
1
|
+
from __future__ import annotations
|
1
2
|
import sys
|
2
|
-
import os.path as osp
|
3
|
-
import io
|
4
3
|
import warnings
|
5
|
-
import
|
6
|
-
import re
|
7
|
-
import pathlib
|
4
|
+
from functools import partial
|
8
5
|
import inspect
|
9
6
|
import types
|
10
7
|
from copy import copy
|
8
|
+
from abc import ABCMeta
|
11
9
|
from collections.abc import (
|
12
10
|
Mapping,
|
13
11
|
Sequence,
|
14
12
|
Iterable )
|
15
13
|
|
16
|
-
|
14
|
+
#===============================================================================
|
17
15
|
# NOTE: Filtering works by changing the traceback linked-list, which means
|
18
16
|
# writing to the 'tb_next' attrbute to the next frame not to be skipped.
|
19
17
|
# However, 'tb_next' was a read-only attribute until Python 3.7
|
20
18
|
FILTER_VALIDATING_FRAMES = sys.version_info >= (3,7)
|
21
19
|
|
22
|
-
|
20
|
+
#===============================================================================
|
23
21
|
def filter_traceback(traceback, ignore):
|
24
22
|
# NOTE: always keep the first frame in the trace-back (even if it would be filtered)
|
25
23
|
cur_tb = traceback
|
@@ -44,18 +42,18 @@ def filter_traceback(traceback, ignore):
|
|
44
42
|
else:
|
45
43
|
prev_kept_tb = cur_tb
|
46
44
|
|
47
|
-
|
45
|
+
#===============================================================================
|
48
46
|
def ignore_validating(frame, lineno):
|
49
47
|
if frame.f_code.co_filename == __file__:
|
50
48
|
return True
|
51
49
|
|
52
50
|
return False
|
53
51
|
|
54
|
-
|
52
|
+
#===============================================================================
|
55
53
|
class ValidationWarning( RuntimeWarning ):
|
56
54
|
pass
|
57
55
|
|
58
|
-
|
56
|
+
#===============================================================================
|
59
57
|
class ValidationError( ValueError ):
|
60
58
|
"""General validation error
|
61
59
|
|
@@ -130,27 +128,27 @@ class ValidationError( ValueError ):
|
|
130
128
|
filename = self.doc_file,
|
131
129
|
path = self.doc_path ))
|
132
130
|
|
133
|
-
|
131
|
+
#===============================================================================
|
134
132
|
class RequiredValueError( ValidationError ):
|
135
133
|
pass
|
136
134
|
|
137
|
-
|
135
|
+
#===============================================================================
|
138
136
|
class ValidDefinitionError( ValidationError ):
|
139
137
|
pass
|
140
138
|
|
141
|
-
|
139
|
+
#===============================================================================
|
142
140
|
class ValidPathError(ValidationError):
|
143
141
|
"""File is not valid
|
144
142
|
"""
|
145
143
|
pass
|
146
144
|
|
147
|
-
|
145
|
+
#===============================================================================
|
148
146
|
class FileOutsideRootError(ValidPathError):
|
149
147
|
"""File path is outside a desired root directory
|
150
148
|
"""
|
151
149
|
pass
|
152
150
|
|
153
|
-
|
151
|
+
#===============================================================================
|
154
152
|
class validating:
|
155
153
|
"""Context manager to append information to a ValidationError as it propagates
|
156
154
|
|
@@ -200,7 +198,7 @@ class validating:
|
|
200
198
|
|
201
199
|
else:
|
202
200
|
raise ValidationError(
|
203
|
-
|
201
|
+
"Error while validating",
|
204
202
|
doc_root = self.root,
|
205
203
|
doc_file = self.file,
|
206
204
|
doc_path = None if self.key is None else [self.key] ) from value
|
@@ -208,15 +206,11 @@ class validating:
|
|
208
206
|
# do not handle any exceptions here
|
209
207
|
return False
|
210
208
|
|
211
|
-
|
209
|
+
#===============================================================================
|
212
210
|
class Special:
|
213
|
-
#-----------------------------------------------------------------------------
|
214
|
-
def __str__(self):
|
215
|
-
return type(self).__name__
|
216
|
-
|
217
211
|
#-----------------------------------------------------------------------------
|
218
212
|
def __repr__(self):
|
219
|
-
return
|
213
|
+
return type(self).__name__
|
220
214
|
|
221
215
|
#-----------------------------------------------------------------------------
|
222
216
|
def __eq__(self, other):
|
@@ -230,25 +224,25 @@ class Special:
|
|
230
224
|
def __hash__(self):
|
231
225
|
return hash(str(self))
|
232
226
|
|
233
|
-
|
227
|
+
#===============================================================================
|
234
228
|
class Optional(Special):
|
235
229
|
"""Optional value
|
236
230
|
"""
|
237
231
|
pass
|
238
232
|
|
239
|
-
|
233
|
+
#===============================================================================
|
240
234
|
class OptionalNone(Special):
|
241
235
|
"""Optional value, but is set to None if not initially set
|
242
236
|
"""
|
243
237
|
pass
|
244
238
|
|
245
|
-
|
239
|
+
#===============================================================================
|
246
240
|
class Required(Special):
|
247
241
|
"""Required value
|
248
242
|
"""
|
249
243
|
pass
|
250
244
|
|
251
|
-
|
245
|
+
#===============================================================================
|
252
246
|
class NotSet(Special):
|
253
247
|
"""Special value indicating a value is not set
|
254
248
|
"""
|
@@ -259,7 +253,7 @@ OPTIONAL_NONE = OptionalNone()
|
|
259
253
|
REQUIRED = Required()
|
260
254
|
NOTSET = NotSet()
|
261
255
|
|
262
|
-
|
256
|
+
#===============================================================================
|
263
257
|
def validate(val, default, validators):
|
264
258
|
"""Internal method to apply default value and validators
|
265
259
|
"""
|
@@ -274,7 +268,7 @@ def validate(val, default, validators):
|
|
274
268
|
return None if default == OPTIONAL_NONE else val
|
275
269
|
|
276
270
|
elif default == REQUIRED:
|
277
|
-
raise RequiredValueError(
|
271
|
+
raise RequiredValueError("Value is required")
|
278
272
|
|
279
273
|
else:
|
280
274
|
val = default
|
@@ -318,7 +312,7 @@ def validate(val, default, validators):
|
|
318
312
|
|
319
313
|
return val
|
320
314
|
|
321
|
-
|
315
|
+
#===============================================================================
|
322
316
|
def fmt_validator(v):
|
323
317
|
|
324
318
|
if isinstance(v, Validator):
|
@@ -360,10 +354,12 @@ def fmt_validator(v):
|
|
360
354
|
|
361
355
|
return f"<{name}>"
|
362
356
|
|
363
|
-
|
357
|
+
#===============================================================================
|
364
358
|
class Validator:
|
365
359
|
"""Validates a value
|
366
360
|
"""
|
361
|
+
__slots__ = ('default', 'validators')
|
362
|
+
|
367
363
|
#-----------------------------------------------------------------------------
|
368
364
|
def __init__(self, *args, default = NOTSET):
|
369
365
|
|
@@ -400,7 +396,7 @@ class Validator:
|
|
400
396
|
except Exception as e:
|
401
397
|
# the type cannot be instantiated without arguments
|
402
398
|
raise ValidDefinitionError(
|
403
|
-
|
399
|
+
"Default value must be specified, or explicitly set as optional or required") from e
|
404
400
|
|
405
401
|
else:
|
406
402
|
# cannot be used as default, put back to use as validator
|
@@ -415,16 +411,16 @@ class Validator:
|
|
415
411
|
# convenience method to used default value to derive type
|
416
412
|
args.append(type(default))
|
417
413
|
|
418
|
-
self.
|
419
|
-
self.
|
414
|
+
self.default = default
|
415
|
+
self.validators = tuple(args)
|
420
416
|
|
421
417
|
#-----------------------------------------------------------------------------
|
422
418
|
def __str__(self):
|
423
419
|
args = list()
|
424
|
-
for v in self.
|
420
|
+
for v in self.validators:
|
425
421
|
args.append(fmt_validator(v))
|
426
422
|
|
427
|
-
args.append(f"default = {fmt_validator(self.
|
423
|
+
args.append(f"default = {fmt_validator(self.default)}")
|
428
424
|
args = ', '.join(args)
|
429
425
|
return f"{type(self).__name__}({args})"
|
430
426
|
|
@@ -434,16 +430,18 @@ class Validator:
|
|
434
430
|
|
435
431
|
#-----------------------------------------------------------------------------
|
436
432
|
def __call__(self, val = NOTSET):
|
437
|
-
return validate(val, self.
|
433
|
+
return validate(val, self.default, self.validators)
|
438
434
|
|
439
|
-
|
435
|
+
#===============================================================================
|
440
436
|
class Restricted(Validator):
|
441
437
|
"""Restricts a value to one of listed options
|
442
438
|
"""
|
439
|
+
__slots__ = ('options',)
|
440
|
+
|
443
441
|
#-----------------------------------------------------------------------------
|
444
442
|
def __init__(self, *options ):
|
445
443
|
if len(options) == 0:
|
446
|
-
raise ValidDefinitionError(
|
444
|
+
raise ValidDefinitionError("Must have at least one option")
|
447
445
|
|
448
446
|
super().__init__(options[0], type(options[0]))
|
449
447
|
|
@@ -454,19 +452,19 @@ class Restricted(Validator):
|
|
454
452
|
with validating(key = i):
|
455
453
|
_options.append(super().__call__(v))
|
456
454
|
|
457
|
-
self.
|
455
|
+
self.options = set(_options)
|
458
456
|
|
459
457
|
#-----------------------------------------------------------------------------
|
460
458
|
def __call__(self, val):
|
461
459
|
val = super().__call__(val)
|
462
460
|
|
463
|
-
if val not in self.
|
461
|
+
if val not in self.options:
|
464
462
|
raise ValidationError(
|
465
|
-
f"Must be one of {self.
|
463
|
+
f"Must be one of {self.options}: {val}")
|
466
464
|
|
467
465
|
return val
|
468
466
|
|
469
|
-
|
467
|
+
#===============================================================================
|
470
468
|
def valid(*validators, default = NOTSET):
|
471
469
|
"""Casts list of objects to Validator, if needed
|
472
470
|
"""
|
@@ -478,19 +476,19 @@ def valid(*validators, default = NOTSET):
|
|
478
476
|
|
479
477
|
return Validator(*validators, default = default)
|
480
478
|
|
481
|
-
|
479
|
+
#===============================================================================
|
482
480
|
def union(*validators):
|
483
481
|
"""Value must pass at least one of listed validators
|
484
482
|
"""
|
485
483
|
return Validator([valid(v) for v in validators], default = REQUIRED)
|
486
484
|
|
487
|
-
|
485
|
+
#===============================================================================
|
488
486
|
def restrict(*options):
|
489
487
|
"""Restricts a value to one of listed options
|
490
488
|
"""
|
491
489
|
return Restricted(*options)
|
492
490
|
|
493
|
-
|
491
|
+
#===============================================================================
|
494
492
|
def valid_type(
|
495
493
|
obj,
|
496
494
|
types ):
|
@@ -502,7 +500,7 @@ def valid_type(
|
|
502
500
|
raise ValidationError(
|
503
501
|
f"Must be of type {types}: {type(obj)}" )
|
504
502
|
|
505
|
-
|
503
|
+
#===============================================================================
|
506
504
|
def valid_keys(
|
507
505
|
obj,
|
508
506
|
key_valid = None,
|
@@ -560,7 +558,7 @@ def valid_keys(
|
|
560
558
|
def copy_once(out):
|
561
559
|
if out is obj:
|
562
560
|
# copy only if 'out' is still the same object as obj
|
563
|
-
return
|
561
|
+
return copy(obj)
|
564
562
|
|
565
563
|
return out
|
566
564
|
|
@@ -705,110 +703,209 @@ def valid_keys(
|
|
705
703
|
|
706
704
|
return out
|
707
705
|
|
708
|
-
|
709
|
-
class
|
710
|
-
|
711
|
-
|
706
|
+
#===============================================================================
|
707
|
+
class _ValidDictAttr:
|
708
|
+
r"""Descriptor for accessing dictionary keys as attributes
|
709
|
+
"""
|
710
|
+
__slots__ = ('name', 'key')
|
712
711
|
|
713
|
-
|
714
|
-
|
712
|
+
#-----------------------------------------------------------------------------
|
713
|
+
def __init__(self, name: str, key: str):
|
714
|
+
self.name = name
|
715
|
+
self.key = key
|
715
716
|
|
716
|
-
|
717
|
-
|
717
|
+
#-----------------------------------------------------------------------------
|
718
|
+
def __get__(self, obj, owner):
|
719
|
+
if obj is None:
|
720
|
+
return self
|
718
721
|
|
719
|
-
|
720
|
-
return False
|
722
|
+
return obj._data[self.key]
|
721
723
|
|
722
|
-
|
723
|
-
def
|
724
|
-
|
725
|
-
|
726
|
-
or obj._p_attrs_modify )
|
724
|
+
#-----------------------------------------------------------------------------
|
725
|
+
def __set__(self, obj, value):
|
726
|
+
obj._data[self.key] = value
|
727
|
+
obj._validate()
|
727
728
|
|
728
|
-
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
729
|
-
class attrs_modify:
|
730
729
|
#-----------------------------------------------------------------------------
|
731
|
-
def
|
732
|
-
self.
|
730
|
+
def __delete__(self, obj):
|
731
|
+
del obj._data[self.key]
|
732
|
+
obj._validate()
|
733
733
|
|
734
734
|
#-----------------------------------------------------------------------------
|
735
|
-
def
|
736
|
-
self.
|
735
|
+
def __repr__(self):
|
736
|
+
return f"{type(self).__name__}({self.name!r}, {self.key!r})"
|
737
737
|
|
738
|
+
#===============================================================================
|
739
|
+
class _ValidDictMeta(ABCMeta):
|
738
740
|
#-----------------------------------------------------------------------------
|
739
|
-
def
|
740
|
-
|
741
|
+
def __new__(mcls,
|
742
|
+
name,
|
743
|
+
bases,
|
744
|
+
namespace):
|
745
|
+
|
746
|
+
schema_keys = (
|
747
|
+
'key_valid',
|
748
|
+
'value_valid',
|
749
|
+
'item_valid',
|
750
|
+
'allow_keys',
|
751
|
+
'require_keys',
|
752
|
+
'min_keys',
|
753
|
+
'wedge_keys',
|
754
|
+
'mutex_keys',
|
755
|
+
'deprecate_keys',
|
756
|
+
'forbid_keys',
|
757
|
+
'default',
|
758
|
+
'proxy_keys')
|
759
|
+
|
760
|
+
schema = {}
|
761
|
+
|
762
|
+
for base in bases:
|
763
|
+
# include options from base classes
|
764
|
+
if isinstance(base, _ValidDictMeta):
|
765
|
+
for k in schema_keys:
|
766
|
+
v = base.__dict__.get(k)
|
767
|
+
|
768
|
+
if v is not None:
|
769
|
+
schema[k] = v
|
770
|
+
|
771
|
+
for k in schema_keys:
|
772
|
+
v = namespace.get(k)
|
773
|
+
|
774
|
+
if v is not None:
|
775
|
+
schema[k] = v
|
776
|
+
|
777
|
+
namespace.update(schema)
|
778
|
+
|
779
|
+
validator = schema.get('validator')
|
780
|
+
key_valid = schema.get('key_valid')
|
781
|
+
value_valid = schema.get('value_valid')
|
782
|
+
item_valid = schema.get('item_valid')
|
783
|
+
allow_keys = schema.get('allow_keys')
|
784
|
+
require_keys = schema.get('require_keys')
|
785
|
+
min_keys = schema.get('min_keys')
|
786
|
+
wedge_keys = schema.get('wedge_keys')
|
787
|
+
mutex_keys = schema.get('mutex_keys')
|
788
|
+
deprecate_keys = schema.get('deprecate_keys')
|
789
|
+
forbid_keys = schema.get('forbid_keys')
|
790
|
+
default = schema.get('default')
|
791
|
+
proxy_keys = schema.get('proxy_keys')
|
792
|
+
|
793
|
+
default = {
|
794
|
+
k: valid(v)
|
795
|
+
for k,v in (default or dict()).items()}
|
796
|
+
all_keys = list()
|
797
|
+
|
798
|
+
all_keys.extend(allow_keys or ())
|
799
|
+
all_keys.extend(require_keys or ())
|
800
|
+
all_keys.extend(default.keys())
|
801
|
+
|
802
|
+
if deprecate_keys:
|
803
|
+
all_keys.extend([
|
804
|
+
k_new
|
805
|
+
for k_old, k_new in deprecate_keys
|
806
|
+
if k_new not in [None, OPTIONAL, OPTIONAL_NONE, REQUIRED]])
|
807
|
+
|
808
|
+
if min_keys:
|
809
|
+
for keys in min_keys:
|
810
|
+
all_keys.extend(keys)
|
741
811
|
|
742
|
-
|
743
|
-
|
812
|
+
if wedge_keys:
|
813
|
+
for keys in wedge_keys:
|
814
|
+
all_keys.extend(keys)
|
815
|
+
|
816
|
+
if mutex_keys:
|
817
|
+
for keys in mutex_keys:
|
818
|
+
all_keys.extend(keys)
|
819
|
+
|
820
|
+
all_keys = tuple(all_keys)
|
821
|
+
|
822
|
+
# compose validator with parameterized valid_keys method
|
823
|
+
validator = valid(
|
824
|
+
validator or (lambda v: v),
|
825
|
+
partial(valid_keys,
|
826
|
+
key_valid = key_valid,
|
827
|
+
value_valid = value_valid,
|
828
|
+
item_valid = item_valid,
|
829
|
+
allow_keys = allow_keys,
|
830
|
+
require_keys = require_keys,
|
831
|
+
min_keys = min_keys,
|
832
|
+
wedge_keys = wedge_keys,
|
833
|
+
mutex_keys = mutex_keys,
|
834
|
+
deprecate_keys = deprecate_keys,
|
835
|
+
forbid_keys = forbid_keys,
|
836
|
+
default = default,
|
837
|
+
proxy_keys = proxy_keys))
|
838
|
+
|
839
|
+
namespace['_all_keys'] = all_keys
|
840
|
+
namespace['_validator'] = validator
|
841
|
+
namespace.setdefault('__slots__', ())
|
842
|
+
|
843
|
+
for k in all_keys:
|
844
|
+
# create attributes mapping to dictionary keys
|
845
|
+
name = k.replace('-','_')
|
846
|
+
attr = _ValidDictAttr(name, k)
|
847
|
+
namespace[name] = attr
|
848
|
+
|
849
|
+
cls = super().__new__(mcls, name, bases, namespace)
|
850
|
+
|
851
|
+
return cls
|
852
|
+
|
853
|
+
#===============================================================================
|
854
|
+
class valid_dict(Mapping, metaclass = _ValidDictMeta):
|
744
855
|
"""Validated Mapping
|
745
856
|
|
746
857
|
Attributes
|
747
858
|
----------
|
748
|
-
|
859
|
+
proxy_key: None | str
|
749
860
|
If initialized with a value that is not a Mapping, this key is assigned the
|
750
861
|
value before performing validation.
|
751
|
-
|
862
|
+
key_valid: None | callable
|
752
863
|
Validates all keys
|
753
|
-
|
864
|
+
value_valid: None | callable
|
754
865
|
Validates all values
|
755
|
-
|
866
|
+
item_valid: None | callable
|
756
867
|
Validates all (key,value) pairs
|
757
|
-
|
868
|
+
allow_keys: None | list[str]
|
758
869
|
Mapping may not contain keys that are not listed.
|
759
|
-
|
870
|
+
require_keys: None | list[str]
|
760
871
|
Mapping must contain all listed keys.
|
761
|
-
|
872
|
+
min_keys: None | list[ list[str] ]
|
762
873
|
Mapping must contain at least one key from each list.
|
763
|
-
|
874
|
+
wedge_keys: None | list[ list[str] ]
|
764
875
|
Mapping must contain either none or all of the listed keys.
|
765
|
-
|
876
|
+
mutex_keys: None | list[ list[str] ]
|
766
877
|
Mapping may contain at most one key from each list.
|
767
|
-
|
878
|
+
deprecate_keys: None | list[ (str, None | str | Required) ]
|
768
879
|
First key is marked as deprecated and removed from the Mapping.
|
769
880
|
If new key is given, the value is remapped to the new key.
|
770
881
|
If new key is Required, an error is raised, otherwise a deprecation warning
|
771
882
|
is reported.
|
772
|
-
|
883
|
+
forbid_keys: None | list[str]
|
773
884
|
Mapping must not contain any of the listed keys.
|
774
|
-
|
885
|
+
default: None | Mapping[object, object | type | Validator]
|
775
886
|
Default value or validator for given keys.
|
776
|
-
|
887
|
+
validator : None | Validator
|
777
888
|
General validator for entire Mapping after above constraints are satisfied.
|
778
889
|
See Also
|
779
890
|
--------
|
780
891
|
* :func:`valid_keys`
|
781
892
|
"""
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
# internal
|
799
|
-
_p_all_keys = list()
|
800
|
-
|
801
|
-
#-----------------------------------------------------------------------------
|
802
|
-
def __new__( cls, *args, **kwargs ):
|
803
|
-
|
804
|
-
self = super().__new__( cls )
|
805
|
-
self._p_attrs_modify = False
|
806
|
-
|
807
|
-
with attrs_modify( self ):
|
808
|
-
self._p_dict = dict()
|
809
|
-
self._p_key_attr = dict()
|
810
|
-
|
811
|
-
return self
|
893
|
+
__slots__ = ('_data',)
|
894
|
+
|
895
|
+
proxy_key = None
|
896
|
+
proxy_keys = None
|
897
|
+
key_valid = None
|
898
|
+
value_valid = None
|
899
|
+
item_valid = None
|
900
|
+
allow_keys = None
|
901
|
+
require_keys = None
|
902
|
+
min_keys = None
|
903
|
+
wedge_keys = None
|
904
|
+
mutex_keys = None
|
905
|
+
deprecate_keys = None
|
906
|
+
forbid_keys = None
|
907
|
+
default = None
|
908
|
+
validator = None
|
812
909
|
|
813
910
|
#---------------------------------------------------------------------------#
|
814
911
|
# pylint: disable-next=E0602
|
@@ -822,224 +919,132 @@ class valid_dict(Mapping):
|
|
822
919
|
|
823
920
|
v = args[0]
|
824
921
|
|
825
|
-
if v in
|
922
|
+
if v in (None, OPTIONAL, OPTIONAL_NONE):
|
826
923
|
args = [dict()]
|
827
|
-
elif cls._proxy_key:
|
828
|
-
args = [{ cls._proxy_key : v }]
|
829
|
-
|
830
|
-
self._p_dict = dict(*args, **kwargs)
|
831
|
-
|
832
|
-
with attrs_modify( self ):
|
833
|
-
self._default = { k: valid(v) for k,v in ( cls._default or dict() ).items() }
|
834
|
-
self._validator = valid(cls._validator or (lambda v: v))
|
835
924
|
|
836
|
-
|
837
|
-
|
925
|
+
elif cls.proxy_key:
|
926
|
+
args = [{ cls.proxy_key : v }]
|
838
927
|
|
839
|
-
self.
|
840
|
-
self.
|
841
|
-
self._p_all_keys.extend( self._default.keys() )
|
842
|
-
|
843
|
-
if self._deprecate_keys:
|
844
|
-
for keys in self._deprecate_keys:
|
845
|
-
self._p_all_keys.extend( [
|
846
|
-
k_new
|
847
|
-
for k_old, k_new in self._deprecate_keys
|
848
|
-
if k_new not in [None, OPTIONAL, OPTIONAL_NONE, REQUIRED] ] )
|
928
|
+
self._data = dict(*args, **kwargs)
|
929
|
+
self._validate()
|
849
930
|
|
850
|
-
|
851
|
-
|
852
|
-
|
931
|
+
#-----------------------------------------------------------------------------
|
932
|
+
def __eq__(self, other):
|
933
|
+
if isinstance(other, valid_dict):
|
934
|
+
other = other._data
|
853
935
|
|
854
|
-
|
855
|
-
for keys in self._wedge_keys:
|
856
|
-
self._p_all_keys.extend(keys)
|
936
|
+
return self._data.__eq__(other)
|
857
937
|
|
858
|
-
|
859
|
-
|
860
|
-
|
938
|
+
#-----------------------------------------------------------------------------
|
939
|
+
def __ne__(self, other):
|
940
|
+
if isinstance(other, valid_dict):
|
941
|
+
other = other._data
|
861
942
|
|
862
|
-
self.
|
863
|
-
self._validate()
|
943
|
+
return self._data.__ne__(other)
|
864
944
|
|
865
945
|
#-----------------------------------------------------------------------------
|
866
946
|
def __copy__(self):
|
867
|
-
|
868
|
-
obj
|
947
|
+
cls = type(self)
|
948
|
+
obj = cls.__new__(cls)
|
949
|
+
obj._data = copy(self._data)
|
869
950
|
return obj
|
870
951
|
|
871
952
|
#-----------------------------------------------------------------------------
|
872
953
|
def __str__(self):
|
873
|
-
return str(self.
|
954
|
+
return str(self._data)
|
874
955
|
|
875
956
|
#-----------------------------------------------------------------------------
|
876
957
|
def __repr__(self):
|
877
|
-
return
|
958
|
+
return repr(self._data)
|
878
959
|
|
879
960
|
#-----------------------------------------------------------------------------
|
880
|
-
def __len__(
|
881
|
-
return len(self.
|
961
|
+
def __len__(self):
|
962
|
+
return len(self._data)
|
882
963
|
|
883
964
|
#-----------------------------------------------------------------------------
|
884
|
-
def __iter__(
|
885
|
-
return iter(self.
|
965
|
+
def __iter__(self):
|
966
|
+
return iter(self._data)
|
886
967
|
|
887
968
|
#-----------------------------------------------------------------------------
|
888
|
-
def
|
889
|
-
return self.
|
969
|
+
def __contains__(self, name):
|
970
|
+
return self._data.__contains__(name)
|
890
971
|
|
891
972
|
#-----------------------------------------------------------------------------
|
892
|
-
def
|
893
|
-
return self.
|
973
|
+
def keys(self):
|
974
|
+
return self._data.keys()
|
894
975
|
|
895
976
|
#-----------------------------------------------------------------------------
|
896
|
-
def
|
897
|
-
return self.
|
977
|
+
def values(self):
|
978
|
+
return self._data.values()
|
898
979
|
|
899
980
|
#-----------------------------------------------------------------------------
|
900
|
-
def
|
901
|
-
self.
|
981
|
+
def items(self):
|
982
|
+
return self._data.items()
|
983
|
+
|
984
|
+
#-----------------------------------------------------------------------------
|
985
|
+
def clear(self):
|
986
|
+
self._data.clear()
|
902
987
|
self._validate()
|
903
988
|
|
904
989
|
#---------------------------------------------------------------------------#
|
905
990
|
def update(self, *args, **kwargs ):
|
906
|
-
self.
|
991
|
+
self._data.update(*args, **kwargs)
|
907
992
|
self._validate()
|
908
993
|
|
909
994
|
#-----------------------------------------------------------------------------
|
910
995
|
def setdefault( self, *args, **kwargs ):
|
911
|
-
val = self.
|
996
|
+
val = self._data.setdefault(*args, **kwargs)
|
912
997
|
self._validate()
|
913
998
|
return val
|
914
999
|
|
915
1000
|
#-----------------------------------------------------------------------------
|
916
1001
|
def get( self, *args, **kwargs ):
|
917
|
-
return self.
|
1002
|
+
return self._data.get(*args, **kwargs)
|
918
1003
|
|
919
1004
|
#-----------------------------------------------------------------------------
|
920
1005
|
def pop( self, *args, **kwargs ):
|
921
|
-
val = self.
|
1006
|
+
val = self._data.pop(*args, **kwargs)
|
1007
|
+
self._validate()
|
1008
|
+
return val
|
1009
|
+
|
1010
|
+
#-----------------------------------------------------------------------------
|
1011
|
+
def popitem( self, *args, **kwargs ):
|
1012
|
+
val = self._data.popitem(*args, **kwargs)
|
922
1013
|
self._validate()
|
923
1014
|
return val
|
924
1015
|
|
925
1016
|
#-----------------------------------------------------------------------------
|
926
1017
|
def __getitem__( self, key ):
|
927
|
-
return self.
|
1018
|
+
return self._data.__getitem__(key)
|
928
1019
|
|
929
1020
|
#-----------------------------------------------------------------------------
|
930
1021
|
def __setitem__( self, key, val ):
|
931
|
-
self.
|
1022
|
+
self._data.__setitem__(key, val)
|
932
1023
|
self._validate()
|
933
1024
|
|
934
1025
|
#-----------------------------------------------------------------------------
|
935
1026
|
def __delitem__( self, key ):
|
936
|
-
self.
|
1027
|
+
self._data.__delitem__( key )
|
937
1028
|
self._validate()
|
938
1029
|
|
939
|
-
#-----------------------------------------------------------------------------
|
940
|
-
def __setattr__( self, name, val ):
|
941
|
-
|
942
|
-
try:
|
943
|
-
|
944
|
-
if name != '_p_attrs_modify' and not attrs_modifiable( self ):
|
945
|
-
# only set mapping if base object doesn't have the attribute
|
946
|
-
super().__getattribute__(name)
|
947
|
-
|
948
|
-
if name in self._p_key_attr:
|
949
|
-
warnings.warn(f"'{type(self).__name__}' attribute shadows mapping key: {name}")
|
950
|
-
|
951
|
-
object.__setattr__( self, name, val )
|
952
|
-
return
|
953
|
-
|
954
|
-
except AttributeError as e:
|
955
|
-
pass
|
956
|
-
|
957
|
-
if name != '_p_dict' and name != '_p_key_attr':
|
958
|
-
if name in self._p_dict:
|
959
|
-
self._p_dict[ name ] = val
|
960
|
-
self._validate()
|
961
|
-
return
|
962
|
-
|
963
|
-
if name in self._p_key_attr:
|
964
|
-
self._p_dict[ self._p_key_attr[name] ] = val
|
965
|
-
self._validate()
|
966
|
-
return
|
967
|
-
|
968
|
-
raise AttributeError(
|
969
|
-
f"'{type(self).__name__}' object has no key '{name}'."
|
970
|
-
" New keys must be added using a Mapping method;"
|
971
|
-
f" E.G. x['{name}'] = {val}" )
|
972
|
-
|
973
|
-
|
974
|
-
#-----------------------------------------------------------------------------
|
975
|
-
def __getattribute__( self, name ):
|
976
|
-
|
977
|
-
try:
|
978
|
-
val = super().__getattribute__(name)
|
979
|
-
|
980
|
-
if name != '_p_dict' and name != '_p_key_attr' and name in self._p_key_attr:
|
981
|
-
warnings.warn(f"'{type(self).__name__}' attribute shadows mapping key: {name}")
|
982
|
-
|
983
|
-
return val
|
984
|
-
|
985
|
-
except AttributeError as e:
|
986
|
-
pass
|
987
|
-
|
988
|
-
# only get mapping if base object does not have attribute
|
989
|
-
if name != '_p_dict' and name != '_p_key_attr':
|
990
|
-
if name in self._p_dict:
|
991
|
-
return self._p_dict[ name ]
|
992
|
-
|
993
|
-
if name in self._p_key_attr:
|
994
|
-
return self._p_dict[ self._p_key_attr[name] ]
|
995
|
-
|
996
|
-
raise AttributeError(
|
997
|
-
f"'{type(self).__name__}' object has no key '{name}'")
|
998
|
-
|
999
|
-
|
1000
1030
|
#-----------------------------------------------------------------------------
|
1001
1031
|
def _validate(self):
|
1002
|
-
|
1003
|
-
return
|
1004
|
-
|
1005
|
-
with validating_block(self):
|
1006
|
-
self.update( **self._validator( valid_keys(
|
1007
|
-
self._p_dict,
|
1008
|
-
key_valid = self._key_valid,
|
1009
|
-
value_valid = self._value_valid,
|
1010
|
-
item_valid = self._item_valid,
|
1011
|
-
allow_keys = self._allow_keys,
|
1012
|
-
require_keys = self._require_keys,
|
1013
|
-
min_keys = self._min_keys,
|
1014
|
-
wedge_keys = self._wedge_keys,
|
1015
|
-
mutex_keys = self._mutex_keys,
|
1016
|
-
deprecate_keys = self._deprecate_keys,
|
1017
|
-
forbid_keys = self._forbid_keys,
|
1018
|
-
default = self._default,
|
1019
|
-
proxy_keys = self._proxy_keys ) ) )
|
1020
|
-
|
1021
|
-
#-----------------------------------------------------------------------------
|
1022
|
-
def __str__(self):
|
1023
|
-
return str(self._p_dict)
|
1024
|
-
|
1025
|
-
#-----------------------------------------------------------------------------
|
1026
|
-
def __repr__(self):
|
1027
|
-
return str(self)
|
1032
|
+
self._data = self._validator(self._data)
|
1028
1033
|
|
1029
|
-
|
1034
|
+
#===============================================================================
|
1030
1035
|
class valid_list(list):
|
1031
1036
|
"""Validated list
|
1032
1037
|
"""
|
1033
1038
|
_as_list = None
|
1034
|
-
|
1039
|
+
value_valid = None
|
1035
1040
|
_min_len = 0
|
1036
1041
|
|
1037
1042
|
#---------------------------------------------------------------------------#
|
1038
1043
|
def __init__( self, vals = None ):
|
1039
1044
|
cls = type(self)
|
1040
1045
|
self._as_list = cls._as_list or list
|
1041
|
-
self.
|
1042
|
-
cls.
|
1046
|
+
self.value_valid = valid(
|
1047
|
+
cls.value_valid or (lambda v: v))
|
1043
1048
|
|
1044
1049
|
if vals is None:
|
1045
1050
|
vals = list()
|
@@ -1049,13 +1054,13 @@ class valid_list(list):
|
|
1049
1054
|
|
1050
1055
|
for i,v in enumerate(vals):
|
1051
1056
|
with validating(key = i):
|
1052
|
-
vals[i] = self.
|
1057
|
+
vals[i] = self.value_valid(v)
|
1053
1058
|
|
1054
1059
|
super().__init__(vals)
|
1055
1060
|
self._validate()
|
1056
1061
|
|
1057
1062
|
#-----------------------------------------------------------------------------
|
1058
|
-
def clear(
|
1063
|
+
def clear(self):
|
1059
1064
|
super().clear()
|
1060
1065
|
self._validate()
|
1061
1066
|
|
@@ -1068,7 +1073,7 @@ class valid_list(list):
|
|
1068
1073
|
#---------------------------------------------------------------------------#
|
1069
1074
|
def append(self, val ):
|
1070
1075
|
with validating(key = len(self)):
|
1071
|
-
val = self.
|
1076
|
+
val = self.value_valid(val)
|
1072
1077
|
|
1073
1078
|
super().append(val)
|
1074
1079
|
|
@@ -1078,14 +1083,14 @@ class valid_list(list):
|
|
1078
1083
|
|
1079
1084
|
for i,v in enumerate(vals):
|
1080
1085
|
with validating(key = len(self) + i):
|
1081
|
-
vals[i] = self.
|
1086
|
+
vals[i] = self.value_valid(v)
|
1082
1087
|
|
1083
1088
|
super().extend(vals)
|
1084
1089
|
|
1085
1090
|
#-----------------------------------------------------------------------------
|
1086
1091
|
def __setitem__( self, key, val ):
|
1087
1092
|
with validating(key = key):
|
1088
|
-
val = self.
|
1093
|
+
val = self.value_valid(val)
|
1089
1094
|
|
1090
1095
|
super().__setitem__(key, val)
|
1091
1096
|
|
@@ -1094,7 +1099,7 @@ class valid_list(list):
|
|
1094
1099
|
if len(self) < self._min_len:
|
1095
1100
|
raise ValidationError(f"Must have length >= {self._min_len}: {len(self)}")
|
1096
1101
|
|
1097
|
-
|
1102
|
+
#===============================================================================
|
1098
1103
|
def mapget(
|
1099
1104
|
obj,
|
1100
1105
|
path,
|
@@ -1124,7 +1129,7 @@ def mapget(
|
|
1124
1129
|
|
1125
1130
|
return _obj
|
1126
1131
|
|
1127
|
-
|
1132
|
+
#===============================================================================
|
1128
1133
|
def as_list(obj):
|
1129
1134
|
if isinstance(obj, (str, Mapping)) or not isinstance(obj, Iterable):
|
1130
1135
|
return [obj]
|