Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a8c01a4

Browse files
渡邉 美希tacaswell
authored and
渡邉 美希
committed
BUG: modified safe_first_element and added tests
Co-authored-by: Thomas A Caswell <[email protected]>
1 parent bf9a451 commit a8c01a4

File tree

5 files changed

+55
-28
lines changed

5 files changed

+55
-28
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,12 +2176,12 @@ def _convert_dx(dx, x0, xconv, convert):
21762176
# removes the units from unit packages like `pint` that
21772177
# wrap numpy arrays.
21782178
try:
2179-
x0 = cbook.safe_first_element(x0)
2179+
x0 = cbook._safe_first_non_none(x0)
21802180
except (TypeError, IndexError, KeyError):
21812181
pass
21822182

21832183
try:
2184-
x = cbook.safe_first_element(xconv)
2184+
x = cbook._safe_first_non_none(xconv)
21852185
except (TypeError, IndexError, KeyError):
21862186
x = xconv
21872187

@@ -2779,11 +2779,11 @@ def broken_barh(self, xranges, yrange, **kwargs):
27792779
"""
27802780
# process the unit information
27812781
if len(xranges):
2782-
xdata = cbook.safe_first_element(xranges)
2782+
xdata = cbook._safe_first_non_none(xranges)
27832783
else:
27842784
xdata = None
27852785
if len(yrange):
2786-
ydata = cbook.safe_first_element(yrange)
2786+
ydata = cbook._safe_first_non_none(yrange)
27872787
else:
27882788
ydata = None
27892789
self._process_unit_info(
@@ -3424,10 +3424,10 @@ def _upcast_err(err):
34243424
# safe_first_element because getitem is index-first not
34253425
# location first on pandas objects so err[0] almost always
34263426
# fails.
3427-
isinstance(cbook.safe_first_element(err), np.ndarray)
3427+
isinstance(cbook._safe_first_non_none(err), np.ndarray)
34283428
):
34293429
# Get the type of the first element
3430-
atype = type(cbook.safe_first_element(err))
3430+
atype = type(cbook._safe_first_non_none(err))
34313431
# Promote the outer container to match the inner container
34323432
if atype is np.ndarray:
34333433
# Converts using np.asarray, because data cannot
@@ -4290,7 +4290,7 @@ def _parse_scatter_color_args(c, edgecolors, kwargs, xsize,
42904290
c_is_string_or_strings = (
42914291
isinstance(c, str)
42924292
or (np.iterable(c) and len(c) > 0
4293-
and isinstance(cbook.safe_first_element(c), str)))
4293+
and isinstance(cbook._safe_first_non_none(c), str)))
42944294

42954295
def invalid_shape_exception(csize, xsize):
42964296
return ValueError(

lib/matplotlib/cbook/__init__.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,22 +1688,42 @@ def safe_first_element(obj):
16881688
"""
16891689
Return the first element in *obj*.
16901690
1691-
This is an type-independent way of obtaining the first element, supporting
1692-
both index access and the iterator protocol.
1693-
"""
1694-
if isinstance(obj, collections.abc.Iterator):
1695-
# needed to accept `array.flat` as input.
1696-
# np.flatiter reports as an instance of collections.Iterator
1697-
# but can still be indexed via [].
1698-
# This has the side effect of re-setting the iterator, but
1699-
# that is acceptable.
1700-
try:
1701-
return obj[0]
1702-
except TypeError:
1703-
pass
1704-
raise RuntimeError("matplotlib does not support generators "
1705-
"as input")
1706-
return next(iter(obj))
1691+
This is an type-independent way of obtaining the first element,
1692+
supporting both index access and the iterator protocol.
1693+
"""
1694+
return _safe_first_non_none(obj, skip_none=False)
1695+
1696+
1697+
def _safe_first_non_none(obj, skip_none=True):
1698+
"""
1699+
Return the first non-None element in *obj*.
1700+
This is a method for internal use.
1701+
1702+
This is an type-independent way of obtaining the first non-None element,
1703+
supporting both index access and the iterator protocol.
1704+
The first non-None element will be obtained when skip_none is True.
1705+
"""
1706+
if skip_none is False:
1707+
if isinstance(obj, collections.abc.Iterator):
1708+
# needed to accept `array.flat` as input.
1709+
# np.flatiter reports as an instance of collections.Iterator
1710+
# but can still be indexed via [].
1711+
# This has the side effect of re-setting the iterator, but
1712+
# that is acceptable.
1713+
try:
1714+
return obj[0]
1715+
except TypeError:
1716+
pass
1717+
raise RuntimeError("matplotlib does not support generators "
1718+
"as input")
1719+
return next(iter(obj))
1720+
elif isinstance(obj, np.flatiter):
1721+
return obj[0]
1722+
elif isinstance(obj, collections.abc.Iterator):
1723+
raise RuntimeError("matplotlib does not "
1724+
"support generators as input")
1725+
else:
1726+
return next(val for val in obj if val is not None)
17071727

17081728

17091729
def sanitize_sequence(data):

lib/matplotlib/dates.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1908,7 +1908,7 @@ def default_units(x, axis):
19081908
x = x.ravel()
19091909

19101910
try:
1911-
x = cbook.safe_first_element(x)
1911+
x = cbook._safe_first_non_none(x)
19121912
except (TypeError, StopIteration):
19131913
pass
19141914

lib/matplotlib/tests/test_cbook.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from weakref import ref
55
from unittest.mock import patch, Mock
66

7-
from datetime import datetime
7+
from datetime import datetime, date, timedelta
88

99
import numpy as np
1010
from numpy.testing import (assert_array_equal, assert_approx_equal,
@@ -602,7 +602,7 @@ def test_flatiter():
602602
it = x.flat
603603
assert 0 == next(it)
604604
assert 1 == next(it)
605-
ret = cbook.safe_first_element(it)
605+
ret = cbook._safe_first_non_none(it)
606606
assert ret == 0
607607

608608
assert 0 == next(it)
@@ -758,7 +758,7 @@ def test_contiguous_regions():
758758
def test_safe_first_element_pandas_series(pd):
759759
# deliberately create a pandas series with index not starting from 0
760760
s = pd.Series(range(5), index=range(10, 15))
761-
actual = cbook.safe_first_element(s)
761+
actual = cbook._safe_first_non_none(s)
762762
assert actual == 0
763763

764764

@@ -888,3 +888,10 @@ def test_format_approx():
888888
assert f(0.0012345600001, 5) == '0.00123'
889889
assert f(-0.0012345600001, 5) == '-0.00123'
890890
assert f(0.0012345600001, 8) == f(0.0012345600001, 10) == '0.00123456'
891+
892+
893+
def test_safe_first_element_with_none():
894+
datetime_lst = [date.today() + timedelta(days=i) for i in range(10)]
895+
datetime_lst[0] = None
896+
actual = cbook._safe_first_non_none(datetime_lst)
897+
assert actual is not None and actual == datetime_lst[1]

lib/matplotlib/units.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def get_converter(self, x):
197197
except KeyError:
198198
pass
199199
try: # If cache lookup fails, look up based on first element...
200-
first = cbook.safe_first_element(x)
200+
first = cbook._safe_first_non_none(x)
201201
except (TypeError, StopIteration):
202202
pass
203203
else:

0 commit comments

Comments
 (0)