Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mypy error - incompatible types in assignment

Tags:

My function looks like this simplified code sample:

def my_func() -> dict:     result = {"success": False}      if condition:         result["success"] = True         return result     else:         result["message"] = "error message"     return result 

When I run Mypy (version 0.52) I get this error:

error: Incompatible types in assignment (expression has type "str", target has type "bool") 

and the error is pointing to the second last line in my code sample. Why mypy is returning this error? is my code invalid (in any way) or is this some mypy bug?

like image 449
Jan Rozycki Avatar asked May 11 '17 09:05

Jan Rozycki


People also ask

How do I reduce MYPY errors?

Silencing errors based on error codes You can use a special comment # type: ignore[code, ...] to only ignore errors with a specific error code (or codes) on a particular line. This can be used even if you have not configured mypy to show error codes.

How do I ignore MYPY check?

Spurious errors and locally silencing the checker You can add a # type: ignore comment to tell mypy to ignore this error: import frobnicate # type: ignore frobnicate. start() # Okay! The second line is now fine, since the ignore comment causes the name frobnicate to get an implicit Any type.

What is MYPY used for?

“Mypy is an optional static type checker for Python that aims to combine the benefits of dynamic (or 'duck') typing and static typing. Mypy combines the expressive power and convenience of Python with a powerful type system and compile-time type checking.” A little background on the Mypy project.


1 Answers

The problem is that mypy inferred that the type of your result variable is Dict[str, bool] due to how you first initialized it on line 2.

Consequently, when you try and insert a str later, mypy (rightfully) complains. You have several options for fixing your code, which I'll list in order of least to most type-safe.

Option 1 is to declare your dictionary such that its values are of type Any -- that is, your values will not be type-checked at all:

from typing import Any, Dict  def my_func(condition: bool) -> Dict[str, Any]:     result = {"success": False}  # type: Dict[str, Any]      if condition:         result["success"] = True     else:         result["message"] = "error message"     return result 

Note that we needed to annotate your second line to give mypy a hint about what the type of result should be, to help its inference process.

If you're using Python 3.6+, you can annotate that line using the following alternate syntax, which uses variable annotations (which are new as of Python 3.6):

result: Dict[str, Any] = {"success": False} 

Option 2 is slightly more type-safe -- declare your values to be either strs or bools, but nothing else, using Union. This isn't fully typesafe, but at least you can still have some checks on your dict.

from typing import Any, Dict  def my_func(condition: bool) -> Dict[str, Union[str, bool]]:     result = {"success": False}  # type: Dict[str, Union[str, bool]]      if condition:         result["success"] = True     else:         result["message"] = "error message"     return result 

You may perhaps find that type annotation to be a little long/annoying to type, so you could use type aliases for readability (and optionally use the variable annotation syntax), like so:

ResultJson = Dict[str, Union[str, bool]]  def my_func(condition: bool) -> ResultJson     result: ResultJson = {"success": False}     # ...snip... 

Option 3 is the most type-safe, although it does require you to use the experimental 'TypedDict' type, which lets you assign specific types to different fields in your dict. That said, use this type at your own risk -- AFAIK it hasn't yet been added to PEP 484, which means other type-checking tools (like Pycharm's checker) aren't obligated to understand this. Mypy itself only recently added support for TypedDict, and so may still be buggy:

from typing import Optional from mypy_extensions import TypedDict  ResultJson = TypedDict('ReturnJson', {'success': bool, 'message': Optional[str]})  def my_func(condition: bool) -> ResultJson:     result = {"success": False, "message": None}  # type: ResultJson      if condition:         result["success"] = True     else:         result["message"] = "error message"     return result 

Be sure to install the mypy_extensions package if you want to use this option.

like image 86
Michael0x2a Avatar answered Sep 20 '22 13:09

Michael0x2a