Skip to content

Commit c3d45b3

Browse files
Rely on array backend for string formatting (#6823)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 9050a8b commit c3d45b3

File tree

3 files changed

+48
-17
lines changed

3 files changed

+48
-17
lines changed

doc/whats-new.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Bug fixes
4040
- :py:attr:`DataArray.nbytes` now uses the ``nbytes`` property of the underlying array if available.
4141
(:pull:`6797`)
4242
By `Max Jones <https://github.com/maxrjones>`_.
43+
- Rely on the array backend for string formatting. (:pull:`6823`).
44+
By `Jimmy Westling <https://github.com/illviljan>`_.
4345
- Fix incompatibility with numpy 1.20 (:issue:`6818`, :pull:`6821`)
4446
By `Michael Niklas <https://github.com/headtr1ck>`_.
4547
- Make FacetGrid.set_titles send kwargs correctly using `handle.udpate(kwargs)`.
@@ -88,6 +90,8 @@ New Features
8890
- Experimental support for wrapping any array type that conforms to the python
8991
`array api standard <https://data-apis.org/array-api/latest/>`_. (:pull:`6804`)
9092
By `Tom White <https://github.com/tomwhite>`_.
93+
- Allow string formatting of scalar DataArrays. (:pull:`5981`)
94+
By `fmaussion <https://github.com/fmaussion>`_.
9195

9296
Bug fixes
9397
~~~~~~~~~

xarray/core/common.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,22 @@ def _repr_html_(self):
163163
return f"<pre>{escape(repr(self))}</pre>"
164164
return formatting_html.array_repr(self)
165165

166-
def __format__(self: Any, format_spec: str) -> str:
167-
# we use numpy: scalars will print fine and arrays will raise
168-
return self.values.__format__(format_spec)
166+
def __format__(self: Any, format_spec: str = "") -> str:
167+
if format_spec != "":
168+
if self.shape == ():
169+
# Scalar values might be ok use format_spec with instead of repr:
170+
return self.data.__format__(format_spec)
171+
else:
172+
# TODO: If it's an array the formatting.array_repr(self) should
173+
# take format_spec as an input. If we'd only use self.data we
174+
# lose all the information about coords for example which is
175+
# important information:
176+
raise NotImplementedError(
177+
"Using format_spec is only supported"
178+
f" when shape is (). Got shape = {self.shape}."
179+
)
180+
else:
181+
return self.__repr__()
169182

170183
def _iter(self: Any) -> Iterator[Any]:
171184
for n in range(len(self)):

xarray/tests/test_formatting.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,10 @@ def test_diff_dataset_repr(self) -> None:
391391
def test_array_repr(self) -> None:
392392
ds = xr.Dataset(coords={"foo": [1, 2, 3], "bar": [1, 2, 3]})
393393
ds[(1, 2)] = xr.DataArray([0], dims="test")
394-
actual = formatting.array_repr(ds[(1, 2)])
394+
ds_12 = ds[(1, 2)]
395+
396+
# Test repr function behaves correctly:
397+
actual = formatting.array_repr(ds_12)
395398
expected = dedent(
396399
"""\
397400
<xarray.DataArray (1, 2) (test: 1)>
@@ -401,6 +404,14 @@ def test_array_repr(self) -> None:
401404

402405
assert actual == expected
403406

407+
# Test repr, str prints returns correctly as well:
408+
assert repr(ds_12) == expected
409+
assert str(ds_12) == expected
410+
411+
# f-strings (aka format(...)) by default should use the repr:
412+
actual = f"{ds_12}"
413+
assert actual == expected
414+
404415
with xr.set_options(display_expand_data=False):
405416
actual = formatting.array_repr(ds[(1, 2)])
406417
expected = dedent(
@@ -422,24 +433,27 @@ def test_array_repr_variable(self) -> None:
422433

423434
@requires_dask
424435
def test_array_scalar_format(self) -> None:
425-
var = xr.DataArray(0)
426-
assert var.__format__("") == "0"
427-
assert var.__format__("d") == "0"
428-
assert var.__format__(".2f") == "0.00"
436+
# Test numpy scalars:
437+
var = xr.DataArray(np.array(0))
438+
assert format(var, "") == repr(var)
439+
assert format(var, "d") == "0"
440+
assert format(var, ".2f") == "0.00"
429441

430-
var = xr.DataArray([0.1, 0.2])
431-
assert var.__format__("") == "[0.1 0.2]"
432-
with pytest.raises(TypeError) as excinfo:
433-
var.__format__(".2f")
434-
assert "unsupported format string passed to" in str(excinfo.value)
442+
# Test dask scalars, not supported however:
443+
import dask.array as da
435444

436-
# also check for dask
437-
var = var.chunk(chunks={"dim_0": 1})
438-
assert var.__format__("") == "[0.1 0.2]"
445+
var = xr.DataArray(da.array(0))
446+
assert format(var, "") == repr(var)
439447
with pytest.raises(TypeError) as excinfo:
440-
var.__format__(".2f")
448+
format(var, ".2f")
441449
assert "unsupported format string passed to" in str(excinfo.value)
442450

451+
# Test numpy arrays raises:
452+
var = xr.DataArray([0.1, 0.2])
453+
with pytest.raises(NotImplementedError) as excinfo: # type: ignore
454+
format(var, ".2f")
455+
assert "Using format_spec is only supported" in str(excinfo.value)
456+
443457

444458
def test_inline_variable_array_repr_custom_repr() -> None:
445459
class CustomArray:

0 commit comments

Comments
 (0)