Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with "incompatible type "Optional[str]"; expected "str""?

Tags:

python

mypy

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?

like image 381
Cleb Avatar asked Nov 16 '25 14:11

Cleb


1 Answers

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 initialized
  • stuff does not have the proper keys -> KeyError on B.from_dict
  • stuff has the proper keys, but key "a"'s value is not of the proper type -> ValueError on B.__init__
like image 198
jfaccioni Avatar answered Nov 18 '25 03:11

jfaccioni



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!