Recently Pylance has started to add red underlines in my code. I've managed to fix most of it, but I have problems with Optional
typing:
def realms(testenv:str, active:bool=True) -> Optional[Dict]:
""" return a dict of active/inactive realms with info from keycloak, on error return None """
dat = api(testenv, endpoint="/admin/realms")
:
all_realms = list(realms(testenv, active=False).keys())
------
Pylance says:
"keys" is not a known attribute of "None"
If I change the def
prototype to:
def realms(testenv:str, active:bool=True) -> Dict:
I get small issues with return None
I can fix with raise exceptions, or just remove it.
The code workaround can be a two-liner:
all_realms_dict = realms(testenv, active=False)
all_realms = list(all_realms_dict.keys()) if all_realms_dict else []
Should I stop using Optional
and switch to raising exceptions? Is returning None
a bad idea?
Since realms()
can return a dict
or None
, Pylance is correct to point out that in case it ever returns None
you will be in trouble due to calling .keys()
on it. So you have three options:
Always return a dict
(get rid of the Optional
in the return type) and on error return an empty dict {}
but then there will be no difference between an error and an empty result, which might be a concern.
Always return Dict but raise an exception in realms()
on errors and catch it in the caller (probably the most Pythonic way)
Keep returning None on errors but check for it in the calling function before doing .keys()
on it.
Example for option 3:
r = realms(testenv, active=False)
if r is None:
# handle error somehow
else:
all_realms = list(r.keys())
If the error case is an unexpected condition which would not come up in normal operation I would go for raising an exception.