-
Notifications
You must be signed in to change notification settings - Fork 170
refactor(typing): Add _native.py
#3086
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
`v1` is different for the frame cases #3016 (comment)
|
@FBruzzesi just pinging you on the off-chance you can review before I'm stranded π |
Hey @dangotbanned I will take a look before the end of the weekend/I leave for vacation :D |
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 @dangotbanned - I didn't check line by line, I assumed that most of the changes were simply due to the different import source and somplifications. I double checked the new module and left a couple of comments. Let me know what your thoughts are
narwhals/_native.py
Outdated
| ### (1) `Native(*Frame|Series)` | ||
| Minimal [`Protocol`]s for matching *almost any* supported native type of that group: | ||
| class NativeThing(Protocol): | ||
| def something_common(self, *args: Any, **kwargs: Any) -> Any: ... | ||
| Note: | ||
| This group is primarily a building block for more useful types. | ||
| ### (2) `Into(*Frame|Series)` | ||
| *Publicly* exported [`TypeAlias`]s of **(1)**: | ||
| IntoThing: TypeAlias = NativeThing | ||
| **But**, occasionally, there'll be an edge-case which we can spell like: | ||
| IntoThing: TypeAlias = Union[<type that does not fit the protocol>, NativeThing] | ||
| Tip: | ||
| Reach for these when there **isn't a need to preserve** the original native type. | ||
| ### (3) `Into(*Frame|Series)T` | ||
| *Publicly* exported [`TypeVar`]s, bound to **(2)**: | ||
| IntoThingT = TypeVar("IntoThingT", bound=IntoThing) | ||
| Important: | ||
| In most situations, you'll want to use these as they **do preserve** the original native type. | ||
| Putting it all together, we can now add a *narwhals-level* wrapper: | ||
| class Thing(Generic[IntoThingT]): | ||
| def to_native(self) -> IntoThingT: ... |
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.
Mostly nitpicking on the usage of Thing. I am trying to put myself into the shoes of a newcomer and I wonder if something along the following lines would be more helpful:
| ### (1) `Native(*Frame|Series)` | |
| Minimal [`Protocol`]s for matching *almost any* supported native type of that group: | |
| class NativeThing(Protocol): | |
| def something_common(self, *args: Any, **kwargs: Any) -> Any: ... | |
| Note: | |
| This group is primarily a building block for more useful types. | |
| ### (2) `Into(*Frame|Series)` | |
| *Publicly* exported [`TypeAlias`]s of **(1)**: | |
| IntoThing: TypeAlias = NativeThing | |
| **But**, occasionally, there'll be an edge-case which we can spell like: | |
| IntoThing: TypeAlias = Union[<type that does not fit the protocol>, NativeThing] | |
| Tip: | |
| Reach for these when there **isn't a need to preserve** the original native type. | |
| ### (3) `Into(*Frame|Series)T` | |
| *Publicly* exported [`TypeVar`]s, bound to **(2)**: | |
| IntoThingT = TypeVar("IntoThingT", bound=IntoThing) | |
| Important: | |
| In most situations, you'll want to use these as they **do preserve** the original native type. | |
| Putting it all together, we can now add a *narwhals-level* wrapper: | |
| class Thing(Generic[IntoThingT]): | |
| def to_native(self) -> IntoThingT: ... | |
| ### (1) `Native(*Frame|Series)` | |
| Minimal [`Protocol`]s for matching *almost any* supported native type of that group: | |
| class NativeObject(Protocol): | |
| def some_common_method(self, *args: Any, **kwargs: Any) -> Any: ... | |
| Note: | |
| This group is primarily a building block for more useful types. | |
| ### (2) `Into(*Frame|Series)` | |
| *Publicly* exported [`TypeAlias`]s of **(1)**: | |
| IntoNarwhalsObject: TypeAlias = NativeObject | |
| **But**, occasionally, there'll be an edge-case which we can spell like: | |
| IntoNarwhalsObject: TypeAlias = Union[<type that does not fit the protocol>, NativeObject] | |
| Tip: | |
| Reach for these when there **isn't a need to preserve** the original native type. | |
| ### (3) `Into(*Frame|Series)T` | |
| *Publicly* exported [`TypeVar`]s, bound to **(2)**: | |
| IntoNarwhalsObjectT = TypeVar("IntoNarwhalsObjectT", bound=IntoNarwhalsObject) | |
| Important: | |
| In most situations, you'll want to use these as they **do preserve** the original native type. | |
| Putting it all together, we can now add a *narwhals-level* wrapper: | |
| class NarwhalsObject(Generic[IntoNarwhalsObjectT]): | |
| def to_native(self) -> IntoNarwhalsObjectT: ... |
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 for the review @FBruzzesi!
Mostly nitpicking on the usage of
Thing
I am tempted to bikeshed on the name π ...
But regardless of what exactly it is - would some kind of intro like this be helpful?
narwhals/narwhals/_translate.py
Lines 1 to 11 in e92fcc9
| """[Protocols] defining conversion methods between representations. | |
| These come in 3 flavors and are [generic] to promote reuse. | |
| The following examples use the placeholder types `Narwhal` and `Other`: | |
| - `Narwhal`: some class written in `narwhals`. | |
| - `Other`: any other class, could be native, compliant, or a builtin. | |
| ## `To<Other>` | |
| When we want to convert or unwrap a `Narwhal` into an `Other`, | |
| we provide an **instance** method: |
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.
Yes I think it might help, but really I don't want to make a fuss out of it - I am not a fan of using a generic thing, and in this situation (i.e. a python context?!) *Class or *Object would be more appropriate π
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.
I am tempted to bikeshed on the name π ...
But regardless of what exactly it is
Sorry @FBruzzesi, I'm reading this back now and it isn't coming across the way that I intended.
My suggestion (#3086 (comment)) was supposed to be another way to help with
I am trying to put myself into the shoes of a newcomer
But not saying that should be instead of choosing a better name than *Thing π
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.
So the naming scheme in (#3086 (comment)) is slightly different from what I was trying to demonstrate
and in this situation (i.e. a python context?!)
*Classor*Objectwould be more appropriate π
Here's what each of those look like:
| Actual | Current | Proposed | Alt 1 | Alt 2 |
|---|---|---|---|---|
NativeSeries |
NativeThing |
NativeObject |
NativeObject |
NativeClass |
IntoSeries |
IntoThing |
IntoNarwhalsObject |
IntoObject |
IntoClass |
IntoSeriesT |
IntoThingT |
IntoNarwhalsObjectT |
IntoObjectT |
IntoClassT |
Series |
Thing |
NarwhalsObject |
Object |
Class |
Note
FWIW, I don't like any of them now - including Thing π
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.
At the end of the day it's a developer documentation, not even visible to a user so I won't be too picky nor a blocker.
If everything else is okay - we could do one more round of brainstorming a better name than Thing to get it over the line
βΊοΈ
For iteration over it, I am quite open to anything which is not called Thing π
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.
For iteration over it, I am quite open to anything which is not called
Thingπ
Alright I'll try to churn out a list of non-Things to choose from shortly π
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.
Okay @FBruzzesi here we go:
ArrayDataColumnMatrixDogScalarLinkedListBoxBear
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.
@dangotbanned I am sold! Let's ship it with Bear's and Dog's π
/sarcam
Really feel free to merge after resolving the conflict
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 @FBruzzesi π
If you decide on one you prefer (including Bear and Dog π), feel free to update the doc in a follow up π
- Use similar syntax to #2455 - Introduce things like #2455 - #3086 (comment) - #3086 (comment) - Sub-divide the 5 cases - Avoid using the terms *wrap* and *match* outside of the two groups - TODOs on #3086 (comment)
|
@FBruzzesi how do you feel about the rest of this besides (#3086 (comment))? I really want to move forward on it to unblock #3125 and I also noticed (main...chore/refactor-pandas-like-pyarrow-branching) would be touching some of the changed bits as well If everything else is okay - we could do one more round of brainstorming a better name than |
Sorry @dangotbanned I went on vacation and somehow thought this PR was done. I will take another look in the weekend |
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 @dangotbanned - I left a nitpick suggestion, everything else looks good to me. Sorry for the headache over naming things
Co-authored-by: Francesco Bruzzesi <[email protected]>
|
thanks for your PR! if you're both happy with it feel free to take it forwards it wasn't clear to me on reading why we're now returning |
Thanks @MarcoGorelli π
Hmm, I seem to have done a bad job on the docs then π Here I was trying to explain ... Lines 34 to 44 in 3a004e8
... which means we can write like this narwhals/narwhals/stable/v1/typing.py Line 27 in 3a004e8
Line 279 in 3a004e8
narwhals/narwhals/stable/v1/typing.py Line 40 in 3a004e8
Line 292 in 3a004e8
This wasn't the original purpose of the aliases, but I've kinda reclaimed them to work as a lil barrier between the protocols |
|
cool, thanks!
oh no, you've done an excellent job, i just hadn't spent much time on it, happy to trust you two on this one |

What type of PR is this? (check all applicable)
Related issues
Implementationless opaqueΒ #3016 (comment)SparkSessiontoo feat: Allow spark-like backends in.lazy(backend=...)Β #3032 (comment)Checklist
If you have comments or can explain your changes, please do so below