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 CHANGED
@@ -2,7 +2,14 @@ from enum import *
2
2
 
3
3
  from .logging import logger
4
4
 
5
- from .exceptions import EnumValueError
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
@@ -14,5 +14,9 @@ class EnumerationSubclassingError(EnumerationError):
14
14
  pass
15
15
 
16
16
 
17
+ class EnumerationExtensibilityError(EnumerationError):
18
+ pass
19
+
20
+
17
21
  class EnumerationNonUniqueError(EnumerationError):
18
22
  pass
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 = False
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 base_configuration.subclassable is False:
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 argument 'subclassable=False' was passed to the class constructor!"
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
- self._enumerations: dict[str, Enumeration] = base_enumerations
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: list[str] = []
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.append(member)
1217
+ members.add(member)
1218
+
1219
+ for name, enumeration in self._enumerations.items():
1220
+ members.add(name)
1142
1221
 
1143
- return members
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.2
1
+ 1.0.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: enumerific
3
- Version: 1.0.2
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 redefining enumeration options;
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 Option
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 MoreColors.PURPLE.name == "PURPLE"
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 10: Subclassing Over
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
- # Subclassed Enumerations can have the same name as the parent class
315
- # The subclass will inherit the enumeration options of its parent
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 11: Unregistering Existing Option
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 12: Aliasing Options
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 13: Non-Unique Options
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 14: Bit Wise Flags
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 15: Annotating Enumeration Option Values
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 16: Annotating Enumeration Option Values with Automatic Sequencing
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,,