LiteralEnum
LiteralEnum is an experiment/prototype for a proposed Python typing construct:
a finite, named set of runtime literals (usually strings) that type checkers can treat as
an exhaustive Literal[...] union.
Status: Prototype / exploration for typing-sig discussion. Not an accepted PEP.
Why this exists
In typed Python today you often have to pick one:
Enum/StrEnum: great runtime namespace, but APIs want callers to pass enum members instead of raw stringsLiteral[...]: great static checking, but no runtime namespace/iteration/validation
So people duplicate values or accept str and validate at runtime.
LiteralEnum aims to make the common case a single source of truth.
It’s designed for “protocol token” style values—HTTP methods, event names, command identifiers, config keys—where you want:
- plain literals at runtime (e.g.
"GET"), - namespaced constants (e.g.
HttpMethod.GET), and - static exhaustiveness checking (i.e. the type is equivalent to
Literal["GET", "POST", ...]).
Table of Contents
- Typing discussion with the Python community
- PEP.md is a draft PEP
- LITMUS.md describes the project goals
- TYPING_DISCUSSION.md is shows drafts from the discussion
- src/typing_literalenum.py is a the draft of the core runtime functionality (proposed to become
typing.LiteralEnumortyping_extensions.LiteralEnum) - src/literalenum is the full proposed PyPi module
- src/literalenum/mypy_plugin.py is an experimental mypy plugin
- src/literalenum/samples shows sample usage
- src/literalenum/stubgen.py provides tools for generating stubs, usable through CLI tool
lestub
Quickstart
Install
This repo is currently set up as a package under src/.
#python -m venv .venv
#source .venv/bin/activate
pip install literalenum
Realistic Current Usage
from typing import Literal
from literalenum import LiteralEnum
HttpMethodT = Literal["GET", "POST", "DELETE"]
class HttpMethod(LiteralEnum):
GET = "GET"
POST = "POST"
DELETE = "DELETE"
def handle(method: HttpMethodT) -> None:
print(f"{method=}")
handle("GET") # this should type-check ✅
handle(HttpMethod.GET) # this should type-check ✅
handle("git") # ❌ should be rejected by a type checker
assert HttpMethod.GET == "GET"
assert list(HttpMethod) == ["GET", "POST", "DELETE"]
assert "GET" in HttpMethod
print(HttpMethod.keys())
print(HttpMethod.values())
print(HttpMethod.mapping)
Optimistic Future Usage
from typing import LiteralEnum # NOT valid right now
class HttpMethod(LiteralEnum):
GET = "GET"
POST = "POST"
DELETE = "DELETE"
def handle(method: HttpMethod) -> None:
print(f"{method=}")
handle("GET") # the GOAL is that this should type-check ✅ , in reality: it will not unless typecheckers change
handle(HttpMethod.GET) # the GOAL is that this should type-check ✅ , in reality: it will not unless typecheckers change
handle("git") # ❌ should be rejected by a type checker
assert HttpMethod.GET == "GET"
assert list(HttpMethod) == ["GET", "POST", "DELETE"]
assert "GET" in HttpMethod
print(HttpMethod.keys())
print(HttpMethod.values())
print(HttpMethod.mapping)
Contributing / discussion
Actively looking for feedback! Please comment at https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000
It would be especially helpful if you are familiar with mypy/pright/pylance and have suggestions on how a future Python version could support the type hinting goals.
License
This project is released into the public domain under The Unlicense.
You are free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
See the LICENSE file for full details.
Metadata
Release files for literalenum 0.4.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 | |
|---|---|---|---|
| literalenum-0.4.0.tar.gz | 44.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| literalenum-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 74.6 kB
Release files / literalenum-0.4.0.tar.gz
| Download URL | literalenum-0.4.0.tar.gz |
|---|---|
| Size | 44.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
774ba0c3165b7dc71d30f677548c7fc7075050b9a9171fbb352854928f6d5a56
|
|
BLAKE2b-256 checksum How to use checksums |
33483825c46b2a3ce3cdbd8d6ac33da01a29dc70b57fa1dbcec9158e6600b26f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Feb 5, 2026.
Transparency logRelease files / literalenum-0.4.0-py3-none-any.whl
| Download URL | literalenum-0.4.0-py3-none-any.whl |
|---|---|
| Size | 29.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f5253aa807358ece4dc79131bd7b638122a83764704c27054f4b6c0cc24ea133
|
|
BLAKE2b-256 checksum How to use checksums |
0b132999be3eb2b6058817c6a86ec01da571ef280814836bca5f7774e18a07c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Feb 5, 2026.
Transparency log