fbenum


Namefbenum JSON
Version 1.0.1 PyPI version JSON
download
home_page
SummaryLibrary provides fallback enum functionality. Fully compatible with pydantic.
upload_time2024-01-18 16:40:56
maintainer
docs_urlNone
author
requires_python>=3.12
licenseMIT
keywords enum pydantic
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # FBEnum

Library provides fallback enum functionality. Fully compatible with pydantic.

It can be helpful to have a fallback value for enums, so that unknown values can be
handled gracefully. This is especially useful when working with external data sources
that may contain values that are not known at the time of writing the code.

## Installation

```bash
pip install fbenum
```

## Usage

`fbenum` provides two possible ways to use it:

- As a class mixin, which can be used to enhance any enum class
- As a pydantic validator, which can be used to validate enum values in pydantic models

### Class mixin

Class mixin can be used to enhance any enum class with fallback functionality.

```python
from enum import Enum
from fbenum.enum import FallbackEnum

@enum.unique
class MyEnum(enum.StrInt, FallbackEnum):
    __unknown_name__ = 'MISSING'

    A = 1
    B = 2

assert MyEnum(1) == MyEnum.A
assert MyEnum(44).name == 'MISSING'
assert MyEnum(44).value == 44
```

### Pydantic validator

As a pydantic validator, `fbenum` can be used to validate enum values in pydantic models.
In this cases, the enum class no longer needs to be a subclass of `FallbackEnum` or somehow
otherwise enhanced.
Two ways of using it are provided:

#### Annotated type validator

```python
from enum import Enum
from fbenum.adapter import FallbackAdapter

@enum.unique
class MyEnum(enum.StrInt):
    A = 1
    B = 2

class MyModel(BaseModel):
    value: Annotated[
        MyEnum, FallbackAdapter(unknown_name='MISSING'),
    ]

model = MyModel(value=1)
assert model.value == MyEnum.A

model = MyModel(value=44)
assert model.value.name == 'MISSING'
assert model.value.value == 44
```

#### Type wrapper

Type wrapper has restricted functionality, as it can only be used to wrap a single enum
class, and it does not support any additional arguments. However, it is more concise.

```python
from enum import Enum
from fbenum.adapter import FallbackAdapter

@enum.unique
class MyEnum(enum.StrInt):
    A = 1
    B = 2

class MyModel(BaseModel):
    value: FallbackAdapter[MyEnum]

model = MyModel(value=1)
assert model.value == MyEnum.A

model = MyModel(value=44)
assert model.value.name == 'MISSING'
assert model.value.value == 44
```


##### Or a more realistic and complex example:

```python
from enum import Enum
from fbenum.adapter import FallbackAdapter


@enum.unique
class UserStatus(enum.StrInt):
    """User status."""
    ACTIVE = 1
    INACTIVE = 2


class UserRequest(BaseModel):
    name: str
    email: str
    status: FallbackAdapter[UserStatus]


class UserResponse(BaseModel):
    name: str
    email: str
    status: FallbackAdapter[UserStatus]


def create_user(request: UserRequest) -> UserResponse:
    """Create a user."""
    # Do some stuff
    resp = ...
    return UserResponse.validate_model(resp)


def get_user(user_id: int) -> UserResponse:
    """Get a user."""
    # Do some stuff
    resp = ...
    return UserResponse.validate_model(resp)


def get_users() -> list[UserResponse]:
    """Get all users."""
    # Do some stuff
    resp = ...
    return UserResponse.validate_model(resp)


if __name__ == '__main__':
    user = create_user(
        UserRequest(
            name='John Doe',
            email='test@emaik.com',
            status=1,
        ),
    )
    # on user cretion status always will be known

    users = get_users()
    # user == [
    #     UserResponse(
    #         name='John Doe',
    #         email='test@emaik',
    #         status=1,
    #     ),
    #     UserResponse(
    #         name='Jane Doe',
    #         email='test2@emaik',
    #         status=3, # unknown status
    # ]
    # on users_getting status can be unknown, so using fallback wrapper for response
    # model will be a good idea to handle unknown values gracefully.
```

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "fbenum",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": "",
    "keywords": "enum pydantic",
    "author": "",
    "author_email": "Vadim Suharnikov <vsuharnikov@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/02/20/319b3fabc1e52c3c11f9a8d35355b1013bc6a8fcbfc3d6202161eae6cbe7/fbenum-1.0.1.tar.gz",
    "platform": null,
    "description": "# FBEnum\n\nLibrary provides fallback enum functionality. Fully compatible with pydantic.\n\nIt can be helpful to have a fallback value for enums, so that unknown values can be\nhandled gracefully. This is especially useful when working with external data sources\nthat may contain values that are not known at the time of writing the code.\n\n## Installation\n\n```bash\npip install fbenum\n```\n\n## Usage\n\n`fbenum` provides two possible ways to use it:\n\n- As a class mixin, which can be used to enhance any enum class\n- As a pydantic validator, which can be used to validate enum values in pydantic models\n\n### Class mixin\n\nClass mixin can be used to enhance any enum class with fallback functionality.\n\n```python\nfrom enum import Enum\nfrom fbenum.enum import FallbackEnum\n\n@enum.unique\nclass MyEnum(enum.StrInt, FallbackEnum):\n    __unknown_name__ = 'MISSING'\n\n    A = 1\n    B = 2\n\nassert MyEnum(1) == MyEnum.A\nassert MyEnum(44).name == 'MISSING'\nassert MyEnum(44).value == 44\n```\n\n### Pydantic validator\n\nAs a pydantic validator, `fbenum` can be used to validate enum values in pydantic models.\nIn this cases, the enum class no longer needs to be a subclass of `FallbackEnum` or somehow\notherwise enhanced.\nTwo ways of using it are provided:\n\n#### Annotated type validator\n\n```python\nfrom enum import Enum\nfrom fbenum.adapter import FallbackAdapter\n\n@enum.unique\nclass MyEnum(enum.StrInt):\n    A = 1\n    B = 2\n\nclass MyModel(BaseModel):\n    value: Annotated[\n        MyEnum, FallbackAdapter(unknown_name='MISSING'),\n    ]\n\nmodel = MyModel(value=1)\nassert model.value == MyEnum.A\n\nmodel = MyModel(value=44)\nassert model.value.name == 'MISSING'\nassert model.value.value == 44\n```\n\n#### Type wrapper\n\nType wrapper has restricted functionality, as it can only be used to wrap a single enum\nclass, and it does not support any additional arguments. However, it is more concise.\n\n```python\nfrom enum import Enum\nfrom fbenum.adapter import FallbackAdapter\n\n@enum.unique\nclass MyEnum(enum.StrInt):\n    A = 1\n    B = 2\n\nclass MyModel(BaseModel):\n    value: FallbackAdapter[MyEnum]\n\nmodel = MyModel(value=1)\nassert model.value == MyEnum.A\n\nmodel = MyModel(value=44)\nassert model.value.name == 'MISSING'\nassert model.value.value == 44\n```\n\n\n##### Or a more realistic and complex example:\n\n```python\nfrom enum import Enum\nfrom fbenum.adapter import FallbackAdapter\n\n\n@enum.unique\nclass UserStatus(enum.StrInt):\n    \"\"\"User status.\"\"\"\n    ACTIVE = 1\n    INACTIVE = 2\n\n\nclass UserRequest(BaseModel):\n    name: str\n    email: str\n    status: FallbackAdapter[UserStatus]\n\n\nclass UserResponse(BaseModel):\n    name: str\n    email: str\n    status: FallbackAdapter[UserStatus]\n\n\ndef create_user(request: UserRequest) -> UserResponse:\n    \"\"\"Create a user.\"\"\"\n    # Do some stuff\n    resp = ...\n    return UserResponse.validate_model(resp)\n\n\ndef get_user(user_id: int) -> UserResponse:\n    \"\"\"Get a user.\"\"\"\n    # Do some stuff\n    resp = ...\n    return UserResponse.validate_model(resp)\n\n\ndef get_users() -> list[UserResponse]:\n    \"\"\"Get all users.\"\"\"\n    # Do some stuff\n    resp = ...\n    return UserResponse.validate_model(resp)\n\n\nif __name__ == '__main__':\n    user = create_user(\n        UserRequest(\n            name='John Doe',\n            email='test@emaik.com',\n            status=1,\n        ),\n    )\n    # on user cretion status always will be known\n\n    users = get_users()\n    # user == [\n    #     UserResponse(\n    #         name='John Doe',\n    #         email='test@emaik',\n    #         status=1,\n    #     ),\n    #     UserResponse(\n    #         name='Jane Doe',\n    #         email='test2@emaik',\n    #         status=3, # unknown status\n    # ]\n    # on users_getting status can be unknown, so using fallback wrapper for response\n    # model will be a good idea to handle unknown values gracefully.\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Library provides fallback enum functionality. Fully compatible with pydantic.",
    "version": "1.0.1",
    "project_urls": null,
    "split_keywords": [
        "enum",
        "pydantic"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "da821bc16f7eac0aa61ed6ba368f807ddcd2dedfa6600a30c86c86a274373ae1",
                "md5": "8166f8de628533ae0acd752be9c2172c",
                "sha256": "5399582bfca2c8eb84b0836bade371f7f3408cbf23af4ec398fdc25ca98da434"
            },
            "downloads": -1,
            "filename": "fbenum-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8166f8de628533ae0acd752be9c2172c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 6996,
            "upload_time": "2024-01-18T16:40:54",
            "upload_time_iso_8601": "2024-01-18T16:40:54.924850Z",
            "url": "https://files.pythonhosted.org/packages/da/82/1bc16f7eac0aa61ed6ba368f807ddcd2dedfa6600a30c86c86a274373ae1/fbenum-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0220319b3fabc1e52c3c11f9a8d35355b1013bc6a8fcbfc3d6202161eae6cbe7",
                "md5": "cc2b2150d3596821a77561460af222ed",
                "sha256": "d2f2606dbd31318ff078a2e3cbf1bcecff6ea215d3f8ed2f626c6207dc5103ba"
            },
            "downloads": -1,
            "filename": "fbenum-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "cc2b2150d3596821a77561460af222ed",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 10201,
            "upload_time": "2024-01-18T16:40:56",
            "upload_time_iso_8601": "2024-01-18T16:40:56.690721Z",
            "url": "https://files.pythonhosted.org/packages/02/20/319b3fabc1e52c3c11f9a8d35355b1013bc6a8fcbfc3d6202161eae6cbe7/fbenum-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-18 16:40:56",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "fbenum"
}
        
Elapsed time: 0.16306s