microconst 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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microconst
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Library for optimizing enum constant values
5
5
  Author-email: triple-raze <weebucks2@gmail.com>
6
6
  License-Expression: MIT
@@ -128,5 +128,20 @@ assert parse_entry(order, int) == 1337
128
128
  assert Data.ORDER.parse_entry(order) == 1337
129
129
  ```
130
130
 
131
+ #### Key usage (literals)
132
+ Unique feature, it's hard to implement, so no comprasion before and after:
133
+ ```python
134
+ from microconst import key, parse_entry
135
+
136
+ class Data:
137
+ ORDER = key(Literal[1, 2, 3])
138
+
139
+ assert Data.ORDER(1) == "aa1"
140
+ # assert Data.ORDER(4) == "aa4" # Mypy error
141
+
142
+ assert Data.ORDER.parse_entry("__3") == 3
143
+ # assert Data.ORDER.parse_entry("__10") == 10 # Mypy error
144
+ ```
145
+
131
146
  ## License
132
147
  MIT
@@ -106,5 +106,20 @@ assert parse_entry(order, int) == 1337
106
106
  assert Data.ORDER.parse_entry(order) == 1337
107
107
  ```
108
108
 
109
+ #### Key usage (literals)
110
+ Unique feature, it's hard to implement, so no comprasion before and after:
111
+ ```python
112
+ from microconst import key, parse_entry
113
+
114
+ class Data:
115
+ ORDER = key(Literal[1, 2, 3])
116
+
117
+ assert Data.ORDER(1) == "aa1"
118
+ # assert Data.ORDER(4) == "aa4" # Mypy error
119
+
120
+ assert Data.ORDER.parse_entry("__3") == 3
121
+ # assert Data.ORDER.parse_entry("__10") == 10 # Mypy error
122
+ ```
123
+
109
124
  ## License
110
125
  MIT
@@ -1,5 +1,5 @@
1
- from microconst.members import create_flag as flag
2
- from microconst.members import create_key as key
1
+ from microconst.factories import create_flag as flag
2
+ from microconst.factories import create_key as key
3
3
  from microconst.types import Entry, Key
4
4
  from microconst.utils import parse_entry
5
5
 
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, overload
4
+
5
+ from typing_extensions import TypeForm
6
+
7
+ from microconst.const import unique_const_generator
8
+ from microconst.types import Key
9
+
10
+ if TYPE_CHECKING:
11
+ from microconst.types import Converter
12
+
13
+
14
+ def create_flag() -> str:
15
+ return next(unique_const_generator)
16
+
17
+
18
+ @overload
19
+ def create_key[T](converterl: Converter[T], /) -> Key[T]: ...
20
+
21
+
22
+ @overload
23
+ def create_key[T](literal: TypeForm[T], /) -> Key[T]: ...
24
+
25
+
26
+ def create_key[T](converter_or_literal: Converter[T] | TypeForm[T]) -> Key[T]:
27
+ name = next(unique_const_generator)
28
+ return Key(name, converter_or_literal)
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from typing import Literal, Self, cast, get_args, get_origin, overload
5
+
6
+ from typing_extensions import TypeForm
7
+
8
+ from microconst.utils import parse_entry
9
+
10
+ # Any type is callable, but mypy doesnt think so
11
+ # It also means you can use functions instead of types technically
12
+ type Converter[T] = Callable[[str], T]
13
+
14
+
15
+ class Key[T](str):
16
+ # Subclasses of str should define __slots__
17
+ __slots__ = ("converter",)
18
+ converter: Converter[T]
19
+
20
+ @overload
21
+ def __new__(cls, name: str, converter: Converter[T], /) -> Key[T]: ...
22
+
23
+ @overload
24
+ def __new__(cls, name: str, literal: TypeForm[T], /) -> Key[T]: ...
25
+
26
+ def __new__(cls, name: str, converter_or_literal: object) -> Key[T]:
27
+ instance = super().__new__(cls, name)
28
+
29
+ # Type forms has __call__, but it throws an exception. We will use isinstance with type insead
30
+ is_converter = isinstance(converter_or_literal, type(object))
31
+
32
+ origin = cast("object", get_origin(converter_or_literal))
33
+
34
+ if not is_converter and origin is not Literal:
35
+ msg = f"Callable or literal excepted, got {type(converter_or_literal)}"
36
+ raise TypeError(msg)
37
+
38
+ if is_converter:
39
+ instance.converter = cast("Converter[T]", converter_or_literal)
40
+ return instance
41
+
42
+ literal_values = cast("tuple[object, ...]", get_args(converter_or_literal))
43
+
44
+ for value in literal_values:
45
+ if type(value) is not type(literal_values[0]):
46
+ msg = (
47
+ "Literal should have items of only one type. "
48
+ f"Excepted {type(literal_values[0])}, found {type(value)}"
49
+ )
50
+ raise TypeError(msg)
51
+
52
+ instance.converter = cast("Converter[T]", type(literal_values[0]))
53
+
54
+ return instance
55
+
56
+ def __call__(self, value: T) -> Entry[T]:
57
+ return Entry(self.__str__(), value)
58
+
59
+ def parse_entry(self, entry: Entry[T] | str) -> T:
60
+ return parse_entry(entry, self.converter)
61
+
62
+
63
+ class Entry[T](str):
64
+ __slots__ = ("key", "value")
65
+ key: str
66
+ value: T
67
+
68
+ def __new__(cls, key: str, value: T) -> Self:
69
+ instance = super().__new__(cls, f"{key}{value}")
70
+ instance.key = key
71
+ instance.value = value
72
+ return instance
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from microconst.types import Converter
7
+
8
+
9
+ def parse_entry[T](data: str, convert: Converter[T]) -> T:
10
+ str_value = data[2:]
11
+ return convert(str_value)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microconst
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Library for optimizing enum constant values
5
5
  Author-email: triple-raze <weebucks2@gmail.com>
6
6
  License-Expression: MIT
@@ -128,5 +128,20 @@ assert parse_entry(order, int) == 1337
128
128
  assert Data.ORDER.parse_entry(order) == 1337
129
129
  ```
130
130
 
131
+ #### Key usage (literals)
132
+ Unique feature, it's hard to implement, so no comprasion before and after:
133
+ ```python
134
+ from microconst import key, parse_entry
135
+
136
+ class Data:
137
+ ORDER = key(Literal[1, 2, 3])
138
+
139
+ assert Data.ORDER(1) == "aa1"
140
+ # assert Data.ORDER(4) == "aa4" # Mypy error
141
+
142
+ assert Data.ORDER.parse_entry("__3") == 3
143
+ # assert Data.ORDER.parse_entry("__10") == 10 # Mypy error
144
+ ```
145
+
131
146
  ## License
132
147
  MIT
@@ -2,7 +2,7 @@ README.md
2
2
  pyproject.toml
3
3
  microconst/__init__.py
4
4
  microconst/const.py
5
- microconst/members.py
5
+ microconst/factories.py
6
6
  microconst/py.typed
7
7
  microconst/types.py
8
8
  microconst/utils.py
@@ -17,13 +17,15 @@ ignore = [
17
17
 
18
18
  [tool.mypy]
19
19
  exclude = ["example/"]
20
+ enable_incomplete_feature = ["TypeForm"]
21
+
20
22
  strict = true
21
23
 
22
24
  disallow_untyped_defs = true
23
25
  disallow_untyped_calls = true
24
26
  check_untyped_defs = true
25
27
 
26
- warn_return_any = true
28
+ warn_return_any = true
27
29
  disallow_any_explicit = true
28
30
  disallow_any_unimported = true
29
31
  disallow_any_decorated = true
@@ -45,7 +47,7 @@ build-backend = "setuptools.build_meta"
45
47
 
46
48
  [project]
47
49
  name = "microconst"
48
- version = "0.1.1"
50
+ version = "0.2.0"
49
51
  description = "Library for optimizing enum constant values"
50
52
 
51
53
  requires-python = ">=3.12"
@@ -0,0 +1,33 @@
1
+ from typing import Literal
2
+
3
+ from microconst import flag, key, parse_entry
4
+
5
+
6
+ def test_member_creation() -> None:
7
+ assert key(int)(10) == "aa10"
8
+
9
+ assert key(str)("hello") == "bahello"
10
+
11
+ assert key(float)(14.1) == "ca14.1"
12
+
13
+ assert flag() == "da"
14
+ assert flag() == "ea"
15
+
16
+
17
+ def test_value_extraction() -> None:
18
+ int_k = key(int)
19
+ data = int_k(123)
20
+
21
+ assert int_k.parse_entry(data) == 123
22
+
23
+ assert data.value == 123
24
+
25
+ assert parse_entry("__1.2", float) == 1.2
26
+
27
+
28
+ def test_literal_key() -> None:
29
+ int_k = key(Literal[1, 2, 3])
30
+ assert int_k(3)
31
+
32
+ str_k = key(Literal["hi", "hello", "greetings"])
33
+ assert str_k.parse_entry("__hi") == "hi"
@@ -1,18 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- from microconst.const import unique_const_generator
6
- from microconst.types import Key
7
-
8
- if TYPE_CHECKING:
9
- from microconst.types import ConverterType
10
-
11
-
12
- def create_flag() -> str:
13
- return next(unique_const_generator)
14
-
15
-
16
- def create_key[T](value_type: ConverterType[T]) -> Key[T]:
17
- name = next(unique_const_generator)
18
- return Key(name, value_type)
@@ -1,39 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Callable
4
- from typing import Self
5
-
6
- from microconst.utils import parse_entry
7
-
8
- # Any type is callable, but mypy doesnt think so
9
- # It also means you can use functions instead of types technically
10
- type ConverterType[T] = Callable[[str], T]
11
-
12
-
13
- class Key[T](str):
14
- # Subclasses of str should define __slots__
15
- __slots__ = ("type",)
16
- type: ConverterType[T]
17
-
18
- def __new__(cls, name: str, value_type: ConverterType[T]) -> Self:
19
- instance = super().__new__(cls, name)
20
- instance.type = value_type
21
- return instance
22
-
23
- def __call__(self, value: T) -> Entry[T]:
24
- return Entry(self.__str__(), value)
25
-
26
- def parse_entry(self, data: str) -> T:
27
- return parse_entry(data, self.type)
28
-
29
-
30
- class Entry[T](str):
31
- __slots__ = ("key", "value")
32
- key: str
33
- value: T
34
-
35
- def __new__(cls, key: str, value: T) -> Self:
36
- instance = super().__new__(cls, f"{key}{value}")
37
- instance.key = key
38
- instance.value = value
39
- return instance
@@ -1,11 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- if TYPE_CHECKING:
6
- from microconst.types import ConverterType
7
-
8
-
9
- def parse_entry[T](data: str, value_type: ConverterType[T]) -> T:
10
- str_value = data[2:]
11
- return value_type(str_value)
@@ -1,23 +0,0 @@
1
- from microconst import flag, key, parse_entry
2
-
3
-
4
- def test_member_creation() -> None:
5
- assert key(int)(10) == "aa10"
6
-
7
- assert key(str)("hello") == "bahello"
8
-
9
- assert key(float)(14.1) == "ca14.1"
10
-
11
- assert flag() == "da"
12
- assert flag() == "ea"
13
-
14
-
15
- def test_value_extraction() -> None:
16
- int_key = key(int)
17
- data = int_key(123)
18
-
19
- assert int_key.parse_entry(data) == 123
20
-
21
- assert data.value == 123
22
-
23
- assert parse_entry("aa1.2", float) == 1.2
File without changes