-
Notifications
You must be signed in to change notification settings - Fork 125
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
ci(typing): add pyright
to ci
#2035
Conversation
Pretty sure `pyarrow-stubs` is going to need an upstream fix for the imports #2007 (comment)
.github/workflows/typing.yml
Outdated
- name: Run pyright | ||
run: pyright | ||
run: | | ||
source .venv/bin/activate | ||
pyright |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expecting to get:
32 errors, 4 warnings, 0 informations
Update 1
Actually got:
25 errors, 4 warnings, 0 informations
close enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarcoGorelli that was easier than expected https://github.com/narwhals-dev/narwhals/actions/runs/13377926539/job/37360986379?pr=2035
Do you want me to fix these or merge with errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update 2
https://github.com/narwhals-dev/narwhals/actions/runs/13379548648/job/37365557071?pr=2035
11 errors, 0 warnings, 0 informations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update 3
https://github.com/narwhals-dev/narwhals/actions/runs/13389097323/job/37392499933?pr=2035
8 errors, 0 warnings, 0 informations
All of these seems to be roughly the same issue mentioned in (#2035 (comment)).
Will take a look at if there are any small changes that could be made on the protocol typing.
It pretty much boils down to defining that it should accept lazy and eager, but then later constraining to only eager or only lazy
Lines 78 to 83 in 9571ad6
class CompliantExpr(Protocol, Generic[CompliantSeriesT_co]): | |
_implementation: Implementation | |
_backend_version: tuple[int, ...] | |
_evaluate_output_names: Callable[ | |
[CompliantDataFrame | CompliantLazyFrame], Sequence[str] | |
] |
Edit
https://github.com/narwhals-dev/narwhals/actions/runs/13389346860/job/37393273341?pr=2035
See commit message: revert(typing): reintroduce arrow errors evaluate_output_names
10 errors, 0 warnings, 0 informations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarcoGorelli I think this is the missing piece in having all the typing tie in together nicely.
I've been playing around with this as a solution:
narwhals.typing
diff
diff --git a/narwhals/typing.py b/narwhals/typing.py
index aa18a999..ca0a0607 100644
--- a/narwhals/typing.py
+++ b/narwhals/typing.py
@@ -70,24 +70,29 @@ class CompliantLazyFrame(Protocol):
# (so, no broadcasting is necessary).
+CompliantFrameT_contra = TypeVar(
+ "CompliantFrameT_contra",
+ bound="CompliantDataFrame | CompliantLazyFrame",
+ contravariant=True,
+)
CompliantSeriesT_co = TypeVar(
"CompliantSeriesT_co", bound=CompliantSeries, covariant=True
)
-class CompliantExpr(Protocol, Generic[CompliantSeriesT_co]):
+class CompliantExpr(Protocol, Generic[CompliantSeriesT_co, CompliantFrameT_contra]):
_implementation: Implementation
_backend_version: tuple[int, ...]
- _evaluate_output_names: Callable[
- [CompliantDataFrame | CompliantLazyFrame], Sequence[str]
- ]
+ _evaluate_output_names: Callable[[CompliantFrameT_contra], Sequence[str]]
_alias_output_names: Callable[[Sequence[str]], Sequence[str]] | None
_depth: int
_function_name: str
def __call__(self, df: Any) -> Sequence[CompliantSeriesT_co]: ...
def __narwhals_expr__(self) -> None: ...
- def __narwhals_namespace__(self) -> CompliantNamespace[CompliantSeriesT_co]: ...
+ def __narwhals_namespace__(
+ self,
+ ) -> CompliantNamespace[CompliantSeriesT_co, CompliantFrameT_contra]: ...
def is_null(self) -> Self: ...
def alias(self, name: str) -> Self: ...
def cast(self, dtype: DType) -> Self: ...
@@ -102,11 +107,13 @@ class CompliantExpr(Protocol, Generic[CompliantSeriesT_co]):
def __pow__(self, other: Any) -> Self: ...
-class CompliantNamespace(Protocol, Generic[CompliantSeriesT_co]):
- def col(self, *column_names: str) -> CompliantExpr[CompliantSeriesT_co]: ...
+class CompliantNamespace(Protocol, Generic[CompliantSeriesT_co, CompliantFrameT_contra]):
+ def col(
+ self, *column_names: str
+ ) -> CompliantExpr[CompliantSeriesT_co, CompliantFrameT_contra]: ...
def lit(
self, value: Any, dtype: DType | None
- ) -> CompliantExpr[CompliantSeriesT_co]: ...
+ ) -> CompliantExpr[CompliantSeriesT_co, CompliantFrameT_contra]: ...
class SupportsNativeNamespace(Protocol):
@@ -306,7 +313,7 @@ if TYPE_CHECKING:
# This one needs to be in TYPE_CHECKING to pass on 3.9,
# and can only be defined after CompliantExpr has been defined
IntoCompliantExpr: TypeAlias = (
- CompliantExpr[CompliantSeriesT_co] | CompliantSeriesT_co
+ CompliantExpr[CompliantSeriesT_co, CompliantFrameT_contra] | CompliantSeriesT_co
)
This checks out, but would require lots of small changes everywhere that CompliantNamespace
and CompliantExpr
are used.
The reason I say "missing piece", is because it would fill in the only non-generic hole in https://github.com/narwhals-dev/narwhals/blob/9571ad67e0da05d753e3595363b1537a3cef40bf/narwhals/_expression_parsing.py
I think you then might be able to start moving some more of the methods up to the Compliant*
-level.
Or at-least their signatures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note
Those changes are over on (https://github.com/narwhals-dev/narwhals/tree/dev-pyright-eval-out-names)
Which is just +1 commit on top of (#2035)
Passes pyright
and mypy
fully for me locally
Fixes: ```py to_py_scalar_test.py:46:39 - error: Second argument to "isinstance" must be a class or tuple of classes Generic type with type arguments not allowed for instance or class checks ```
docs state `str` is allowed
Shape typing is an ongoing issue numpy/numpy#28076
@@ -15,7 +15,7 @@ | |||
def test_with_columns(constructor_eager: ConstructorEager) -> None: | |||
result = ( | |||
nw.from_native(constructor_eager(data)) | |||
.with_columns(d=np.array([4, 5])) | |||
.with_columns(d=np.array([4, 5])) # pyright: ignore[reportArgumentType] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See (numpy/numpy#28076)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that happy about this.
Might need to change _(1|2)DArray
to just both alias _AnyDArray
Lines 270 to 273 in 9571ad6
_NDArray: TypeAlias = "np.ndarray[_ShapeT, Any]" | |
_1DArray: TypeAlias = "_NDArray[tuple[int]]" # noqa: PYI042, PYI047 | |
_2DArray: TypeAlias = "_NDArray[tuple[int, int]]" # noqa: PYI042, PYI047 | |
_AnyDArray: TypeAlias = "_NDArray[tuple[int, ...]]" # noqa: PYI047 |
Maybe with a doc linking back to the numpy
issue and a description of what we actually mean?
The problem stems from most functions returning shape: tuple[int, ...]
- which fails both _(1|2)DArray
.
- Now passes both type checkers, without ignore comments - Pass `polars` an iterator directly - `aggs` is only iterated over **once** on the `polars` side, rather than **twice** in `narwhals` + again in `polars` #2035 (comment)
`pyright` doesn't recognise `_expr`, but can see: https://github.com/dask/dask-expr/blob/42e7a8958ba286a4c7b2f199d143a70b0b479489/dask_expr/_collection.py#L77 via: https://github.com/dask/dask-expr/blob/42e7a8958ba286a4c7b2f199d143a70b0b479489/dask_expr/__init__.py#L4
To demonstrate that this appears on every use of `CompliantExpr` #2035 (comment)
pyright
to ci?pyright
to ci
- Will always be the same result on every call to the inner `evaluate_output_names` - Unsure how frequent it would be called though, but noticed in (#2035 (comment))
no runtime change, but now we get syntax highlighting
`dask_expr` already imports this for `wraps` (and loads of dependencies), so we didn't even get a performance boost
thanks - generally looks good, if we can get it green i think we can merge! |
Thanks @MarcoGorelli, did you see this? (#2035 (comment)) That gets everything green, but it requires a bigger change - which I split out into another branch for comparison |
@MarcoGorelli could we merge this if I just add this ignore (b26c94c) for all the current errors? We can solve these with either (or maybe both?):
But I'd rather get this part in first because it doesn't redefine any protocols/typevars |
sure, happy to do things incrementally π |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @MarcoGorelli |
What type of PR is this? (check all applicable)
Related issues
mypy
&pyright
errors for_arrow
Β #2007 (comment)Checklist
If you have comments or can explain your changes, please do so below
pyright
as a command.