NamespacedEnums
Library for defining containers within Enum Python classes.
Installation
Run
$ pip install namespaced_enums
Using mypy? See mypy support to enable the bundled plugin.
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']
mypy support
The library ships with a mypy plugin (and a
py.typed marker). Without it, mypy sees container attributes as enum members
and rejects indexing them ("Enum" is not indexable).
Enabling the plugin
mypy does not load plugins automatically, so enabling support is two steps:
1. Install the optional dependency (requires mypy >= 1.0):
$ pip install namespaced_enums[mypy]
2. Register the plugin in your mypy configuration. Add the following to whichever config file your project uses:
mypy.ini (or the [mypy] section of setup.cfg):
[mypy]
plugins = namespaced_enums.plugin
pyproject.toml:
[tool.mypy]
plugins = ["namespaced_enums.plugin"]
That's it — no import changes are needed in your own code.
What you get
With the plugin enabled, containers are typed correctly instead of being seen as enum members:
class DogBreed(NamespacedEnum):
BULLDOG = 'bulldog'
PUG = 'pug'
SHIBA = 'shiba'
size = StrictEnumContainer({BULLDOG: 40, PUG: 30, SHIBA: 35})
reveal_type(DogBreed.size) # dict[DogBreed, int]
n: int = DogBreed.size[DogBreed.PUG] # ok, no "not indexable" error
More importantly, the plugin turns the runtime RuntimeError for an incomplete
StrictEnumContainer into a static error (error code namespaced-enum),
so a forgotten member is caught by mypy instead of at import time:
class DogBreed(NamespacedEnum):
BULLDOG = 'bulldog'
PUG = 'pug'
SHIBA = 'shiba'
size = StrictEnumContainer({BULLDOG: 40, PUG: 30})
# error: StrictEnumContainer "size" is missing keys for enum members: SHIBA [namespaced-enum]
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]
Metadata
Release files for namespaced-enums 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| namespaced_enums-0.1.0.tar.gz | 12.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| namespaced_enums-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.1 kB
Release files / namespaced_enums-0.1.0.tar.gz
| Download URL | namespaced_enums-0.1.0.tar.gz |
|---|---|
| Size | 12.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9a7dde383662d5f50ddbabff50b0e96a002b6a4fe9a13390cebbc310006fa583
|
|
BLAKE2b-256 checksum How to use checksums |
b61549f40c784c8d39b5122ce5a82fa901c2d5e3feb1d3e3a319c3ea7d22a523
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.
Transparency logRelease files / namespaced_enums-0.1.0-py3-none-any.whl
| Download URL | namespaced_enums-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c3ab6ce924f83dfc12f1564dd4f59f065dabe04fad43268914854afef7dad86
|
|
BLAKE2b-256 checksum How to use checksums |
cd47e6f2b7b9db37e14fc758e9f47e6199b46771cc54fd98496b08c32620d55b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.
Transparency logSecurity for namespaced-enums 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for namespaced_enums-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.