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

Improve type hints relating to query parameters #12411

Closed
DMRobertson opened this issue Apr 7, 2022 · 1 comment · Fixed by #12415
Closed

Improve type hints relating to query parameters #12411

DMRobertson opened this issue Apr 7, 2022 · 1 comment · Fixed by #12415
Labels
T-Task Refactoring, removal, replacement, enabling or disabling functionality, other engineering tasks.

Comments

@DMRobertson
Copy link
Contributor

The regression fixed by #12410 was not spotted because we annotated args as a Dict[str, Any] but then added args["limit"] as an int. This is fine because int is a subtype of Any.

args: Dict[str, Any] = {
"include_all_networks": "true" if include_all_networks else "false"
}
if third_party_instance_id:
args["third_party_instance_id"] = (third_party_instance_id,)
if limit:
args["limit"] = [limit]
if since_token:
args["since"] = [since_token]
try:
response = await self.client.get_json(
destination=remote_server, path=path, args=args, ignore_backoff=True
)

We pass args to get_json, which expects args: Optional[QueryArgs], which is:

QueryArgs = Dict[str, Union[str, List[str]]]

This isn't found by mypy because args: Dict[str, Any] means that we do no typechecking of the values in args.

All functions which accept args: QueryArgs forward args as the query attribute of MatrixFederationRequest. That attribute is typed more weakly as Dict[Any, Any].

query: Optional[dict] = None
"""Query arguments.
"""

The query attribute is seems to only ever be passed to encode_query_args. That expects a type similar to QueryArgs, and converts its argument list in a form that can be passed to urlencode.

def encode_query_args(args: Optional[Mapping[str, Union[str, List[str]]]]) -> bytes:
"""
Encodes a map of query arguments to bytes which can be appended to a URL.
Args:
args: The query arguments, a mapping of string to string or list of strings.
Returns:
The query arguments encoded as bytes.
"""
if args is None:
return b""
encoded_args = {}
for k, vs in args.items():
if isinstance(vs, str):
vs = [vs]
encoded_args[k] = [v.encode("utf8") for v in vs]
query_str = urllib.parse.urlencode(encoded_args, True)
return query_str.encode("utf8")

We also have a QueryParams type elsewhere, which again is only forwarded to or passed to urlencode.

# the type of the query params, to be passed into `urlencode`
QueryParamValue = Union[str, bytes, Iterable[Union[str, bytes]]]
QueryParams = Union[Mapping[str, QueryParamValue], Mapping[bytes, QueryParamValue]]

I would like to see:

  • A stronger type annotation for MatrixFederationRequest.params
  • Some unification of QueryArgs and QueryParams
  • Some kind of audit of how we pass query parameters to MatrixFederationRequest
@DMRobertson DMRobertson added the T-Task Refactoring, removal, replacement, enabling or disabling functionality, other engineering tasks. label Apr 7, 2022
@DMRobertson
Copy link
Contributor Author

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
T-Task Refactoring, removal, replacement, enabling or disabling functionality, other engineering tasks.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant