When you’re puzzled or when things are complicated

  1. from typing import Union, Any, List, Optional, cast
  2.  
  3. # To find out what type mypy infers for an expression anywhere in
  4. # your program, wrap it in reveal_type(). Mypy will print an error
  5. # message with the type; remove it again before running the code.
  6. reveal_type(1) # -> Revealed type is 'builtins.int'
  7.  
  8. # Use Union when something could be one of a few types
  9. x: List[Union[int, str]] = [3, 5, "test", "fun"]
  10.  
  11. # Use Any if you don't know the type of something or it's too
  12. # dynamic to write a type for
  13. x: Any = mystery_function()
  14.  
  15. # If you initialize a variable with an empty container or "None"
  16. # you may have to help mypy a bit by providing a type annotation
  17. x: List[str] = []
  18. x: Optional[str] = None
  19.  
  20. # This makes each positional arg and each keyword arg a "str"
  21. def call(self, *args: str, **kwargs: str) -> str:
  22. request = make_request(*args, **kwargs)
  23. return self.do_api_query(request)
  24.  
  25. # Use a "type: ignore" comment to suppress errors on a given line,
  26. # when your code confuses mypy or runs into an outright bug in mypy.
  27. # Good practice is to comment every "ignore" with a bug link
  28. # (in mypy, typeshed, or your own code) or an explanation of the issue.
  29. x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
  30.  
  31. # "cast" is a helper function that lets you override the inferred
  32. # type of an expression. It's only for mypy -- there's no runtime check.
  33. a = [4]
  34. b = cast(List[int], a) # Passes fine
  35. c = cast(List[str], a) # Passes fine (no runtime check)
  36. reveal_type(c) # -> Revealed type is 'builtins.list[builtins.str]'
  37. print(c) # -> [4]; the object is not cast
  38.  
  39. # If you want dynamic attributes on your class, have it override "__setattr__"
  40. # or "__getattr__" in a stub or in your source code.
  41. #
  42. # "__setattr__" allows for dynamic assignment to names
  43. # "__getattr__" allows for dynamic access to names
  44. class A:
  45. # This will allow assignment to any A.x, if x is the same type as "value"
  46. # (use "value: Any" to allow arbitrary types)
  47. def __setattr__(self, name: str, value: int) -> None: ...
  48.  
  49. # This will allow access to any A.x, if x is compatible with the return type
  50. def __getattr__(self, name: str) -> int: ...
  51.  
  52. a.foo = 42 # Works
  53. a.bar = 'Ex-parrot' # Fails type checking