literalenum 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- literalenum-0.1.1/.github/workflows/publish.yml +45 -0
- literalenum-0.1.1/.gitignore +73 -0
- literalenum-0.1.1/LICENSE +24 -0
- literalenum-0.1.1/LITMUS.md +58 -0
- literalenum-0.1.1/PEP.md +512 -0
- literalenum-0.1.1/PKG-INFO +108 -0
- literalenum-0.1.1/README.md +94 -0
- literalenum-0.1.1/TYPING_DISCUSSION.md +177 -0
- literalenum-0.1.1/pyproject.toml +74 -0
- literalenum-0.1.1/pyrightconfig.json +3 -0
- literalenum-0.1.1/src/literalenum/__init__.py +21 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/__init__.py +15 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/annotated.py +6 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/bare_class.py +2 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/base_model.py +23 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/click_choice.py +3 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/django_choices.py +2 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/enum.py +7 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/graphene_enum.py +18 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/int_enum.py +9 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/json_schema.py +145 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/literal.py +9 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/random_choice.py +3 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/regex.py +10 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/sqlalchemy_enum.py +6 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/str_enum.py +9 -0
- literalenum-0.1.1/src/literalenum/compatibility_extensions/strawberry_enum.py +18 -0
- literalenum-0.1.1/src/literalenum/literal_enum.py +137 -0
- literalenum-0.1.1/src/literalenum/mypy_plugin.py +333 -0
- literalenum-0.1.1/src/literalenum/py.typed +0 -0
- literalenum-0.1.1/src/literalenum/samples/__init__.py +0 -0
- literalenum-0.1.1/src/literalenum/samples/http.py +109 -0
- literalenum-0.1.1/src/literalenum/samples/http.pyi +110 -0
- literalenum-0.1.1/src/literalenum/stubgen.py +438 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/__init__.py +0 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/a_strenum.py +28 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/b_str_enum.py +28 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/c_enum.py +29 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/d_literal.py +13 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/e_literal_plus_namespace.py +17 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/f_literal_hack.py +19 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/g_custom_type.py +66 -0
- literalenum-0.1.1/src/sample_str_enum_solutions/h_custom_literal_namespace.py +149 -0
- literalenum-0.1.1/src/typing_literalenum.py +670 -0
- literalenum-0.1.1/tests/test_literalenum.py +459 -0
- literalenum-0.1.1/tests/test_typing_literalenum.py +676 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v5
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.12"
|
|
15
|
+
- run: pip install -e ".[dev]" 2>/dev/null || pip install -e .
|
|
16
|
+
- run: pip install pytest
|
|
17
|
+
- run: pytest
|
|
18
|
+
|
|
19
|
+
build:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
needs: test
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
- run: pip install build
|
|
28
|
+
- run: python -m build
|
|
29
|
+
- uses: actions/upload-artifact@v4
|
|
30
|
+
with:
|
|
31
|
+
name: dist
|
|
32
|
+
path: dist/
|
|
33
|
+
|
|
34
|
+
publish:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
needs: build
|
|
37
|
+
permissions:
|
|
38
|
+
id-token: write
|
|
39
|
+
environment: pypi
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/download-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: dist
|
|
44
|
+
path: dist/
|
|
45
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# =====================
|
|
2
|
+
# Python / Build
|
|
3
|
+
# =====================
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*.pyo
|
|
7
|
+
*.pyd
|
|
8
|
+
*.so
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
wheels/
|
|
14
|
+
pip-wheel-metadata/
|
|
15
|
+
|
|
16
|
+
# =====================
|
|
17
|
+
# Virtual Environments
|
|
18
|
+
# =====================
|
|
19
|
+
.venv/
|
|
20
|
+
venv/
|
|
21
|
+
env/
|
|
22
|
+
ENV/
|
|
23
|
+
|
|
24
|
+
# =====================
|
|
25
|
+
# Tooling
|
|
26
|
+
# =====================
|
|
27
|
+
.mypy_cache/
|
|
28
|
+
.pytest_cache/
|
|
29
|
+
.ruff_cache/
|
|
30
|
+
.coverage
|
|
31
|
+
coverage.xml
|
|
32
|
+
htmlcov/
|
|
33
|
+
|
|
34
|
+
# =====================
|
|
35
|
+
# Logs / Temp
|
|
36
|
+
# =====================
|
|
37
|
+
*.log
|
|
38
|
+
*.tmp
|
|
39
|
+
*.swp
|
|
40
|
+
|
|
41
|
+
# =====================
|
|
42
|
+
# Runtime Outputs
|
|
43
|
+
# =====================
|
|
44
|
+
workspace/
|
|
45
|
+
*.annotated.py
|
|
46
|
+
annotations.json
|
|
47
|
+
report.json
|
|
48
|
+
|
|
49
|
+
# =====================
|
|
50
|
+
# Web Demo (if present)
|
|
51
|
+
# =====================
|
|
52
|
+
node_modules/
|
|
53
|
+
dist-frontend/
|
|
54
|
+
.build/
|
|
55
|
+
.cache/
|
|
56
|
+
|
|
57
|
+
# =====================
|
|
58
|
+
# Secrets / Local Config
|
|
59
|
+
# =====================
|
|
60
|
+
.env
|
|
61
|
+
.env.*
|
|
62
|
+
config.local.toml
|
|
63
|
+
*untracked*
|
|
64
|
+
|
|
65
|
+
# =====================
|
|
66
|
+
# Editors / OS
|
|
67
|
+
# =====================
|
|
68
|
+
.vscode/
|
|
69
|
+
.idea/
|
|
70
|
+
.DS_Store
|
|
71
|
+
Thumbs.db
|
|
72
|
+
|
|
73
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org/>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
1. **Namespace** for member access, e.g. `FieldType.A`
|
|
2
|
+
- ```python
|
|
3
|
+
x = HttpMethod.GET # automatically seen as having type of Literal["GET"] and value of "GET"
|
|
4
|
+
```
|
|
5
|
+
- `Literal` fails this, and I see it as `Literal`'s biggest weakness
|
|
6
|
+
2. **Raw literals accepted**: `"A"` should be an acceptable input to a param typed as `t: FieldType`
|
|
7
|
+
- ```python
|
|
8
|
+
def handle(method: HttpMethod) -> None: ...
|
|
9
|
+
handle("GET") # this should be considered OK, as though HttpMethod was synonymous with Literal["GET", "POST"]
|
|
10
|
+
```
|
|
11
|
+
- `Enum/StrEnum` fail this and I see it as their biggest weakness for SOME use cases
|
|
12
|
+
- NOTE: there are definitely times devs WANT to reject raw strings to avoid floating literals : I would not want to change `Enum/StrEnum` behavior here
|
|
13
|
+
3. **Named members accepted**: `FieldType.A` should be an acceptable input to a param typed as `t: FieldType`
|
|
14
|
+
- ```python
|
|
15
|
+
def handle(method: HttpMethod) -> None: ...
|
|
16
|
+
handle(HttpMethod.GET) # this should be considered OK, because HttpMethod.GET is JUST a raw string literal exactly "GET", and HttpMethod is synonymous with Literal["GET", "POST"]
|
|
17
|
+
```
|
|
18
|
+
- comparing an `Enum` member against a `Literal` type hint currently fails, and I think this is one thing @Randolf Sholz was trying to address with his PEP 586 amendment
|
|
19
|
+
4. **Iteration and containment**: `x in FieldType` and `for x in FieldType` should be first-class
|
|
20
|
+
- ```python
|
|
21
|
+
assert "GET" in HttpMethod # True because HttpMethod acts as an iterable of the unique values, in first-seen order
|
|
22
|
+
assert HttpMethod.GET in HttpMethod # True because HttpMethod acts as an iterable of the unique values, in first-seen order
|
|
23
|
+
```
|
|
24
|
+
- both `Literal` and `Enum` provide ways to do this, but it could be more natural (and as @beauxq suggested, even `Literal` could benefit from `in` support)
|
|
25
|
+
5. **Single source of truth**: if I have to write `"A"` more than once when defining my type, it fails this test
|
|
26
|
+
- ```python
|
|
27
|
+
class HttpMethod(LiteralEnum):
|
|
28
|
+
GET = "GET"
|
|
29
|
+
POST = "POST"
|
|
30
|
+
```
|
|
31
|
+
- user experience and readability matters
|
|
32
|
+
- single source of truth == easier to refactor/extend/edit == less error prone
|
|
33
|
+
6. **One type, not two**: most current solutions require separate variables for different parts of the functionality, which I find error-prone
|
|
34
|
+
- ```python
|
|
35
|
+
def handle(method: HttpMethod) -> None:
|
|
36
|
+
assert method in HttpMethod
|
|
37
|
+
if method == HttpMethod.GET:
|
|
38
|
+
return
|
|
39
|
+
```
|
|
40
|
+
- user experience and readability matters
|
|
41
|
+
- minimizing number of imports improves user eperience
|
|
42
|
+
- if there is one type for typehinting, another for iteration/validation, and a third for namespace, it is very easy to get confused and use the wrong one
|
|
43
|
+
7. **Serializable**: values should pass `json.`
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
Here's how the current approaches score:
|
|
47
|
+
|
|
48
|
+
| Approach | #1 Namespace | #2 Raw lit | #3 Member | #4 Iterate | #5 Single source | #6 One type that does it all |
|
|
49
|
+
|----------------------------------------|--------------|------------|-----------|------------|------------------|------------------------------|
|
|
50
|
+
| `Literal` alone | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ |
|
|
51
|
+
| `Literal` + `get_args` (@peter) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ |
|
|
52
|
+
| `StrEnum` | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ |
|
|
53
|
+
| `StrEnum` + PEP 586 amend (@Randolf) | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ |
|
|
54
|
+
| `Enum` + `ParamOf` (@Tinche) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
|
55
|
+
| `Final` class + `Literal` alias (@tmk) | ✅ | ⚠️ | ✅ | ⚠️ | ❌ | ❌ |
|
|
56
|
+
| Runtime `in` on `Literal` (@beauxq) | ❌ | ✅ | ❌ | ⚠️ | ✅ | ❌ |
|
|
57
|
+
| **LiteralEnum (proposed)** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
58
|
+
|