No project description provided
Project description
NamespacedEnums
Library for defining containers within Enum Python classes.
Installation
Run
$ pip install namespaced_enums
Usage
Library provides two special descriptors for Enum classes:
EnumContainerStrictEnumContainer
as well as an additional enum-subclass:
NamespacedEnum
EnumContainer
This allows for defining arbitrary containers within Enum classes, e.g.
from enum import Enum
from namespaced_enum import EnumContainer
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
LIGHT_RED = 4
LIGHT_GREEN = 5
LIGHT_BLUE = 6
DARK_RED = 7
DARK_GREEN = 8
DARK_BLUE = 9
light_colors = EnumContainer([LIGHT_RED, LIGHT_GREEN, LIGHT_BLUE])
dark_colors = EnumContainer([DARK_RED, DARK_GREEN, DARK_BLUE])
---
>>> print(Color.RED.value in Color.light_colors) # False
>>> print(Color.DARK_BLUE.value in Color.dark_colors) # True
# Caution!
# Values within containers are of enum value types
>>> print(Color.dark_colors) # prints [7, 8, 9] and not [DARK_RED, DARK_GREEN, DARK_BLUE]!
StrictEnumContainer and NamespacedEnum
StrictEnumContainer accepts only dict containers. Using this descriptor within
a class inheriting from NamespacedEnum will enforce that the provided
dictionary contains all enum possible values:
from namespaced_enums import NamespacedEnum, StrictEnumContainer
class Food(NamespacedEnum):
spam = "spam"
eggs = "eggs"
foo = "foo"
reactions = StrictEnumContainer(
{
spam: "I like it",
eggs: "I don't like it...",
foo: "I like?",
}
)
---
>>> print(Food.reactions[Food.spam]) # "I like it"
# Caution!
# Unlike the `EnumContainer` this one converts dict keys to enums!
>>> print(list[Food.reactions.keys()]) # prints [<Food.spam: spam>, <Food.eggs: eggs>, <Food.foo: foo>]
Forgetting to provide all possible enum values within a strict container will
raise a RuntimeError:
from namespaced_enums import NamespacedEnum, StrictEnumContainer
class Food(NamespacedEnum):
spam = "spam"
eggs = "eggs"
foo = "foo"
reactions = StrictEnumContainer(
{
spam: "I like it",
eggs: "I don't like it...",
# missing foo in the dict
}
)
---
>>> # Trying to start the program raises a `RuntimeError`:
# The following Food fields do not contain all possible enum values: ['reactions']
Rationale
It's a common practice to use enums in a project as a way to denote "characteristics" of certain objects.
Consider the following example:
from enum import Enum
class DogBreed(Enum):
BULLDOG = 'bulldog'
PUG = 'pug'
SHIBA = 'shiba'
class Dog:
def __init__(self, breed: DogBreed) -> None:
self.breed = breed
@property
def size(self) -> int:
"""Returns size of the dog (in centimeters)."""
if self.breed == DogBreed.BULLDOG:
return 40
elif self.breed == DogBreed.PUG:
return 30
elif self.breed == DogBreed.SHIBA:
return 35
else: # pragma: no cover
raise ValueError(f"Unknown dog breed: {self.breed}")
The Dog.size property implementation poses a threat when it comes to further
additions to the DogBreed enum:
- programmers would have to remember to update it every time they add a new breed support. What if there are more such properties like color, weight or tail length?
- the if-elif-else chain is hard to test as the last
elseclause would require injecting some arbitrary value into theDogBreedenum during runtime in order to ensure proper coverage. In my experience, most developers would prefer to add# pragma: no coverinstead. - the size characteristic should arguably be not part of the
Dogclass as it is more specific to theDogBreedenum - theDogclass should be aware of how to retrieve that data.
That's why I decided to create a NamespacedEnum class that allows for writing
self-contained enums, that can help in maintaining the integrity of the written
code. The example above could be rewritten in a following manner:
from namespaced_enums import NamespacedEnum, StrictEnumContainer
class DogBreed(NamespacedEnum):
BULLDOG = 'bulldog'
PUG = 'pug'
SHIBA = 'shiba'
size = StrictEnumContainer({
BULLDOG: 40,
PUG: 30,
SHIBA: 35,
})
class Dog:
def __init__(self, breed: DogBreed) -> None:
self.breed = breed
@property
def size(self) -> int:
"""Returns size of the dog (in centimeters)."""
return DogBreed.size[self.breed]
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file namespaced_enums-0.0.2.tar.gz.
File metadata
- Download URL: namespaced_enums-0.0.2.tar.gz
- Upload date:
- Size: 5.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.7.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81ae175c094a7041c47b897f8f96cad4d6163bf2fc6b554358baa05f4277ede6
|
|
| MD5 |
080d16f799f05f517e6e8c656ed3c8cb
|
|
| BLAKE2b-256 |
ec1eb59c257374121d476c3a9872fc8de0377f9a87a5dcf6100a226f95344524
|