Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 95a038c

Browse files
author
David Robertson
authored
Unify HTTP query parameter type hints (#12415)
* Pull out query param types to `synapse.http.types` * Use QueryParams everywhere * Simplify `encode_query_args` * Add annotation which would have caught #12410
1 parent 2e2d8cc commit 95a038c

File tree

6 files changed

+43
-38
lines changed

6 files changed

+43
-38
lines changed

changelog.d/12415.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve type hints related to HTTP query parameters.

synapse/federation/federation_client.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
from synapse.events import EventBase, builder
5757
from synapse.federation.federation_base import FederationBase, event_from_pdu_json
5858
from synapse.federation.transport.client import SendJoinResponse
59+
from synapse.http.types import QueryParams
5960
from synapse.types import JsonDict, UserID, get_domain_from_id
6061
from synapse.util.async_helpers import concurrently_execute
6162
from synapse.util.caches.expiringcache import ExpiringCache
@@ -154,7 +155,7 @@ async def make_query(
154155
self,
155156
destination: str,
156157
query_type: str,
157-
args: dict,
158+
args: QueryParams,
158159
retry_on_dns_fail: bool = False,
159160
ignore_backoff: bool = False,
160161
) -> JsonDict:

synapse/federation/transport/client.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
from synapse.events import EventBase, make_event_from_dict
4545
from synapse.federation.units import Transaction
4646
from synapse.http.matrixfederationclient import ByteParser
47+
from synapse.http.types import QueryParams
4748
from synapse.types import JsonDict
4849

4950
logger = logging.getLogger(__name__)
@@ -255,7 +256,7 @@ async def make_query(
255256
self,
256257
destination: str,
257258
query_type: str,
258-
args: dict,
259+
args: QueryParams,
259260
retry_on_dns_fail: bool,
260261
ignore_backoff: bool = False,
261262
prefix: str = FEDERATION_V1_PREFIX,
@@ -503,7 +504,7 @@ async def get_public_rooms(
503504
else:
504505
path = _create_v1_path("/publicRooms")
505506

506-
args: Dict[str, Any] = {
507+
args: Dict[str, Union[str, Iterable[str]]] = {
507508
"include_all_networks": "true" if include_all_networks else "false"
508509
}
509510
if third_party_instance_id:

synapse/http/client.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
BinaryIO,
2323
Callable,
2424
Dict,
25-
Iterable,
2625
List,
2726
Mapping,
2827
Optional,
@@ -72,6 +71,7 @@
7271
from synapse.api.errors import Codes, HttpResponseException, SynapseError
7372
from synapse.http import QuieterFileBodyProducer, RequestTimedOutError, redact_uri
7473
from synapse.http.proxyagent import ProxyAgent
74+
from synapse.http.types import QueryParams
7575
from synapse.logging.context import make_deferred_yieldable
7676
from synapse.logging.opentracing import set_tag, start_active_span, tags
7777
from synapse.types import ISynapseReactor
@@ -97,10 +97,6 @@
9797
# the entries can either be Lists or bytes.
9898
RawHeaderValue = Sequence[Union[str, bytes]]
9999

100-
# the type of the query params, to be passed into `urlencode`
101-
QueryParamValue = Union[str, bytes, Iterable[Union[str, bytes]]]
102-
QueryParams = Union[Mapping[str, QueryParamValue], Mapping[bytes, QueryParamValue]]
103-
104100

105101
def check_against_blacklist(
106102
ip_address: IPAddress, ip_whitelist: Optional[IPSet], ip_blacklist: IPSet
@@ -911,7 +907,7 @@ def read_body_with_max_size(
911907
return d
912908

913909

914-
def encode_query_args(args: Optional[Mapping[str, Union[str, List[str]]]]) -> bytes:
910+
def encode_query_args(args: Optional[QueryParams]) -> bytes:
915911
"""
916912
Encodes a map of query arguments to bytes which can be appended to a URL.
917913
@@ -924,13 +920,7 @@ def encode_query_args(args: Optional[Mapping[str, Union[str, List[str]]]]) -> by
924920
if args is None:
925921
return b""
926922

927-
encoded_args = {}
928-
for k, vs in args.items():
929-
if isinstance(vs, str):
930-
vs = [vs]
931-
encoded_args[k] = [v.encode("utf8") for v in vs]
932-
933-
query_str = urllib.parse.urlencode(encoded_args, True)
923+
query_str = urllib.parse.urlencode(args, True)
934924

935925
return query_str.encode("utf8")
936926

synapse/http/matrixfederationclient.py

+13-22
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
read_body_with_max_size,
6868
)
6969
from synapse.http.federation.matrix_federation_agent import MatrixFederationAgent
70+
from synapse.http.types import QueryParams
7071
from synapse.logging import opentracing
7172
from synapse.logging.context import make_deferred_yieldable, run_in_background
7273
from synapse.logging.opentracing import set_tag, start_active_span, tags
@@ -98,10 +99,6 @@
9899

99100
_next_id = 1
100101

101-
102-
QueryArgs = Dict[str, Union[str, List[str]]]
103-
104-
105102
T = TypeVar("T")
106103

107104

@@ -144,7 +141,7 @@ class MatrixFederationRequest:
144141
"""A callback to generate the JSON.
145142
"""
146143

147-
query: Optional[dict] = None
144+
query: Optional[QueryParams] = None
148145
"""Query arguments.
149146
"""
150147

@@ -165,10 +162,7 @@ def __attrs_post_init__(self) -> None:
165162

166163
destination_bytes = self.destination.encode("ascii")
167164
path_bytes = self.path.encode("ascii")
168-
if self.query:
169-
query_bytes = encode_query_args(self.query)
170-
else:
171-
query_bytes = b""
165+
query_bytes = encode_query_args(self.query)
172166

173167
# The object is frozen so we can pre-compute this.
174168
uri = urllib.parse.urlunparse(
@@ -485,10 +479,7 @@ async def _send_request(
485479
method_bytes = request.method.encode("ascii")
486480
destination_bytes = request.destination.encode("ascii")
487481
path_bytes = request.path.encode("ascii")
488-
if request.query:
489-
query_bytes = encode_query_args(request.query)
490-
else:
491-
query_bytes = b""
482+
query_bytes = encode_query_args(request.query)
492483

493484
scope = start_active_span(
494485
"outgoing-federation-request",
@@ -746,7 +737,7 @@ async def put_json(
746737
self,
747738
destination: str,
748739
path: str,
749-
args: Optional[QueryArgs] = None,
740+
args: Optional[QueryParams] = None,
750741
data: Optional[JsonDict] = None,
751742
json_data_callback: Optional[Callable[[], JsonDict]] = None,
752743
long_retries: bool = False,
@@ -764,7 +755,7 @@ async def put_json(
764755
self,
765756
destination: str,
766757
path: str,
767-
args: Optional[QueryArgs] = None,
758+
args: Optional[QueryParams] = None,
768759
data: Optional[JsonDict] = None,
769760
json_data_callback: Optional[Callable[[], JsonDict]] = None,
770761
long_retries: bool = False,
@@ -781,7 +772,7 @@ async def put_json(
781772
self,
782773
destination: str,
783774
path: str,
784-
args: Optional[QueryArgs] = None,
775+
args: Optional[QueryParams] = None,
785776
data: Optional[JsonDict] = None,
786777
json_data_callback: Optional[Callable[[], JsonDict]] = None,
787778
long_retries: bool = False,
@@ -891,7 +882,7 @@ async def post_json(
891882
long_retries: bool = False,
892883
timeout: Optional[int] = None,
893884
ignore_backoff: bool = False,
894-
args: Optional[QueryArgs] = None,
885+
args: Optional[QueryParams] = None,
895886
) -> Union[JsonDict, list]:
896887
"""Sends the specified json data using POST
897888
@@ -961,7 +952,7 @@ async def get_json(
961952
self,
962953
destination: str,
963954
path: str,
964-
args: Optional[QueryArgs] = None,
955+
args: Optional[QueryParams] = None,
965956
retry_on_dns_fail: bool = True,
966957
timeout: Optional[int] = None,
967958
ignore_backoff: bool = False,
@@ -976,7 +967,7 @@ async def get_json(
976967
self,
977968
destination: str,
978969
path: str,
979-
args: Optional[QueryArgs] = ...,
970+
args: Optional[QueryParams] = ...,
980971
retry_on_dns_fail: bool = ...,
981972
timeout: Optional[int] = ...,
982973
ignore_backoff: bool = ...,
@@ -990,7 +981,7 @@ async def get_json(
990981
self,
991982
destination: str,
992983
path: str,
993-
args: Optional[QueryArgs] = None,
984+
args: Optional[QueryParams] = None,
994985
retry_on_dns_fail: bool = True,
995986
timeout: Optional[int] = None,
996987
ignore_backoff: bool = False,
@@ -1085,7 +1076,7 @@ async def delete_json(
10851076
long_retries: bool = False,
10861077
timeout: Optional[int] = None,
10871078
ignore_backoff: bool = False,
1088-
args: Optional[QueryArgs] = None,
1079+
args: Optional[QueryParams] = None,
10891080
) -> Union[JsonDict, list]:
10901081
"""Send a DELETE request to the remote expecting some json response
10911082
@@ -1150,7 +1141,7 @@ async def get_file(
11501141
destination: str,
11511142
path: str,
11521143
output_stream,
1153-
args: Optional[QueryArgs] = None,
1144+
args: Optional[QueryParams] = None,
11541145
retry_on_dns_fail: bool = True,
11551146
max_size: Optional[int] = None,
11561147
ignore_backoff: bool = False,

synapse/http/types.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2022 The Matrix.org Foundation C.I.C.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
from typing import Iterable, Mapping, Union
16+
17+
# the type of the query params, to be passed into `urlencode` with `doseq=True`.
18+
QueryParamValue = Union[str, bytes, Iterable[Union[str, bytes]]]
19+
QueryParams = Union[Mapping[str, QueryParamValue], Mapping[bytes, QueryParamValue]]
20+
21+
__all__ = ["QueryParams"]

0 commit comments

Comments
 (0)