Skip to content

Commit 6577b2b

Browse files
committed
Update MultiSource to use *args for the expected delivery types, pass **kwargs to those delivery types
1 parent 9e09847 commit 6577b2b

File tree

4 files changed

+72
-28
lines changed

4 files changed

+72
-28
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Using the `MultiSource` parameter type, parameters can be accepted from any comb
8787
@app.route("/<v>") # If accepting parameters by Route and another type, a path with and without that Route parameter must be specified
8888
@ValidateParameters()
8989
def multi_source_example(
90-
value: int = MultiSource([Route(), Query(), Json()])
90+
value: int = MultiSource(Route, Query, Json, min_int=0)
9191
)
9292
```
9393

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
from typing import Type
2+
13
from flask_parameter_validation.parameter_types.parameter import Parameter
24

35

46
class MultiSource(Parameter):
57
name = "multi_source"
68

7-
def __init__(self, sources: list[Parameter], default=None, **kwargs):
8-
self.sources = sources
9-
super().__init__(default, **kwargs)
9+
def __init__(self, *sources: list[Type[Parameter]], **kwargs):
10+
self.sources = [Source(**kwargs) for Source in sources]
11+
super().__init__(**kwargs)

flask_parameter_validation/test/test_multi_source_params.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,4 +513,42 @@ def test_multi_source_optional_union(client, source_a, source_b):
513513
assert r.json["v"] == s
514514
# Test that missing input yields error
515515
r = client.get(url)
516-
assert r.json["v"] is None
516+
assert r.json["v"] is None
517+
518+
519+
@pytest.mark.parametrize(*common_parameters)
520+
def test_multi_source_int(client, source_a, source_b):
521+
if source_a == source_b: # This shouldn't be something someone does, so we won't test for it
522+
return
523+
url = f"/ms_{source_a}_{source_b}/kwargs"
524+
for source in [source_a, source_b]:
525+
# Test that present input matching validation yields input value
526+
r = None
527+
i = 3
528+
if source == "query":
529+
r = client.get(url, query_string={"v": i})
530+
elif source == "form":
531+
r = client.get(url, data={"v": i})
532+
elif source == "json":
533+
r = client.get(url, json={"v": i})
534+
elif source == "route":
535+
r = client.get(f"{url}/{i}")
536+
assert r is not None
537+
assert "v" in r.json
538+
assert r.json["v"] == i
539+
# Test that present input failing validation yields error
540+
r = None
541+
i = -1
542+
if source == "query":
543+
r = client.get(url, query_string={"v": i})
544+
elif source == "form":
545+
r = client.get(url, data={"v": i})
546+
elif source == "json":
547+
r = client.get(url, json={"v": i})
548+
elif source == "route":
549+
r = client.get(f"{url}/{i}")
550+
assert r is not None
551+
assert "error" in r.json
552+
# Test that missing input yields error
553+
r = client.get(url)
554+
assert "error" in r.json

flask_parameter_validation/test/testing_blueprints/multi_source_blueprint.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,88 +13,86 @@ def get_multi_source_blueprint(sources, name):
1313
@param_bp.route("/required_bool", methods=["GET", "POST"])
1414
@param_bp.route("/required_bool/<v>", methods=["GET", "POST"])
1515
@ValidateParameters()
16-
def multi_source_bool(v: bool = MultiSource([sources[0](), sources[1]()])):
16+
def multi_source_bool(v: bool = MultiSource(sources[0], sources[1])):
1717
assert type(v) is bool
1818
return jsonify({"v": v})
1919

2020
@param_bp.route("/optional_bool", methods=["GET", "POST"])
2121
@param_bp.route("/optional_bool/<v>", methods=["GET", "POST"])
2222
@ValidateParameters()
23-
def multi_source_optional_bool(v: Optional[bool] = MultiSource([sources[0](), sources[1]()])):
23+
def multi_source_optional_bool(v: Optional[bool] = MultiSource(sources[0], sources[1])):
2424
return jsonify({"v": v})
2525

2626
@param_bp.route("/required_date", methods=["GET", "POST"])
2727
@param_bp.route("/required_date/<v>", methods=["GET", "POST"])
2828
@ValidateParameters()
29-
def multi_source_date(v: datetime.date = MultiSource([sources[0](), sources[1]()])):
29+
def multi_source_date(v: datetime.date = MultiSource(sources[0], sources[1])):
3030
assert type(v) is datetime.date
3131
return jsonify({"v": v.isoformat()})
3232

3333
@param_bp.route("/optional_date", methods=["GET", "POST"])
3434
@param_bp.route("/optional_date/<v>", methods=["GET", "POST"])
3535
@ValidateParameters()
36-
def multi_source_optional_date(v: Optional[datetime.date] = MultiSource([sources[0](), sources[1]()])):
36+
def multi_source_optional_date(v: Optional[datetime.date] = MultiSource(sources[0], sources[1])):
3737
return jsonify({"v": v.isoformat() if v else v})
3838

3939
@param_bp.route("/required_datetime", methods=["GET", "POST"])
4040
@param_bp.route("/required_datetime/<v>", methods=["GET", "POST"])
4141
@ValidateParameters()
42-
def multi_source_datetime(v: datetime.datetime = MultiSource([sources[0](), sources[1]()])):
42+
def multi_source_datetime(v: datetime.datetime = MultiSource(sources[0], sources[1])):
4343
assert type(v) is datetime.datetime
4444
return jsonify({"v": v.isoformat()})
4545

4646
@param_bp.route("/optional_datetime", methods=["GET", "POST"])
4747
@param_bp.route("/optional_datetime/<v>", methods=["GET", "POST"])
4848
@ValidateParameters()
49-
def multi_source_optional_datetime(v: Optional[datetime.datetime] = MultiSource([sources[0](), sources[1]()])):
49+
def multi_source_optional_datetime(v: Optional[datetime.datetime] = MultiSource(sources[0], sources[1])):
5050
return jsonify({"v": v.isoformat() if v else v})
5151

5252
@param_bp.route("/required_dict", methods=["GET", "POST"])
5353
# Route doesn't support dict parameters
5454
@ValidateParameters()
55-
def multi_source_dict(v: dict = MultiSource([sources[0](), sources[1]()])):
55+
def multi_source_dict(v: dict = MultiSource(sources[0], sources[1])):
5656
assert type(v) is dict
5757
return jsonify({"v": v})
5858

5959
@param_bp.route("/optional_dict", methods=["GET", "POST"])
6060
# Route doesn't support dict parameters
6161
@ValidateParameters()
62-
def multi_source_optional_dict(v: Optional[dict] = MultiSource([sources[0](), sources[1]()])):
62+
def multi_source_optional_dict(v: Optional[dict] = MultiSource(sources[0], sources[1])):
6363
return jsonify({"v": v})
6464

6565
@param_bp.route("/required_float", methods=["GET", "POST"])
6666
@param_bp.route("/required_float/<v>", methods=["GET", "POST"])
6767
@ValidateParameters()
68-
def multi_source_float(v: float = MultiSource([sources[0](), sources[1]()])):
68+
def multi_source_float(v: float = MultiSource(sources[0], sources[1])):
6969
assert type(v) is float
7070
return jsonify({"v": v})
7171

7272
@param_bp.route("/optional_float", methods=["GET", "POST"])
7373
@param_bp.route("/optional_float/<v>", methods=["GET", "POST"])
7474
@ValidateParameters()
75-
def multi_source_optional_float(v: Optional[float] = MultiSource([sources[0](), sources[1]()])):
75+
def multi_source_optional_float(v: Optional[float] = MultiSource(sources[0], sources[1])):
7676
return jsonify({"v": v})
7777

78-
7978
@param_bp.route("/required_int", methods=["GET", "POST"])
8079
@param_bp.route("/required_int/<v>", methods=["GET", "POST"])
8180
@ValidateParameters()
82-
def multi_source_int(v: int = MultiSource([sources[0](), sources[1]()])):
81+
def multi_source_int(v: int = MultiSource(sources[0], sources[1])):
8382
assert type(v) is int
8483
return jsonify({"v": v})
8584

8685
@param_bp.route("/optional_int", methods=["GET", "POST"])
8786
@param_bp.route("/optional_int/<v>", methods=["GET", "POST"])
8887
@ValidateParameters()
89-
def multi_source_optional_int(v: Optional[int] = MultiSource([sources[0](), sources[1]()])):
88+
def multi_source_optional_int(v: Optional[int] = MultiSource(sources[0], sources[1])):
9089
return jsonify({"v": v})
9190

92-
9391
# Only List[int] is tested here - the other existing tests for lists should be exhaustive enough to catch issues
9492
@param_bp.route("/required_list", methods=["GET", "POST"])
9593
# Route doesn't support List parameters
9694
@ValidateParameters()
97-
def multi_source_list(v: List[int] = MultiSource([sources[0](), sources[1]()])):
95+
def multi_source_list(v: List[int] = MultiSource(sources[0], sources[1])):
9896
assert type(v) is list
9997
assert len(v) > 0
10098
assert type(v[0]) is int
@@ -103,46 +101,52 @@ def multi_source_list(v: List[int] = MultiSource([sources[0](), sources[1]()])):
103101
@param_bp.route("/optional_list", methods=["GET", "POST"])
104102
# Route doesn't support List parameters
105103
@ValidateParameters()
106-
def multi_source_optional_list(v: Optional[List[int]] = MultiSource([sources[0](), sources[1]()])):
104+
def multi_source_optional_list(v: Optional[List[int]] = MultiSource(sources[0], sources[1])):
107105
return jsonify({"v": v})
108106

109107
@param_bp.route("/required_str", methods=["GET", "POST"])
110108
@param_bp.route("/required_str/<v>", methods=["GET", "POST"])
111109
@ValidateParameters()
112-
def multi_source_str(v: str = MultiSource([sources[0](), sources[1]()])):
110+
def multi_source_str(v: str = MultiSource(sources[0], sources[1])):
113111
assert type(v) is str
114112
return jsonify({"v": v})
115113

116114
@param_bp.route("/optional_str", methods=["GET", "POST"])
117115
@param_bp.route("/optional_str/<v>", methods=["GET", "POST"])
118116
@ValidateParameters()
119-
def multi_source_optional_str(v: Optional[str] = MultiSource([sources[0](), sources[1]()])):
117+
def multi_source_optional_str(v: Optional[str] = MultiSource(sources[0], sources[1])):
120118
return jsonify({"v": v})
121119

122120
@param_bp.route("/required_time", methods=["GET", "POST"])
123121
@param_bp.route("/required_time/<v>", methods=["GET", "POST"])
124122
@ValidateParameters()
125-
def multi_source_time(v: datetime.time = MultiSource([sources[0](), sources[1]()])):
123+
def multi_source_time(v: datetime.time = MultiSource(sources[0], sources[1])):
126124
assert type(v) is datetime.time
127125
return jsonify({"v": v.isoformat()})
128126

129127
@param_bp.route("/optional_time", methods=["GET", "POST"])
130128
@param_bp.route("/optional_time/<v>", methods=["GET", "POST"])
131129
@ValidateParameters()
132-
def multi_source_optional_time(v: Optional[datetime.time] = MultiSource([sources[0](), sources[1]()])):
130+
def multi_source_optional_time(v: Optional[datetime.time] = MultiSource(sources[0], sources[1])):
133131
return jsonify({"v": v.isoformat() if v else v})
134132

135133
@param_bp.route("/required_union", methods=["GET", "POST"])
136134
@param_bp.route("/required_union/<v>", methods=["GET", "POST"])
137135
@ValidateParameters()
138-
def multi_source_union(v: Union[int, str] = MultiSource([sources[0](), sources[1]()])):
136+
def multi_source_union(v: Union[int, str] = MultiSource(sources[0], sources[1])):
139137
assert type(v) is int or type(v) is str
140138
return jsonify({"v": v})
141139

142140
@param_bp.route("/optional_union", methods=["GET", "POST"])
143141
@param_bp.route("/optional_union/<v>", methods=["GET", "POST"])
144142
@ValidateParameters()
145-
def multi_source_optional_union(v: Optional[Union[int, str]] = MultiSource([sources[0](), sources[1]()])):
143+
def multi_source_optional_union(v: Optional[Union[int, str]] = MultiSource(sources[0], sources[1])):
144+
return jsonify({"v": v})
145+
146+
@param_bp.route("/kwargs", methods=["GET", "POST"])
147+
@param_bp.route("/kwargs/<v>", methods=["GET", "POST"])
148+
@ValidateParameters()
149+
def multi_source_kwargs(v: int = MultiSource(sources[0], sources[1], min_int=0)):
146150
return jsonify({"v": v})
147151

148-
return param_bp
152+
return param_bp

0 commit comments

Comments
 (0)