Skip to main content

Data Enums

Build Status Coverage: 10%0 PyPI version

An alternative to the built-in Python enum implementation. Supports Python 3.11+, including free-threaded Python (3.14t).

Data enums allow you to:

  • Define enum members with associated data using type hints
  • Enforce unique constraints on attributes
  • Look up members by name or unique attribute values
  • Filter members by any attribute
  • Use pure enums without any data attributes

Usage

Install via PyPI:

pip install data-enum

Basic example

from typing import Annotated

from data_enum import DataEnum, UNIQUE, UniqueTogether

class Currency(DataEnum):
    __members__ = ("USD", "EUR", "GBP")

    symbol: str
    name: str
    code: Annotated[str, UNIQUE]

Currency.USD = Currency(symbol="$", name="US Dollar", code="USD")
Currency.EUR = Currency(symbol="€", name="Euro", code="EUR")
Currency.GBP = Currency(symbol="£", name="Pound Sterling", code="GBP")

Access data on members

Currency.USD.name      # 'US Dollar'
Currency.EUR.symbol    # '€'
str(Currency.USD)      # 'USD'
repr(Currency.USD)     # 'Currency.USD'

Look up members by name

Currency.get("USD")                          # Currency.USD
Currency.get("MISSING", default=None)        # None
Currency.get("MISSING", default=Currency.USD)  # Currency.USD

Look up by unique attribute

Currency.get(code="EUR")                          # Currency.EUR
Currency.get(code="MISSING", default=Currency.USD)  # Currency.USD

Filter by any attribute

Currency.filter(symbol="$")  # frozenset({Currency.USD})
Currency.filter(symbol="₿")  # frozenset()

Compare and hash

Currency.USD == Currency.EUR  # False
Currency.USD == Currency.USD  # True

{Currency.USD, Currency.EUR}  # works in sets
{Currency.USD: "dollar"}      # works as dict keys

Default values

Use standard Python default syntax to make attributes optional:

class Currency(DataEnum):
    __members__ = ("USD", "EUR", "GBP")

    symbol: str
    name: str
    code: Annotated[str, UNIQUE]
    active: bool = True

Currency.USD = Currency(symbol="$", name="US Dollar", code="USD")           # active=True
Currency.EUR = Currency(symbol="€", name="Euro", code="EUR", active=False)  # active=False

Defaults work with Annotated types too:

tag: Annotated[str, UNIQUE] = "none"

Unique-together constraints

Use UniqueTogether("group_name") to enforce that a combination of attributes is unique:

class State(DataEnum):
    __members__ = ("CA_US", "TX_US", "ON_CA", "BC_CA")

    country: Annotated[str, UniqueTogether("location")]
    code: Annotated[str, UniqueTogether("location")]
    name: str

State.CA_US = State(country="US", code="CA", name="California")
State.TX_US = State(country="US", code="TX", name="Texas")
State.ON_CA = State(country="CA", code="ON", name="Ontario")
State.BC_CA = State(country="CA", code="BC", name="British Columbia")

Individual attributes can repeat (country="US" appears twice), but the combination must be unique. Look up by passing all group attributes to get():

State.get(country="US", code="CA")  # State.CA_US
State.get(country="CA", code="ON")  # State.ON_CA

UniqueTogether works alongside UNIQUE and defaults:

class Place(DataEnum):
    __members__ = ("A", "B")

    country: Annotated[str, UniqueTogether("location")]
    code: Annotated[str, UniqueTogether("location")]
    full_name: Annotated[str, UNIQUE]
    active: bool = True

Type checker support

DataEnum uses PEP 681 (@dataclass_transform) so type checkers (mypy, pyright, ty) understand the constructor signature generated from your annotations:

Currency(symbol="$", name="US Dollar", code="USD")  # type checker knows these kwargs
Currency(symbol="$")                                  # type checker flags missing args

No-data enums

class Direction(DataEnum):
    __members__ = ("NORTH", "SOUTH", "EAST", "WEST")

Direction.NORTH = Direction()
Direction.SOUTH = Direction()
Direction.EAST = Direction()
Direction.WEST = Direction()

All members (in declaration order)

Currency.members  # (Currency.USD, Currency.EUR, Currency.GBP)

Thread safety

DataEnum is safe for use with free-threaded Python (3.14t, no-GIL). All runtime operations — get(), filter(), attribute access, iteration — are read-only on frozen data structures. Define your enum members at module load time (the normal usage pattern), and they are safe to access concurrently from any number of threads.

Safety

Members are immutable:

Currency.USD.name = "Bitcoin"  # raises AttributeError

Duplicate unique values are rejected:

Currency.GBP = Currency(symbol="£", name="Pound", code="EUR")  # raises ConfigurationError

All declared members must be assigned before use:

class Color(DataEnum):
    __members__ = ("RED", "BLUE")
    name: str

Color.RED = Color(name="Red")
Color.get("RED")  # raises ConfigurationError (BLUE not yet assigned)

Development

Set up the development environment:

make setup
source .venv/bin/activate

Run the full pipeline:

make
Task Command
Full pipeline make (sync, configure, format, lint, check, test)
Format make format
Lint make lint (format first!)
Type check make check
Test make test

License

Licensed under the Apache License, Version 2.0.

Metadata

Release files for data-enum 3.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for data-enum 3.0.1
File Size Uploaded Provenance
data_enum-3.0.1.tar.gz 15.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for data-enum 3.0.1
File Interpreter ABI Platform
data_enum-3.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 31.5 kB

Release files / data_enum-3.0.1.tar.gz

Download URL data_enum-3.0.1.tar.gz
Size 15.5 kB
Tags Source
SHA-256 checksum
How to use checksums
7933241ffee842c48eeaca7f04c4760290a910d39fbc8e6ee903f13f94b0c4e9
BLAKE2b-256 checksum
How to use checksums
6003f08db10184860db285a9a9d6668601e4524e7c7131b4ac0b208f3b6a22f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / data_enum-3.0.1-py3-none-any.whl

Download URL data_enum-3.0.1-py3-none-any.whl
Size 16.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3e0032086381f5d5944e152ce5881af6847a77844991b86bb6042f471ee742e
BLAKE2b-256 checksum
How to use checksums
24fcb486cb6b1a383d729141620f41cc7d94bbaf0faf79142bbd9321071d23c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Security for data-enum 3.0.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page