-
Notifications
You must be signed in to change notification settings - Fork 170
refactor: *(Namespace|DataFrame).from_numpy
#2283
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
`to_numpy` is already handled via `__getattr__`
Don't need to explicitly define in `CompliantDataFrame`, as it gets it from `NumpyConvertible`
The module already has a top-level `pl` import
- I thought what I had was allowed - but caused a runtime error in subclasses that *didn't* fill the missing `FromNumpyDT_contra` > TypeError: Too few arguments for <class 'narwhals._compliant.dataframe.CompliantDataFrame'>; actual 3, expected at least 4
One step towards `CompliantNamespace.from_numpy`
Adding the annotation of `CompliantNamespace` revealed a lot of gaps
Towards fixing this error, but without subclassing
```py
narwhals/utils.py:363: error: Incompatible return value type (got "PolarsNamespace", expected "CompliantNamespace[Any, Any]") [return-value]
return PolarsNamespace(backend_version=backend_version, version=version)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
narwhals/utils.py:363: note: Following member(s) of "PolarsNamespace" have conflicts:
narwhals/utils.py:363: note: selectors: expected "CompliantSelectorNamespace[Any, Any]", got "PolarsSelectors"
```
See note on property for blockers
Now we've got access to both `from_numpy` constructors from `Implementation`!
- Important to this PR is `is_eager_allowed` - Allows us to match `PolarsNamespace`, without defining redundant stuff in protocols/classes
- Spent too long trying to solve this - `pyright` has no issues - I can see moving `_to_compliant_namespace` into a function working - But I don't want that, and seems like a bug
Resolves #2283 (comment)
This part is independent of backends following (50a39df)
- All of that is functionally the same as what is covered - `_series.from_numpy` will get used in upcoming PRs https://github.com/narwhals-dev/narwhals/actions/runs/14045870768/job/39326463172?pr=2283
*(Namespace|DataFrame).from_numpy*(Namespace|DataFrame).from_numpy
|
The longer-term goal would be to transition more of We might already have everything in place for |
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 Will investigate in #2283 (comment) |
*(Namespace|DataFrame).from_numpy*(Namespace|DataFrame).from_numpy
| def concat( | ||
| self: Self, | ||
| items: Iterable[PolarsLazyFrame], | ||
| *, | ||
| how: Literal["vertical", "horizontal", "diagonal"], | ||
| ) -> PolarsLazyFrame: ... | ||
|
|
||
| def concat( | ||
| self: Self, | ||
| items: Iterable[PolarsDataFrame] | Iterable[PolarsLazyFrame], | ||
| items: Iterable[FrameT], | ||
| *, | ||
| how: Literal["vertical", "horizontal", "diagonal"], | ||
| ) -> PolarsDataFrame | PolarsLazyFrame: |
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.
Resolves (#2283 (comment)) via (0e67a1e)
@MarcoGorelli
I had no idea a TypeVar could be used this way 🤔
One rule I thought was that a TypeVar on a parameter annotation must either:
- Be present in the class def (e.g.
Generic[T]orProtocol[T]) - Or appear in the return type
narwhals/narwhals/_polars/typing.py
Line 21 in 4f1b172
| FrameT = TypeVar("FrameT", PolarsDataFrame, PolarsLazyFrame) |
FrameT doesn't meet either of those rules - so I'd have expected this to get rejected.
But why work??
My best guess is there seems to be an understanding of what FrameT represents - and how that is consistent with:
narwhals/narwhals/_compliant/namespace.py
Lines 72 to 77 in 4f1b172
| def concat( | |
| self, | |
| items: Iterable[CompliantFrameT], | |
| *, | |
| how: Literal["horizontal", "vertical", "diagonal"], | |
| ) -> CompliantFrameT: ... |
narwhals/narwhals/_compliant/typing.py
Line 74 in 4f1b172
| CompliantFrameT = TypeVar("CompliantFrameT", bound=CompliantFrameAny) |
narwhals/narwhals/_compliant/typing.py
Lines 40 to 42 in 4f1b172
| CompliantDataFrameAny: TypeAlias = "CompliantDataFrame[Any, Any, Any]" | |
| CompliantLazyFrameAny: TypeAlias = "CompliantLazyFrame[Any, Any]" | |
| CompliantFrameAny: TypeAlias = "CompliantDataFrameAny | CompliantLazyFrameAny" |
Follow up to #2283 (comment)

What type of PR is this? (check all applicable)
Related issues
CompliantSeries.from_numpy#2196 (comment)Checklist
If you have comments or can explain your changes, please do so below
Compliant*protocols #2230)from_numpyas all the supported backends already had ato_numpy, to complete theNumpyConvertiblepairfunctions.pypyright, butmypyhad issues with definingoverload(s) onImplementationnw.Namespaceclass to provide a scope for the singleImplementation->CompliantNamespacecontext