tie IntoFrameT to NativeFrame#3496
Conversation
yup, thanks for taking a look! |
…als into another-typing-readme
…als into another-typing-readme
Thanks! I think this is addressible with some extra specialised overloads, have pushed
Aren't these generally tested already? Any particular tests you'd like to see? |
|
Hey folks, any update on this one? Drove me mad for 30 minutes till I realized it is pyrefly specific error |
|
I don't think it's pyrefly-specific, pyright flags it too to respond to Dan's comment point by point:
If you do collect, then you can't hope to have a
same
This isn't an incompatible API, it returns
Yup, this one's problematic (as it currently is on Something I wouldn't be opposed to would be to change the def lazy(self) -> LazyFrame[Any]:as, realistically, if you're calling .
Also not an incompatible API, it returns
This returns |
|
thanks @dangotbanned , have addressed most comments Regarding the overlap, don't type checkers usually match the first valid overload? At least, for from typing import overload, Sequence, reveal_type
@overload
def foo(a: str) -> int: ... # type: ignore[overload-overlap]
@overload
def foo(a: Sequence[str]) -> str: ...
def foo(a: str | Sequence[str]) -> int | str:
if isinstance(a, str):
return 0
return 'zero'
reveal_type(foo('abc'))
reveal_type(foo(['abc']))All of mypy, pyright, pyrefly, ty, and zuban, do exactly that. pandas and numpy both rely on this in their stubs, so I think this is unlikely to change? (scratch) marcogorelli@DESKTOP-U8OKFP3:~/scratch$ mypy t.py
t.py:14: note: Revealed type is "int"
t.py:15: note: Revealed type is "str"
Success: no issues found in 1 source file
(scratch) marcogorelli@DESKTOP-U8OKFP3:~/scratch$ pyright t.py
/home/marcogorelli/scratch/t.py
/home/marcogorelli/scratch/t.py:14:13 - information: Type of "foo('abc')" is "int"
/home/marcogorelli/scratch/t.py:15:13 - information: Type of "foo(['abc'])" is "str"
0 errors, 0 warnings, 2 informations
(scratch) marcogorelli@DESKTOP-U8OKFP3:~/scratch$ pyrefly check t.py
INFO revealed type: int [reveal-type]
--> t.py:14:12
|
14 | reveal_type(foo('abc'))
| ------------
|
INFO revealed type: str [reveal-type]
--> t.py:15:12
|
15 | reveal_type(foo(['abc']))
| --------------
|
INFO 0 errors
(scratch) marcogorelli@DESKTOP-U8OKFP3:~/scratch$ ty check t.py
info[revealed-type]: Revealed type
--> t.py:14:13
|
12 | return 'zero'
13 |
14 | reveal_type(foo('abc'))
| ^^^^^^^^^^ `int`
15 | reveal_type(foo(['abc']))
|
info[revealed-type]: Revealed type
--> t.py:15:13
|
14 | reveal_type(foo('abc'))
15 | reveal_type(foo(['abc']))
| ^^^^^^^^^^^^ `str`
|
Found 2 diagnostics
(scratch) marcogorelli@DESKTOP-U8OKFP3:~/scratch$ zuban check t.py
t.py:14: note: Revealed type is "builtins.int"
t.py:15: note: Revealed type is "builtins.str"
Success: no issues found in 1 source file |
|
just checking if you still disagree with the approach of whether there can be a way forwards here? |
|
Hey Marco, I haven't got back to this yet - so this isn't a comment on the most recent changes - but appreciate you taking things on board 😊
In my last review I didn't mean to give off that impression, sorry for that 😔 That isn't to say my worries are correct, and I would much rather your changes turn out to be fine 🤞 I'll do my best to go through your changes this weekend, if that's okay? One thing for now, re overloads (#3496 (comment)) I was thinking about this PR a couple of days ago when I saw this potential spec change: I think the 2nd spec change there is related - might be worth reading to see if (#3496 (comment)) would be handled differently? |
|
thanks! yeah no hurry at all, just checking if there was a potential way forwards or if you were firmly against it btw, i think we're already relying on inconsistent overlapping overloads here narwhals/narwhals/dataframe.py Lines 1049 to 1057 in 25bdb8f |
I read through (python/typing#2250) and it looks like that would be non-conformant behavior: It's worth noting that this is being proposed by a |
| @overload | ||
| def from_native( # type: ignore[overload-overlap] | ||
| native_object: IntoFrameT, **kwds: Unpack[AllowLazy] | ||
| ) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: ... |
There was a problem hiding this comment.
I don't know for sure if it'll work, but one way to make the overload defs non-overlapping might be:
@overload
def from_native(native_object: IntoFrameT) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: ...Since AllowLazy is using total=False, that might not be enough though 🤔
I'll ask, but my understanding is that it wouldn't be non-conformant because if you have @overload
def foo(a: str) -> int: ... # type: ignore[overload-overlap]
@overload
def foo(a: Sequence[str]) -> str: ...
def foo(a: str | Sequence[str]) -> int | str:
...
foo('foo')then all materialisations of the |
|
To tie this back specifically to the spec, in step 5, it says
In this case, My reading of the linked issues (python/typing#566 (comment)) and Spec change: ambiguous arguments in overload call evaluation is that they're about different issues |
I think this is the same issue Which > # Step 5 eliminates the first overload because there exists a
> # materialization of `A[Any]` that is not assignable to `A[None]`. Step 6
> # picks the second overload.Show pre-3.12 version
from typing import TypeVar, Generic, Any, assert_type, overload
T = TypeVar("T")
class A(Generic[T]):
x: T
def f(self) -> T:
return self.x
@overload
def example12(x: A[None]) -> A[None]: ...
@overload
def example12(x: A[Any]) -> A[Any]: ...
def example12(x: A[Any]) -> A[Any]:
return x
def check_example12(x: Any):
# Step 5 eliminates the first overload because there exists a
# materialization of `A[Any]` that is not assignable to `A[None]`. Step 6
# picks the second overload.
ret = example12(x)
assert_type(ret, A[Any]) # "assert_type" mismatch: expected "A[Any]" but received "A[None] "Pylance(reportAssertTypeFailure)" |
|
That's dealing with a case where an argument of type In the example I gave, we're passing a string argument, in which every materialisation matches the first overload If you believe that the example I gave (#3496 (comment)) is non-conformant, may I please ask that you open a discussion on the typing discourse or on their github? |
This PR is not about that example, although both are related to overlapping overloads. By my count,
I believe this is why you see At worst, it couldn't hurt to try? I'm not sure what issue is being surpressed on this line: But I do know that it would also prevent other type checkers from showing a diagnostic there if they had one So bringing it back to (#3496 (comment)) But I currently feel:
|
Sure, but just to check that we're on the same page - do you agree that that example is conformant or not?
Yes, and all materialisations of
Yup, thanks 🙏 . Have tried --git a/narwhals/translate.py b/narwhals/translate.py
index f9ef32461..5ed0bde06 100644
--- a/narwhals/translate.py
+++ b/narwhals/translate.py
@@ -148,17 +148,19 @@ def from_native(
native_object: IntoLazyFrameT, **kwds: Unpack[AllowLazy]
) -> LazyFrame[IntoLazyFrameT]: ...
@overload
-def from_native( # type: ignore[overload-overlap]
+def from_native(
native_object: IntoDataFrameT | IntoSeriesT, **kwds: Unpack[AllowSeries]
) -> DataFrame[IntoDataFrameT] | Series[IntoSeriesT]: ...
@overload
def from_native(
native_object: IntoDataFrameT | IntoLazyFrameT, **kwds: Unpack[AllowLazy]
) -> DataFrame[IntoDataFrameT] | LazyFrame[IntoLazyFrameT]: ...
+# @overload
+# def from_native( # type: ignore[overload-overlap]
+# native_object: IntoFrameT, **kwds: Unpack[AllowLazy]
+# ) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: ...
@overload
-def from_native( # type: ignore[overload-overlap]
- native_object: IntoFrameT, **kwds: Unpack[AllowLazy]
-) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: ...
+def from_native(native_object: IntoFrameT) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: ...
@overload
def from_native(
native_object: IntoDataFrameT | IntoLazyFrameT | IntoSeriesT, **kwds: Unpack[AllowAny]
@@ -175,7 +177,7 @@ def from_native(
series_only: bool,
allow_series: bool | None,
) -> Any: ...
-def from_native( # type: ignore[misc]
+def from_native(
native_object: IntoFrameT
| IntoLazyFrameT
| IntoDataFrameT, and mypy reports |
|
For reference i asked about that on the pyrefly discord and got the response
https://discord.com/channels/1319086885024567347/1494693618441519205/1494806090368679997 |
Thanks for asking! I think I'd need to join the discord to find out, but what was the question?
I can't tell if this means they're talking about a case like Edit: from typing import overload, Sequence, reveal_type
@overload
def foo(a: str) -> int: ... # type: ignore[overload-overlap]
@overload
def foo(a: Sequence[str]) -> str: ...
def foo(a: str | Sequence[str]) -> int | str:
if isinstance(a, str):
return 0
return 'zero'
reveal_type(foo('abc')) # Revealed type is "int"
reveal_type(foo(['abc'])) # Revealed type is "str"In my head I wouldn't think a Or maybe this is just saying the type doesn't contain |
Thanks, really appreciate you trying that out.
Just so I understand, this error was already present - but ignored - and my suggestion didn't change that right? |
|
Yup, that's right! We also have pyrefly running on the test suite now, and it's encouraging that that reports no issues with this pr |
|
What would this PR look like if we approached this as widening only
EditThe goal of this would not be to support |
🤔 might this be a solution to #3493 ?
Description
What type of PR is this? (check all applicable)
Related issues
Checklist