Let's say I have a code structure like this
from __future__ import annotations
from typing import TypedDict
class ValDict(TypedDict):
something: str
a: A
class A:
def __init__(self, x: str) -> None:
if x and isinstance(x, str):
self.x = x
else:
raise ValueError("x has to be a non-empty string")
class B:
def __init__(self, something: str, a: A) -> None:
self.something = something
if isinstance(a, A):
self.a = a
else:
raise ValueError("a has to be of type A")
@classmethod
def from_dict(cls, stuff: ValDict) -> B:
something = stuff.get('something')
a = stuff.get('a')
return cls(something, a)
and I run mypy on this, I will receive 2 errors
error: Argument 1 to "B" has incompatible type "Optional[str]"; expected "str"
error: Argument 2 to "B" has incompatible type "Optional[A]"; expected "A"
The errors are quite clear: As .get can also return None, I might not pass the correct types to the cls call in my from_dict method.
My question is how to avoid it. For the argument something I could potentially get away with modifying to
something = stuff.get('something', '')
but how would I handle the case for a? Any ideas?
I would simply drop the use of get entirely and just access the keys directly. Sure, this raises a KeyError, but the class would fail to initialize properly anyway if you pass in anything other than an instance of A.
You could have a "default instance" of A to use whenever it isn't present in stuff, but judging from your B.__init__ you don't seem to want default parameters.
So the method would become:
@classmethod
def from_dict(cls, stuff: ValDict) -> B:
something = stuff['something']
a = stuff['a']
return cls(something, a)
This way, three things can happen:
stuff has the proper keys and values -> B is initializedstuff does not have the proper keys -> KeyError on B.from_dictstuff has the proper keys, but key "a"'s value is not of the proper type -> ValueError on B.__init__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