mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 06:23:38 +00:00
docs: Add documentation on mypy @overload.
We only use this in a few places, but they're really important places for understanding the types in the codebase, and so it's worth having a bit of expository documentation explaining how we use it. (And I expect we'll add more with time).
This commit is contained in:
@@ -148,6 +148,42 @@ because a list can have many elements, which would make the output too large.
|
||||
Similarly in dicts, one key's type and the corresponding value's type are printed.
|
||||
So `{1: 'a', 2: 'b', 3: 'c'}` will be printed as `{int: str, ...}`.
|
||||
|
||||
## Using @overload to accurately describe variations
|
||||
|
||||
Sometimes, a function's type is most precisely expressed as a few
|
||||
possibilites, and which possibility can be determined by looking at
|
||||
the arguments. You can express that idea in a way mypy understands
|
||||
using `@overload`. For example, `check_list` returns a `Validator`
|
||||
function that verifies that an object is a list, raising an exception
|
||||
if it isn't.
|
||||
|
||||
It supports being passed a `sub_validator`, which will verify that
|
||||
each element in the list has a given type as well. One can express
|
||||
the idea "If `sub_validator` validates that something is a `ResultT`,
|
||||
`check_list(sub_validator)` validators that something is a
|
||||
`List[ResultT]` as follows:
|
||||
|
||||
~~~ py
|
||||
@overload
|
||||
def check_list(sub_validator: None, length: Optional[int]=None) -> Validator[List[object]]:
|
||||
...
|
||||
@overload
|
||||
def check_list(sub_validator: Validator[ResultT],
|
||||
length: Optional[int]=None) -> Validator[List[ResultT]]:
|
||||
...
|
||||
def check_list(sub_validator: Optional[Validator[ResultT]]=None,
|
||||
length: Optional[int]=None) -> Validator[List[ResultT]]:
|
||||
~~~
|
||||
|
||||
The first overload expresses the types for the case where no
|
||||
`sub_validator` is passed, in which case all we know is that it
|
||||
returns a `Validator[List[object]]`; whereas the second defines the
|
||||
type logic for the case where we are passed a `sub_validator`.
|
||||
|
||||
See the [mypy overloading documentation][mypy-overloads] for more details.
|
||||
|
||||
[mypy-overloads]: https://mypy.readthedocs.io/en/stable/more_types.html#function-overloading
|
||||
|
||||
## Troubleshooting advice
|
||||
|
||||
All of our linters, including mypy, are designed to only check files
|
||||
|
||||
@@ -137,7 +137,10 @@ class _REQ(Generic[ResultT]):
|
||||
# functions using has_request_variables. In reality, REQ returns an
|
||||
# instance of class _REQ to enable the decorator to scan the parameter
|
||||
# list for _REQ objects and patch the parameters as the true types.
|
||||
|
||||
#
|
||||
# See also this documentation to learn how @overload helps here.
|
||||
# https://zulip.readthedocs.io/en/latest/testing/mypy.html#using-overload-to-accurately-describe-variations
|
||||
#
|
||||
# Overload 1: converter
|
||||
@overload
|
||||
def REQ(
|
||||
|
||||
@@ -186,6 +186,7 @@ def check_none_or(sub_validator: Validator[ResultT]) -> Validator[ResultT]:
|
||||
return sub_validator(var_name, val)
|
||||
return f
|
||||
|
||||
# https://zulip.readthedocs.io/en/latest/testing/mypy.html#using-overload-to-accurately-describe-variations
|
||||
@overload
|
||||
def check_list(sub_validator: None, length: Optional[int]=None) -> Validator[List[object]]:
|
||||
...
|
||||
@@ -220,6 +221,7 @@ def check_list(sub_validator: Optional[Validator[ResultT]]=None, length: Optiona
|
||||
return cast(List[ResultT], val)
|
||||
return f
|
||||
|
||||
# https://zulip.readthedocs.io/en/latest/testing/mypy.html#using-overload-to-accurately-describe-variations
|
||||
@overload
|
||||
def check_dict(required_keys: Iterable[Tuple[str, Validator[object]]]=[],
|
||||
optional_keys: Iterable[Tuple[str, Validator[object]]]=[],
|
||||
|
||||
Reference in New Issue
Block a user