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.
Files changed (46) hide show
  1. literalenum-0.1.1/.github/workflows/publish.yml +45 -0
  2. literalenum-0.1.1/.gitignore +73 -0
  3. literalenum-0.1.1/LICENSE +24 -0
  4. literalenum-0.1.1/LITMUS.md +58 -0
  5. literalenum-0.1.1/PEP.md +512 -0
  6. literalenum-0.1.1/PKG-INFO +108 -0
  7. literalenum-0.1.1/README.md +94 -0
  8. literalenum-0.1.1/TYPING_DISCUSSION.md +177 -0
  9. literalenum-0.1.1/pyproject.toml +74 -0
  10. literalenum-0.1.1/pyrightconfig.json +3 -0
  11. literalenum-0.1.1/src/literalenum/__init__.py +21 -0
  12. literalenum-0.1.1/src/literalenum/compatibility_extensions/__init__.py +15 -0
  13. literalenum-0.1.1/src/literalenum/compatibility_extensions/annotated.py +6 -0
  14. literalenum-0.1.1/src/literalenum/compatibility_extensions/bare_class.py +2 -0
  15. literalenum-0.1.1/src/literalenum/compatibility_extensions/base_model.py +23 -0
  16. literalenum-0.1.1/src/literalenum/compatibility_extensions/click_choice.py +3 -0
  17. literalenum-0.1.1/src/literalenum/compatibility_extensions/django_choices.py +2 -0
  18. literalenum-0.1.1/src/literalenum/compatibility_extensions/enum.py +7 -0
  19. literalenum-0.1.1/src/literalenum/compatibility_extensions/graphene_enum.py +18 -0
  20. literalenum-0.1.1/src/literalenum/compatibility_extensions/int_enum.py +9 -0
  21. literalenum-0.1.1/src/literalenum/compatibility_extensions/json_schema.py +145 -0
  22. literalenum-0.1.1/src/literalenum/compatibility_extensions/literal.py +9 -0
  23. literalenum-0.1.1/src/literalenum/compatibility_extensions/random_choice.py +3 -0
  24. literalenum-0.1.1/src/literalenum/compatibility_extensions/regex.py +10 -0
  25. literalenum-0.1.1/src/literalenum/compatibility_extensions/sqlalchemy_enum.py +6 -0
  26. literalenum-0.1.1/src/literalenum/compatibility_extensions/str_enum.py +9 -0
  27. literalenum-0.1.1/src/literalenum/compatibility_extensions/strawberry_enum.py +18 -0
  28. literalenum-0.1.1/src/literalenum/literal_enum.py +137 -0
  29. literalenum-0.1.1/src/literalenum/mypy_plugin.py +333 -0
  30. literalenum-0.1.1/src/literalenum/py.typed +0 -0
  31. literalenum-0.1.1/src/literalenum/samples/__init__.py +0 -0
  32. literalenum-0.1.1/src/literalenum/samples/http.py +109 -0
  33. literalenum-0.1.1/src/literalenum/samples/http.pyi +110 -0
  34. literalenum-0.1.1/src/literalenum/stubgen.py +438 -0
  35. literalenum-0.1.1/src/sample_str_enum_solutions/__init__.py +0 -0
  36. literalenum-0.1.1/src/sample_str_enum_solutions/a_strenum.py +28 -0
  37. literalenum-0.1.1/src/sample_str_enum_solutions/b_str_enum.py +28 -0
  38. literalenum-0.1.1/src/sample_str_enum_solutions/c_enum.py +29 -0
  39. literalenum-0.1.1/src/sample_str_enum_solutions/d_literal.py +13 -0
  40. literalenum-0.1.1/src/sample_str_enum_solutions/e_literal_plus_namespace.py +17 -0
  41. literalenum-0.1.1/src/sample_str_enum_solutions/f_literal_hack.py +19 -0
  42. literalenum-0.1.1/src/sample_str_enum_solutions/g_custom_type.py +66 -0
  43. literalenum-0.1.1/src/sample_str_enum_solutions/h_custom_literal_namespace.py +149 -0
  44. literalenum-0.1.1/src/typing_literalenum.py +670 -0
  45. literalenum-0.1.1/tests/test_literalenum.py +459 -0
  46. 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
+