https://github.com/rjotanm/enumetyped
Type-containing enumeration
https://github.com/rjotanm/enumetyped
enum enumeration hints parsing pydantic python validation
Last synced: 11 months ago
JSON representation
Type-containing enumeration
- Host: GitHub
- URL: https://github.com/rjotanm/enumetyped
- Owner: rjotanm
- License: mit
- Created: 2025-01-29T08:34:37.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-13T12:20:20.000Z (about 1 year ago)
- Last Synced: 2025-03-24T05:31:04.433Z (11 months ago)
- Topics: enum, enumeration, hints, parsing, pydantic, python, validation
- Language: Python
- Homepage: https://pypi.org/project/enumetyped/
- Size: 43.9 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Enumetyped
This package provide a way to create typed enumerations.
# Install
- `pip install enumetyped`
- `pip install enumetyped[pydantic]` - install with pydantic `>=2.9`
# Quickstart
#### Without pydantic
```python
from enumetyped import TypEnum, TypEnumContent
class SimpleEnum(TypEnum[TypEnumContent]):
A: type["SimpleEnum[NoValue]"]
Int: type["SimpleEnum[int]"]
# isinstance checking
assert isinstance(SimpleEnum.A(...), SimpleEnum)
assert isinstance(SimpleEnum.Int(123), SimpleEnum.Int)
assert not isinstance(SimpleEnum.Int(123), SimpleEnum.A)
# fully pattern-matching
match SimpleEnum.Int(1):
case SimpleEnum.Int(2):
a = False
case SimpleEnum.Int(1):
a = True
case SimpleEnum.Int():
a = True
case _:
a = False
assert a
```
#### With pydantic
```python
import typing
from dataclasses import dataclass
from pydantic import BaseModel
from enumetyped import TypEnum, TypEnumContent, NoValue
from enumetyped.pydantic import TypEnumPydantic, FieldMetadata, Rename
from typing_extensions import Annotated, TypedDict
class Enum(TypEnum[NoValue]):
V1: type["Enum"]
V2: type["Enum"]
@dataclass
class TestDataClass:
a: int
class TestModel(BaseModel):
b: str
class TestTypedDict(TypedDict):
tm: TestModel
class SimpleEnum(TypEnumPydantic[NoValue]):
V1: type["SimpleEnum"]
V2: type["SimpleEnum"]
class OtherEnum(TypEnumPydantic[TypEnumContent]):
Int: type["OtherEnum[int]"]
Int: type["OtherEnum[str]"]
# class MyEnum(TypEnumPydantic[TypEnumContent], variant="key", content="value"): <- adjacently
# class MyEnum(TypEnumPydantic[TypEnumContent], variant="key"): <- internally
class MyEnum(TypEnumPydantic[TypEnumContent]): # <- externally, default
# MyEnum.Int(123)
Int: type["MyEnum[int]"]
# MyEnum.Str(123)
Str: type["MyEnum[str]"]
# MyEnum.Str(OtherEnum.Int(1))
Other: type["MyEnum[OtherEnum[Any]]"] # any from OtherEnum variants
# MyEnum.Str(MyEnum.Int(1)) | MyEnum.Str(MyEnum.Str(1))
Self: type["MyEnum[MyEnum[Any]]"] # any from self variants
# MyEnum.OnlySelf(...) - any parameters skipped, serialized just by name
NoValue: type["MyEnum[NoValue]"]
# MyEnum.OnlySelf2(None)
Optional: type["MyEnum[Optional[bool]]"]
# MyEnum.List(["1", "2", "3"])
List: type["MyEnum[list[str]]"]
# MyEnum.Dict({"key": "value"})
Dict: type["MyEnum[dict[str, str]]"]
# TypedDict: type["MyEnum[{"b": str}]"]
TypedDict: type["MyEnum[TestD]"] # python doesn`t have inline TypedDict now
# MyEnum.DC(TestDataClass(a=1))
DataClass: type["MyEnum[TestDataClass]"]
# MyEnum.Model(TestModel(b="2"))
Model: type["MyEnum[TestModel]"]
# MyEnum.StrTuple(("1", "2")))
StringTuple: Annotated[type["MyEnum[tuple[str, str]]"], FieldMetadata(rename="just_str_tuple")]
# or use enumetyped.pydantic.Rename
# StrTuple: Annotated[type["MyEnum[tuple[str, str]]"], Rename("some_other_name")]
class FinModel(BaseModel):
enum: MyEnum
def dump_and_load(e: MyEnum):
model = FinModel(enum=e)
json_ = model.model_dump_json()
print(json_)
restored = FinModel.model_validate_json(json_)
assert model == restored
# externally -> {"enum":{"Int":1}}
# adjacently -> {"enum":{"key":"Int","value":1}}
# internally -> not supported
dump_and_load(MyEnum.Int(1))
# externally -> {"enum":{"Str":"str"}}
# adjacently -> {"enum":{"key":"Str","value":"str"}}
# internally -> not supported
dump_and_load(MyEnum.Str("str"))
# externally -> {"enum":{"List":["list"]}}
# adjacently -> {"enum":{"key":"List","value":["list"]}}
# internally -> not supported
dump_and_load(MyEnum.List(["list"]))
# externally -> {"enum":{"just_str_tuple":["str","str2"]}}
# adjacently -> {"enum":{"key":"just_str_tuple","value":["str","str2"]}}
# internally -> not supported
dump_and_load(MyEnum.StringTuple(("str", "str2")))
# externally -> {"enum":{"Self":{"Int":1}}}
# adjacently -> {"enum":{"key":"Self","value":{"key":"Int","value":1}}}
# internally -> not supported
dump_and_load(MyEnum.Self(MyEnum.Int(1)))
# externally -> {"enum":{"DC":{"a":1}}}
# adjacently -> {"enum":{"key":"DC","value":{"a":1}}}
# internally -> {"enum":{"key":"DC","a":1}}}
dump_and_load(MyEnum.DataClass(TestDataClass(a=1)))
# externally -> {"enum":{"Model":{"b":"test_model"}}}
# adjacently -> {"enum":{"key":"Model","value":{"b":"test_model"}}}
# internally -> {"enum":{"key":"Model", "b":"test_model"}}
dump_and_load(MyEnum.Model(TestModel(b="test_model")))
# externally -> {"enum":{"TypedDict":{"tm":{"b":"test_model"}}}}
# adjacently -> {"enum":{"key":"TypedDict","value":{"tm":{"b":"test_model"}}}}
# internally -> {"enum":{"key":"TypedDict","tm":{"b":"test_model"}}}
dump_and_load(MyEnum.TypedDict(TestTypedDict(tm=TestModel(b="test_model"))))
# externally -> {"enum":{"Dict":{"a":"1","b":"2"}}}
# adjacently -> {"enum":{"key":"Dict","value":{"a":"1","b":"2"}}}
# internally -> not supported
dump_and_load(MyEnum.Dict({"a": "1", "b": "2"}))
# externally -> {"enum":"NoValue"}
# adjacently -> {"enum":{"key":"NoValue"}}
# internally -> {"enum":{"key":"NoValue"}}
dump_and_load(MyEnum.NoValue(...))
# externally -> {"enum":{"Optional":null}}
# adjacently -> {"enum":{"key":"Optional","value":null}}
# internally -> not supported
dump_and_load(MyEnum.Optional(None))
```
#### Other
- [Compatibility](docs/compatibility.md)
- [Limitations](docs/limitations.md)