-
Notifications
You must be signed in to change notification settings - Fork 170
chore: fixup operator type ignores for SQLExpr
#2920
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
chore: fixup operator type ignores for SQLExpr
#2920
Conversation
narwhals/_sql/typing.py
Outdated
| # not sure how to initialise the class, I want it to have all the methods etc of SQLExprT and add its own operator | ||
| # methods in addition to those | ||
| def __init__(self, other: [Int | Float]) -> None: | ||
| super().__init__(other) |
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.
this class will only be used for type-checking purposes, so there's no need to fill in the implementations for any methods, in particular, you don't need to define __init__
for the others, you can just return ...
2bd2b9b to
f8e853c
Compare
narwhals/_sql/typing.py
Outdated
|
|
||
| class NativeSQLExpr(NativeExpr): | ||
| # TODO @mp: fix input type for all these! | ||
| def __gt__(self, value: float) -> Boolean: ... |
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.
the return type should be Self
In [11]: import duckdb
In [12]: duckdb.ColumnExpression('a') == 3
Out[12]: (a = 3)
In [13]: type(duckdb.ColumnExpression('a') == 3)
Out[13]: duckdb.duckdb.Expressionwhen you do arithmetic / comparisons between these expressions, the output is still an expression
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.
ah thanks for that, now I understand why Self!
d3af7d3 to
a4de0bb
Compare
9377eb7 to
d372db6
Compare
|
pytests seem to suggest something going on with the arguments to NativeSQLExprT, I think I do need to define the arguments by making a NativeSQLExprTAny; looking into this! but NativeSQLExpr doesn't take any arguments, so unlikely to be the solution.. |
yup, that's right!
EDIT: discussed over a call how to resolve this |
efcbd68 to
3a97dcb
Compare
ah just seen this, thanks! |
f540cd8 to
9a544e8
Compare
c0e19c5 to
266cab9
Compare
660b4e3 to
4aae069
Compare
247ad11 to
7ad112a
Compare
23eb022 to
937e2a1
Compare
|
hmm i can see why the typing errors happen, i'm not sure how to fix though. I'll add comments to the files where the errors are flagged. |
|
2 ibis type errors remain - don't know if my technique is right, is there a better way? |
|
I'm seriously tempted to say that we should just switch to Afterall, Ibis doesn't export its type annotations, nor do they even check them, so I don't think it's worth bending backwards over their non-public types anyway. We're having to introduce cc @dangotbanned in case you have thoughts |
|
re going for an 'Any' type, let me know if/when I can implement or if I should try to find another fix |
|
Thanks for the ping @MarcoGorelli Let me have a think on it today |
My preference would be to open issue(s) upstream first. These operator issues would also fall into that category as we want the methods defined in https://github.com/ibis-project/ibis/blob/db1a727b3c4c75e8e4af0f7ef3d0101d26d4450b/ibis/expr/types/numeric.py and not From the looks of (ibis-project/ibis#11511), I'm getting the feeling that the We do have the benefit of an entire sub-package documenting where we've struggled π If we don't have any success there, another option is isolating the problematic paths and wrapping them with our own annotations. Show examples
narwhals/narwhals/_pandas_like/utils.py Lines 396 to 404 in a8b89fd
narwhals/narwhals/_pandas_like/utils.py Line 657 in a8b89fd
narwhals/narwhals/_pandas_like/namespace.py Lines 374 to 410 in a8b89fd
narwhals/narwhals/_namespace.py Lines 102 to 150 in a8b89fd
narwhals/narwhals/_spark_like/namespace.py Lines 53 to 60 in a8b89fd
While this is an option, I wouldn't suggest it until we know that the only alternative is typing everything as |
|
All I can think to suggest is, in and fill in the missing bits Alternatively, use perhaps i'll give this a go later |
Sadly this won't work IIRC, as a |
|
π€ i'm wondering if In [1]: import ibis
In [2]: ibis._['a']
Out[2]: _['a']
In [3]: type(_)
Out[3]: ibis.common.deferred.Deferred |
Replaces them with calls to `operator` functions, which use `Any`
|
How do you feel about this? I've tried to keep the terseness of using operators through aliasing. This works due to most of these functions being typed more permissively |
| # NOTE: None of these are annotated for `dx.Series`, but are added imperatively | ||
| # Probably better to define a sub-protocol for `NativeSQLExpr` | ||
| # - match `dx.Series` to `NativeExpr` | ||
| # - match the others to `NativeSQLExpr` | ||
| def __gt__(self, value: Any, /) -> Self: ... | ||
| def __lt__(self, value: Any, /) -> Self: ... | ||
| def __ge__(self, value: Any, /) -> Self: ... | ||
| def __le__(self, value: Any, /) -> Self: ... | ||
| def __eq__(self, value: Any, /) -> Self: ... # type: ignore[override] | ||
| def __ne__(self, value: Any, /) -> Self: ... # type: ignore[override] |
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.
oh my π€¦
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.
looks good to me, thanks @dangotbanned
So, the idea is to put the comparison operators in NativeExpr, and for the arithmetic ones we just use operator? And just ignore for Dask, which implements these in a hacky way anyway
@ym-pett I think if you clean up the temporary comments, then I think we can ship this
| # NOTE: None of these are annotated for `dx.Series`, but are added imperatively | ||
| # Probably better to define a sub-protocol for `NativeSQLExpr` | ||
| # - match `dx.Series` to `NativeExpr` | ||
| # - match the others to `NativeSQLExpr` | ||
| def __gt__(self, value: Any, /) -> Self: ... | ||
| def __lt__(self, value: Any, /) -> Self: ... | ||
| def __ge__(self, value: Any, /) -> Self: ... | ||
| def __le__(self, value: Any, /) -> Self: ... | ||
| def __eq__(self, value: Any, /) -> Self: ... # type: ignore[override] | ||
| def __ne__(self, value: Any, /) -> Self: ... # type: ignore[override] |
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.
looks good, thanks - if anything, I like it better if we match on these than if we match on between and isin (which, for example, Daft doesn't have)
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.
This is the important bit
narwhals/narwhals/_compliant/expr.py
Lines 57 to 62 in 5bcdb6e
| class NativeExpr(Protocol): | |
| """An `Expr`-like object from a package with [Lazy-only support](https://narwhals-dev.github.io/narwhals/extending/#levels-of-support). | |
| Protocol members are chosen *purely* for matching statically - as they | |
| are common to all currently supported packages. | |
| """ |
which, for example, Daft doesn't have
I had a similar issue for ibis.Table in (#2944)
Line 124 in 0d4b6f7
| IntoLazyFrame: TypeAlias = Union["NativeLazyFrame", "_NativeIbis"] |
It's okay to have multiple protocols/sub-protocols/aliases if we need that now
I started with 1 because we had a common denominator, but we grow π
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.
had a common denominator
right, so if we add these comparison operators, we can remove isin and between?
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.
Keep between if possible
Kind of like how we have filter for NativeSeries - it's something to avoid false-positives
Waaaaay more than just the types we're interested in will have comparison dunders, but fewer will also have between as well
SQLExpr
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.

What type of PR is this? (check all applicable)
Related issues
Checklist
If you have comments or can explain your changes, please do so below