Skip to content

Commit 4b21b79

Browse files
committed
Add support for 'Optional' Data Type
1 parent bfbf7d7 commit 4b21b79

File tree

3 files changed

+27
-8
lines changed

3 files changed

+27
-8
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,21 @@
1111
## Simple Usage
1212
```py
1313
from flask import Flask
14-
from typing import List
14+
from typing import List, Optional
1515
from flask_parameter_validation import ValidateParameters, Route, Json
1616

1717
app = Flask(__name__)
1818

19+
1920
@app.route("/update/<int:id>", methods=["POST"])
2021
@ValidateParameters()
2122
def hello(
2223
id: int = Route(),
2324
username: str = Json(min_length=5, blacklist="<>"),
2425
age: int = Json(min_int=18, max_int=99),
2526
nicknames: List[str] = Json(),
26-
password_expiry: int = Json(5)
27-
):
27+
password_expiry: Optional[int] = Json(5)
28+
):
2829
return "Hello World!"
2930

3031
if __name__ == "__main__":

flask_parameter_validation/parameter_validation.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python3
22

33
import typing
44
from inspect import signature
@@ -39,6 +39,7 @@ def nested_func(**kwargs):
3939
param_type = arg.default # ie. Route(), Json()
4040
param_name = arg.name # ie. id, username
4141
param_annotation = arg.annotation or typing.Any # ie. str, int
42+
is_list_or_union = hasattr(param_annotation, "__args__")
4243
# Ensure param type is valid
4344
if param_type.__class__ not in request_inputs.keys():
4445
return self.error_function("Invalid parameter type.")
@@ -55,9 +56,15 @@ def nested_func(**kwargs):
5556
# If no default and no input, error
5657
elif user_input is None:
5758
ptype = param_type.name
58-
return self.error_function(
59+
error_response = self.error_function(
5960
f"Required {ptype} parameter '{param_name}' not given."
6061
)
62+
# If "None" is allowed in Union, then continue
63+
if is_list_or_union:
64+
if type(None) not in param_annotation.__args__:
65+
return error_response
66+
else:
67+
return error_response
6168

6269
# If typing's Any, ClassVar or Optional, don't validate type
6370
if isinstance(param_annotation, typing._SpecialForm):
@@ -68,7 +75,7 @@ def nested_func(**kwargs):
6875
else:
6976
allowed_types = []
7077
# If List or Union, get all "inner" types
71-
if hasattr(param_annotation, "__args__"):
78+
if is_list_or_union:
7279
allowed_types = param_annotation.__args__
7380
else:
7481
allowed_types = (param_annotation,)
@@ -82,6 +89,9 @@ def nested_func(**kwargs):
8289
valid = all(
8390
isinstance(i, allowed_types) for i in user_input
8491
)
92+
elif type(user_input) != list and annotation_is_list:
93+
allowed_types = [list]
94+
valid = False
8595
else:
8696
# If not list, just validate singular data type
8797
valid = isinstance(user_input, allowed_types)
@@ -96,9 +106,17 @@ def nested_func(**kwargs):
96106
f"Parameter '{param_name}' {e}"
97107
)
98108
else:
109+
if type(None) in allowed_types:
110+
allowed_types = list(allowed_types)
111+
allowed_types.remove(type(None))
112+
startphrase = "Optional parameter"
113+
else:
114+
startphrase = "Parameter"
99115
types = "/".join(t.__name__ for t in allowed_types)
116+
if annotation_is_list:
117+
types = "List[" + types + "]"
100118
return decorator_self.error_function(
101-
f"Parameter '{param_name}' should be type {types}."
119+
f"{startphrase} '{param_name}' should be type {types}."
102120
)
103121

104122
return f(**parsed_inputs)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
setup(
1313
name='Flask-Parameter-Validation',
14-
version='1.0.16',
14+
version='1.0.17',
1515
url='https://github.com/Ge0rg3/Flask-Parameter-Validation',
1616
license='MIT',
1717
author='George Omnet',

0 commit comments

Comments
 (0)