You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+84-29Lines changed: 84 additions & 29 deletions
Original file line number
Diff line number
Diff line change
@@ -7,14 +7,13 @@ A pure python (no special compiler required) type enforcer for type annotations.
7
7
8
8
# Setup
9
9
10
-
Make sure you have Python 3.10.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/).
10
+
Make sure you have Python 3.11.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/).
11
11
12
12
- Unsupported python versions can be used, however newer features will not be available.
13
13
- For 3.7: use type_enforced==0.0.16 (only very basic type checking is supported)
14
14
- For 3.8: use type_enforced==0.0.16 (only very basic type checking is supported)
15
15
- For 3.9: use type_enforced<=1.9.0 (`staticmethod`, union with `|` and `from __future__ import annotations` typechecking are not supported)
16
-
- Other notes:
17
-
- For python 3.10: `from __future__ import annotations` may cause errors (EG: when using staticmethods and classmethods)
16
+
- For 3.10: use type_enforced<=10.2.0 (`from __future__ import annotations` may cause errors (EG: when using staticmethods and classmethods))
18
17
19
18
### Installation
20
19
@@ -27,23 +26,45 @@ pip install type_enforced
27
26
import type_enforced
28
27
29
28
@type_enforced.Enforcer(enabled=True)
30
-
defmy_fn(a: int , b: [int, str]=2, c: int=3) -> None:
29
+
defmy_fn(a: int , b: int|str=2, c: int=3) -> None:
31
30
pass
32
31
```
33
32
- Note: `enabled=True` by default if not specified. You can set `enabled=False` to disable type checking for a specific function, method, or class. This is useful for a production vs debugging environment or for undecorating a single method in a larger wrapped class.
34
33
35
-
# Getting Started
34
+
##Getting Started
36
35
37
36
`type_enforcer` contains a basic `Enforcer` wrapper that can be used to enforce many basic python typing hints. [Technical Docs Here](https://connor-makowski.github.io/type_enforced/type_enforced/enforcer.html).
38
37
39
-
`type_enforcer` currently supports many single and multi level python types. This includes class instances and classes themselves. For example, you can force an input to be an `int`, a number `[int, float]`, an instance of the self defined `MyClass`, or a even a vector with `list[int]`. Items like `typing.List`, `typing.Dict`, `typing.Union` and `typing.Optional` are supported.
38
+
`type_enforcer` currently supports many single and multi level python types. This includes class instances and classes themselves. For example, you can force an input to be an `int`, a number `int | float`, an instance of the self defined `MyClass`, or a even a vector with `list[int]`. Items like `typing.List`, `typing.Dict`, `typing.Union` and `typing.Optional` are supported.
40
39
41
-
You can pass union types to validate one of multiple types. For example, you could validate an input was an int or a float with `[int, float]`, `[int | float]` or even`typing.Union[int, float]`.
40
+
You can pass union types to validate one of multiple types. For example, you could validate an input was an int or a float with `int| float` or `typing.Union[int, float]`.
42
41
43
42
Nesting is allowed as long as the nested items are iterables (e.g. `typing.List`, `dict`, ...). For example, you could validate that a list is a vector with `list[int]` or possibly `typing.List[int]`.
44
43
45
44
Variables without an annotation for type are not enforced.
46
45
46
+
## What changed in 2.0.0?
47
+
The main changes in version 2.0.0 revolve around migrating towards the standard python typing hint process and away from the original type_enfoced type hints (as type enforced was originally created before the `|` operator was added to python).
48
+
- Support for python3.10 has been dropped.
49
+
- List based union types are no longer supported.
50
+
- For example `[int, float]` is no longer a supported type hint.
51
+
- Use `int|float` or `typing.Union[int, float]` instead.
52
+
- Dict types now require two types to be specified.
53
+
- The first type is the key type and the second type is the value type.
54
+
- For example, `dict[str, int|float]` or `dict[int, float]` are valid types.
55
+
- Tuple types now allow for `N` types to be specified.
56
+
- Each item refers to the positional type of each item in the tuple.
57
+
- Support for elipsis (`...`) is supported if you only specify two types and the second is the elipsis type.
58
+
- For example, `tuple[int, ...]` or `tuple[int|str, ...]` are valid types.
59
+
- Note: Unions between two tuples are not supported.
60
+
- For example, `tuple[int, str] | tuple[str, int]` will not work.
61
+
- Constraints and Literals can now be stacked with unions.
62
+
- For example, `int | Constraint(ge=0) | Constraint(le=5)` will require any passed values to be integers that are greater than or equal to `0` and less than or equal to `5`.
63
+
- For example, `Literal['a', 'b'] | Literal[1, 2]` will require any passed values that are equal (`==`) to `'a'`, `'b'`, `1` or `2`.
64
+
- Literals now evaluate during the same time as type checking and operate as OR checks.
65
+
- For example, `int | Literal['a', 'b']` will validate that the type is an int or the value is equal to `'a'` or `'b'`.
66
+
- Constraints are still are evaluated after type checking and operate independently of the type checking.
67
+
47
68
## Supported Type Checking Features:
48
69
49
70
- Function/Method Input Typing
@@ -52,19 +73,30 @@ Variables without an annotation for type are not enforced.
52
73
- All standard python types (`str`, `list`, `int`, `dict`, ...)
53
74
- Union types
54
75
- typing.Union
55
-
-`,` separated list (e.g. `[int, float]`)
56
-
-`|` separated list (e.g. `[int | float]`)
57
76
-`|` separated items (e.g. `int | float`)
58
-
- Nested types (e.g. `dict[str]` or `list[int, float]`)
77
+
- Nested types (e.g. `dict[str, int]` or `list[int|float]`)
59
78
- Note: Each parent level must be an iterable
60
79
- Specifically a variant of `list`, `set`, `tuple` or `dict`
61
-
- Note: `dict` keys are not validated, only values
80
+
- Note: `dict` requires two types to be specified (unions count as a single type)
81
+
- The first type is the key type and the second type is the value type
82
+
- e.g. `dict[str, int|float]` or `dict[int, float]`
83
+
- Note: `list` and `set` require a single type to be specified (unions count as a single type)
84
+
- e.g. `list[int]`, `set[str]`, `list[float|str]`
85
+
- Note: `tuple` Allows for `N` types to be specified
86
+
- Each item refers to the positional type of each item in the tuple
87
+
- Support for elipsis (`...`) is supported if you only specify two types and the second is the elipsis type
88
+
- e.g. `tuple[int, ...]` or `tuple[int|str, ...]`
89
+
- Note: Unions between two tuples are not supported
90
+
- e.g. `tuple[int, str] | tuple[str, int]` will not work
62
91
- Deeply nested types are supported too:
63
92
-`dict[dict[int]]`
64
93
-`list[set[str]]`
65
94
- Many of the `typing` (package) functions and methods including:
66
95
- Standard typing functions:
67
-
- `List`, `Set`, `Dict`, `Tuple`
96
+
- `List`
97
+
- `Set`
98
+
- `Dict`
99
+
- `Tuple`
68
100
-`Union`
69
101
-`Optional`
70
102
-`Sized`
@@ -76,8 +108,16 @@ Variables without an annotation for type are not enforced.
76
108
- Only allow certain values to be passed. Operates slightly differently than other checks.
77
109
- e.g. `Literal['a', 'b']` will require any passed values that are equal (`==`) to `'a'` or `'b'`.
78
110
- This compares the value of the passed input and not the type of the passed input.
79
-
- Note: Multiple types can be passed in the same `Literal`.
80
-
- Note: Literals are evaluated after type checking occurs.
111
+
- Note: Multiple types can be passed in the same `Literal` as acceptable values.
112
+
- e.g. Literal['a', 'b', 1, 2] will require any passed values that are equal (`==`) to `'a'`, `'b'`, `1` or `2`.
113
+
- Note: If type is a `str | Literal['a', 'b']`
114
+
- The check will validate that the type is a string or the value is equal to `'a'` or `'b'`.
115
+
- This means that an input of `'c'` will pass the check since it matches the string type, but an input of `1` will fail.
116
+
- Note: If type is a `int | Literal['a', 'b']`
117
+
- The check will validate that the type is an int or the value is equal to `'a'` or `'b'`.
118
+
- This means that an input of `'c'` will fail the check, but an input of `1` will pass.
119
+
- Note: Literals stack when used with unions.
120
+
- e.g. `Literal['a', 'b'] | Literal[1, 2]` will require any passed values that are equal (`==`) to `'a'`, `'b'`, `1` or `2`.
@@ -87,7 +127,11 @@ Variables without an annotation for type are not enforced.
87
127
- This is a special type of validation that allows passed input to be validated.
88
128
- Standard and custom constraints are supported.
89
129
- This is useful for validating that a passed input is within a certain range or meets a certain criteria.
90
-
- Note: The constraint is checked after type checking occurs.
130
+
- Note: Constraints stack when used with unions.
131
+
- e.g. `int | Constraint(ge=0) | Constraint(le=5)` will require any passed values to be integers that are greater than or equal to `0` and less than or equal to `5`.
132
+
- Note: The constraint is checked after type checking occurs and operates independently of the type checking.
133
+
- This operates differently than other checks (like `Literal`) and is evaluated post type checking.
134
+
- For example, if you have an annotation of `str | Constraint(ge=0)`, this will always raise an exception since if you pass a string, it will raise on the constraint check and if you pass an integer, it will raise on the type check.
91
135
- Note: See the example below or technical [constraint](https://connor-makowski.github.io/type_enforced/type_enforced/utils.html#Constraint) and [generic constraint](https://connor-makowski.github.io/type_enforced/type_enforced/utils.html#GenericConstraint) docs for more information.
92
136
```
93
137
@@ -96,21 +140,29 @@ Variables without an annotation for type are not enforced.
96
140
```py
97
141
>>> import type_enforced
98
142
>>> @type_enforced.Enforcer
99
-
... def my_fn(a: int , b: [int, str] =2, c: int =3) -> None:
143
+
... def my_fn(a: int , b: int|str =2, c: int =3) -> None:
100
144
... pass
101
145
...
102
146
>>> my_fn(a=1, b=2, c=3)
103
147
>>> my_fn(a=1, b='2', c=3)
104
148
>>> my_fn(a='a', b=2, c=3)
105
149
Traceback (most recent call last):
106
-
File "<stdin>", line 1, in <module>
107
-
File "/home/conmak/development/personal/type_enforced/type_enforced/enforcer.py", line 85, in __call__
150
+
File "<python-input-2>", line 1, in <module>
151
+
my_fn(a='a', b=2, c=3)
152
+
~~~~~^^^^^^^^^^^^^^^^^
153
+
File "/app/type_enforced/enforcer.py", line 233, in __call__
TypeError: TypeEnforced Exception (my_fn): Type mismatch for typed variable `a`. Expected one of the following `[<class 'int'>]` but got `<class 'str'>` with value `a` instead.
114
166
```
115
167
116
168
## Nested Examples
@@ -120,15 +172,15 @@ import typing
120
172
121
173
@type_enforced.Enforcer
122
174
defmy_fn(
123
-
a: dict[dict[int, float]], # Note: dict keys are not validated, only values
175
+
a: dict[str,dict[str, int|float]], # Note: dict keys are not validated, only values
124
176
b: list[typing.Set[str]] # Could also just use set
125
177
) -> None:
126
178
returnNone
127
179
128
180
my_fn(a={'i':{'j':1}}, b=[{'x'}]) # Success
129
181
130
-
my_fn(a={'i':{'j':'k'}}, b=[{'x'}]) # Error:
131
-
# TypeError: (my_fn): Type mismatch for typed variable `a[i][j]`. Expected one of the following `[<class 'int'>]` but got `<class 'str'>` instead.
182
+
my_fn(a={'i':{'j':'k'}}, b=[{'x'}]) # Error =>
183
+
# TypeError: TypeEnforced Exception (my_fn): Type mismatch for typed variable `a['i']['j']`. Expected one of the following `[<class 'int'>, <class 'float'>]` but got `<class 'str'>` with value `k` instead.
A special helper utility is provided to get all the subclasses of a class (with delayed evaluation - so you can validate subclasses even if they were defined later or in other files).
341
+
342
+
See: [WithSubclasses](https://connor-makowski.github.io/type_enforced/type_enforced/utils.html#WithSubclasses) for more information.
0 commit comments