Metadata-Version: 2.4
Name: StrEnum
Version: 0.5.0
Summary: An Enum that inherits from str.
Author-email: James Sinclair <james@nurfherder.com>
Project-URL: Homepage, https://github.com/irgeek/StrEnum
Project-URL: Documentation, https://strenum.readthedocs.io/
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# StrEnum

[![Build Status](https://github.com/irgeek/StrEnum/workflows/Python%20package/badge.svg)](https://github.com/irgeek/StrEnum/actions)

StrEnum is a Python `enum.Enum` that inherits from `str` to complement
`enum.IntEnum` in the standard library. Supports python 3.7+.

## Installation

You can use [pip](https://pip.pypa.io/en/stable/) to install.

```bash
pip install StrEnum
```

## Usage

```python
from enum import auto
from strenum import StrEnum


class HttpMethod(StrEnum):
    GET = auto()
    HEAD = auto()
    POST = auto()
    PUT = auto()
    DELETE = auto()
    CONNECT = auto()
    OPTIONS = auto()
    TRACE = auto()
    PATCH = auto()


assert HttpMethod.GET == "GET"

# You can use StrEnum values just like strings:

import urllib.request

req = urllib.request.Request('https://www.python.org/', method=HttpMethod.HEAD)
with urllib.request.urlopen(req) as response:
    html = response.read()

assert len(html) == 0  # HEAD requests do not (usually) include a body
```

There are classes whose `auto()` value folds each member name to upper or lower
case:

```python
from enum import auto
from strenum import LowercaseStrEnum, UppercaseStrEnum


class Tag(LowercaseStrEnum):
    Head = auto()
    Body = auto()
    Div = auto()


assert Tag.Head == "head"
assert Tag.Body == "body"
assert Tag.Div == "div"


class HttpMethod(UppercaseStrEnum):
    Get = auto()
    Head = auto()
    Post = auto()


assert HttpMethod.Get == "GET"
assert HttpMethod.Head == "HEAD"
assert HttpMethod.Post == "POST"
```

As well as classes whose `auto()` value converts each member name to camelCase,
PascalCase, kebab-case, snake_case and MACRO_CASE:

```python
from enum import auto
from strenum import CamelCaseStrEnum, PascalCaseStrEnum
from strenum import KebabCaseStrEnum, SnakeCaseStrEnum
from strenum import MacroCaseStrEnum


class CamelTestEnum(CamelCaseStrEnum):
    OneTwoThree = auto()


class PascalTestEnum(PascalCaseStrEnum):
    OneTwoThree = auto()


class KebabTestEnum(KebabCaseStrEnum):
    OneTwoThree = auto()


class SnakeTestEnum(SnakeCaseStrEnum):
    OneTwoThree = auto()


class MacroTestEnum(MacroCaseStrEnum):
    OneTwoThree = auto()


assert CamelTestEnum.OneTwoThree == "oneTwoThree"
assert PascalTestEnum.OneTwoThree == "OneTwoThree"
assert KebabTestEnum.OneTwoThree == "one-two-three"
assert SnakeTestEnum.OneTwoThree == "one_two_three"
assert MacroTestEnum.OneTwoThree == "ONE_TWO_THREE"
```

As with any Enum you can, of course, manually assign values.

```python
from strenum import StrEnum


class Shape(StrEnum):
    CIRCLE = "Circle"


assert Shape.CIRCLE == "Circle"
```

Doing this with the case-changing classes, though, won't manipulate
values--whatever you assign is the value they end up with.

```python
from strenum import KebabCaseStrEnum


class Shape(KebabCaseStrEnum):
    CIRCLE = "Circle"


# This will raise an AssertionError because the value wasn't converted to kebab-case.
assert Shape.CIRCLE == "circle"
```

## Contributing

Pull requests are welcome. For major changes, please open an issue first to
discuss what you would like to change.

Please ensure tests pass before submitting a PR. This repository uses
[Black](https://black.readthedocs.io/en/stable/) and
[Pylint](https://www.pylint.org/) for consistency. Both can be run with
`make lint`.

## Running the tests

This project is managed with [uv](https://docs.astral.sh/uv/). Tests can be
run using `make`:

```
make test
```

This will create a virtual environment, install the module and its
development dependencies and run the tests. Alternatively you can do the same
thing directly with uv:

```
uv run pytest
uv run black --check .
uv run pylint src/strenum/*.py tests/*.py
```

## Releasing

Releases are published to PyPI by the `Release` GitHub workflow. The version
comes from the git tag, so there is nothing to edit before releasing:

```
git tag -a v0.4.16 -m "Release 0.4.16"
git push origin v0.4.16
```

The workflow runs the tests and linters, builds the sdist and wheel, checks
that their version matches the tag, and then waits for approval in the `pypi`
environment before uploading to PyPI using trusted publishing.

## License

[MIT](https://choosealicense.com/licenses/mit/)

**N.B. Starting with Python 3.11, `enum.StrEnum` is available in the standard
library. This implementation is _not_ a drop-in replacement for the standard
library implementation. Specifically, the Python devs have decided to case fold
name to lowercase by default when `auto()` is used which I think violates the
principle of least surprise.**
