-
Notifications
You must be signed in to change notification settings - Fork 0
Add Hint for Type Narrowing When Using Optional Types #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Source commit: python/typeshed@9e506eb
This PR resolves an issue where the Cobertura XML report generated by MyPy was missing the lines-covered and lines-valid attributes in the <coverage> element. Changes made: - Added the lines-covered and lines-valid attributes to the <coverage> element in the Cobertura XML report. - Updated the CoberturaReportSuite test suite to validate that these attributes are correctly included in the generated XML. Fixes #17689
There was confusion about the fullnames of type variables in nested generic classes. A type variable could be defined internally as `m.OuterClass.T`, but it was sometimes accessed as `m.T`. The root cause was that the semantic analyzer didn't initialize the attribute that refers to the enclosing class consistently. Fixes #17596. Fixes #17630.
The rvalue expression isn't semantically analyzed, so we can't rely on the `fullname` attribute to check if there is a reference to `Annotated`. Instead, use a lookup function provided by the caller to determine the fullname. Error reporting in the second argument to `Annotated` is still inconsistent, but this seems lower priority. I'll create a follow-up issue about (or update an existing issue if one exists). Fixes #17751.
…17782) Fix this conformance test: ``` class ShouldBeCovariant5[T]: def __init__(self, x: T) -> None: self._x = x @Property def x(self) -> T: return self._x vo5_1: ShouldBeCovariant5[float] = ShouldBeCovariant5[int](1) # OK vo5_2: ShouldBeCovariant5[int] = ShouldBeCovariant5[float](1) # E ``` My fix is to treat such attributes as not settable when inferring variance. Link: https://github.com/python/typing/blob/main/conformance/tests/generics_variance_inference.py#L79
Fix this conformance test: ``` @DataClass(frozen=True) class ShouldBeCovariant4[T]: x: T vo4_1: ShouldBeCovariant4[float] = ShouldBeCovariant4[int](1) # OK vo4_2: ShouldBeCovariant4[int] = ShouldBeCovariant4[float](1) # E ``` Link: https://github.com/python/typing/blob/main/conformance/tests/generics_variance_inference.py#L66
Closes #17570. This is my first contribution to mypy! 🐍 Added an error code for overlapping function signatures. Test in check-errorcodes.test is a derivative of this post: https://stackoverflow.com/q/69341607 Co-authored-by: Jelle Zijlstra <[email protected]> Co-authored-by: Alex Waygood <[email protected]>
Test case from typing conformance test suite: https://github.com/python/typing/blob/main/conformance/tests/generics_syntax_declarations.py#L45
Previously we only inferred variance based on member types, but if a base class has explicit variance for some type variables, we need to consider it as well.
…17789) It doesn't work at runtime.
I think the PEP 695 syntax is supported well enough now to enable it by default.
…ables (#17802) Fixes #17792. Related to #17791. Currently, [`pretty_callable`](https://github.com/python/mypy/blob/5dfc7d941253553ab77836e9845cb8fdfb9d23a9/mypy/messages.py#L2862) only renders `TypeVar` upper bounds if they are of type `Instance`: https://github.com/python/mypy/blob/5dfc7d941253553ab77836e9845cb8fdfb9d23a9/mypy/messages.py#L2943-L2949 However, there are some types that can appear as `TypeVar` upper bounds which are not represented by `Instance`, such as `UnionType` and `CallableType`. This PR allows such non-`Instance` upper bounds to be rendered as well. ## Effect Consider the below code. Playground link: https://mypy-play.net/?mypy=1.11.2&python=3.12&enable-incomplete-feature=NewGenericSyntax&gist=ba30c820cc3668e0919dadf2f391ff4b ```python from collections.abc import Callable from typing import Any, overload ### No matching overloads @overload def f1[T: int](x: T) -> T: ... @overload def f1[T: Callable[..., None]](x: T) -> T: ... @overload def f1[T: tuple[int]](x: T) -> T: ... @overload def f1[T: None](x: T) -> T: ... @overload def f1[T: type[int]](x: T) -> T: ... @overload def f1[T: bytes | bytearray](x: T) -> T: ... def f1(x): return x f1(1.23) ### Mismatching conditional definitions if input(): def f2[T](x: T) -> T: return x else: def f2[T: Callable[..., None]](x: T) -> T: return x ``` ### Before * In the first error on line 20, all overloads aside from the first one are displayed as `def [T] f1(x: T) -> T` (upper bound missing). Duplicate entries are suppressed. * In the second error on line 28, the second definition is displayed as `def [T] f2(x: T) -> T` (upper bound missing), and is removed as an apparent duplicate of the first. ```none main.py:20: error: No overload variant of "f1" matches argument type "float" [call-overload] main.py:20: note: Possible overload variants: main.py:20: note: def [T: int] f1(x: T) -> T main.py:20: note: def [T] f1(x: T) -> T main.py:28: error: All conditional function variants must have identical signatures [misc] main.py:28: note: Original: main.py:28: note: def [T] f2(x: T) -> T main.py:28: note: Redefinition: Found 2 errors in 1 file (checked 1 source file) ``` ### After * All type var upper bounds are rendered. ```none main.py:20: error: No overload variant of "f1" matches argument type "float" [call-overload] main.py:20: note: Possible overload variants: main.py:20: note: def [T: int] f1(x: T) -> T main.py:20: note: def [T: Callable[..., None]] f1(x: T) -> T main.py:20: note: def [T: tuple[int]] f1(x: T) -> T main.py:20: note: def [T: None] f1(x: T) -> T main.py:20: note: def [T: type[int]] f1(x: T) -> T main.py:20: note: def [T: bytes | bytearray] f1(x: T) -> T main.py:28: error: All conditional function variants must have identical signatures [misc] main.py:28: note: Original: main.py:28: note: def [T] f2(x: T) -> T main.py:28: note: Redefinition: main.py:28: note: def [T: Callable[..., None]] f2(x: T) -> T Found 2 errors in 1 file (checked 1 source file) ```
…accepting single ParamSpec (#17770) Fixes #17765 The offender for this crash appears to be this snippet: https://github.com/python/mypy/blob/72c413d2352da5ce1433ef241faca8f40fa1fe27/mypy/semanal.py#L5905-L5910 This branch triggers when applying type args to a type that is generic with respect to a single `ParamSpec`. It allows double brackets to be omitted when providing a parameter specification by wrapping all of the provided type arguments into a single parameter specification argument (i.e. equating `Foo[int, int]` to `Foo[[int, int]]`). This wrapping occurs *unless*: * there is only a single type argument, and it resolves to `Any` (e.g. `Foo[Any]`) * **there is only a single type argument**, and it's a bracketed parameter specification or a `ParamSpec` (e.g. `Foo[[int, int]]`) The problem occurs when multiple type arguments provided and at least one of them is a bracketed parameter specification, as in `Foo[[int, int], str]`. Per the rules above, since there is more than 1 type argument, mypy attempts to wrap the arguments into a single parameter specification. This results in the attempted creation of a `Parameters` instance that contains another `Parameters` instance, which triggers this assert inside `Parameters.__init__`: https://github.com/python/mypy/blob/72c413d2352da5ce1433ef241faca8f40fa1fe27/mypy/types.py#L1634 I think a reasonable solution is to forgo wrapping the type arguments into a single `Parameters` if **any** of the provided type arguments are a `Parameters`/`ParamSpecType`. That is, don't transform `Foo[A1, A2, ...]` to `Foo[[A1, A2, ...]]` if any of `A1, A2, ...` are a parameter specification. This change brings the crash case inline with mypy's current behavior for a similar case: ```python # Current behavior P = ParamSpec("P") class C(Generic[P]): ... c: C[int, [int, str], str] # E: Nested parameter specifications are not allowed ``` Before this change: ```python P = ParamSpec("P") class C(Generic[P]): ... class D(C[int, [int, str], str]): ... # !!! CRASH !!! ``` After this change: ```python P = ParamSpec("P") class C(Generic[P]): ... class D(C[int, [int, str], str]): ... # E: Nested parameter specifications are not allowed ````
…17323) Fixes #14571. When type checking a call of a `ParamSpec`-typed callable, currently there is an incorrect "fast path" (if there are two arguments of shape `(*args: P.args, **kwargs: P.kwargs)`, accept), which breaks with `Concatenate` (such call was accepted even for `Concatenate[int, P]`). Also there was no checking that args and kwargs are actually present: since `*args` and `**kwargs` are not required, their absence was silently accepted.
Fix variance inference in this fragment from a typing conformance test: ``` class ClassA[T1, T2, T3](list[T1]): def method1(self, a: T2) -> None: ... def method2(self) -> T3: ... ``` Previously T2 was incorrectly inferred as invariant due to `list` having methods that return `Self`. Be more flexible with return types to allow inferring contravariance for type variables even if there are `Self` return types, in particular. We could probably make this even more lenient, but after thinking about this for a while, I wasn't sure what the most general rule would be, so I decided to just make a tweak to support the likely most common use case (which is probably actually not that common either). Link to conformance test: https://github.com/python/typing/blob/main/conformance/tests/generics_variance_inference.py#L15C1-L20C12
Provide examples using both syntax variants, and give both of the syntax variants similar prominence. It's likely that both syntax variants will continue to be widely used for a long time. Also adjust terminology (e.g. use 'type parameter' / 'type argument' more consistently), since otherwise some descriptions would be unclear. I didn't update examples outside the generics chapter. I'll do this in a follow-up PR. Work on #17810. --------- Co-authored-by: Jelle Zijlstra <[email protected]> Co-authored-by: Brian Schubert <[email protected]>
Finish work started in #17816. Document `type` statement when discussing type aliases. Update some examples to have both old-style and new-style variants. In less common scenarios, examples only use a single syntax variant to reduce verbosity. Also update some examples to generally use more modern features. Closes #17810.
Closes #16891 ### Before ```python from typing import Literal def f1(a: str) -> Literal[""]: return a and exit() # E: Incompatible return value type (got "str", expected "Literal['']") def f2(a: int) -> Literal[0]: return a and exit() # E: Incompatible return value type (got "int", expected "Literal[0]") def f3(a: bytes) -> Literal[b""]: return a and exit() # E: Incompatible return value type (got "bytes", expected "Literal[b'']") ``` ### After ```none Success: no issues found in 1 source file ```
The explanation of self types uses upper bounds, so it makes sense to discuss them earlier. I also made some other minor documentation tweaks to improve clarity.
Use `collections.abc.Iterable`, for example, instead of `typing.Iterable`, unless we are discussing support for older Python versions. The latter has been deprecated since Python 3.9. Also update a few other out-of-date things that I happened to notice. Part of the motivation is that Python 3.8 will reach end of life in October, so we can soon start mostly assuming that users are on 3.9 or newer (even if we'll continue supporting 3.8 for a while still). --------- Co-authored-by: Jelle Zijlstra <[email protected]>
Soon 4 out of 5 supported Python versions will support the `X | Y` syntax, so we can make it more prominent (Python 3.13 will be out soon, and 3.8 will reach end of life). Use it in most examples. The syntax is available starting from Python 3.10, but it can be used in annotations in earlier Python versions as well if using `from __future__ import annotations`. --------- Co-authored-by: Brian Schubert <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
Source commit: python/typeshed@a94c927
Cases like following: class B: x: A | B terminal: main.py:9: error: Item "A" of "A | B" has no attribute "bar" [union-attr] has also been handled, specifically to narrow down None data type cases and rest as usual like the case of user defined data types A & B in above case. index1.py:9: error: Item "A" of "A | B" has no attribute "bar" [union-attr] no note! |
Fixes python#17036
The added note makes it easier for new mypy users to understand where the errors are coming from and suggests a potentially simple fix.
Note: You can use "if <variable_name> is not None" check to guard against a None value.