chore: Remove level from main and v2 classes init#3558
Conversation
| @@ -1922,7 +1922,7 @@ def convert_str_slice_to_int_slice( | |||
|
|
|||
|
|
|||
| def inherit_doc( | |||
| tp_parent: Callable[P, R1], / | |||
| tp_parent: Callable[..., R1], / | |||
There was a problem hiding this comment.
@dangotbanned you might have a better way of doing this but here what happened - by changing the main namespace __init__ signatures, now the V1 is overriding them and the arguments are different, to so the child ones are not bind to the parent ones - hence removing the P from the parent here.
This meant that return DataFrame(self, level="interchange") was resulting in a typing issue
There was a problem hiding this comment.
So I fixed that now 🎉
But it made me realize we don't need it for any Series, DataFrame, LazyFrame if we just remove the constructor override?
narwhals/src/narwhals/stable/v1/__init__.py
Lines 133 to 137 in cd256d6
That assertion is pointless - as it checks a ClassVar, and that's it AFAICT?
|
I'm not sure how exactly, but I think the The error output isn't helping narrow it down though FAILED tests/_data/test_preview_column.py::test_get_column_preview_for_duckdb - AssertionError: assert None is not None
+ where None = DataColumnPreviewNotification(chart_spec=None, chart_code=None, error=None, missing_packages=None, stats=ColumnStats(t...=0.502518907629606, true=None, false=None, p5=0.0, p25=0.0, p75=1.0, p95=1.0), table_name='tbl', column_name='outcome').chart_spec
FAILED tests/_data/test_preview_column.py::test_get_column_preview_for_duckdb_categorical - AssertionError: assert None is not None
+ where None = DataColumnPreviewNotification(chart_spec=None, chart_code=None, error=None, missing_packages=None, stats=ColumnStats(t...one, std=None, true=None, false=None, p5=None, p25=None, p75=None, p95=None), table_name='tbl', column_name='category').chart_spec
FAILED tests/_data/test_preview_column.py::test_get_column_preview_for_duckdb_date - AssertionError: assert None is not None
+ where None = DataColumnPreviewNotification(chart_spec=None, chart_code=None, error=None, missing_packages=None, stats=ColumnStats(t...std=None, true=None, false=None, p5=None, p25=None, p75=None, p95=None), table_name='date_tbl', column_name='date_col').chart_spec
FAILED tests/_data/test_preview_column.py::test_get_column_preview_for_duckdb_datetime - AssertionError: assert None is not None
+ where None = DataColumnPreviewNotification(chart_spec=None, chart_code=None, error=None, missing_packages=None, stats=ColumnStats(t..., true=None, false=None, p5=None, p25=None, p75=None, p95=None), table_name='datetime_tbl', column_name='datetime_col').chart_spec
FAILED tests/_data/test_preview_column.py::test_get_column_preview_for_duckdb_bool - AssertionError: assert None is not None
+ where None = DataColumnPreviewNotification(chart_spec=None, chart_code=None, error=None, missing_packages=None, stats=ColumnStats(t...ne, std=None, true=50, false=50, p5=None, p25=None, p75=None, p95=None), table_name='bool_tbl', column_name='bool_col').chart_spec
= 5 failed, 2402 passed, 10 skipped, 26 xfailed, 1 xpassed, 49 warnings in 65.09s (0:01:05) = |
|
|
||
| return DataFrameV1(self, level="interchange") # type: ignore[no-any-return] | ||
| return self._version.lazyframe(self, level="lazy") | ||
| return DataFrameV1(self) # type: ignore[no-any-return] |
There was a problem hiding this comment.
Right I think I've found the issue for (#3558 (comment))
The repro is this:
import narwhals as nw
import narwhals.stable.v1 as nw_v1 # noqa: F811
native_duck = nw.from_dict({"a": [1, 2, 3]}, backend="polars").lazy("duckdb").to_native()
v1_duck = nw_v1.from_native(native_duck)
nw_v1.get_level(v1_duck)"full"The issue is that I've misunderstood what these guys are for:
narwhals/src/narwhals/stable/v1/__init__.py
Lines 926 to 933 in cd256d6
I thought that we'd have used InterchangeFrame, e.g. here:
narwhals/src/narwhals/translate.py
Lines 456 to 468 in cd256d6
There was a problem hiding this comment.
I'm still pretty confused why we aren't doing that, and were instead passing around a string 🤔
There was a problem hiding this comment.
Okay more digging...
The tests added from #1266 appear to have been invalid since #1725.
On main (71a0204)
import duckdb
import narwhals as nw
import narwhals.stable.v1 as nw_v1 # noqa: F811
native_duck = nw.from_dict({"a": [1, 2, 3]}, backend="polars").lazy("duckdb").to_native()
v1_duck:nw_v1.DataFrame[duckdb.DuckDBPyRelation] = nw_v1.from_native(native_duck)
print(v1_duck._compliant.__class__.__name__, repr(nw_v1.get_level(v1_duck)))
v1_duck.select(nw_v1.col("a").max())DuckDBLazyFrame 'interchange'
┌──────────────────┐
|Narwhals DataFrame|
|------------------|
| ┌───────┐ |
| │ a │ |
| │ int64 │ |
| ├───────┤ |
| │ 3 │ |
| └───────┘ |
└──────────────────┘
This looks like more than interchange-only support?
There was a problem hiding this comment.
Just wanna be sure you see this, since it looks like a 🐛 that's been hiding in interchange only support for a long time
There was a problem hiding this comment.
is this issue that it's allowing select(nw_v1.col("a").max()), whereas it should be erroring?
if so, that doesn't really look like an issue? i don't think interchange level was ever meant to mean "only interchange"
There was a problem hiding this comment.
That said, it's still not clear to me what marimo is relying on that this PR is breaking leading to their CI to fail
The CI failure is because of how I tried to factor out level:
if isinstance(obj, DataFrame):
return "interchange" if isinstance(obj._compliant, InterchangeFrame) else "full"
# ^^^^^^^^^^^^^^^^^ (me not realising that this was a `DuckDBPyRelation`)That can be fixed by changing the condition to use both Version and Implementation.
But fixing that doesn't change (#3558 (comment)) - which I thought was a big issue
There was a problem hiding this comment.
That can be fixed
As promised (fix: try a different level refactor?) does fix (marimo)
There was a problem hiding this comment.
As an experiment
I'm gonna branch off here (#3721) and see how bad downstream breaks if we enforce (#3558 (comment))
I think the answer will be a lot, but who knows 😅
There was a problem hiding this comment.
but I am confident that a DuckDBPyRelation is not a DataFrame.
not sure what this means tbh, could you explain please?
There was a problem hiding this comment.
Show thread
@MarcoGorelli
I don't think interchange level was ever meant to mean "only interchange"@dangotbanned
Maybe I've misunderstood, and this never meant that:but I am confident that a
DuckDBPyRelationis not aDataFrame.@MarcoGorelli
not sure what this means tbh, could you explain please?
not sure what this means tbh, could you explain please?
Sure.
If you asked me a week ago what interchange level meant; I would've described a subset of this.
If I did my homework; I'd have taken a look at InterchangeFrame and describe that.
But both of those are wrong.
So now, if I want to describe what it means - what am I left with?
- To a type checker it is
v1.DataFrame[DuckDBPyRelation] - At runtime, it's anything that doesn't raise an error?
Summary
- I don't understand what is being promised by interchange-level
- That concerns me because we are supporting it indefinitely
- Our test suite does not cover anything beyond IO, selecting columns by name, and dtypes
Updated
See (#3721), (#3721 (comment))
... but this reveals another bug 😭 Mentioned in (#3558 (comment))
Going scorched-earth to find out who's using it downstream Part 1 of (#3558 (comment))
I'm dismissing my review, because I left it before finding (#3558 (comment)), (#3558 (comment))
Just want to avoid this merging before finishing (#3721)
Really sorry, I shouldn't have approved while we still had downstream CI running
Description
Not really user facing but I had it started some time ago, so why not finish it 😇
What type of PR is this? (check all applicable)
Related issues
level,DataFrameLikefrommain,v2#2932Checklist