Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5845809
Coerce unknown types to O dtype
brynpickering May 20, 2025
ef3df17
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 20, 2025
b82fc90
Merge branch 'main' into fix-obj-dtype-infer
kmuehlbauer May 23, 2025
1756bc4
Add comment on setting obj dtype
brynpickering May 23, 2025
8f0e197
Merge branch 'main' into fix-obj-dtype-infer
brynpickering Jun 11, 2025
5c3acf1
Merge branch 'main' into fix-obj-dtype-infer
brynpickering Sep 17, 2025
8d15d2f
Update xarray/compat/array_api_compat.py
brynpickering Nov 5, 2025
5fc7ccc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 5, 2025
0afd465
Merge branch 'main' into fix-obj-dtype-infer
brynpickering Nov 12, 2025
22ab662
import datetime
keewis Nov 12, 2025
4cea3fa
typo
keewis Nov 12, 2025
8f26768
use `zip` with `strict=True`
keewis Nov 12, 2025
46ae113
refactor the dtype checks into functions
keewis Nov 12, 2025
788eedb
return a dtype object instead of the dtype type
keewis Nov 12, 2025
6512e09
Merge branch 'main' into fix-obj-dtype-infer
jsignell Feb 10, 2026
e51a8c4
revert the changes to `result_type`
keewis Feb 11, 2026
602adc5
Update given TypeError fallback
brynpickering Feb 22, 2026
78751f8
Merge branch 'main' into fix-obj-dtype-infer
brynpickering Mar 30, 2026
0eb085d
Merge branch 'main' into fix-obj-dtype-infer
brynpickering May 1, 2026
791bf98
Merge branch 'main' into fix-obj-dtype-infer
keewis Jun 4, 2026
46b5670
Merge branch 'main' into fix-obj-dtype-infer
brynpickering Jun 19, 2026
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
28 changes: 22 additions & 6 deletions xarray/compat/array_api_compat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import datetime as dt

import numpy as np

from xarray.namedarray.pycompat import array_type

builtin_types = (
bool,
int,
float,
complex,
str,
bytes,
dt.datetime,
dt.timedelta,
)
Comment on lines +7 to +16

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not look like this is used in the current version of this PR



def is_weak_scalar_type(t):
return isinstance(t, bool | int | float | complex | str | bytes)
Expand Down Expand Up @@ -38,12 +51,15 @@ def _future_array_api_result_type(*arrays_and_dtypes, xp):


def result_type(*arrays_and_dtypes, xp) -> np.dtype:
if xp is np or any(
isinstance(getattr(t, "dtype", t), np.dtype) for t in arrays_and_dtypes
):
return xp.result_type(*arrays_and_dtypes)
else:
return _future_array_api_result_type(*arrays_and_dtypes, xp=xp)
try:
if xp is np or any(
isinstance(getattr(t, "dtype", t), np.dtype) for t in arrays_and_dtypes
):
return xp.result_type(*arrays_and_dtypes)
else:
return _future_array_api_result_type(*arrays_and_dtypes, xp=xp)
except TypeError:
return np.dtype(object)
Comment on lines +61 to +62

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire module is intended as forwards compatible replacements for array API functionality, so we shouldn't add behavior here that deviates from result_type in the array API. I would much rather prefer that this changed behavior be done in Xarray's specific dtypes.result_type(). (Also, it should have a brief comment explaining why TypeError mean object dtype is appropriate.)



def get_array_namespace(*values):
Expand Down
17 changes: 6 additions & 11 deletions xarray/core/dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,17 +278,11 @@ def should_promote_to_object(
"""
np_result_types = set()
for arr_or_dtype in arrays_and_dtypes:
try:
result_type = array_api_compat.result_type(
maybe_promote_to_variable_width(arr_or_dtype), xp=xp
)
if isinstance(result_type, np.dtype):
np_result_types.add(result_type)
except TypeError:
# passing individual objects to xp.result_type (i.e., what `array_api_compat.result_type` calls) means NEP-18 implementations won't have
# a chance to intercept special values (such as NA) that numpy core cannot handle.
# Thus they are considered as types that don't need promotion i.e., the `arr_or_dtype` that rose the `TypeError` will not contribute to `np_result_types`.
pass
result_type = array_api_compat.result_type(
maybe_promote_to_variable_width(arr_or_dtype), xp=xp
)
if isinstance(result_type, np.dtype):
np_result_types.add(result_type)

if np_result_types:
for left, right in PROMOTE_TO_OBJECT:
Expand Down Expand Up @@ -328,6 +322,7 @@ def result_type(

if should_promote_to_object(arrays_and_dtypes, xp):
return np.dtype(object)

maybe_promote = functools.partial(
maybe_promote_to_variable_width,
# let extension arrays handle their own str/bytes
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def maybe_coerce_to_str(index, original_coords):

try:
result_type = dtypes.result_type(*original_coords)
except (TypeError, ValueError):
except ValueError:
pass
else:
if result_type.kind in "SU":
Expand Down
4 changes: 4 additions & 0 deletions xarray/tests/test_dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class DummyArrayAPINamespace:
([np.dtype("<U2"), str], np.dtype("U")),
([np.dtype("S3"), np.bytes_], np.dtype("S")),
([np.dtype("S10"), bytes], np.dtype("S")),
([type("Foo", (object,), {"foo": "bar"})()], np.object_),
([np.float32, type("Foo", (object,), {"foo": "bar"})()], np.object_),
([np.str_, type("Foo", (object,), {"foo": "bar"})()], np.object_),
([np.bytes_, type("Foo", (object,), {"foo": "bar"})()], np.object_),
],
)
def test_result_type(args, expected) -> None:
Expand Down
Loading