Repository navigation
feat: Generic Table Conversion through Narwhals - #18435
Conversation
|
Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.
|
|
👋 Thank you for your draft pull request! Do you know that you can use |
|
@TheSkyentist - thanks for this draft PR, it looks excellent and a significant step toward better interoperability! Here is a quick response to your first two questions, more to come...
|
|
I think this is great advice. I've gone ahead and added the to/from pandas methods back to maintain compatibility. I've also added import warnings to the new methods. |
|
Nullable integers - as a general rule the priority goes to maintaining existing tests since (in practice) they define the behavior of astropy more than the documentation. So here you should revert to so the original test passes and fix the documentation. |
|
Error Handling - when possible the goal is to catch common/expected exceptions before they happen downstream and raise exceptions with helpful suggestions. I'm wondering now if it might make sense to make a class-based implementation that allows for backend-specific handling of the interface issues. I.e. a class with a method to validate the input columns for It would then be good to make a distinction in the docs between dataframe types that are explicitly tested vs. those that are not. I'm also thinking there should be a new module e.g. |
|
I have updated the behaviour with |
|
This will definitely deserve a What's New section! |
|
@TheSkyentist - FYI I'll be on vacation July 16-26 so I won't be responding during that time. |
|
Thank you for your feedback already! I do think being explicit about the tested dataframes is a good idea. It's worth thinking about how best to place this code within the Astropy Table ecosystem and do rigorous input checks. I think an entire module might be overkill, at least while the Astropy Table isn't attempting to be fully DataFrame compliant. I'm happy to discuss more after you get back from your vacation and hold of on major changes until then. Side note, how do I add a a What's New beyond the changes.rst? |
|
Re: What's New -- It is not managed by towncrier; rather one manually adds a narrative section in Thank you! |
|
@TheSkyentist - about the separate module, the The biggest hassle I notice with factoring out methods to the actual work functions is duplicate docstrings. I'm not sure if there are clean and accepted ways to handle this. |
|
Have some time to work on this again, not quite ready for merge, still need to fix up and debug the tests, but I've refactor the code into dataframes.py (and test_df.py) and expanded the documentation. It would be great to get feedback at this stage as I continue to make sure all behaviour is as expected in the test suite. |
|
All tests passing! The only feature I haven't managed to get working yet is 1D arrays as entries when converting to/from PyArrow tables, but multidimensions support works for Polars. I will try this a little longer but, if it remains elusive, I think we can leave it for a future PR. Currently the additional features already satisfy the original purpose. I will work on the What's New next. I've also rebased to make merging easy. |
|
I think we are ready for review and potential merge :-) |
|
Only test failing is with the oldest supported versions of all dependencies as Narwhals conversion with PyArrow requires PyArrow >= 11 whereas the astropy has a minimum version of 10. Bumping PyArrow would likely solve this. Is this desired? |
If https://pypi.org/project/pyarrow/#history is the release history you are referring to , then I think it is okay since 11.0.0 was released on 2023-01-27, which is more than 2 years ago. |
|
Hmm still failing with pyarrow 11 |
|
A little trial and error on my part find that the tests pass with PyArrow >= 18. About nine months ago in terms of release date. |
|
I went through and made the appropriate changes to the testing suite :-) |
neutrinoceros
left a comment
There was a problem hiding this comment.
Hopefully this should be my last request for changes :)
Co-authored-by: Clément Robert <[email protected]>
neutrinoceros
left a comment
There was a problem hiding this comment.
(Very) happy to approve this now ! thanks for all your work and patience. The review process has been a pleasure on my part and I hope you enjoyed it too (to the extent that it's possible). I want to give @taldcroft's the last word here, so please do no squash your commits just yet, as he might have a much easier time glancing over anything that changed while he was away in the branch's current state !
|
@neutrinoceros It's been a pleasure! It's been a great experience contributing to Astropy and hopefully it won't be the last time! I appreciate everyone's hard work on getting this PR production ready and I've learned a lot along the way :-) |
|
Why was the type check that |
|
@TheSkyentist - I'd like to ask you to revert a change requested by @neutrinoceros which was renaming There is some discussion on this, but the overriding policy at this time is to maintain the existing style and conventions of a sub-package. For |
|
I fear this would set a dangerous precedent that we cannot ever mark any module as explicitly private: adding the leading |
|
I'll hold of on the renaming of the dataframes module, but to the point on type checking for backend. Currently backend is type checked as a string, so this would be caught by a linter/debugger. The reason for the more explicit catch/except before was that I was not properly using the Narwhals typing system so the previous backend argument only had a type of "Any" which cannot help in debugging. I think type-hinting and express statements in the documentation should be sufficient, i.e. we don't expressly type check all other inputs/arguments. |
At some level the precedent has already been set by 14 years of development, as there are just 11 "private" modules out of 841 in astropy, and Pandas is similar. The question is what is really being gained, especially in context of overwhelming precedent. The main reason I would want to mark an entire module private is if it might credibly disappear entirely in the future or need to be moved or renamed, but I think |
I think that, to one digit of precision, about 0% of astropy users would catch an error in that way (myself included). 😄
Sure. I worry a little about folks with just a bit of deeper knowledge that figure out that other types actually work and start putting that in code. But I guess that is their problem. |
|
In any case, since we can indeed revert Congratuations @TheSkyentist on your first PR and a very substantial and important one at that! |
| dependency-groups = | ||
| alldeps: dataframe | ||
|
|
There was a problem hiding this comment.
@neutrinoceros or @TheSkyentist - what's going on with these new dependency-groups keys?
There was a problem hiding this comment.
And I forgot about this... we can fix in a new PR if necessary.
There was a problem hiding this comment.
I did this myself actually, so it's very much intentional, and I don't see anything to fix. But do feel free to come and chat about it if you want to discuss my reasoning !
There was a problem hiding this comment.
I have no idea what this is doing! Presumably I'll learn in the docs PR you are doing. 😄
There was a problem hiding this comment.
@taldcroft @pllim actually the PR in question already exists: #18342
please discuss there if you need more details
Simple: the ability to change our mind if we ever need to
It's not so much about the status of the functions themselves, rather, that of the namespace.
While true, this only works for readers of downstream code who care enough to either read the module's source, or use type checkers (or linters) that might of unincluded functions as private. Either way it's a minority. Marking the namespace itself as private makes it less likely that someone comes to us with complains that we pulled a rug under them we didn't know they'd rely on. I'd argue if you feel strongly about dropping the underscore, it would be extremely easy to do as a follow up PR so I'd advise that we defer this point. What do you think ? |
|
Oh, I got there too late apparently. Well, at least we converged exactly where I hoped to ! |
| "pyerfa>=2.0.1.1"] | ||
| build-backend = "setuptools.build_meta" | ||
|
|
||
| [dependency-groups] |
There was a problem hiding this comment.
@neutrinoceros , does the dev docs need updating to teach devs how to use this locally?
There was a problem hiding this comment.
Good point. I'll see if I can open a PR shortly.
|
Should not have skipped doctest blindly, see #19716 |
Description
I have added generic DataFrame conversion methods to the Table class:
from_dfallows the user to convert from any Narwhals supported DataFrame library to an astropy Table, e.g. pandas, polars, duckDB, cuDF, etc.to_dfallows the user to convert an Astropy Table into any Narwhals eager-supported DataFrame library, i.e. pandas, polars, cuDF, pyArrow.In addition, I have deprecated the to_pandas and from_pandas methods as they are superseded by these generic methods.Finally, I have updated the documentation to reflect the changes.
I am also requesting feedback on the changes I have made so they can best fit the Astropy project.
Motivation
The discussion in #17146 makes compelling arguments for why the Astropy Table/QTable module exists! However, it is still nice to have features that allow seamless interfacing with other libraries, such as Pandas and Polars. Narwhals allows us to have the best of all worlds by providing a common interface layer so we can transform to/from any DataFrame libraries.
I started to build polars compliance in #18412 but realized it would make more sense to go straight to as general support as possible. In the long run, it may be possible to add astropy.Table as a fully supported Narwhals DataFrame, though this may be overkill since I imagine most users simply want to convert to/from, rather than build agnostic pipelines that can accept Astropy Tables. But this discussion is beyond the scope of this PR.
Feedback
I am hoping to solicit feedback on this PR for some decisions/changes I have made.
Is
pandasthe desired primary DataFrame Library? I have currently added pandas as the default backend forto_df. However I have also added deprecation decorators toto_pandasandfrom_pandas. Do we want to make pandas the default DataFrame conversion library? If so, perhaps we should not deprecate theto_pandasandfrom_pandasaliases?Dependencies. This would add
narwhalsas a dependency for importing/exporting a Table, along with the desired conversion library. What is the best way to ensure that this occurs? Should it be added as a strict Astropy dependency? Or should we warn users that they need it installed? Narhwals has 0 dependencies itself, which is great, but I wanted to ask what the approach should be here.Error Handling. One disadvantage of unifying our export methodologies is that not every dataframe supports the same input. Pandas does not support arrays as entries in a table. PyArrow supports 1D arrays, while polars supports ND arrays. With only pandas we would raise an error with ND arrays, but now we either succeed at exporting the table with multi-dimensional arrays if the backend supports it, or an error is raised by the target backend. Similar issues can occur with mixed d-type columns. Is it worth wrapping our
nw.from_dictimport in try/except clauses to point the user in the direction of why it might be failing?Nullable Integers. Before, the Table testing suite expected a failure when attempting to convert an Astropy.Table with a masked integer column to a pandas DataFrame if use_nullable_int was set to False. However the documentation states that if use_nullable_int is False that the array should be coerced to floats. I have implemented the second and therefore removed the expected failure from the test. Which is the desired behaviour?