I am working with a dictionary in Python where a key ("expiryTime"
) initially holds a str
value in ISO 8601 format (e.g., "2025-01-23T12:34:56"
). At some point in my code, I convert this string into a datetime
object using datetime.strptime
. However, I encounter a mypy
error during type checking:
error: Incompatible types in assignment (expression has type "datetime", target has type "str") [assignment]
Here is a simplified version of the code:
from datetime import datetime
# Initial dictionary with string value
token_dict: dict[str, str] = {"expiryTime": "2025-01-23T12:34:56"}
# Convert the string to datetime
expiry_time_dt = datetime.strptime(token_dict["expiryTime"], "%Y-%m-%dT%H:%M:%S")
token_dict["expiryTime"] = expiry_time_dt # Error here: incompatible types
I understand that mypy
complains because the dictionary's value was initially declared as a str
, and assigning a datetime
object violates the declared type. However, I need to store the datetime
object for further processing in my code.
What is the best way to handle this situation while maintaining type safety with mypy
? Should I:
# type: ignore
?Union[str, datetime]
type for the dictionary values, despite the strptime
error?The goal is to ensure the code remains type-safe while handling the necessary conversions between str
and datetime
. Any advice or recommendations for improving this workflow would be appreciated!
Suppressed the Error:
I used # type: ignore
to bypass the issue temporarily:
token_dict["expiryTime"] = expiry_time_dt # type: ignore
While this works, it's not a clean or type-safe solution.
Using Union[str, datetime]
:
I updated the type hint of the dictionary:
token_dict: dict[str, Union[str, datetime]] = {"expiryTime": "2025-01-23T12:34:56"}
This was the only viable solution until I encountered the following mypy
error:
error: Argument 1 to "strptime" of "datetime" has incompatible type "Union[str, datetime]"; expected "str" [arg-type]
The error occurs when I try to pass a Union[str, datetime]
value to strptime
, which expects a str
. This creates additional complexity because mypy
requires explicit type checks for every access to token_dict["expiryTime"]
, making it harder to maintain type correctness.
Conversion to str
for Mocking:
When mocking requests that interact with this dictionary, I must ensure the value is serialized back to a string (since datetime
is not JSON-serializable). This back-and-forth conversion is unavoidable, and I need to ensure type correctness in my code.
The key "expiryTime"
is part of a token dictionary that represents metadata for authentication. When mocking requests, I serialize the dictionary using JSON, which does not support datetime
objects. This necessitates the conversion of datetime
values back to strings before serialization. The back-and-forth conversions, combined with type annotations, have made this problem challenging to address cleanly.
For your options...
I recommend not mutating the object at all, and processing it into a new dictionary:
new_token_dict: dict[str, datetime] = {k: datetime.strptime(v, "%Y-%m-%dT%H:%M:%S") for k,v in token_dict.items()}
Mutating the variable (and even worse, its type), adds extra complexity to your code since you now need to handle that variable differently depending on whether you've performed your manipulation or not. You've lost the benefits of having the static types.
By creating a separate variable, you can keep the concepts separate with their own purpose.