Skip to content

(fix): remove _getattr__ method for PandasExtensionArray #10250

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

Merged
merged 258 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
258 commits
Select commit Hold shift + click to select a range
5d68bfe
reorganize pandas compatibility code, remove unneeded code, attempt t…
kmuehlbauer Oct 14, 2024
07bba69
another attempt to finally fix mypy
kmuehlbauer Oct 14, 2024
6e7f0bb
refactor out _check_date_is_after_shift
kmuehlbauer Oct 14, 2024
b4a49bb
refactor out _maybe_strip_tz_from_timestamp
kmuehlbauer Oct 14, 2024
2e1ff4f
more refactoring in coding.times.py
kmuehlbauer Oct 14, 2024
d5a7da0
more refactoring in coding.times.py
kmuehlbauer Oct 14, 2024
821b68d
minor fix in time-coding.rst
kmuehlbauer Oct 14, 2024
d066edf
set default resolution to "s", which actually means, use pandas lowes…
kmuehlbauer Oct 14, 2024
ed22da1
Add section for default units, fix options
kmuehlbauer Oct 14, 2024
8bf23f4
attempt to fix typing
kmuehlbauer Oct 14, 2024
c3a2b39
attempt to fix typing
kmuehlbauer Oct 14, 2024
3c44aed
fix scalar datetime/timedelta
kmuehlbauer Oct 15, 2024
48be73a
fix user docs
kmuehlbauer Oct 15, 2024
7ac9983
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 18, 2024
d86ad04
Fix variable tests, mostly datetime/timedelta is inittialized with us…
kmuehlbauer Oct 18, 2024
b5d0795
revert changes in _possible_convert_objects, this needs to be checked…
kmuehlbauer Oct 18, 2024
60324f0
fix doc link
kmuehlbauer Oct 18, 2024
c2bc4df
(fix): allow all extension array data types in pandas adapters
ilan-gold Oct 23, 2024
84569bc
(fix): dataframes have no `array` attr
ilan-gold Oct 23, 2024
90e390d
(fix): allow chunked numpy extension arrays because of `test_pandas_a…
ilan-gold Oct 24, 2024
7c32bd0
(fix): dtypes for `PandasIndex`
ilan-gold Oct 24, 2024
795ecf6
(chore): remove test for unnecessary conversion
ilan-gold Oct 24, 2024
8eca6e9
(revert): don't let through so much in `as_compatible_data`
ilan-gold Oct 24, 2024
fb91812
(fix): account for series -> numpy conversions
ilan-gold Oct 25, 2024
a06f2b1
(fix): ensure dtype check is for numpy type
ilan-gold Oct 25, 2024
14027e8
(fix): convert pandas `IntervalArray`
ilan-gold Oct 25, 2024
a47a96f
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Oct 25, 2024
6f2861a
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 8, 2024
1f07500
Apply suggestions from code review
kmuehlbauer Nov 8, 2024
798b444
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 8, 2024
f487599
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 16, 2024
20d6c9d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 16, 2024
7391948
remove outdated description
kmuehlbauer Nov 16, 2024
308091c
use set instead list
kmuehlbauer Nov 16, 2024
5f40b4e
remove global option
kmuehlbauer Nov 16, 2024
2a65d8d
mypy thinks `unit` is Literal, because the pandas-stubs suggest so, b…
kmuehlbauer Nov 17, 2024
43f7d61
ignore mypy arg-type
kmuehlbauer Nov 17, 2024
59934b9
fix docstring of `default_precision_timestamp`
kmuehlbauer Nov 17, 2024
a01f9f3
add 'time_unit'-kwarg to decode_cf and descendent functions with "ns"…
kmuehlbauer Nov 17, 2024
8b91128
fix tests
kmuehlbauer Nov 17, 2024
0e351ca
fix more tests
kmuehlbauer Nov 17, 2024
07a8e9c
fix docstring
kmuehlbauer Nov 17, 2024
2be5739
use pd.Timestamp(np.datetime64(cftime)) to convert from cftime to numpy
kmuehlbauer Nov 17, 2024
b9d0a8e
use dt = np.datetime64(cftime.isoformat()) to convert from cftime to …
kmuehlbauer Nov 18, 2024
08afc3b
fix time-coding.rst
kmuehlbauer Nov 18, 2024
edc55e1
use us in to_datetimeindex
kmuehlbauer Nov 18, 2024
bffe919
revert back to us for datetimeindex tests
kmuehlbauer Nov 18, 2024
150b982
estimate fitting resolution for floating point values, when decoding …
kmuehlbauer Nov 18, 2024
7113ceb
add test
kmuehlbauer Nov 18, 2024
7f47f0b
refactor floating point decoding
kmuehlbauer Nov 18, 2024
512808d
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 18, 2024
63c83f4
simplify recursive function, update tests
kmuehlbauer Nov 18, 2024
0efbbeb
more refactoring, update tests
kmuehlbauer Nov 19, 2024
2910250
add fixture, apply fixture to more tests.
kmuehlbauer Nov 19, 2024
57d8d72
update time-coding.rst
kmuehlbauer Nov 19, 2024
5333240
fix typing
kmuehlbauer Nov 19, 2024
6f35c81
try to fix test, remove stale print
kmuehlbauer Nov 19, 2024
d0c17a4
another attempt to fix test
kmuehlbauer Nov 19, 2024
b2b6bb1
debug failing test
kmuehlbauer Nov 19, 2024
5dbc8a7
refactor cftime fallback in datetime decoding
kmuehlbauer Nov 21, 2024
be0d3e0
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 21, 2024
f95408a
fix merge-collission
kmuehlbauer Nov 21, 2024
609e15c
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 21, 2024
ec7f165
use CFDatetimeCoder instance to transport unit/use_cftime
kmuehlbauer Nov 22, 2024
1f1cf1c
decode_times with CFDatetimeCoder
kmuehlbauer Nov 25, 2024
14b1a88
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 25, 2024
05627dd
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 25, 2024
e7cbf3a
fix mypy, warning/error
kmuehlbauer Nov 26, 2024
fc87e04
api, docs, docstrings
kmuehlbauer Nov 26, 2024
9ae645e
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 26, 2024
6e3ca57
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 27, 2024
277d1c6
docs, whats-new.rst
kmuehlbauer Nov 27, 2024
81a9d94
fix whats-new.rst
kmuehlbauer Nov 27, 2024
be8642f
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 27, 2024
f3f62e5
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 2, 2024
c07df41
Merge remote-tracking branch 'origin/main' into any-time-resolution-2
kmuehlbauer Dec 10, 2024
ae49850
Merge branch 'any-time-resolution-2' into ig/fix_extension_indexer
ilan-gold Dec 10, 2024
e8f5aa8
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Dec 10, 2024
9653a01
fix tests after merge
kmuehlbauer Dec 10, 2024
a405f03
Merge branch 'any-time-resolution-2' into ig/fix_extension_indexer
ilan-gold Dec 10, 2024
503b313
(fix): `dtype` type handling
ilan-gold Dec 11, 2024
c8ab8f3
(fix): move out of type checking block
ilan-gold Dec 11, 2024
66e5b06
(fix): satisfy mypy
ilan-gold Dec 11, 2024
f9fde3a
(fix): doctest
ilan-gold Dec 11, 2024
8a3e834
(fix): `nbytes` test?
ilan-gold Dec 11, 2024
f5822fd
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 12, 2024
66c0b9f
Apply suggestions from code review
kmuehlbauer Dec 13, 2024
ba51274
provide CFDatetimeCoder from xarray.coders
kmuehlbauer Dec 13, 2024
3ba3e3f
provide CFDatetimeCoder from xarray.coders
kmuehlbauer Dec 13, 2024
1ab43eb
provide CFDatetimeCoder from xarray.coders
kmuehlbauer Dec 13, 2024
45ba9d3
fix tests as suggested by code review
kmuehlbauer Dec 13, 2024
091a90d
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 14, 2024
ab3c9ed
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 14, 2024
53fe43a
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 16, 2024
a16a890
Move scalar handling logic into `_possibly_convert_objects` as sugges…
kmuehlbauer Dec 16, 2024
4283f8a
Add note on ``proleptic_gregorian`` calendar
kmuehlbauer Dec 16, 2024
0ba848d
remove time_resolution from docstring
kmuehlbauer Dec 16, 2024
6cb8702
update time.coding.rst wrt default time unit
kmuehlbauer Dec 16, 2024
5de8d0d
fix empty array
kmuehlbauer Dec 16, 2024
fc985d9
revert some tests to align with scalar logic handling
kmuehlbauer Dec 16, 2024
799b750
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 16, 2024
a2d8e69
split out CFDatetimeCoder into coders, deprecate use_cftime as keywor…
kmuehlbauer Nov 22, 2024
d6fe956
add whats-new.rst entry
kmuehlbauer Dec 17, 2024
bd6a5d1
Apply suggestions from code review
kmuehlbauer Dec 17, 2024
6557ef9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 17, 2024
759fb72
fix warning
kmuehlbauer Dec 17, 2024
2118191
fix docstrings
kmuehlbauer Dec 17, 2024
262295a
try fix typing
kmuehlbauer Dec 17, 2024
941c4b5
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 18, 2024
6e41425
Merge branch 'main' into coders
kmuehlbauer Dec 18, 2024
adebafa
Apply suggestions from code review
kmuehlbauer Dec 30, 2024
6cd81e5
Apply suggestions from code review
kmuehlbauer Dec 30, 2024
1ae9a22
Merge branch 'main' into coders
kmuehlbauer Dec 30, 2024
1cec644
Update xarray/conventions.py
kmuehlbauer Dec 30, 2024
60aed87
Merge branch 'main' into coders
kmuehlbauer Jan 1, 2025
797dc85
Merge branch 'main' into any-time-resolution-2-wip
kmuehlbauer Jan 1, 2025
225c5b3
remove duplicate function (introduced when merging main)
kmuehlbauer Jan 1, 2025
33a1563
Update deprecated directive
kmuehlbauer Jan 2, 2025
4efe8b0
merge main into any-time-resolution-2
kmuehlbauer Jan 3, 2025
21a0ec6
Merge branch 'main' into coders
kmuehlbauer Jan 3, 2025
48dea20
merge coders into any-time-resolution-2
kmuehlbauer Jan 3, 2025
1145f4b
fix typing
kmuehlbauer Jan 3, 2025
a9990cf
re-fix doctests
kmuehlbauer Jan 3, 2025
5fa630f
merge main into any-time-resolution-2
kmuehlbauer Jan 4, 2025
43c85d1
fix whats-new.rst after merging main
kmuehlbauer Jan 4, 2025
a4702d6
Apply suggestions from code review
kmuehlbauer Jan 4, 2025
9bd292a
Apply suggestions from code review
kmuehlbauer Jan 4, 2025
25b797e
rewrite recursive function using for-loop
kmuehlbauer Jan 5, 2025
3bd8cf4
remove astype-construct in _possibly_convert_objects
kmuehlbauer Jan 5, 2025
8b9c85a
Update xarray/coding/times.py
kmuehlbauer Jan 5, 2025
2555d89
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 7, 2025
3b2d861
add suggestions from code review
kmuehlbauer Jan 7, 2025
66e181c
rephrase per suggestion
kmuehlbauer Jan 7, 2025
e380968
add article per suggestion
kmuehlbauer Jan 7, 2025
305938c
Apply suggestions from code review
kmuehlbauer Jan 7, 2025
b32b02c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 7, 2025
a2c46b1
fix scalar handling for timedelta based indexer
kmuehlbauer Jan 7, 2025
fa2c4b6
remove stale error message and "ignore:Converting non-default" in tes…
kmuehlbauer Jan 7, 2025
c65c9af
add per review suggestions
kmuehlbauer Jan 7, 2025
21dffc1
add/remove todo
kmuehlbauer Jan 7, 2025
8eeeb78
rename timeunit -> format
kmuehlbauer Jan 7, 2025
7ad2183
return "ns" resolution per default for timedeltas, if not specified
kmuehlbauer Jan 7, 2025
9e4cab6
Be specific on types/dtpyes
kmuehlbauer Jan 7, 2025
5964a9e
add comment
kmuehlbauer Jan 7, 2025
308391d
add suggestions from code review
kmuehlbauer Jan 7, 2025
0e886d6
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 7, 2025
80dc10b
Merge branch 'any-time-resolution-2' into ig/fix_extension_indexer
ilan-gold Jan 7, 2025
d494fe0
fix docs
kmuehlbauer Jan 8, 2025
ef6f722
fix test which isn't run for numpy2 atm
kmuehlbauer Jan 8, 2025
4ea5241
add notes on to_datetime section, update examples showing usage of 'a…
kmuehlbauer Jan 8, 2025
151e9cd
use np.timedelta64 for to_timedelta example, update as_unit example, …
kmuehlbauer Jan 8, 2025
8ecda4e
remove note
kmuehlbauer Jan 8, 2025
2bbf0ff
Apply suggestions from code review
kmuehlbauer Jan 8, 2025
0308672
refactor timedelta decoding to _numbers_to_timedelta and res-use it w…
kmuehlbauer Jan 9, 2025
b043020
fix conventions test, add todo
kmuehlbauer Jan 9, 2025
7182ce2
run times through pd.Timestamp to catch possible overflows
kmuehlbauer Jan 9, 2025
470235e
fix tests for cftime_to_nptime
kmuehlbauer Jan 9, 2025
e619a4c
fix cftime_to_nptime in cftimeindex
kmuehlbauer Jan 9, 2025
700e78d
introduce pd.Timestamp instance check
kmuehlbauer Jan 9, 2025
4525ea1
warn if out-of-bound datetimes are encoded with standard calendar, fa…
kmuehlbauer Jan 9, 2025
0b93dbd
fix time-coding.rst, add reference to time-series.rst.
kmuehlbauer Jan 9, 2025
b38cd7e
try to fix typing, ignore one
kmuehlbauer Jan 9, 2025
a2d1c96
try to fix docs
kmuehlbauer Jan 9, 2025
c4b2af3
revert doc-changes
kmuehlbauer Jan 9, 2025
45a0d56
Add a non-ns test for polyval, polyfit
dcherian Jan 9, 2025
3ef79cd
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 10, 2025
ac719e8
more doc cosmetics
kmuehlbauer Jan 10, 2025
5292569
add whats-new.rst entry
kmuehlbauer Jan 10, 2025
ecd603b
add/fix coder docstring
kmuehlbauer Jan 10, 2025
f6716dc
add xr.date_range example as suggested per review
kmuehlbauer Jan 10, 2025
0556376
Apply suggestions from code review
kmuehlbauer Jan 13, 2025
ffc1828
Implement `time_unit` option for `decode_cf_timedelta` (#3)
spencerkclark Jan 13, 2025
eaf3c73
fix typing
kmuehlbauer Jan 13, 2025
1e6ba18
use nanmin/nanmax, catch numpy RuntimeWarnings
kmuehlbauer Jan 13, 2025
85a340b
Apply suggestions from code review
spencerkclark Jan 14, 2025
9d77885
Merge branch 'any-time-resolution-2' into ig/fix_extension_indexer
ilan-gold Jan 15, 2025
db69b63
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 15, 2025
b120917
Merge branch 'any-time-resolution-2' into ig/fix_extension_indexer
ilan-gold Jan 15, 2025
f7cda22
merge
ilan-gold Jan 15, 2025
4d70fd1
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Jan 27, 2025
666d279
Merge branch 'main' into ig/fix_extension_indexer
kmuehlbauer Jan 29, 2025
3623dd5
(fix): try to address pandas comments
ilan-gold Jan 31, 2025
da0ee36
(fix): try-logic was not correct
ilan-gold Jan 31, 2025
b53ba64
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Jan 31, 2025
2068b8c
(refactor): remove super class casting
ilan-gold Feb 4, 2025
13fc8fe
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Feb 4, 2025
067f8f2
(fix): namedarray mypy issues
ilan-gold Feb 4, 2025
459f56b
(fix): typing patch
ilan-gold Feb 4, 2025
0aa5862
(fix): revert dataarray dtype change
ilan-gold Feb 4, 2025
4a73535
(fix): just ignore dtype issue
ilan-gold Feb 4, 2025
9b4ce62
(fix): ignore redefinition issue
ilan-gold Feb 4, 2025
e1be388
(fix): remove erroneous generic hint
ilan-gold Feb 7, 2025
1fee9d4
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Feb 7, 2025
1a7650c
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Feb 7, 2025
62f3892
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Feb 21, 2025
36dcbb6
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Feb 24, 2025
91e31b1
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Mar 13, 2025
5809b2f
(fix): use `coord_type` check
ilan-gold Mar 21, 2025
a22ff34
(chore): clean up numpy dtype handling
ilan-gold Mar 21, 2025
d41e5ee
Merge branch 'ig/fix_extension_indexer' of github.com:ilan-gold/xarra…
ilan-gold Mar 21, 2025
ef54645
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Mar 21, 2025
5c64310
(chore): try casting earlier?
ilan-gold Mar 21, 2025
d9fc4ca
Update xarray/core/indexing.py
ilan-gold Mar 21, 2025
7169fb1
Update xarray/core/indexing.py
ilan-gold Mar 21, 2025
ea5c066
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Mar 27, 2025
2e1a6ae
Small cleanup
dcherian Mar 29, 2025
4a5cf1d
Skip dask tests with pandas index
dcherian Mar 29, 2025
44a05a4
fix test, typing
dcherian Mar 29, 2025
983f5e0
Merge branch 'main' into ig/fix_extension_indexer
dcherian Mar 29, 2025
c25c824
fix
dcherian Mar 29, 2025
3eb3372
Add nbytes
dcherian Mar 29, 2025
fbae574
Update pandas_to_xarray tests
dcherian Mar 29, 2025
8eb0685
Revert nbytes
dcherian Mar 29, 2025
516aa68
One more fix.
dcherian Mar 29, 2025
dd3dd51
Expose PandasExtensionArray
dcherian Mar 31, 2025
2e32b92
Merge branch 'main' into ig/fix_extension_indexer
dcherian Mar 31, 2025
6fbdf8b
Better comment
dcherian Mar 31, 2025
b9167b6
Fix tests
dcherian Apr 1, 2025
2f4bbba
fix groupby test
dcherian Apr 1, 2025
7888609
revert _maybe_wrap_data
dcherian Apr 1, 2025
259fe0d
Cast int, float, str to numpy
dcherian Apr 4, 2025
350691a
Fix mypy
dcherian Apr 4, 2025
f4df964
try fixing array_ufunc
dcherian Apr 4, 2025
2e4db52
Merge branch 'main' into ig/fix_extension_indexer
dcherian Apr 4, 2025
65a55fc
(fix): catch more instances of extension arrays
ilan-gold Apr 9, 2025
02c887c
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Apr 22, 2025
bddccce
(fix): typing issues
ilan-gold Apr 22, 2025
6134d10
(fix): remove unnecessary casting + `nbytes`
ilan-gold Apr 22, 2025
cfca8f5
(fix): `nbytes` value
ilan-gold Apr 22, 2025
18b78d1
(fix): handling of non-unique dtype with extension arrays
ilan-gold Apr 22, 2025
cfd099f
(fix): `mypy`?
ilan-gold Apr 22, 2025
b147efb
Merge branch 'main' into ig/fix_extension_indexer
ilan-gold Apr 22, 2025
78cc243
(fix): return `get_valid_numpy_dtype`
ilan-gold Apr 23, 2025
96a1ddd
Merge branch 'ig/fix_extension_indexer' of github.com:ilan-gold/xarra…
ilan-gold Apr 23, 2025
364e9cd
(feat): remove wrapper around `var.data` output for extension arrays
ilan-gold Apr 23, 2025
b977144
(fix): add copy + deepcopy to extension array
ilan-gold Apr 25, 2025
8689d5f
Merge branch 'main' into ig/fix_same_reindexer
dcherian Apr 26, 2025
89d66ef
Merge branch 'main' into ig/vardata_extension_array_without_adapter
ilan-gold Apr 28, 2025
3b9e151
(chore): add relnote
ilan-gold Apr 28, 2025
9f04cef
(fix): recursion on `getattr`
ilan-gold Apr 28, 2025
ac7d75a
Merge branch 'ig/vardata_extension_array_without_adapter' into ig/fix…
ilan-gold Apr 28, 2025
a136f2f
Merge branch 'ig/fix_same_reindexer' of github.com:ilan-gold/xarray i…
ilan-gold Apr 28, 2025
b3a8edd
(refactor): remove unnecessary explicit methods
ilan-gold Apr 28, 2025
84f4953
(fix): `getattr` + fix `__getitem__` bug
ilan-gold Apr 29, 2025
442f20a
Update test_dataset.py
ilan-gold Apr 29, 2025
6f87daa
Merge branch 'main' into ig/fix_same_reindexer
dcherian Apr 29, 2025
f9e5548
Fix type
dcherian Apr 29, 2025
ea87b22
Merge branch 'main' into ig/fix_same_reindexer
dcherian Apr 29, 2025
ba4e689
Fix for numpy < 2
dcherian Apr 29, 2025
ea13a17
fix import
dcherian Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ New Features
- Improved compatibility with OPeNDAP DAP4 data model for backend engine ``pydap``. This
includes ``datatree`` support, and removing slashes from dimension names. By
`Miguel Jimenez-Urias <https://github.com/Mikejmnez>`_.
- Improved support pandas Extension Arrays. (:issue:`9661`, :pull:`9671`)
- Improved support pandas categorical extension as indices (i.e., :py:class:`pandas.IntervalIndex`). (:issue:`9661`, :pull:`9671`)
By `Ilan Gold <https://github.com/ilan-gold>`_.
- Improved checks and errors raised when trying to align objects with conflicting indexes.
It is now possible to align objects each with multiple indexes sharing common dimension(s).
Expand All @@ -52,6 +52,7 @@ Breaking changes
now return objects indexed by :py:meth:`pandas.IntervalArray` objects,
instead of numpy object arrays containing tuples. This change enables interval-aware indexing of
such Xarray objects. (:pull:`9671`). By `Ilan Gold <https://github.com/ilan-gold>`_.
- Remove ``PandasExtensionArrayIndex`` from :py:attr:`xarray.Variable.data` when the attribute is a :py:class:`pandas.api.extensions.ExtensionArray` (:pull:`10263`). By `Ilan Gold <https://github.com/ilan-gold>`_.
- The html and text ``repr`` for ``DataTree`` are now truncated. Up to 6 children are displayed
for each node -- the first 3 and the last 3 children -- with a ``...`` between them. The number
of children to include in the display is configurable via options. For instance use
Expand Down
6 changes: 3 additions & 3 deletions xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -7091,21 +7091,21 @@ def _to_dataframe(self, ordered_dims: Mapping[Any, int]):
{
**dict(zip(non_extension_array_columns, data, strict=True)),
**{
c: self.variables[c].data.array
c: self.variables[c].data
for c in extension_array_columns_same_index
},
},
index=index,
)
for extension_array_column in extension_array_columns_different_index:
extension_array = self.variables[extension_array_column].data.array
extension_array = self.variables[extension_array_column].data
index = self[
self.variables[extension_array_column].dims[0]
].coords.to_index()
extension_array_df = pd.DataFrame(
{extension_array_column: extension_array},
index=pd.Index(index.array)
if isinstance(index, PandasExtensionArray)
if isinstance(index, PandasExtensionArray) # type: ignore[redundant-expr]
else index,
)
extension_array_df.index.name = self.variables[extension_array_column].dims[
Expand Down
60 changes: 35 additions & 25 deletions xarray/core/extension_array.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from __future__ import annotations

from collections.abc import Callable, Sequence
from dataclasses import dataclass
from typing import Generic, cast

import numpy as np
import pandas as pd
from packaging.version import Version
from pandas.api.types import is_extension_array_dtype

from xarray.core.types import DTypeLikeSave, T_ExtensionArray
from xarray.core.utils import NDArrayMixin

HANDLED_EXTENSION_ARRAY_FUNCTIONS: dict[Callable, Callable] = {}

Expand All @@ -33,12 +36,12 @@ def __extension_duck_array__issubdtype(
def __extension_duck_array__broadcast(arr: T_ExtensionArray, shape: tuple):
if shape[0] == len(arr) and len(shape) == 1:
return arr
raise NotImplementedError("Cannot broadcast 1d-only pandas categorical array.")
raise NotImplementedError("Cannot broadcast 1d-only pandas extension array.")


@implements(np.stack)
def __extension_duck_array__stack(arr: T_ExtensionArray, axis: int):
raise NotImplementedError("Cannot stack 1d-only pandas categorical array.")
raise NotImplementedError("Cannot stack 1d-only pandas extension array.")


@implements(np.concatenate)
Expand All @@ -62,21 +65,22 @@ def __extension_duck_array__where(
return cast(T_ExtensionArray, pd.Series(x).where(condition, pd.Series(y)).array)


class PandasExtensionArray(Generic[T_ExtensionArray]):
array: T_ExtensionArray
@dataclass(frozen=True)
class PandasExtensionArray(Generic[T_ExtensionArray], NDArrayMixin):
"""NEP-18 compliant wrapper for pandas extension arrays.

Parameters
----------
array : T_ExtensionArray
The array to be wrapped upon e.g,. :py:class:`xarray.Variable` creation.
```
"""

def __init__(self, array: T_ExtensionArray):
"""NEP-18 compliant wrapper for pandas extension arrays.
array: T_ExtensionArray

Parameters
----------
array : T_ExtensionArray
The array to be wrapped upon e.g,. :py:class:`xarray.Variable` creation.
```
"""
if not isinstance(array, pd.api.extensions.ExtensionArray):
raise TypeError(f"{array} is not an pandas ExtensionArray.")
self.array = array
def __post_init__(self):
if not isinstance(self.array, pd.api.extensions.ExtensionArray):
raise TypeError(f"{self.array} is not an pandas ExtensionArray.")

def __array_function__(self, func, types, args, kwargs):
def replace_duck_with_extension_array(args) -> list:
Expand Down Expand Up @@ -105,19 +109,13 @@ def replace_duck_with_extension_array(args) -> list:
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
return ufunc(*inputs, **kwargs)

def __repr__(self):
return f"PandasExtensionArray(array={self.array!r})"

def __getattr__(self, attr: str) -> object:
return getattr(self.array, attr)

def __getitem__(self, key) -> PandasExtensionArray[T_ExtensionArray]:
item = self.array[key]
if is_extension_array_dtype(item):
return type(self)(item)
if np.isscalar(item):
return type(self)(type(self.array)([item])) # type: ignore[call-arg] # only subclasses with proper __init__ allowed
return item
return PandasExtensionArray(item)
if np.isscalar(item) or isinstance(key, int):
return PandasExtensionArray(type(self.array)._from_sequence([item])) # type: ignore[call-arg,attr-defined,unused-ignore]
return PandasExtensionArray(item)

def __setitem__(self, key, val):
self.array[key] = val
Expand All @@ -132,3 +130,15 @@ def __ne__(self, other):

def __len__(self):
return len(self.array)

@property
def ndim(self) -> int:
return 1

def __array__(
self, dtype: np.typing.DTypeLike = None, /, *, copy: bool | None = None
) -> np.ndarray:
if Version(np.__version__) >= Version("2.0.0"):
return np.asarray(self.array, dtype=dtype, copy=copy)
else:
return np.asarray(self.array, dtype=dtype)
2 changes: 2 additions & 0 deletions xarray/core/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@ def short_array_repr(array):

if isinstance(array, AbstractArray):
array = array.data
if isinstance(array, pd.api.extensions.ExtensionArray):
return repr(array)
array = to_duck_array(array)

# default to lower precision so a full (abbreviated) line can fit on
Expand Down
4 changes: 3 additions & 1 deletion xarray/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from xarray.core import duck_array_ops
from xarray.core.coordinate_transform import CoordinateTransform
from xarray.core.extension_array import PandasExtensionArray
from xarray.core.nputils import NumpyVIndexAdapter
from xarray.core.options import OPTIONS
from xarray.core.types import T_Xarray
Expand All @@ -37,6 +36,7 @@
from xarray.namedarray.pycompat import array_type, integer_types, is_chunked_array

if TYPE_CHECKING:
from xarray.core.extension_array import PandasExtensionArray
from xarray.core.indexes import Index
from xarray.core.types import Self
from xarray.core.variable import Variable
Expand Down Expand Up @@ -1797,6 +1797,8 @@ def get_duck_array(self) -> np.ndarray | PandasExtensionArray:
# We return an PandasExtensionArray wrapper type that satisfies
# duck array protocols. This is what's needed for tests to pass.
if pd.api.types.is_extension_array_dtype(self.array):
from xarray.core.extension_array import PandasExtensionArray

return PandasExtensionArray(self.array.array)
return np.asarray(self)

Expand Down
18 changes: 13 additions & 5 deletions xarray/core/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,12 +410,20 @@ def data(self):
Variable.as_numpy
Variable.values
"""
if is_duck_array(self._data):
return self._data
if isinstance(self._data, PandasExtensionArray):
duck_array = self._data.array
elif isinstance(self._data, indexing.ExplicitlyIndexed):
return self._data.get_duck_array()
duck_array = self._data.get_duck_array()
elif is_duck_array(self._data):
duck_array = self._data
else:
return self.values
duck_array = self.values
if isinstance(duck_array, PandasExtensionArray):
# even though PandasExtensionArray is a duck array,
# we should not return the PandasExtensionArray wrapper,
# and instead return the underlying data.
return duck_array.array
return duck_array

@data.setter
def data(self, data: T_DuckArray | ArrayLike) -> None:
Expand Down Expand Up @@ -1366,7 +1374,7 @@ def set_dims(self, dim, shape=None):
elif shape is not None:
dims_map = dict(zip(dim, shape, strict=True))
tmp_shape = tuple(dims_map[d] for d in expanded_dims)
expanded_data = duck_array_ops.broadcast_to(self.data, tmp_shape)
expanded_data = duck_array_ops.broadcast_to(self._data, tmp_shape)
else:
indexer = (None,) * (len(expanded_dims) - self.ndim) + (...,)
expanded_data = self.data[indexer]
Expand Down
4 changes: 3 additions & 1 deletion xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ def assert_writeable(ds):
name
for name, var in ds.variables.items()
if not isinstance(var, IndexVariable)
and not isinstance(var.data, PandasExtensionArray)
and not isinstance(
var.data, PandasExtensionArray | pd.api.extensions.ExtensionArray
)
and not var.data.flags.writeable
]
assert not readonly, readonly
Expand Down
6 changes: 3 additions & 3 deletions xarray/tests/test_concat.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ def test_concat_categorical() -> None:
concatenated = concat([data1, data2], dim="dim1")
assert (
concatenated["var4"]
== type(data2["var4"].variable.data.array)._concat_same_type(
== type(data2["var4"].variable.data)._concat_same_type(
[
data1["var4"].variable.data.array,
data2["var4"].variable.data.array,
data1["var4"].variable.data,
data2["var4"].variable.data,
]
)
).all()
Expand Down
6 changes: 6 additions & 0 deletions xarray/tests/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1826,6 +1826,12 @@ def test_categorical_reindex(self) -> None:
actual = ds.reindex(cat=["foo"])["cat"].values
assert (actual == np.array(["foo"])).all()

def test_extension_array_reindex_same(self) -> None:
series = pd.Series([1, 2, pd.NA, 3], dtype=pd.Int32Dtype())
test = xr.Dataset({"test": series})
res = test.reindex(dim_0=series.index)
align(res, test, join="exact")

def test_categorical_multiindex(self) -> None:
i1 = pd.Series([0, 0])
cat = pd.CategoricalDtype(categories=["foo", "baz", "bar"])
Expand Down
9 changes: 2 additions & 7 deletions xarray/tests/test_duck_array_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ def test_extension_array_pyarrow_concatenate(self, arrow1, arrow2):
concatenated = concatenate(
(PandasExtensionArray(arrow1), PandasExtensionArray(arrow2))
)
assert concatenated[2]["x"] == 3
assert concatenated[3]["y"]
assert concatenated[2].array[0]["x"] == 3
assert concatenated[3].array[0]["y"]

def test___getitem__extension_duck_array(self, categorical1):
extension_duck_array = PandasExtensionArray(categorical1)
Expand Down Expand Up @@ -1094,8 +1094,3 @@ def test_extension_array_singleton_equality(categorical1):
def test_extension_array_repr(int1):
int_duck_array = PandasExtensionArray(int1)
assert repr(int1) in repr(int_duck_array)


def test_extension_array_attr(int1):
int_duck_array = PandasExtensionArray(int1)
assert (~int_duck_array.fillna(10)).all()
2 changes: 1 addition & 1 deletion xarray/tests/test_groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ def test_groupby_getitem(dataset) -> None:
assert_identical(dataset.cat.sel(y=[1]), dataset.cat.groupby("y")[1])

with pytest.raises(
NotImplementedError, match="Cannot broadcast 1d-only pandas categorical array."
NotImplementedError, match="Cannot broadcast 1d-only pandas extension array."
):
dataset.groupby("boo")
dataset = dataset.drop_vars(["cat"])
Expand Down
Loading