|
2 | 2 |
|
3 | 3 | ## Next Release |
4 | 4 |
|
| 5 | +## Mypy 2.2 |
| 6 | + |
| 7 | +We've just uploaded mypy 2.2.0 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)). |
| 8 | +Mypy is a static type checker for Python. This release includes new features, performance |
| 9 | +improvements and bug fixes. You can install it as follows: |
| 10 | + |
| 11 | + python3 -m pip install -U mypy |
| 12 | + |
| 13 | +You can read the full documentation for this release on [Read the Docs](http://mypy.readthedocs.io). |
| 14 | + |
| 15 | +### Support for Closed TypedDicts (PEP 728) |
| 16 | + |
| 17 | +Mypy now supports closed TypedDicts as specified in PEP 728. A closed TypedDict cannot have extra |
| 18 | +keys beyond those explicitly defined. This allows the type checker to determine that certain |
| 19 | +operations are safe when they otherwise wouldn't be due to the potential presence of unknown keys. |
| 20 | + |
| 21 | +You can use the `closed` keyword argument with `TypedDict`: |
| 22 | + |
| 23 | +```python |
| 24 | +HasName = TypedDict("HasName", {"name": str}) |
| 25 | +HasOnlyName = TypedDict("HasOnlyName", {"name": str}, closed=True) |
| 26 | +Movie = TypedDict("Movie", {"name": str, "year": int}) |
| 27 | + |
| 28 | +movie: Movie = {"name": "Nimona", "year": 2023} |
| 29 | +has_name: HasName = movie # OK: HasName is open (default) |
| 30 | +has_only_name: HasOnlyName = movie # Error: HasOnlyName is closed and Movie has extra "year" key |
| 31 | +``` |
| 32 | + |
| 33 | +Closed TypedDicts enable more precise type checking because the type checker knows exactly which |
| 34 | +keys are present. This is particularly useful when working with TypedDict unions or when you want |
| 35 | +to ensure that a TypedDict conforms to an exact shape. |
| 36 | + |
| 37 | +The `closed` keyword also enables safe type narrowing with `in` checks: |
| 38 | + |
| 39 | +```python |
| 40 | +Book = TypedDict('Book', {'book': str}, closed=True) |
| 41 | +DVD = TypedDict('DVD', {'dvd': str}, closed=True) |
| 42 | +type Inventory = Book | DVD |
| 43 | + |
| 44 | +def print_type(inventory: Inventory) -> None: |
| 45 | + if "book" in inventory: |
| 46 | + # Type is narrowed to Book here - safe because DVD is closed |
| 47 | + print(inventory["book"]) |
| 48 | + else: |
| 49 | + # Type is narrowed to DVD here |
| 50 | + print(inventory["dvd"]) |
| 51 | +``` |
| 52 | + |
| 53 | +The `closed` keyword is also supported in class-based syntax: |
| 54 | + |
| 55 | +```python |
| 56 | +class HasOnlyName(TypedDict, closed=True): |
| 57 | + name: str |
| 58 | +``` |
| 59 | + |
| 60 | +Note that closed TypedDicts are structural types, so a closed TypedDict is assignable to an open |
| 61 | +TypedDict with the same keys, but not vice versa. |
| 62 | + |
| 63 | +Contributed by Alice (PR [21382](https://github.com/python/mypy/pull/21382)). |
| 64 | + |
| 65 | +### Complete Support for Type Variable Defaults (PEP 696) |
| 66 | + |
| 67 | +Mypy now has complete support for type variable defaults as specified in PEP 696. This allows you to |
| 68 | +specify default values for type parameters in generic classes, functions, and type aliases. |
| 69 | + |
| 70 | +Traditional syntax (Python 3.11 and earlier): |
| 71 | + |
| 72 | +```python |
| 73 | +T = TypeVar("T", default=int) # This means that if no type is specified T = int |
| 74 | + |
| 75 | +@dataclass |
| 76 | +class Box(Generic[T]): |
| 77 | + value: T | None = None |
| 78 | + |
| 79 | +reveal_type(Box()) # type is Box[int] |
| 80 | +reveal_type(Box(value="Hello World!")) # type is Box[str] |
| 81 | +``` |
| 82 | + |
| 83 | +New syntax (Python 3.12+): |
| 84 | + |
| 85 | +```python |
| 86 | +class Box[T = int]: |
| 87 | + def __init__(self, value: T) -> None: |
| 88 | + self.value = value |
| 89 | + |
| 90 | +reveal_type(Box()) # type is Box[int] |
| 91 | +reveal_type(Box(value="Hello World!")) # type is Box[str] |
| 92 | +``` |
| 93 | + |
| 94 | +Type variable defaults work with all forms of generics, including classes, functions, and type aliases. |
| 95 | +This release completes the implementation by fixing various edge cases involving recursive defaults, |
| 96 | +dependencies between type variables, and interactions with variadic generics. |
| 97 | + |
| 98 | +Contributed by Ivan Levkivskyi (PRs [21491](https://github.com/python/mypy/pull/21491), |
| 99 | +[21526](https://github.com/python/mypy/pull/21526), [21544](https://github.com/python/mypy/pull/21544)). |
| 100 | + |
| 101 | +### Respect Explicit Return Type of `__new__()` |
| 102 | + |
| 103 | +Mypy now respects explicitly annotated return types in `__new__()` methods. Previously, mypy would |
| 104 | +always assume that `__new__()` returns an instance of the current class, ignoring explicit annotations. |
| 105 | + |
| 106 | +With this change, if you explicitly annotate a return type that differs from the implicit type, mypy |
| 107 | +will use the explicit annotation: |
| 108 | + |
| 109 | +```python |
| 110 | +class Factory: |
| 111 | + def __new__(cls) -> Product: |
| 112 | + return Product() |
| 113 | + |
| 114 | +reveal_type(Factory()) # type is Product, not Factory |
| 115 | +``` |
| 116 | + |
| 117 | +Note that mypy still gives an error at the definition site if the explicit annotation is not a |
| 118 | +subtype of the current class, since this is technically not type-safe. |
| 119 | + |
| 120 | +For backwards compatibility, there are two exceptions: |
| 121 | +- If the return type is `Any`, mypy will still use the current class as the return type. |
| 122 | +- If the explicit return type comes from a superclass and is a supertype of the implicit return type, |
| 123 | + mypy will use the implicit (more specific) type: |
| 124 | + |
| 125 | +```python |
| 126 | +class A: |
| 127 | + def __new__(cls) -> A: ... |
| 128 | + |
| 129 | +reveal_type(A()) # type is A |
| 130 | + |
| 131 | +class B: |
| 132 | + def __new__(cls) -> B: |
| 133 | + return cls() |
| 134 | + |
| 135 | +class C(B): ... |
| 136 | +reveal_type(C()) # type is C |
| 137 | +``` |
| 138 | + |
| 139 | +This fixes several long-standing issues where explicit `__new__()` return types were ignored. |
| 140 | + |
| 141 | +Contributed by Ivan Levkivskyi (PR [21441](https://github.com/python/mypy/pull/21441)). |
| 142 | + |
| 143 | +### TypeForm Support No Longer Experimental |
| 144 | + |
| 145 | +Support for `TypeForm` is no longer experimental. `TypeForm` (introduced in Python 3.14) allows you |
| 146 | +to annotate parameters that accept type expressions, providing better type checking for functions |
| 147 | +that work with types as values. |
| 148 | + |
| 149 | +```python |
| 150 | +from typing import TypeForm |
| 151 | + |
| 152 | +def make_list(tp: TypeForm[T]) -> list[T]: |
| 153 | + ... |
| 154 | + |
| 155 | +# Correctly typed as list[int] |
| 156 | +int_list = make_list(int) |
| 157 | +``` |
| 158 | + |
| 159 | +`TypeForm` support was previously reverted from mypy 2.1 due to a performance regression, but this |
| 160 | +has now been mitigated. |
| 161 | + |
| 162 | +Contributed by Ivan Levkivskyi and Jelle Zijlstra (PRs [21262](https://github.com/python/mypy/pull/21262), [21591](https://github.com/python/mypy/pull/21591), |
| 163 | +[21459](https://github.com/python/mypy/pull/21459)). |
| 164 | + |
| 165 | +### Experimental WASM Wheel for Python 3.14 |
| 166 | + |
| 167 | +Mypy now ships an experimental WebAssembly (WASM) wheel for Python 3.14. This allows mypy to run |
| 168 | +in WASM environments such as Pyodide and browser-based Python implementations. |
| 169 | + |
| 170 | +The WASM wheel is considered experimental and may have limitations compared to native builds. Please |
| 171 | +report any issues you encounter when using mypy in WASM environments. |
| 172 | + |
| 173 | +Contributed by Ivan Levkivskyi (PR [21671](https://github.com/python/mypy/pull/21671)). |
| 174 | + |
| 175 | +### Mypyc Free-threading Improvements |
| 176 | + |
| 177 | +- Make function wrappers thread-safe on free-threaded builds (Jukka Lehtosalo, PR [21620](https://github.com/python/mypy/pull/21620)) |
| 178 | +- Make list remove and index thread-safe on free-threaded builds (Jukka Lehtosalo, PR [21614](https://github.com/python/mypy/pull/21614)) |
| 179 | +- Fix dict iteration memory safety on free-threaded builds (Jukka Lehtosalo, PR [21617](https://github.com/python/mypy/pull/21617)) |
| 180 | +- Make some dict primitives thread-safe on free-threading builds (Jukka Lehtosalo, PR [21616](https://github.com/python/mypy/pull/21616)) |
| 181 | +- Fix free-threading race condition in argument parsing (Jukka Lehtosalo, PR [21613](https://github.com/python/mypy/pull/21613)) |
| 182 | +- Document free threading and other doc updates (Jukka Lehtosalo, PR [21494](https://github.com/python/mypy/pull/21494)) |
| 183 | + |
| 184 | +### `librt.strings` Updates |
| 185 | + |
| 186 | +- Add `librt.strings.toupper` and `librt.strings.tolower` codepoint primitives (Vaggelis Danias, PR [21553](https://github.com/python/mypy/pull/21553)) |
| 187 | +- Add `librt.strings.isidentifier` codepoint primitive (Vaggelis Danias, PR [21522](https://github.com/python/mypy/pull/21522)) |
| 188 | +- Add `librt.strings.isalpha` codepoint primitive (Vaggelis Danias, PR [21521](https://github.com/python/mypy/pull/21521)) |
| 189 | +- Add `librt.strings.isalnum` codepoint primitive (Vaggelis Danias, PR [21509](https://github.com/python/mypy/pull/21509)) |
| 190 | +- Add `librt.strings.isdigit` codepoint primitive (Vaggelis Danias, PR [21504](https://github.com/python/mypy/pull/21504)) |
| 191 | +- Add `librt.strings.isspace` char primitive (Vaggelis Danias, PR [21462](https://github.com/python/mypy/pull/21462)) |
| 192 | + |
| 193 | +### Mypyc Improvements |
| 194 | + |
| 195 | +- Fix name lookup when class var and module var have the same name (Jukka Lehtosalo, PR [21594](https://github.com/python/mypy/pull/21594)) |
| 196 | +- Report file and line number on uncaught exceptions (Jukka Lehtosalo, PR [21584](https://github.com/python/mypy/pull/21584)) |
| 197 | +- Use `other` arg instead of `self` for RHS type (Ryan Heard, PR [21569](https://github.com/python/mypy/pull/21569)) |
| 198 | +- Use `method_sig` to get the method signature (Ryan Heard, PR [21567](https://github.com/python/mypy/pull/21567)) |
| 199 | +- Preserve inherited attribute defaults under `separate=True` (Jo, PR [21547](https://github.com/python/mypy/pull/21547)) |
| 200 | +- Fix missing cross-group header deps in incremental builds (Jo, PR [21490](https://github.com/python/mypy/pull/21490)) |
| 201 | +- Fix cross-group call to inherited `__mypyc_defaults_setup` (Jo, PR [21481](https://github.com/python/mypy/pull/21481)) |
| 202 | +- Fix non-deterministic class struct layout under `separate=True` (Vaggelis Danias, PR [21530](https://github.com/python/mypy/pull/21530)) |
| 203 | +- Specialize `s[i] == 'x'` to a codepoint int compare (Vaggelis Danias, PR [21579](https://github.com/python/mypy/pull/21579)) |
| 204 | +- Fix reference leak in mypyc bytes concatenation (Colinxu2020, PR [21469](https://github.com/python/mypy/pull/21469)) |
| 205 | + |
| 206 | +### Fixes to Crashes |
| 207 | + |
| 208 | +- Fix crash on invalid recursive variadic alias (Ivan Levkivskyi, PR [21572](https://github.com/python/mypy/pull/21572)) |
| 209 | +- Fix crashes on variadic unpacking in synthetic types (Ivan Levkivskyi, PR [21555](https://github.com/python/mypy/pull/21555)) |
| 210 | +- Fix crash on unhandled meet variadic tuple vs instance (Ivan Levkivskyi, PR [21558](https://github.com/python/mypy/pull/21558)) |
| 211 | +- Fix crash on deferred generic class nested in function (Ivan Levkivskyi, PR [21557](https://github.com/python/mypy/pull/21557)) |
| 212 | +- Fix crash in new-style type alias with variadic unpack (Ivan Levkivskyi, PR [21551](https://github.com/python/mypy/pull/21551)) |
| 213 | +- Fix various crashes on recursive type variable defaults (Ivan Levkivskyi, PR [21491](https://github.com/python/mypy/pull/21491)) |
| 214 | +- Fix crash for empty `Annotated` type application (Rayan Salhab, PR [21503](https://github.com/python/mypy/pull/21503)) |
| 215 | +- Fix crash on `Unpack` used without arguments in class bases (Sai Asish Y, PR [21470](https://github.com/python/mypy/pull/21470)) |
| 216 | + |
| 217 | +### Performance Improvements |
| 218 | + |
| 219 | +- Memoize the options snapshot (Kevin Kannammalil, PR [21354](https://github.com/python/mypy/pull/21354)) |
| 220 | +- Don't include `not_ready_deps` tracking as relating to mypy internals (Kevin Kannammalil, PR [21389](https://github.com/python/mypy/pull/21389)) |
| 221 | +- Speed up transitive dependency hash for singleton SCCs (Kevin Kannammalil, PR [21390](https://github.com/python/mypy/pull/21390)) |
| 222 | +- Optimize typeform checks (Jelle Zijlstra, PR [21459](https://github.com/python/mypy/pull/21459)) |
| 223 | + |
| 224 | +### Improvements to the Native Parser |
| 225 | + |
| 226 | +- Support `--shadow-file` with `--native-parser` (Jukka Lehtosalo, PR [21623](https://github.com/python/mypy/pull/21623)) |
| 227 | +- Add Python version checks to native parser (Kevin Kannammalil, PR [21539](https://github.com/python/mypy/pull/21539)) |
| 228 | +- Allow nativeparse to parse source code directly (bzoracler, PR [21260](https://github.com/python/mypy/pull/21260)) |
| 229 | + |
| 230 | +### Other Notable Fixes and Improvements |
| 231 | + |
| 232 | +- Add function definition notes for `too many positional arguments` errors (Kevin Kannammalil, PR [21410](https://github.com/python/mypy/pull/21410)) |
| 233 | +- Fix the exportjson tool (.ff cache to .json conversion) (Jukka Lehtosalo, PR [21628](https://github.com/python/mypy/pull/21628)) |
| 234 | +- Support floats in JSON in fixed-format cache (Ivan Levkivskyi, PR [21603](https://github.com/python/mypy/pull/21603)) |
| 235 | +- Update `TypedDictType.__init__` signature to preserve backward compat (Jukka Lehtosalo, PR [21590](https://github.com/python/mypy/pull/21590)) |
| 236 | +- Fix constructor calls for union-bounded `TypeVar`s (Jingchen Ye, PR [21571](https://github.com/python/mypy/pull/21571)) |
| 237 | +- Fix `TypedDict` indexing with literal keys in comprehensions (Jingchen Ye, PR [21556](https://github.com/python/mypy/pull/21556)) |
| 238 | +- Correctly handle empty tuple index when unpacked (Ivan Levkivskyi, PR [21545](https://github.com/python/mypy/pull/21545)) |
| 239 | +- Support protocol checks for self-types in tuple types (Ivan Levkivskyi, PR [21535](https://github.com/python/mypy/pull/21535)) |
| 240 | +- Fix edge cases in variadic tuple subclasses (Ivan Levkivskyi, PR [21518](https://github.com/python/mypy/pull/21518)) |
| 241 | +- Special-case constructor for tuple types (Ivan Levkivskyi, PR [21502](https://github.com/python/mypy/pull/21502)) |
| 242 | +- Fix false positive "Expected TypedDict key to be string literal" for `Union[TypedDict, dict[K, V]]` (Zakir Jiwani, PR [21511](https://github.com/python/mypy/pull/21511)) |
| 243 | +- Use explicit `Never` for type inference (Ivan Levkivskyi, PR [21497](https://github.com/python/mypy/pull/21497)) |
| 244 | +- Narrow membership in statically known containers (Shantanu, PR [21461](https://github.com/python/mypy/pull/21461)) |
| 245 | +- Improve negative narrowing for membership checks on tuples (Shantanu, PR [21456](https://github.com/python/mypy/pull/21456)) |
| 246 | +- Analyze `TypedDict` decorators (Pranav Manglik, PR [21267](https://github.com/python/mypy/pull/21267)) |
| 247 | +- Start testing Python 3.15 (Marc Mueller, PR [21439](https://github.com/python/mypy/pull/21439)) |
| 248 | +- Improved handling of `NamedTuple`, `TypedDict`, `Enum`, and regular classes nested in functions (Ivan Levkivskyi, PR [21478](https://github.com/python/mypy/pull/21478)) |
| 249 | + |
| 250 | +### Typeshed Updates |
| 251 | + |
| 252 | +Please see [git log](https://github.com/python/typeshed/commits/main?after=616424285beccaa76f90e87e1e922b1dc68710ca+0&branch=main&path=stdlib) for full list of standard library typeshed stub changes. |
| 253 | + |
| 254 | +### Acknowledgements |
| 255 | + |
| 256 | +Thanks to all mypy contributors who contributed to this release: |
| 257 | + |
| 258 | +- Adam Turner |
| 259 | +- alicederyn |
| 260 | +- bzoracler |
| 261 | +- Colinxu2020 |
| 262 | +- georgesittas |
| 263 | +- Ivan Levkivskyi |
| 264 | +- Jelle Zijlstra |
| 265 | +- Jingchen Ye |
| 266 | +- Jukka Lehtosalo |
| 267 | +- Kevin Kannammalil |
| 268 | +- lphuc2250gma |
| 269 | +- Marc Mueller |
| 270 | +- Pranav Manglik |
| 271 | +- Rayan Salhab |
| 272 | +- Ryan Heard |
| 273 | +- Sai Asish Y |
| 274 | +- Shantanu |
| 275 | +- sobolevn |
| 276 | +- Vaggelis Danias |
| 277 | +- Victor Letichevsky |
| 278 | +- Zakir Jiwani |
| 279 | + |
| 280 | +I'd also like to thank my employer, Dropbox, for supporting mypy development. |
| 281 | + |
5 | 282 | ## Mypy 2.1 |
6 | 283 |
|
7 | 284 | We’ve just uploaded mypy 2.1.0 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)). |
|
0 commit comments