enumerific 1.0.2__py3-none-any.whl → 1.0.3__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.
- enumerific/__init__.py +8 -1
- enumerific/exceptions.py +4 -0
- enumerific/extensible.py +121 -22
- enumerific/version.txt +1 -1
- {enumerific-1.0.2.dist-info → enumerific-1.0.3.dist-info}/METADATA +97 -29
- enumerific-1.0.3.dist-info/RECORD +12 -0
- enumerific-1.0.2.dist-info/RECORD +0 -12
- {enumerific-1.0.2.dist-info → enumerific-1.0.3.dist-info}/WHEEL +0 -0
- {enumerific-1.0.2.dist-info → enumerific-1.0.3.dist-info}/licenses/LICENSE.md +0 -0
- {enumerific-1.0.2.dist-info → enumerific-1.0.3.dist-info}/top_level.txt +0 -0
- {enumerific-1.0.2.dist-info → enumerific-1.0.3.dist-info}/zip-safe +0 -0
enumerific/__init__.py
CHANGED
|
@@ -2,7 +2,14 @@ from enum import *
|
|
|
2
2
|
|
|
3
3
|
from .logging import logger
|
|
4
4
|
|
|
5
|
-
from .exceptions import
|
|
5
|
+
from .exceptions import (
|
|
6
|
+
EnumValueError,
|
|
7
|
+
EnumerationError,
|
|
8
|
+
EnumerationOptionError,
|
|
9
|
+
EnumerationSubclassingError,
|
|
10
|
+
EnumerationExtensibilityError,
|
|
11
|
+
EnumerationNonUniqueError,
|
|
12
|
+
)
|
|
6
13
|
|
|
7
14
|
from .extensible import (
|
|
8
15
|
Enumeration,
|
enumerific/exceptions.py
CHANGED
enumerific/extensible.py
CHANGED
|
@@ -9,6 +9,7 @@ from enumerific.exceptions import (
|
|
|
9
9
|
EnumerationError,
|
|
10
10
|
EnumerationOptionError,
|
|
11
11
|
EnumerationSubclassingError,
|
|
12
|
+
EnumerationExtensibilityError,
|
|
12
13
|
EnumerationNonUniqueError,
|
|
13
14
|
)
|
|
14
15
|
|
|
@@ -196,10 +197,12 @@ class EnumerationConfiguration(object):
|
|
|
196
197
|
"""The EnumerationConfiguration class holds the Enumeration configuration options"""
|
|
197
198
|
|
|
198
199
|
_unique: bool = None
|
|
199
|
-
_aliased: bool =
|
|
200
|
+
_aliased: bool = None
|
|
201
|
+
_backfill: bool = None
|
|
200
202
|
_overwritable: bool = None
|
|
201
203
|
_removable: bool = None
|
|
202
204
|
_subclassable: bool = None
|
|
205
|
+
_extensible: bool = None
|
|
203
206
|
_raises: bool = None
|
|
204
207
|
_flags: bool = None
|
|
205
208
|
_start: int = None
|
|
@@ -211,9 +214,11 @@ class EnumerationConfiguration(object):
|
|
|
211
214
|
self,
|
|
212
215
|
unique: bool = None,
|
|
213
216
|
aliased: bool = None,
|
|
217
|
+
backfill: bool = None,
|
|
214
218
|
overwritable: bool = None,
|
|
215
219
|
removable: bool = None,
|
|
216
220
|
subclassable: bool = None,
|
|
221
|
+
extensible: bool = None,
|
|
217
222
|
raises: bool = None,
|
|
218
223
|
flags: bool = None,
|
|
219
224
|
start: int = None,
|
|
@@ -223,9 +228,11 @@ class EnumerationConfiguration(object):
|
|
|
223
228
|
):
|
|
224
229
|
self.unique = unique
|
|
225
230
|
self.aliased = aliased
|
|
231
|
+
self.backfill = backfill
|
|
226
232
|
self.overwritable = overwritable
|
|
227
233
|
self.removable = removable
|
|
228
234
|
self.subclassable = subclassable
|
|
235
|
+
self.extensible = extensible
|
|
229
236
|
self.raises = raises
|
|
230
237
|
self.flags = flags
|
|
231
238
|
self.start = start
|
|
@@ -237,9 +244,11 @@ class EnumerationConfiguration(object):
|
|
|
237
244
|
return [
|
|
238
245
|
"unique",
|
|
239
246
|
"aliased",
|
|
247
|
+
"backfill",
|
|
240
248
|
"overwritable",
|
|
241
249
|
"removable",
|
|
242
250
|
"subclassable",
|
|
251
|
+
"extensible",
|
|
243
252
|
"raises",
|
|
244
253
|
"flags",
|
|
245
254
|
"start",
|
|
@@ -310,6 +319,20 @@ class EnumerationConfiguration(object):
|
|
|
310
319
|
)
|
|
311
320
|
self._aliased = aliased
|
|
312
321
|
|
|
322
|
+
@property
|
|
323
|
+
def backfill(self) -> bool | None:
|
|
324
|
+
return self._backfill
|
|
325
|
+
|
|
326
|
+
@backfill.setter
|
|
327
|
+
def backfill(self, backfill: bool | None):
|
|
328
|
+
if backfill is None:
|
|
329
|
+
pass
|
|
330
|
+
elif not isinstance(backfill, bool):
|
|
331
|
+
raise TypeError(
|
|
332
|
+
"The 'backfill' argument, if specified, must have a boolean value!"
|
|
333
|
+
)
|
|
334
|
+
self._backfill = backfill
|
|
335
|
+
|
|
313
336
|
@property
|
|
314
337
|
def overwritable(self) -> bool | None:
|
|
315
338
|
return self._overwritable
|
|
@@ -352,6 +375,20 @@ class EnumerationConfiguration(object):
|
|
|
352
375
|
)
|
|
353
376
|
self._subclassable = subclassable
|
|
354
377
|
|
|
378
|
+
@property
|
|
379
|
+
def extensible(self) -> bool | None:
|
|
380
|
+
return self._extensible
|
|
381
|
+
|
|
382
|
+
@extensible.setter
|
|
383
|
+
def extensible(self, extensible: bool | None):
|
|
384
|
+
if extensible is None:
|
|
385
|
+
pass
|
|
386
|
+
elif not isinstance(extensible, bool):
|
|
387
|
+
raise TypeError(
|
|
388
|
+
"The 'extensible' argument, if specified, must have a boolean value!"
|
|
389
|
+
)
|
|
390
|
+
self._extensible = extensible
|
|
391
|
+
|
|
355
392
|
@property
|
|
356
393
|
def raises(self) -> bool | None:
|
|
357
394
|
return self._raises
|
|
@@ -463,8 +500,10 @@ class EnumerationMetaClass(type):
|
|
|
463
500
|
bases: tuple[type],
|
|
464
501
|
unique: bool = None,
|
|
465
502
|
aliased: bool = None,
|
|
503
|
+
backfill: bool = None,
|
|
466
504
|
overwritable: bool = None,
|
|
467
505
|
subclassable: bool = None,
|
|
506
|
+
extensible: bool = None,
|
|
468
507
|
removable: bool = None,
|
|
469
508
|
raises: bool = None,
|
|
470
509
|
flags: bool = None,
|
|
@@ -481,14 +520,16 @@ class EnumerationMetaClass(type):
|
|
|
481
520
|
any other keyword arguments that are included in the class signature call."""
|
|
482
521
|
|
|
483
522
|
logger.debug(
|
|
484
|
-
"[EnumerationMetaClass] %s.__prepare__(name: %s, bases: %s, unique: %s, aliased: %s, overwritable: %s, subclassable: %s, removable: %s, raises: %s, flags: %s, start: %s, steps: %s, times: %s, typecast: %s, kwargs: %s)",
|
|
523
|
+
"[EnumerationMetaClass] %s.__prepare__(name: %s, bases: %s, unique: %s, aliased: %s, backfill: %s, overwritable: %s, subclassable: %s, extensible: %s, removable: %s, raises: %s, flags: %s, start: %s, steps: %s, times: %s, typecast: %s, kwargs: %s)",
|
|
485
524
|
name,
|
|
486
525
|
name,
|
|
487
526
|
bases,
|
|
488
527
|
unique,
|
|
489
528
|
aliased,
|
|
529
|
+
backfill,
|
|
490
530
|
overwritable,
|
|
491
531
|
subclassable,
|
|
532
|
+
extensible,
|
|
492
533
|
removable,
|
|
493
534
|
raises,
|
|
494
535
|
flags,
|
|
@@ -581,8 +622,10 @@ class EnumerationMetaClass(type):
|
|
|
581
622
|
*args,
|
|
582
623
|
unique: bool = None, # True
|
|
583
624
|
aliased: bool = None, # False
|
|
625
|
+
backfill: bool = None, # False
|
|
584
626
|
overwritable: bool = None, # False
|
|
585
627
|
subclassable: bool = None, # True
|
|
628
|
+
extensible: bool = None, # True
|
|
586
629
|
removable: bool = None, # False
|
|
587
630
|
raises: bool = None, # False
|
|
588
631
|
flags: bool = None, # False
|
|
@@ -613,6 +656,13 @@ class EnumerationMetaClass(type):
|
|
|
613
656
|
"The 'aliased' argument, if specified, must have a boolean value!"
|
|
614
657
|
)
|
|
615
658
|
|
|
659
|
+
if backfill is None:
|
|
660
|
+
pass
|
|
661
|
+
elif not isinstance(backfill, bool):
|
|
662
|
+
raise TypeError(
|
|
663
|
+
"The 'backfill' argument, if specified, must have a boolean value!"
|
|
664
|
+
)
|
|
665
|
+
|
|
616
666
|
if overwritable is None:
|
|
617
667
|
pass
|
|
618
668
|
elif not isinstance(overwritable, bool):
|
|
@@ -627,6 +677,13 @@ class EnumerationMetaClass(type):
|
|
|
627
677
|
"The 'subclassable' argument, if specified, must have a boolean value!"
|
|
628
678
|
)
|
|
629
679
|
|
|
680
|
+
if extensible is None:
|
|
681
|
+
pass
|
|
682
|
+
elif not isinstance(extensible, bool):
|
|
683
|
+
raise TypeError(
|
|
684
|
+
"The 'extensible' argument, if specified, must have a boolean value!"
|
|
685
|
+
)
|
|
686
|
+
|
|
630
687
|
if removable is None:
|
|
631
688
|
pass
|
|
632
689
|
elif not isinstance(removable, bool):
|
|
@@ -679,8 +736,10 @@ class EnumerationMetaClass(type):
|
|
|
679
736
|
configuration = EnumerationConfiguration(
|
|
680
737
|
unique=unique,
|
|
681
738
|
aliased=aliased,
|
|
739
|
+
backfill=backfill,
|
|
682
740
|
overwritable=overwritable,
|
|
683
741
|
subclassable=subclassable,
|
|
742
|
+
extensible=extensible,
|
|
684
743
|
removable=removable,
|
|
685
744
|
raises=raises,
|
|
686
745
|
flags=flags,
|
|
@@ -746,12 +805,18 @@ class EnumerationMetaClass(type):
|
|
|
746
805
|
logger.debug(
|
|
747
806
|
" >>> aliased => %s", base_configuration.aliased
|
|
748
807
|
)
|
|
808
|
+
logger.debug(
|
|
809
|
+
" >>> backfill => %s", base_configuration.backfill
|
|
810
|
+
)
|
|
749
811
|
logger.debug(
|
|
750
812
|
" >>> overwritable => %s", base_configuration.overwritable
|
|
751
813
|
)
|
|
752
814
|
logger.debug(
|
|
753
815
|
" >>> subclassable => %s", base_configuration.subclassable
|
|
754
816
|
)
|
|
817
|
+
logger.debug(
|
|
818
|
+
" >>> extensible => %s", base_configuration.extensible
|
|
819
|
+
)
|
|
755
820
|
logger.debug(
|
|
756
821
|
" >>> removable => %s", base_configuration.removable
|
|
757
822
|
)
|
|
@@ -774,9 +839,12 @@ class EnumerationMetaClass(type):
|
|
|
774
839
|
" >>> typecast => %s", base_configuration.typecast
|
|
775
840
|
)
|
|
776
841
|
|
|
777
|
-
if
|
|
842
|
+
if (
|
|
843
|
+
base_configuration.subclassable is False
|
|
844
|
+
or base_configuration.extensible is False
|
|
845
|
+
):
|
|
778
846
|
raise EnumerationSubclassingError(
|
|
779
|
-
"The '%s' enumeration class cannot be subclassed when the keyword
|
|
847
|
+
"The '%s' enumeration class cannot be subclassed when the keyword arguments 'subclassable=False' or 'extensible=False` are passed to the class constructor!"
|
|
780
848
|
% (base.__name__)
|
|
781
849
|
)
|
|
782
850
|
|
|
@@ -791,6 +859,9 @@ class EnumerationMetaClass(type):
|
|
|
791
859
|
logger.debug(
|
|
792
860
|
" >>> (updated) aliased => %s", configuration.aliased
|
|
793
861
|
)
|
|
862
|
+
logger.debug(
|
|
863
|
+
" >>> (updated) backfill => %s", configuration.backfill
|
|
864
|
+
)
|
|
794
865
|
logger.debug(
|
|
795
866
|
" >>> (updated) overwritable => %s",
|
|
796
867
|
configuration.overwritable,
|
|
@@ -799,6 +870,10 @@ class EnumerationMetaClass(type):
|
|
|
799
870
|
" >>> (updated) subclassable => %s",
|
|
800
871
|
configuration.subclassable,
|
|
801
872
|
)
|
|
873
|
+
logger.debug(
|
|
874
|
+
" >>> (updated) extensible => %s",
|
|
875
|
+
configuration.extensible,
|
|
876
|
+
)
|
|
802
877
|
logger.debug(
|
|
803
878
|
" >>> (updated) removable => %s", configuration.removable
|
|
804
879
|
)
|
|
@@ -824,7 +899,6 @@ class EnumerationMetaClass(type):
|
|
|
824
899
|
# logger.debug(" >>> found base (%s) that is an instance of EnumerationMetaClass and a subclass of Enumeration" % (base))
|
|
825
900
|
|
|
826
901
|
if not (base is Enumeration or Enumeration in base.__bases__):
|
|
827
|
-
# enumerations = base._enumerations # reference to the _enumerations dictionary
|
|
828
902
|
_enumerations = base._enumerations
|
|
829
903
|
|
|
830
904
|
logger.debug(" >>> enumerations => %s" % (base._enumerations))
|
|
@@ -846,8 +920,10 @@ class EnumerationMetaClass(type):
|
|
|
846
920
|
configuration.defaults(
|
|
847
921
|
unique=True,
|
|
848
922
|
aliased=False,
|
|
923
|
+
backfill=False,
|
|
849
924
|
overwritable=False,
|
|
850
925
|
subclassable=True,
|
|
926
|
+
extensible=True,
|
|
851
927
|
removable=False,
|
|
852
928
|
raises=False,
|
|
853
929
|
flags=False,
|
|
@@ -859,12 +935,14 @@ class EnumerationMetaClass(type):
|
|
|
859
935
|
|
|
860
936
|
logger.debug(" >>> (after defaults) unique => %s", configuration.unique)
|
|
861
937
|
logger.debug(" >>> (after defaults) aliased => %s", configuration.aliased)
|
|
938
|
+
logger.debug(" >>> (after defaults) backfill => %s", configuration.backfill)
|
|
862
939
|
logger.debug(
|
|
863
940
|
" >>> (after defaults) overwritable => %s", configuration.overwritable
|
|
864
941
|
)
|
|
865
942
|
logger.debug(
|
|
866
943
|
" >>> (after defaults) subclassable => %s", configuration.subclassable
|
|
867
944
|
)
|
|
945
|
+
logger.debug(" >>> (after defaults) extensible => %s", configuration.extensible)
|
|
868
946
|
logger.debug(
|
|
869
947
|
" >>> (after defaults) removable => %s", configuration.removable
|
|
870
948
|
)
|
|
@@ -998,28 +1076,20 @@ class EnumerationMetaClass(type):
|
|
|
998
1076
|
|
|
999
1077
|
logger.debug(" >>> bases => %s", [base for base in bases])
|
|
1000
1078
|
|
|
1001
|
-
# if "EnumerationInteger" in globals():
|
|
1002
|
-
# if EnumerationInteger in bases and EnumerationFlag in bases:
|
|
1003
|
-
# bases = tuple([base for base in bases if not EnumerationInteger])
|
|
1004
|
-
|
|
1005
1079
|
args: tuple[object] = (name, bases, attributes)
|
|
1006
1080
|
|
|
1007
1081
|
# Create the new enumeration class instance
|
|
1008
1082
|
instance = super().__new__(cls, *args, **kwargs)
|
|
1009
1083
|
|
|
1010
|
-
# logger.debug(
|
|
1011
|
-
# " >>> metaclass => %s (base: %s, type: %s, bases: %s)\n"
|
|
1012
|
-
# % (enumclass, instance, type(instance), instance.__bases__)
|
|
1013
|
-
# )
|
|
1014
|
-
# logger.debug(" >>> metaclass => %s (base: %s, type: %s, bases: %s)\n" % (enumclass, instance, type(instance), instance.__bases__))
|
|
1015
|
-
|
|
1016
1084
|
logger.debug(" >>> baseclass => %s", baseclass)
|
|
1017
1085
|
logger.debug(" >>> instance => %s", instance)
|
|
1018
1086
|
|
|
1019
1087
|
logger.debug(" >>> unique => %s", configuration.unique)
|
|
1020
1088
|
logger.debug(" >>> aliased => %s", configuration.aliased)
|
|
1089
|
+
logger.debug(" >>> backfill => %s", configuration.backfill)
|
|
1021
1090
|
logger.debug(" >>> overwritable => %s", configuration.overwritable)
|
|
1022
1091
|
logger.debug(" >>> subclassable => %s", configuration.subclassable)
|
|
1092
|
+
logger.debug(" >>> extensible => %s", configuration.extensible)
|
|
1023
1093
|
logger.debug(" >>> removable => %s", configuration.removable)
|
|
1024
1094
|
logger.debug(" >>> raises => %s", configuration.raises)
|
|
1025
1095
|
logger.debug(" >>> flags => %s", configuration.flags)
|
|
@@ -1048,7 +1118,16 @@ class EnumerationMetaClass(type):
|
|
|
1048
1118
|
)
|
|
1049
1119
|
|
|
1050
1120
|
if isinstance(base_enumerations := attributes.get("base_enumerations"), dict):
|
|
1051
|
-
|
|
1121
|
+
if (
|
|
1122
|
+
self._configuration.backfill is True
|
|
1123
|
+
and self._configuration.extensible is True
|
|
1124
|
+
):
|
|
1125
|
+
self._enumerations: dict[str, Enumeration] = base_enumerations
|
|
1126
|
+
else:
|
|
1127
|
+
self._enumerations: dict[str, Enumeration] = {}
|
|
1128
|
+
|
|
1129
|
+
for enumeration_name, enumeration in base_enumerations.items():
|
|
1130
|
+
self._enumerations[enumeration_name] = enumeration
|
|
1052
1131
|
else:
|
|
1053
1132
|
self._enumerations: dict[str, Enumeration] = {}
|
|
1054
1133
|
|
|
@@ -1131,16 +1210,19 @@ class EnumerationMetaClass(type):
|
|
|
1131
1210
|
)
|
|
1132
1211
|
|
|
1133
1212
|
def __dir__(self) -> list[str]:
|
|
1134
|
-
members:
|
|
1135
|
-
|
|
1136
|
-
for name, enumeration in self._enumerations.items():
|
|
1137
|
-
members.append(name)
|
|
1213
|
+
members: set[str] = set()
|
|
1138
1214
|
|
|
1139
1215
|
for member in object.__dir__(self):
|
|
1140
1216
|
if member.startswith("_") or member in self._special:
|
|
1141
|
-
members.
|
|
1217
|
+
members.add(member)
|
|
1218
|
+
|
|
1219
|
+
for name, enumeration in self._enumerations.items():
|
|
1220
|
+
members.add(name)
|
|
1142
1221
|
|
|
1143
|
-
|
|
1222
|
+
for member in vars(self):
|
|
1223
|
+
members.add(member)
|
|
1224
|
+
|
|
1225
|
+
return list(members)
|
|
1144
1226
|
|
|
1145
1227
|
def __contains__(self, other: Enumeration | object) -> bool:
|
|
1146
1228
|
logger.debug(
|
|
@@ -1326,6 +1408,12 @@ class EnumerationMetaClass(type):
|
|
|
1326
1408
|
value,
|
|
1327
1409
|
)
|
|
1328
1410
|
|
|
1411
|
+
if self.configuration.extensible is False:
|
|
1412
|
+
raise EnumerationExtensibilityError(
|
|
1413
|
+
"The '%s' enumeration class has been configured to prevent extensibility, so cannot be extended with new options either through registration or subclassing, so the '%s' option cannot be registered!"
|
|
1414
|
+
% (self.__name__, name)
|
|
1415
|
+
)
|
|
1416
|
+
|
|
1329
1417
|
if self.configuration.overwritable is False and name in self._enumerations:
|
|
1330
1418
|
raise EnumerationNonUniqueError(
|
|
1331
1419
|
"The '%s' enumeration class already has an option named '%s', so a new option with the same name cannot be created unless the 'overwritable=True' argument is passed during class construction!"
|
|
@@ -1430,6 +1518,14 @@ class EnumerationMetaClass(type):
|
|
|
1430
1518
|
)
|
|
1431
1519
|
)
|
|
1432
1520
|
|
|
1521
|
+
# When an enumeration option is reconciled, it may be defined in another class
|
|
1522
|
+
# but have been accessed through a subclass; in order for attribute lookups to
|
|
1523
|
+
# work within the subclass, we need to provide the current lookup context to the
|
|
1524
|
+
# reconciled enumeration option, so that any attribute access on this object can
|
|
1525
|
+
# perform their lookup in the correct part of the class hierarchy
|
|
1526
|
+
if isinstance(reconciled, Enumeration):
|
|
1527
|
+
reconciled._context = self
|
|
1528
|
+
|
|
1433
1529
|
return reconciled
|
|
1434
1530
|
|
|
1435
1531
|
def validate(self, value: Enumeration | object = None, name: str = None) -> bool:
|
|
@@ -1449,6 +1545,7 @@ class Enumeration(metaclass=EnumerationMetaClass):
|
|
|
1449
1545
|
"""The Enumeration class is the subclass of all enumerations and their subtypes."""
|
|
1450
1546
|
|
|
1451
1547
|
_metaclass: EnumerationMetaClass = None
|
|
1548
|
+
_context: EnumerationMetaClass = None
|
|
1452
1549
|
_enumeration: Enumeration = None
|
|
1453
1550
|
_enumerations: dict[str, Enumeration] = None
|
|
1454
1551
|
_annotations: anno = None
|
|
@@ -1609,6 +1706,8 @@ class Enumeration(metaclass=EnumerationMetaClass):
|
|
|
1609
1706
|
return self._enumerations[name]
|
|
1610
1707
|
elif self._annotations and name in self._annotations:
|
|
1611
1708
|
return self._annotations[name]
|
|
1709
|
+
elif self._context and name in dir(self._context):
|
|
1710
|
+
return object.__getattribute__(self._context, name)
|
|
1612
1711
|
else:
|
|
1613
1712
|
# EnumerationOptionError subclasses AttributeError so we adhere to convention
|
|
1614
1713
|
raise EnumerationOptionError(
|
enumerific/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: enumerific
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: Simplifies working with Python enums.
|
|
5
5
|
Author: Daniel Sissman
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,8 +41,9 @@ The Enumerific library's `Enumeration` class offers the following features:
|
|
|
41
41
|
* Enumerific enumerations options can be added after an `Enumeration` class has been created either through extending an existing enumerations class by subclassing or by registering new options directly on an existing enumerations class via the `.register()` method; this is especially useful for cases where enumeration options may not all be known prior to runtime;
|
|
42
42
|
* Enumerific enumerations options can be removed after an `Enumeration` class has been created via the `.unregister()` method; this specialised behaviour is prevented by default, but can be enabled for advanced use cases;
|
|
43
43
|
* Enforcement of unique values for all options within an enumeration, unless overridden;
|
|
44
|
-
* Support for aliasing enumeration options;
|
|
45
|
-
* Support for
|
|
44
|
+
* Support for aliasing enumeration options, and control over this behaviour;
|
|
45
|
+
* Support for backfilling enumeration options on a superclass when subclassing, and control over this behaviour
|
|
46
|
+
* Support for redefining enumeration options, and control over this behaviour;
|
|
46
47
|
* Support for automatically generating unique number sequences for enumeration options, including powers of two for bitwise enumeration flags, as well as other sequences such as powers of other numbers and factoring;
|
|
47
48
|
* Support for annotating enumeration options with additional arbitrary key-value pairs, which can be particularly useful for associating additional data with a given enumeration option, which may be accessed later anywhere in code that the enumeration option is available;
|
|
48
49
|
* Simple one-line reconciliation of `Enumeration` class options to the corresponding `enums.Enum` class instance that represents the corresponding option; reconciliation by enumeration option name, value and enumeration class instance reference are all supported through the `.reconcile()` class method;
|
|
@@ -253,7 +254,7 @@ for value in Colors.values():
|
|
|
253
254
|
print(value)
|
|
254
255
|
```
|
|
255
256
|
|
|
256
|
-
#### Example 8: Registering New
|
|
257
|
+
#### Example 8: Registering New Options
|
|
257
258
|
|
|
258
259
|
```python
|
|
259
260
|
from enumerific import Enumeration
|
|
@@ -264,11 +265,17 @@ class Colors(Enumeration):
|
|
|
264
265
|
BLUE = 3
|
|
265
266
|
|
|
266
267
|
Colors.register("PURPLE", 4)
|
|
268
|
+
Colors.register("GOLD", 5)
|
|
267
269
|
|
|
268
270
|
assert "PURPLE" in Colors
|
|
269
271
|
assert Colors.PURPLE.name == "PURPLE"
|
|
270
272
|
assert Colors.PURPLE.value == 4
|
|
271
273
|
assert Colors.PURPLE == 4
|
|
274
|
+
|
|
275
|
+
assert "GOLD" in Colors
|
|
276
|
+
assert Colors.GOLD.name == "GOLD"
|
|
277
|
+
assert Colors.GOLD.value == 5
|
|
278
|
+
assert Colors.GOLD == 5
|
|
272
279
|
```
|
|
273
280
|
|
|
274
281
|
#### Example 9: Subclassing
|
|
@@ -281,27 +288,64 @@ class Colors(Enumeration):
|
|
|
281
288
|
GREEN = 2
|
|
282
289
|
BLUE = 3
|
|
283
290
|
|
|
291
|
+
# Ensure that Colors has the expected options
|
|
292
|
+
assert "RED" in Colors
|
|
293
|
+
assert "GREEN" in Colors
|
|
294
|
+
assert "BLUE" in Colors
|
|
295
|
+
|
|
296
|
+
# Create a subclass of Colors, inheriting its options
|
|
284
297
|
class MoreColors(Colors):
|
|
285
298
|
PURPLE = 4
|
|
286
299
|
GOLD = 5
|
|
287
300
|
|
|
301
|
+
# Ensure that MoreColors inherited the options from Colors, as well as adding its own
|
|
302
|
+
assert "RED" in MoreColors
|
|
303
|
+
assert "GREEN" in MoreColors
|
|
304
|
+
assert "BLUE" in MoreColors
|
|
305
|
+
assert "PURPLE" in MoreColors
|
|
306
|
+
assert "GOLD" in MoreColors
|
|
307
|
+
|
|
308
|
+
# As backfilling is off by default subclass options won't be available on the superclass
|
|
309
|
+
assert not "PURPLE" in Colors
|
|
310
|
+
assert not "GOLD" in Colors
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### Example 10: Subclassing with Backfilling
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
from enumerific import Enumeration
|
|
317
|
+
|
|
318
|
+
# To override the default behaviour and to allow backfilling of options from subclasses,
|
|
319
|
+
# the `backfill` keyword argument can be set to `True` when creating the class. This
|
|
320
|
+
# effectively creates another way to extend an existing enumeration class through
|
|
321
|
+
# subclassing and its side-effect of backfilling, compared to using the `.register()`
|
|
322
|
+
# method to add new options to an existing enumeration class:
|
|
323
|
+
class Colors(Enumeration, backfill=True):
|
|
324
|
+
RED = 1
|
|
325
|
+
GREEN = 2
|
|
326
|
+
BLUE = 3
|
|
327
|
+
|
|
328
|
+
assert "RED" in Colors
|
|
329
|
+
assert "GREEN" in Colors
|
|
288
330
|
assert "BLUE" in Colors
|
|
289
|
-
assert Colors.BLUE.name == "BLUE"
|
|
290
|
-
assert Colors.BLUE.value == 3
|
|
291
|
-
assert Colors.BLUE == 3
|
|
292
331
|
|
|
332
|
+
class MoreColors(Colors):
|
|
333
|
+
PURPLE = 4
|
|
334
|
+
GOLD = 5
|
|
335
|
+
|
|
336
|
+
assert "RED" in MoreColors
|
|
337
|
+
assert "GREEN" in MoreColors
|
|
338
|
+
assert "BLUE" in MoreColors
|
|
293
339
|
assert "PURPLE" in MoreColors
|
|
294
|
-
assert
|
|
295
|
-
assert MoreColors.PURPLE.value == 4
|
|
296
|
-
assert MoreColors.PURPLE == 4
|
|
340
|
+
assert "GOLD" in MoreColors
|
|
297
341
|
|
|
342
|
+
# As backfilling has been enabled for the superclass, subclass options are available on
|
|
343
|
+
# both the subclass as seen above as well as on the superclass through backfilling:
|
|
344
|
+
assert "PURPLE" in Colors
|
|
298
345
|
assert "GOLD" in Colors
|
|
299
|
-
assert Colors.GOLD.name == "GOLD"
|
|
300
|
-
assert Colors.GOLD.value == 5
|
|
301
|
-
assert Colors.GOLD == 5
|
|
302
346
|
```
|
|
303
347
|
|
|
304
|
-
#### Example
|
|
348
|
+
#### Example 11: Subclassing Over
|
|
305
349
|
|
|
306
350
|
```python
|
|
307
351
|
from enumerific import Enumeration
|
|
@@ -311,29 +355,34 @@ class Colors(Enumeration):
|
|
|
311
355
|
GREEN = 2
|
|
312
356
|
BLUE = 3
|
|
313
357
|
|
|
314
|
-
|
|
315
|
-
|
|
358
|
+
assert "RED" in Colors
|
|
359
|
+
assert Colors.RED == 1
|
|
360
|
+
|
|
361
|
+
assert "GREEN" in Colors
|
|
362
|
+
assert Colors.GREEN == 2
|
|
363
|
+
|
|
364
|
+
assert "BLUE" in Colors
|
|
365
|
+
assert Colors.BLUE == 3
|
|
366
|
+
|
|
367
|
+
# Subclasses of Enumerations classes can be given the same name as the parent class, so
|
|
368
|
+
# within this scope, the subclass shadows the superclass; the subclass inherits all the
|
|
369
|
+
# enumeration options of its parent(s) superclasses:
|
|
316
370
|
class Colors(Colors):
|
|
317
371
|
PURPLE = 4
|
|
318
372
|
GOLD = 5
|
|
319
373
|
|
|
374
|
+
assert "RED" in Colors
|
|
375
|
+
assert "GREEN" in Colors
|
|
320
376
|
assert "BLUE" in Colors
|
|
321
|
-
assert Colors.BLUE.name == "BLUE"
|
|
322
|
-
assert Colors.BLUE.value == 3
|
|
323
|
-
assert Colors.BLUE == 3
|
|
324
377
|
|
|
325
378
|
assert "PURPLE" in Colors
|
|
326
|
-
assert Colors.PURPLE.name == "PURPLE"
|
|
327
|
-
assert Colors.PURPLE.value == 4
|
|
328
379
|
assert Colors.PURPLE == 4
|
|
329
380
|
|
|
330
381
|
assert "GOLD" in Colors
|
|
331
|
-
assert Colors.GOLD.name == "GOLD"
|
|
332
|
-
assert Colors.GOLD.value == 5
|
|
333
382
|
assert Colors.GOLD == 5
|
|
334
383
|
```
|
|
335
384
|
|
|
336
|
-
#### Example
|
|
385
|
+
#### Example 12: Unregistering Existing Option
|
|
337
386
|
|
|
338
387
|
```python
|
|
339
388
|
from enumerific import Enumeration
|
|
@@ -352,7 +401,26 @@ assert "GREEN" not in Colors
|
|
|
352
401
|
assert "BLUE" in Colors
|
|
353
402
|
```
|
|
354
403
|
|
|
355
|
-
#### Example
|
|
404
|
+
#### Example 13: Preventing Subclassing of Enumeration Classes
|
|
405
|
+
|
|
406
|
+
```python
|
|
407
|
+
from enumerific import Enumeration, EnumerationSubclassingError
|
|
408
|
+
import pytest
|
|
409
|
+
|
|
410
|
+
# To prevent an enumeration class from being extended through subclassing, the
|
|
411
|
+
# `subclassable` keyword argument can be set when creating the class; this will
|
|
412
|
+
# result in an `EnumerationSubclassingError` exception being raised on subclassing:
|
|
413
|
+
class Colors(Enumeration, subclassable=False):
|
|
414
|
+
RED = 1
|
|
415
|
+
GREEN = 2
|
|
416
|
+
BLUE = 3
|
|
417
|
+
|
|
418
|
+
with pytest.raises(EnumerationSubclassingError):
|
|
419
|
+
class MoreColors(Colors):
|
|
420
|
+
PURPLE = 4
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
#### Example 14: Aliasing Options
|
|
356
424
|
|
|
357
425
|
```python
|
|
358
426
|
from enumerific import Enumeration
|
|
@@ -402,7 +470,7 @@ assert Colors.GREEN.aliases == [Colors.VERTE]
|
|
|
402
470
|
assert Colors.BLUE.aliases == [] # BLUE has not been aliased
|
|
403
471
|
```
|
|
404
472
|
|
|
405
|
-
#### Example
|
|
473
|
+
#### Example 15: Non-Unique Options
|
|
406
474
|
|
|
407
475
|
```python
|
|
408
476
|
from enumerific import Enumeration
|
|
@@ -441,7 +509,7 @@ assert Colors.RED == Colors.GREEN
|
|
|
441
509
|
assert Colors.BLUE != Colors.RED
|
|
442
510
|
```
|
|
443
511
|
|
|
444
|
-
#### Example
|
|
512
|
+
#### Example 16: Bit Wise Flags
|
|
445
513
|
|
|
446
514
|
```python
|
|
447
515
|
from enumerific import Enumeration
|
|
@@ -513,7 +581,7 @@ assert Permissions.DELETE in permissions
|
|
|
513
581
|
assert str(permissions) == "Permissions.READ|WRITE|DELETE"
|
|
514
582
|
```
|
|
515
583
|
|
|
516
|
-
#### Example
|
|
584
|
+
#### Example 17: Annotating Enumeration Option Values
|
|
517
585
|
|
|
518
586
|
```python
|
|
519
587
|
from enumerific import Enumeration, anno
|
|
@@ -557,7 +625,7 @@ assert Colors.PURPLE.rgb == (255, 0, 255)
|
|
|
557
625
|
assert Colors.PURPLE.primary is False
|
|
558
626
|
```
|
|
559
627
|
|
|
560
|
-
#### Example
|
|
628
|
+
#### Example 18: Annotating Enumeration Option Values with Automatic Sequencing
|
|
561
629
|
|
|
562
630
|
```python
|
|
563
631
|
from enumerific import Enumeration, auto
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
enumerific/__init__.py,sha256=K9iFirgxSkrHgXfhocOvgRkskGe0VfWRgxEvppnVWBM,587
|
|
2
|
+
enumerific/exceptions.py,sha256=lvfcH1cz43hDjzSUpgm1-OZjKzxo--fyZ8UsBS-GiZA,359
|
|
3
|
+
enumerific/extensible.py,sha256=AS9rU-luPjfau_PHFa52r-rlaDWpbxiF4qgnh4BdH9o,84320
|
|
4
|
+
enumerific/logging.py,sha256=zz1Phnot1BFWMoxwvZ0FlZDsiYZZYhz-_S4IzgPYc40,97
|
|
5
|
+
enumerific/standard.py,sha256=xQhhwlcYZ6-8DmgscbV38g2Ol5Z8_vvBwonz-Ww0I40,3254
|
|
6
|
+
enumerific/version.txt,sha256=INLLCW0atBpBQCRtEvB79rjLdD_UgSK3JTLAPUTFwUo,5
|
|
7
|
+
enumerific-1.0.3.dist-info/licenses/LICENSE.md,sha256=j1XidOCGUhPx7CyXA31uC0XGKDRnvUcZpMp161qHI6g,1077
|
|
8
|
+
enumerific-1.0.3.dist-info/METADATA,sha256=EEriXyK6TOyNDx0_juEMGnyf4h5NKP_o2JNWncNssgY,32990
|
|
9
|
+
enumerific-1.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
+
enumerific-1.0.3.dist-info/top_level.txt,sha256=hyemsMgPYZgSx71XHmFRF-gvc_2Y4rDAESR8e0hbYHU,11
|
|
11
|
+
enumerific-1.0.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
12
|
+
enumerific-1.0.3.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
enumerific/__init__.py,sha256=Qe_3I0e4a_eA4quVKz05eufYtX4soq1Ku-pnXiQxxAQ,429
|
|
2
|
-
enumerific/exceptions.py,sha256=u0-efY2ufY__DZPs56L_SblvhnFZjUb2AcMjL_AxtKw,293
|
|
3
|
-
enumerific/extensible.py,sha256=YSYyVi8oUzQuNUBmdJcqtMd-Fs15cjvMqEMHi2F4JcA,80452
|
|
4
|
-
enumerific/logging.py,sha256=zz1Phnot1BFWMoxwvZ0FlZDsiYZZYhz-_S4IzgPYc40,97
|
|
5
|
-
enumerific/standard.py,sha256=xQhhwlcYZ6-8DmgscbV38g2Ol5Z8_vvBwonz-Ww0I40,3254
|
|
6
|
-
enumerific/version.txt,sha256=v-wuNFg62n5q8stzmT-3Wj9xR6bJQ-X_X1xClPxXe5A,5
|
|
7
|
-
enumerific-1.0.2.dist-info/licenses/LICENSE.md,sha256=j1XidOCGUhPx7CyXA31uC0XGKDRnvUcZpMp161qHI6g,1077
|
|
8
|
-
enumerific-1.0.2.dist-info/METADATA,sha256=F632r_SiMpT5u4nskU8K_c4fDDxDbaOgrIoiGYZfNmA,30755
|
|
9
|
-
enumerific-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
-
enumerific-1.0.2.dist-info/top_level.txt,sha256=hyemsMgPYZgSx71XHmFRF-gvc_2Y4rDAESR8e0hbYHU,11
|
|
11
|
-
enumerific-1.0.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
12
|
-
enumerific-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|