literalenum 0.1.1__tar.gz → 0.2.0__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 → literalenum-0.2.0}/PKG-INFO +32 -4
  2. {literalenum-0.1.1 → literalenum-0.2.0}/README.md +31 -3
  3. {literalenum-0.1.1 → literalenum-0.2.0}/pyproject.toml +1 -1
  4. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/stubgen.py +44 -2
  5. literalenum-0.1.1/pyrightconfig.json +0 -3
  6. {literalenum-0.1.1 → literalenum-0.2.0}/.github/workflows/publish.yml +0 -0
  7. {literalenum-0.1.1 → literalenum-0.2.0}/.gitignore +0 -0
  8. {literalenum-0.1.1 → literalenum-0.2.0}/LICENSE +0 -0
  9. {literalenum-0.1.1 → literalenum-0.2.0}/LITMUS.md +0 -0
  10. {literalenum-0.1.1 → literalenum-0.2.0}/PEP.md +0 -0
  11. {literalenum-0.1.1 → literalenum-0.2.0}/TYPING_DISCUSSION.md +0 -0
  12. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/__init__.py +0 -0
  13. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/__init__.py +0 -0
  14. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/annotated.py +0 -0
  15. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/bare_class.py +0 -0
  16. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/base_model.py +0 -0
  17. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/click_choice.py +0 -0
  18. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/django_choices.py +0 -0
  19. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/enum.py +0 -0
  20. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/graphene_enum.py +0 -0
  21. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/int_enum.py +0 -0
  22. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/json_schema.py +0 -0
  23. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/literal.py +0 -0
  24. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/random_choice.py +0 -0
  25. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/regex.py +0 -0
  26. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/sqlalchemy_enum.py +0 -0
  27. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/str_enum.py +0 -0
  28. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/compatibility_extensions/strawberry_enum.py +0 -0
  29. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/literal_enum.py +0 -0
  30. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/mypy_plugin.py +0 -0
  31. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/py.typed +0 -0
  32. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/samples/__init__.py +0 -0
  33. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/samples/http.py +0 -0
  34. {literalenum-0.1.1 → literalenum-0.2.0}/src/literalenum/samples/http.pyi +0 -0
  35. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/__init__.py +0 -0
  36. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/a_strenum.py +0 -0
  37. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/b_str_enum.py +0 -0
  38. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/c_enum.py +0 -0
  39. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/d_literal.py +0 -0
  40. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/e_literal_plus_namespace.py +0 -0
  41. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/f_literal_hack.py +0 -0
  42. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/g_custom_type.py +0 -0
  43. {literalenum-0.1.1 → literalenum-0.2.0}/src/sample_str_enum_solutions/h_custom_literal_namespace.py +0 -0
  44. {literalenum-0.1.1 → literalenum-0.2.0}/src/typing_literalenum.py +0 -0
  45. {literalenum-0.1.1 → literalenum-0.2.0}/tests/test_literalenum.py +0 -0
  46. {literalenum-0.1.1 → literalenum-0.2.0}/tests/test_typing_literalenum.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: literalenum
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: A Python typing construct that provides namespaced literal constants with advanced typing features.
5
5
  Project-URL: Homepage, https://github.com/modularizer/literalenum
6
6
  Project-URL: Repository, https://github.com/modularizer/literalenum
@@ -12,6 +12,8 @@ Keywords: python,typehinting
12
12
  Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
 
15
+ from sample_str_enum_solutions.a_strenum import HttpMethod
16
+
15
17
  # LiteralEnum
16
18
 
17
19
  **LiteralEnum** is an experiment/prototype for a proposed Python typing construct:
@@ -60,10 +62,36 @@ This repo is currently set up as a package under `src/`.
60
62
  #source .venv/bin/activate
61
63
  pip install literalenum
62
64
  ```
63
-
65
+ ## Realistic Current Usage
64
66
  ```python
67
+ from typing import Literal
65
68
  from literalenum import LiteralEnum
66
69
 
70
+ HttpMethodT = Literal["GET", "POST", "DELETE"]
71
+ class HttpMethod(LiteralEnum):
72
+ GET = "GET"
73
+ POST = "POST"
74
+ DELETE = "DELETE"
75
+
76
+ def handle(method: HttpMethodT) -> None:
77
+ print(f"{method=}")
78
+
79
+ handle("GET") # this should type-check ✅
80
+ handle(HttpMethod.GET) # this should type-check ✅
81
+ handle("git") # ❌ should be rejected by a type checker
82
+
83
+ assert HttpMethod.GET == "GET"
84
+ assert list(HttpMethod) == ["GET", "POST", "DELETE"]
85
+ assert "GET" in HttpMethod
86
+ print(HttpMethod.keys())
87
+ print(HttpMethod.values())
88
+ print(HttpMethod.mapping)
89
+ ```
90
+
91
+ ## Optimistic Future Usage
92
+ ```python
93
+ from typing import LiteralEnum # NOT valid right now
94
+
67
95
  class HttpMethod(LiteralEnum):
68
96
  GET = "GET"
69
97
  POST = "POST"
@@ -72,8 +100,8 @@ class HttpMethod(LiteralEnum):
72
100
  def handle(method: HttpMethod) -> None:
73
101
  print(f"{method=}")
74
102
 
75
- handle("GET") # should type-check
76
- handle(HttpMethod.GET) # should type-check
103
+ handle("GET") # the GOAL is that this should type-check ✅ , in reality: it will not unless typecheckers change
104
+ handle(HttpMethod.GET) # the GOAL is that this should type-check ✅ , in reality: it will not unless typecheckers change
77
105
  handle("git") # ❌ should be rejected by a type checker
78
106
 
79
107
  assert HttpMethod.GET == "GET"
@@ -1,3 +1,5 @@
1
+ from sample_str_enum_solutions.a_strenum import HttpMethod
2
+
1
3
  # LiteralEnum
2
4
 
3
5
  **LiteralEnum** is an experiment/prototype for a proposed Python typing construct:
@@ -46,10 +48,36 @@ This repo is currently set up as a package under `src/`.
46
48
  #source .venv/bin/activate
47
49
  pip install literalenum
48
50
  ```
49
-
51
+ ## Realistic Current Usage
50
52
  ```python
53
+ from typing import Literal
51
54
  from literalenum import LiteralEnum
52
55
 
56
+ HttpMethodT = Literal["GET", "POST", "DELETE"]
57
+ class HttpMethod(LiteralEnum):
58
+ GET = "GET"
59
+ POST = "POST"
60
+ DELETE = "DELETE"
61
+
62
+ def handle(method: HttpMethodT) -> None:
63
+ print(f"{method=}")
64
+
65
+ handle("GET") # this should type-check ✅
66
+ handle(HttpMethod.GET) # this should type-check ✅
67
+ handle("git") # ❌ should be rejected by a type checker
68
+
69
+ assert HttpMethod.GET == "GET"
70
+ assert list(HttpMethod) == ["GET", "POST", "DELETE"]
71
+ assert "GET" in HttpMethod
72
+ print(HttpMethod.keys())
73
+ print(HttpMethod.values())
74
+ print(HttpMethod.mapping)
75
+ ```
76
+
77
+ ## Optimistic Future Usage
78
+ ```python
79
+ from typing import LiteralEnum # NOT valid right now
80
+
53
81
  class HttpMethod(LiteralEnum):
54
82
  GET = "GET"
55
83
  POST = "POST"
@@ -58,8 +86,8 @@ class HttpMethod(LiteralEnum):
58
86
  def handle(method: HttpMethod) -> None:
59
87
  print(f"{method=}")
60
88
 
61
- handle("GET") # should type-check
62
- handle(HttpMethod.GET) # should type-check
89
+ handle("GET") # the GOAL is that this should type-check ✅ , in reality: it will not unless typecheckers change
90
+ handle(HttpMethod.GET) # the GOAL is that this should type-check ✅ , in reality: it will not unless typecheckers change
63
91
  handle("git") # ❌ should be rejected by a type checker
64
92
 
65
93
  assert HttpMethod.GET == "GET"
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
 
6
6
  [project]
7
7
  name = "literalenum"
8
- version = "0.1.1"
8
+ version = "0.2.0"
9
9
  description = "A Python typing construct that provides namespaced literal constants with advanced typing features."
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
@@ -384,9 +384,50 @@ def _parse_out_args(raw: list[str] | None) -> list[Path]:
384
384
  return uniq
385
385
 
386
386
 
387
+ def _resolve_root(raw: str) -> str:
388
+ """Resolve *raw* to a dotted module name importable by Python.
389
+
390
+ Accepts:
391
+ - A dotted import path: ``myapp.models``
392
+ - A file path: ``src/myapp/models.py``
393
+ - A directory path: ``src/myapp/``
394
+
395
+ When a file or directory is given its parent is added to ``sys.path``
396
+ so that ``importlib`` can find it.
397
+ """
398
+ import sys
399
+
400
+ p = Path(raw)
401
+
402
+ # --- file path: /some/path/module.py ---
403
+ if p.is_file() and p.suffix == ".py":
404
+ parent = str(p.parent.resolve())
405
+ if parent not in sys.path:
406
+ sys.path.insert(0, parent)
407
+ return p.stem if p.name != "__init__.py" else p.parent.name
408
+
409
+ # --- directory path: /some/path/package/ ---
410
+ if p.is_dir():
411
+ parent = str(p.parent.resolve())
412
+ if parent not in sys.path:
413
+ sys.path.insert(0, parent)
414
+ return p.name
415
+
416
+ # --- dotted import name (ensure cwd is on path) ---
417
+ cwd = str(Path.cwd())
418
+ if cwd not in sys.path:
419
+ sys.path.insert(0, cwd)
420
+ return raw
421
+
422
+
387
423
  def main() -> int:
388
424
  ap = argparse.ArgumentParser()
389
- ap.add_argument("root", help="Root import (package or module) to scan, e.g. myapp")
425
+ ap.add_argument(
426
+ "root",
427
+ help="Root to scan: a dotted import (myapp), "
428
+ "a .py file (src/myapp/models.py), "
429
+ "or a directory (src/myapp/).",
430
+ )
390
431
  ap.add_argument(
391
432
  "--out",
392
433
  action="append",
@@ -402,7 +443,8 @@ def main() -> int:
402
443
 
403
444
  write_adjacent: bool = not args.no_adjacent
404
445
  out_roots: list[Path] = _parse_out_args(args.out) if args.out else []
405
- infos = _find_literal_enums(args.root)
446
+ root = _resolve_root(args.root)
447
+ infos = _find_literal_enums(root)
406
448
 
407
449
  by_module: dict[str, list[EnumInfo]] = {}
408
450
  for e in infos:
@@ -1,3 +0,0 @@
1
- {
2
- "stubPath": "typings"
3
- }
File without changes
File without changes
File without changes
File without changes