Tuesday, 20 June 2023

Mypy 1.4.0 Released

 

We’ve just uploaded mypy 1.4 to the Python Package Index (PyPI). Mypy is a static type checker for Python. This release includes new features, performance improvements and bug fixes. You can install it as follows:
    python3 -m pip install -U mypy

You can read the full documentation for this release on Read the Docs.

The Override Decorator

Mypy can now ensure that when renaming a method, overrides are also renamed. You can explicitly mark a method as overriding a base class method by using the @typing.override decorator (PEP 698). If the method is then renamed in the base class while the method override is not, mypy will generate an error. The decorator will be available in typing in Python 3.12, but you can also use the backport from a recent version of typing_extensions on all supported Python versions.

This feature was contributed byThomas M Kehrenberg (PR 14609).

Propagating Type Narrowing to Nested Functions

Previously, type narrowing was not propagated to nested functions because it would not be sound if the narrowed variable changed between the definition of the nested function and the call site. Mypy will now propagate the narrowed type if the variable is not assigned to after the definition of the nested function:

    def outer(x: str | None = None) -> None:
        if x is None:
            x = calculate_default()
        reveal_type(x)  # "str" (narrowed)
    
        def nested() -> None:
            reveal_type(x)  # Now "str" (used to be "str | None")
    
        nested()

This may generate some new errors because asserts that were previously necessary may become tautological or no-ops.

This was contributed by Jukka Lehtosalo (PR 15133).

Narrowing Enum Values Using “==”

Mypy now allows narrowing enum types using the == operator. Previously this was only supported when using the is operator. This makes exhaustiveness checking with enum types more usable, as the requirement to use the is operator was not very intuitive. In this example mypy can detect that the developer forgot to handle the value MyEnum.C in example

    from enum import Enum
    
    class MyEnum(Enum):
        A = 0
        B = 1
        C = 2
    
    def example(e: MyEnum) -> str:  # Error: Missing return statement
        if e == MyEnum.A:
            return 'x'
        elif e == MyEnum.B:
            return 'y'

Adding an extra elif case resolves the error:

    ...
    def example(e: MyEnum) -> str:  # No error -- all values covered
        if e == MyEnum.A:
            return 'x'
        elif e == MyEnum.B:
            return 'y'
        elif e == MyEnum.C:
            return 'z'

This change can cause false positives in test cases that have assert statements like assert o.x == SomeEnum.X when using --strict-equality. Example:

    # mypy: strict-equality
    
    from enum import Enum
    
    class MyEnum(Enum):
        A = 0
        B = 1
    
    class C:
        x: MyEnum
        ...
    
    def test_something() -> None:
        c = C(...)
        assert c.x == MyEnum.A
        c.do_something_that_changes_x()
        assert c.x == MyEnum.B  # Error: Non-overlapping equality check

These errors can be ignored using # type: ignore[comparison-overlap], or you can perform the assertion using a temporary variable as a workaround:

    ...
    def test_something() -> None:
        ...
        x = c.x
        assert x == MyEnum.A  # Does not narrow c.x
        c.do_something_that_changes_x()
        x = c.x
        assert x == MyEnum.B  # OK

This feature was contributed by Shantanu (PR 11521).

Performance Improvements

  • Speed up simplification of large union types and also fix a recursive tuple crash (Shantanu, PR 15128)
  • Speed up union subtyping (Shantanu, PR 15104)
  • Don't type check most function bodies when type checking third-party library code, or generally when ignoring errors (Jukka Lehtosalo, PR 14150)

Improvements to Plugins

  • attrs.evolve: Support generics and unions (Ilya Konstantinov, PR 15050)
  • Fix ctypes plugin (Alex Waygood)

Fixes to Crashes

  • Fix a crash when function-scope recursive alias appears as upper bound (Ivan Levkivskyi, PR 15159)
  • Fix crash on follow_imports_for_stubs (Ivan Levkivskyi, PR 15407)
  • Fix stubtest crash in explicit init subclass (Shantanu, PR 15399)
  • Fix crash when indexing TypedDict with empty key (Shantanu, PR 15392)
  • Fix crash on NamedTuple as attribute (Ivan Levkivskyi, PR 15404)
  • Correctly track loop depth for nested functions/classes (Ivan Levkivskyi, PR 15403)
  • Fix crash on joins with recursive tuples (Ivan Levkivskyi, PR 15402)
  • Fix crash with custom ErrorCode subclasses (Marc Mueller, PR 15327)
  • Fix crash in dataclass protocol with self attribute assignment (Ivan Levkivskyi, PR 15157)
  • Fix crash on lambda in generic context with generic method in body (Ivan Levkivskyi, PR 15155)
  • Fix recursive type alias crash in make_simplified_union (Ivan Levkivskyi, PR 15216)

Improvements to Error Messages

  • Use lower-case built-in collection types such as list[…] instead of List[…] in errors when targeting Python 3.9+ (Max Murin, PR 15070)
  • Use X | Y union syntax in error messages when targeting Python 3.10+ (Omar Silva, PR 15102)
  • Use type instead of Type in errors when targeting Python 3.9+ (Rohit Sanjay, PR 15139)
  • Do not show unused-ignore errors in unreachable code, and make it a real error code (Ivan Levkivskyi, PR 15164)
  • Don’t limit the number of errors shown by default (Rohit Sanjay, PR 15138)
  • Improver message for truthy functions (madt2709, PR 15193)
  • Output distinct types when type names are ambiguous (teresa0605, PR 15184)
  • Update message about invalid exception type in try (AJ Rasmussen, PR 15131)
  • Add explanation if argument type is incompatible because of an unsupported numbers type (Jukka Lehtosalo, PR 15137)
  • Add more detail to 'signature incompatible with supertype' messages for non-callables (Ilya Priven, PR 15263)

Documentation Updates

  • Add --local-partial-types note to dmypy docs (Alan Du, PR 15259)
  • Update getting started docs for mypyc for Windows (Valentin Stanciu, PR 15233)
  • Clarify usage of callables regarding type object in docs (Viicos, PR 15079)
  • Clarify difference between disallow_untyped_defs and disallow_incomplete_defs (Ilya Priven, PR 15247)
  • Use attrs and @attrs.define in documentation and tests (Ilya Priven, PR 15152)

Mypyc Improvements

  • Fix unexpected TypeError for certain variables with an inferred optional type (Richard Si, PR 15206)
  • Inline math literals (Logan Hunt, PR 15324)
  • Support unpacking mappings in dict display (Richard Si, PR 15203)

Changes to Stubgen

  • Do not remove Generic from base classes (Ali Hamdan, PR 15316)
  • Support yield from statements (Ali Hamdan, PR 15271)
  • Fix missing total from TypedDict class (Ali Hamdan, PR 15208)
  • Fix call-based namedtuple omitted from class bases (Ali Hamdan, PR 14680)
  • Support TypedDict alternative syntax (Ali Hamdan, PR 14682)
  • Make stubgen respect MYPY_CACHE_DIR (Henrik Bäärnhielm, PR 14722)
  • Fixes and simplifications (Ali Hamdan, PR 15232)

Other Notable Fixes and Improvements

  • Fix nested async functions when using TypeVar value restriction (Jukka Lehtosalo, PR 14705)
  • Always allow returning Any from lambda (Ivan Levkivskyi, PR 15413)
  • Add foundation for TypeVar defaults (PEP 696) (Marc Mueller, PR 14872)
  • Update semantic analyzer for TypeVar defaults (PEP 696) (Marc Mueller, PR 14873)
  • Make dict expression inference more consistent (Ivan Levkivskyi, PR 15174)
  • Do not block on duplicate base classes (Nikita Sobolev, PR 15367)
  • Generate an error when both staticmethod and classmethod decorators are used (Juhi Chandalia, PR 15118)
  • Fix assert_type behaviour with literals (Carl Karsten, PR 15123)
  • Fix match subject ignoring redefinitions (Vincent Vanlaer, PR 15306)
  • Support __all__.remove (Shantanu, PR 15279)

Typeshed Updates

Typeshed is now modular and distributed as separate PyPI packages for everything except the standard library stubs. Please see git log for full list of typeshed changes.

Acknowledgements

Thanks to all mypy contributors who contributed to this release:

  • Adrian Garcia Badaracco
  • AJ Rasmussen
  • Alan Du
  • Alex Waygood
  • Ali Hamdan
  • Carl Karsten
  • dosisod
  • Ethan Smith
  • Gregory Santosa
  • Heather White
  • Henrik Bäärnhielm
  • Ilya Konstantinov
  • Ilya Priven
  • Ivan Levkivskyi
  • Juhi Chandalia
  • Jukka Lehtosalo
  • Logan Hunt
  • madt2709
  • Marc Mueller
  • Max Murin
  • Nikita Sobolev
  • Omar Silva
  • Özgür
  • Richard Si
  • Rohit Sanjay
  • Shantanu
  • teresa0605
  • Thomas M Kehrenberg
  • Tin Tvrtković
  • Tushar Sadhwani
  • Valentin Stanciu
  • Viicos
  • Vincent Vanlaer
  • Wesley Collin Wright
  • William Santosa
  • yaegassy

I’d also like to thank my employer, Dropbox, for supporting mypy development.