Say I have a generic function that can return a number of different types depending on what properties I select:
def json_parser(json_data: Dict[str, Any], property_tree: List[str]
) -> Union[Dict[str, Any], List[str], str, None]:
....
I then call this generic function with specific properties that I know will return a string.
def get_language(self, metadata_json: Dict[str, Any]) -> str:
return json_parser(metadata_json, ["volumeInfo", "language"])
I get the following error when running Mypy.
error: Incompatible return value type (got "Union[Dict[str, Any], List[str], str, None]", expected "List[str]") [return-value]
From my understanding, this is because Mypy doesn't know to expect a string. What is the best way of handling this?
You've got two options, depending on how careful you want to be.
First, typing.cast
is a function that takes a type and a value and... magically makes the value have that type. At runtime it's defined as
def cast(ty, value):
return value
but type-checkers are instructed to treat it as some magic black box. You could write
from typing import cast
...
return cast(str, json_parser(metadata_json, ["volumeInfo", "language"]))
and your type checker will simply accept the reality that the value is a str
. This is not checked at runtime. If you made a mistake and that turned out to be a dictionary or something else, cast
will let it pass, and your beautiful statically-typed code will fail with a type error at runtime.
That leads us to our second option: assertions. Mypy and other type checkers understand assertions, if statements, and other constructs, and they also understand isinstance
. So if you can convince Mypy that you've done your due diligence, it will accept your type outright.
result = json_parser(metadata_json, ["volumeInfo", "language"])
assert isinstance(result, str)
return result # Accepted as str by mypy
or
result = json_parser(metadata_json, ["volumeInfo", "language"])
if isinstance(result, str):
return result # Accepted as str by mypy
else:
raise SomeSpecificError(...)
This is checked at runtime. If someone hands you bad data or you made a mistake, you'll get a runtime error, which is better than nothing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With