I have some functions that return dictionaries:
def get_metadata_from_file(filepath:str)->dict[str, bool|dict[str, Any]]:
'''Get metadata about a file if it exists'''
answer = {}
if os.path.isfile(filepath):
answer['exists'] = True
answer['metadata'] = { dict of metadata attributes }
else:
answer['exists'] = False
answer['metadata'] = {}
return answer
Later in other functions I have issues:
def get_creation_time(filepath:str)->str|None:
metadata = get_metadata_from_file(filepath)
if metadata['exists']:
return metadata['metadata']['created_at'] # Mypy gets angry here
else:
return None
Clearly the program's logic handles the case where the file does not exist, but Mypy is concerned that the metadata['metadata']['created_at'] key might not exist / that metadata['metadata'] will be a boolean.
I'm sure there is a solution to this, what is the recommended approach?
When using type checkers like
mypy, you should always try to define the expected types as precisely as possible. There are, however, situations where defining all the expected types becomes counterproductive and sometimes impossible. For these situations, you might want to specify broad type hints, likeAny, orobject, although these should be avoided as much as possible.Solutions to Address
mypyConcernsYour code specifically contains a nested dictionary with mixed types, which
mypyfinds ambiguous based on your function signatures and handling inside the functions. You could solve themypywarnings by implementing the following changes:Use TypedDict for Precise Type Definitions:
TypedDictis useful when you want to specify types for keys in a dictionary. This allowsmypyto understand what keys are expected in the dictionary and their corresponding value types.Explicit Type Checks and Use of
.get()Method: Before accessing a nested key, check if the key exists or use the.get()method of dictionaries which can returnNone(or a default value you provide) if the key is not present. This is a safer way to access values in dictionaries and can satisfymypythat you've handled potentialKeyErrors.Optional Types for Dictionary Values: Indicate that dictionary values, especially in nested structures, can be
Noneby usingOptional[type].Revised Example with the Above Solutions
The refactored code above should address the
mypyissues you're experiencing: