Skip to content

Commit 5bc2ba5

Browse files
committed
A whole bunch of stuff
1 parent d234627 commit 5bc2ba5

File tree

17 files changed

+116
-42
lines changed

17 files changed

+116
-42
lines changed

pandas/core/arrays/base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from pandas.util._decorators import Appender, Substitution
2020
from pandas.util._validators import validate_fillna_kwargs
2121

22-
from pandas.core.dtypes.cast import maybe_cast_to_extension_array
22+
from pandas.core.dtypes.cast import maybe_astype, maybe_cast_to_extension_array
2323
from pandas.core.dtypes.common import (
2424
is_array_like,
2525
is_dtype_equal,
@@ -438,7 +438,7 @@ def nbytes(self) -> int:
438438
# Additional Methods
439439
# ------------------------------------------------------------------------
440440

441-
def astype(self, dtype, copy=True):
441+
def astype(self, dtype, copy: bool = True, errors: str = "raise"):
442442
"""
443443
Cast to a NumPy array with 'dtype'.
444444
@@ -450,6 +450,9 @@ def astype(self, dtype, copy=True):
450450
Whether to copy the data, even if not necessary. If False,
451451
a copy is made only if the old dtype does not match the
452452
new dtype.
453+
errors : str, {'raise', 'ignore'}, default 'ignore'
454+
- ``raise`` : allow exceptions to be raised
455+
- ``ignore`` : suppress exceptions. On error return original object
453456
454457
Returns
455458
-------
@@ -462,7 +465,8 @@ def astype(self, dtype, copy=True):
462465
if isinstance(dtype, StringDtype): # allow conversion to StringArrays
463466
return dtype.construct_array_type()._from_sequence(self, copy=False)
464467

465-
return np.array(self, dtype=dtype, copy=copy)
468+
values = maybe_astype(values=self, dtype=dtype, copy=copy, errors=errors)
469+
return values
466470

467471
def isna(self) -> ArrayLike:
468472
"""

pandas/core/arrays/boolean.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pandas.compat import set_function_name
1010
from pandas.compat.numpy import function as nv
1111

12+
from pandas.core.dtypes.cast import maybe_astype
1213
from pandas.core.dtypes.common import (
1314
is_bool_dtype,
1415
is_extension_array_dtype,
@@ -345,7 +346,7 @@ def reconstruct(x):
345346
def _coerce_to_array(self, value) -> Tuple[np.ndarray, np.ndarray]:
346347
return coerce_to_array(value)
347348

348-
def astype(self, dtype, copy: bool = True) -> ArrayLike:
349+
def astype(self, dtype, copy: bool = True, errors: str = "raise") -> ArrayLike:
349350
"""
350351
Cast to a NumPy array or ExtensionArray with 'dtype'.
351352
@@ -357,6 +358,9 @@ def astype(self, dtype, copy: bool = True) -> ArrayLike:
357358
Whether to copy the data, even if not necessary. If False,
358359
a copy is made only if the old dtype does not match the
359360
new dtype.
361+
errors : str, {'raise', 'ignore'}, default 'ignore'
362+
- ``raise`` : allow exceptions to be raised
363+
- ``ignore`` : suppress exceptions. On error return original object
360364
361365
Returns
362366
-------
@@ -388,9 +392,14 @@ def astype(self, dtype, copy: bool = True) -> ArrayLike:
388392
if is_extension_array_dtype(dtype) and is_integer_dtype(dtype):
389393
from pandas.core.arrays import IntegerArray
390394

391-
return IntegerArray(
392-
self._data.astype(dtype.numpy_dtype), self._mask.copy(), copy=False
395+
result = maybe_astype(
396+
values=self._data, dtype=dtype.numpy_dtype, copy=copy, errors=errors
393397
)
398+
399+
if result is self._data:
400+
return self
401+
else:
402+
return IntegerArray(result, self._mask.copy(), copy=False)
394403
# for integer, error if there are missing values
395404
if is_integer_dtype(dtype):
396405
if self._hasna:
@@ -401,7 +410,15 @@ def astype(self, dtype, copy: bool = True) -> ArrayLike:
401410
if is_float_dtype(dtype):
402411
na_value = np.nan
403412
# coerce
404-
return self.to_numpy(dtype=dtype, na_value=na_value, copy=False)
413+
try:
414+
result = self.to_numpy(dtype=dtype, na_value=na_value, copy=False)
415+
except (ValueError, TypeError):
416+
if errors == "ignore":
417+
result = self
418+
else:
419+
raise
420+
421+
return result
405422

406423
def _values_for_argsort(self) -> np.ndarray:
407424
"""

pandas/core/arrays/categorical.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from pandas.core.dtypes.cast import (
1919
coerce_indexer_dtype,
20+
maybe_astype,
2021
maybe_cast_to_extension_array,
2122
maybe_infer_to_datetimelike,
2223
)
@@ -450,7 +451,9 @@ def _formatter(self, boxed=False):
450451
# Defer to CategoricalFormatter's formatter.
451452
return None
452453

453-
def astype(self, dtype: Dtype, copy: bool = True) -> ArrayLike:
454+
def astype(
455+
self, dtype: Dtype, copy: bool = True, errors: str = "raise"
456+
) -> ArrayLike:
454457
"""
455458
Coerce this type to another dtype
456459
@@ -461,6 +464,9 @@ def astype(self, dtype: Dtype, copy: bool = True) -> ArrayLike:
461464
By default, astype always returns a newly allocated object.
462465
If copy is set to False and dtype is categorical, the original
463466
object is returned.
467+
errors : str, {'raise', 'ignore'}, default 'ignore'
468+
- ``raise`` : allow exceptions to be raised
469+
- ``ignore`` : suppress exceptions. On error return original object
464470
"""
465471
if is_categorical_dtype(dtype):
466472
dtype = cast(Union[str, CategoricalDtype], dtype)
@@ -475,7 +481,9 @@ def astype(self, dtype: Dtype, copy: bool = True) -> ArrayLike:
475481
return array(self, dtype=dtype, copy=copy)
476482
if is_integer_dtype(dtype) and self.isna().any():
477483
raise ValueError("Cannot convert float NaN to integer")
478-
return np.array(self, dtype=dtype, copy=copy)
484+
485+
values = maybe_astype(values=self, dtype=dtype, copy=copy, errors=errors)
486+
return values
479487

480488
@cache_readonly
481489
def itemsize(self) -> int:

pandas/core/arrays/datetimelike.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from pandas.util._decorators import Appender, Substitution
3131
from pandas.util._validators import validate_fillna_kwargs
3232

33+
from pandas.core.dtypes.cast import maybe_astype
3334
from pandas.core.dtypes.common import (
3435
is_categorical_dtype,
3536
is_datetime64_any_dtype,
@@ -622,7 +623,7 @@ def _maybe_clear_freq(self):
622623
# DatetimeArray and TimedeltaArray
623624
pass
624625

625-
def astype(self, dtype, copy=True):
626+
def astype(self, dtype, copy: bool = True, errors: str = "raise"):
626627
# Some notes on cases we don't have to handle here in the base class:
627628
# 1. PeriodArray.astype handles period -> period
628629
# 2. DatetimeArray.astype handles conversion between tz.
@@ -655,13 +656,17 @@ def astype(self, dtype, copy=True):
655656
) or is_float_dtype(dtype):
656657
# disallow conversion between datetime/timedelta,
657658
# and conversions for any datetimelike to float
658-
msg = f"Cannot cast {type(self).__name__} to dtype {dtype}"
659-
raise TypeError(msg)
659+
if errors == "ignore":
660+
return self
661+
else:
662+
msg = f"Cannot cast {type(self).__name__} to dtype {dtype}"
663+
raise TypeError(msg)
660664
elif is_categorical_dtype(dtype):
661665
arr_cls = dtype.construct_array_type()
662666
return arr_cls(self, dtype=dtype)
663667
else:
664-
return np.asarray(self, dtype=dtype)
668+
result = maybe_astype(values=self, dtype=dtype, copy=copy, errors=errors)
669+
return result
665670

666671
def view(self, dtype=None):
667672
if dtype is None or dtype is self.dtype:

pandas/core/arrays/datetimes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ def __iter__(self):
569569
for v in converted:
570570
yield v
571571

572-
def astype(self, dtype, copy=True):
572+
def astype(self, dtype, copy: bool = True, errors: str = "raise"):
573573
# We handle
574574
# --> datetime
575575
# --> period
@@ -596,7 +596,7 @@ def astype(self, dtype, copy=True):
596596
return self
597597
elif is_period_dtype(dtype):
598598
return self.to_period(freq=dtype.freq)
599-
return dtl.DatetimeLikeArrayMixin.astype(self, dtype, copy)
599+
return dtl.DatetimeLikeArrayMixin.astype(self, dtype, copy, errors=errors)
600600

601601
# -----------------------------------------------------------------
602602
# Rendering Methods

pandas/core/arrays/integer.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ def reconstruct(x):
425425
def _coerce_to_array(self, value) -> Tuple[np.ndarray, np.ndarray]:
426426
return coerce_to_array(value, dtype=self.dtype)
427427

428-
def astype(self, dtype, copy: bool = True) -> ArrayLike:
428+
def astype(self, dtype, copy: bool = True, errors: str = "raise") -> ArrayLike:
429429
"""
430430
Cast to a NumPy array or ExtensionArray with 'dtype'.
431431
@@ -437,6 +437,9 @@ def astype(self, dtype, copy: bool = True) -> ArrayLike:
437437
Whether to copy the data, even if not necessary. If False,
438438
a copy is made only if the old dtype does not match the
439439
new dtype.
440+
errors : str, {'raise', 'ignore'}, default 'ignore'
441+
- ``raise`` : allow exceptions to be raised
442+
- ``ignore`` : suppress exceptions. On error return original object
440443
441444
Returns
442445
-------
@@ -477,7 +480,15 @@ def astype(self, dtype, copy: bool = True) -> ArrayLike:
477480
else:
478481
na_value = lib.no_default
479482

480-
return self.to_numpy(dtype=dtype, na_value=na_value, copy=False)
483+
try:
484+
result = self.to_numpy(dtype=dtype, na_value=na_value, copy=False)
485+
except (ValueError, TypeError):
486+
if errors == "ignore":
487+
result = self
488+
else:
489+
raise
490+
491+
return result
481492

482493
def _values_for_argsort(self) -> np.ndarray:
483494
"""

pandas/core/arrays/interval.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ def fillna(self, value=None, method=None, limit=None):
661661
def dtype(self):
662662
return IntervalDtype(self.left.dtype)
663663

664-
def astype(self, dtype, copy=True):
664+
def astype(self, dtype, copy: bool = True, errors: str = "raise"):
665665
"""
666666
Cast to an ExtensionArray or NumPy array with dtype 'dtype'.
667667
@@ -674,6 +674,9 @@ def astype(self, dtype, copy=True):
674674
Whether to copy the data, even if not necessary. If False,
675675
a copy is made only if the old dtype does not match the
676676
new dtype.
677+
errors : str, {'raise', 'ignore'}, default 'ignore'
678+
- ``raise`` : allow exceptions to be raised
679+
- ``ignore`` : suppress exceptions. On error return original object
677680
678681
Returns
679682
-------
@@ -694,10 +697,12 @@ def astype(self, dtype, copy=True):
694697
new_left = self.left.astype(dtype.subtype)
695698
new_right = self.right.astype(dtype.subtype)
696699
except TypeError as err:
697-
msg = (
698-
f"Cannot convert {self.dtype} to {dtype}; subtypes are incompatible"
699-
)
700-
raise TypeError(msg) from err
700+
if errors == "ignore":
701+
new_left = self.left
702+
new_right = self.right
703+
else:
704+
msg = f"Cannot convert {self.dtype} to {dtype}; subtypes are incompatible"
705+
raise TypeError(msg) from err
701706
return self._shallow_copy(new_left, new_right)
702707
elif is_categorical_dtype(dtype):
703708
return Categorical(np.asarray(self))
@@ -708,8 +713,11 @@ def astype(self, dtype, copy=True):
708713
try:
709714
return np.asarray(self).astype(dtype, copy=copy)
710715
except (TypeError, ValueError) as err:
711-
msg = f"Cannot cast {type(self).__name__} to dtype {dtype}"
712-
raise TypeError(msg) from err
716+
if errors == "ignore":
717+
return self
718+
else:
719+
msg = f"Cannot cast {type(self).__name__} to dtype {dtype}"
720+
raise TypeError(msg) from err
713721

714722
@classmethod
715723
def _concat_same_type(cls, to_concat):

pandas/core/arrays/period.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,14 +573,14 @@ def _format_native_types(self, na_rep="NaT", date_format=None, **kwargs):
573573

574574
# ------------------------------------------------------------------
575575

576-
def astype(self, dtype, copy: bool = True):
576+
def astype(self, dtype, copy: bool = True, errors: str = "raise"):
577577
# We handle Period[T] -> Period[U]
578578
# Our parent handles everything else.
579579
dtype = pandas_dtype(dtype)
580580

581581
if is_period_dtype(dtype):
582582
return self.asfreq(dtype.freq)
583-
return super().astype(dtype, copy=copy)
583+
return super().astype(dtype, copy=copy, errors=errors)
584584

585585
# ------------------------------------------------------------------
586586
# Arithmetic Methods

pandas/core/arrays/sparse/array.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ def _concat_same_type(cls, to_concat):
10061006

10071007
return cls(data, sparse_index=sp_index, fill_value=fill_value)
10081008

1009-
def astype(self, dtype=None, copy=True):
1009+
def astype(self, dtype=None, copy: bool = True, errors: str = "raise"):
10101010
"""
10111011
Change the dtype of a SparseArray.
10121012
@@ -1025,6 +1025,10 @@ def astype(self, dtype=None, copy=True):
10251025
copy : bool, default True
10261026
Whether to ensure a copy is made, even if not necessary.
10271027
1028+
errors : str, {'raise', 'ignore'}, default 'ignore'
1029+
- ``raise`` : allow exceptions to be raised
1030+
- ``ignore`` : suppress exceptions. On error return original object
1031+
10281032
Returns
10291033
-------
10301034
SparseArray
@@ -1063,7 +1067,13 @@ def astype(self, dtype=None, copy=True):
10631067
IntIndex
10641068
Indices: array([2, 3], dtype=int32)
10651069
"""
1066-
dtype = self.dtype.update_dtype(dtype)
1070+
try:
1071+
dtype = self.dtype.update_dtype(dtype)
1072+
except ValueError:
1073+
if errors == "ignore":
1074+
return self
1075+
else:
1076+
raise
10671077
subtype = dtype._subtype_with_str
10681078
# TODO copy=False is broken for astype_nansafe with int -> float, so cannot
10691079
# passthrough copy keyword: https://github.com/pandas-dev/pandas/issues/34456

pandas/core/arrays/string_.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ def fillna(self, value=None, method=None, limit=None):
262262
# TODO: validate dtype
263263
return super().fillna(value, method, limit)
264264

265-
def astype(self, dtype, copy=True):
265+
def astype(self, dtype, copy: bool = True, errors: str = "raise"):
266266
dtype = pandas_dtype(dtype)
267267
if isinstance(dtype, StringDtype):
268268
if copy:
@@ -275,7 +275,7 @@ def astype(self, dtype, copy=True):
275275
values = arr.astype(dtype.numpy_dtype)
276276
return IntegerArray(values, mask, copy=False)
277277

278-
return super().astype(dtype, copy)
278+
return super().astype(dtype, copy, errors=errors)
279279

280280
def _reduce(self, name: str, skipna: bool = True, **kwargs):
281281
if name in ["min", "max"]:

pandas/core/dtypes/cast.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,18 @@ def maybe_promote(dtype, fill_value=np.nan):
595595
return dtype, fill_value
596596

597597

598+
def maybe_astype(values, dtype, copy, errors="raise"):
599+
try:
600+
result = np.array(values, dtype=dtype, copy=copy)
601+
except (ValueError, TypeError):
602+
if errors == "ignore":
603+
result = values
604+
else:
605+
raise
606+
607+
return result
608+
609+
598610
def _ensure_dtype_type(value, dtype):
599611
"""
600612
Ensure that the given value is an instance of the given dtype.

pandas/core/internals/blocks.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -580,13 +580,7 @@ def astype(self, dtype, copy: bool = False, errors: str = "raise"):
580580

581581
# force the copy here
582582
if self.is_extension:
583-
try:
584-
values = self.values.astype(dtype)
585-
except (ValueError, TypeError):
586-
if errors == "ignore":
587-
values = self.values
588-
else:
589-
raise
583+
values = self.values.astype(dtype, errors=errors)
590584
else:
591585
if issubclass(dtype.type, str):
592586

pandas/tests/extension/arrow/arrays.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def __getitem__(self, item):
9595
def __len__(self):
9696
return len(self._data)
9797

98-
def astype(self, dtype, copy=True):
98+
def astype(self, dtype, copy=True, errors="raise"):
9999
# needed to fix this astype for the Series constructor.
100100
if isinstance(dtype, type(self.dtype)) and dtype == self.dtype:
101101
if copy:

0 commit comments

Comments
 (0)