diff --git a/pandas/core/arrays/numpy_.py b/pandas/core/arrays/numpy_.py index bc7de0e2c4e1e..13748e03e856d 100644 --- a/pandas/core/arrays/numpy_.py +++ b/pandas/core/arrays/numpy_.py @@ -72,7 +72,12 @@ def _is_boolean(self): @classmethod def construct_from_string(cls, string): - return cls(np.dtype(string)) + try: + return cls(np.dtype(string)) + except TypeError as err: + raise TypeError( + f"Cannot construct a 'PandasDtype' from '{string}'" + ) from err def construct_array_type(cls): return PandasArray diff --git a/pandas/core/arrays/sparse/dtype.py b/pandas/core/arrays/sparse/dtype.py index 941db116589e8..a295dfed2cf96 100644 --- a/pandas/core/arrays/sparse/dtype.py +++ b/pandas/core/arrays/sparse/dtype.py @@ -199,7 +199,7 @@ def construct_from_string(cls, string): ------- SparseDtype """ - msg = f"Could not construct SparseDtype from '{string}'" + msg = f"Cannot construct a 'SparseDtype' from '{string}'" if string.startswith("Sparse"): try: sub_type, has_fill_value = cls._parse_subtype(string) @@ -208,7 +208,7 @@ def construct_from_string(cls, string): else: result = SparseDtype(sub_type) msg = ( - f"Could not construct SparseDtype from '{string}'.\n\nIt " + f"Cannot construct a 'SparseDtype' from '{string}'.\n\nIt " "looks like the fill_value in the string is not " "the default for the dtype. Non-default fill_values " "are not supported. Use the 'SparseDtype()' " diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index e45f4ce1b72b1..4421fad5f19d1 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -732,7 +732,7 @@ def construct_from_string(cls, string: str_type): datetime64[ns, UTC] """ if isinstance(string, str): - msg = "Could not construct DatetimeTZDtype from '{string}'" + msg = f"Cannot construct a 'DatetimeTZDtype' from '{string}'" match = cls._match.match(string) if match: d = match.groupdict() @@ -743,10 +743,10 @@ def construct_from_string(cls, string: str_type): # pytz timezone (actually pytz.UnknownTimeZoneError). # TypeError if we pass a nonsense tz; # ValueError if we pass a unit other than "ns" - raise TypeError(msg.format(string=string)) from err - raise TypeError(msg.format(string=string)) + raise TypeError(msg) from err + raise TypeError(msg) - raise TypeError("Could not construct DatetimeTZDtype") + raise TypeError("Cannot construct a 'DatetimeTZDtype'") def __str__(self) -> str_type: return "datetime64[{unit}, {tz}]".format(unit=self.unit, tz=self.tz) @@ -883,7 +883,7 @@ def construct_from_string(cls, string): return cls(freq=string) except ValueError: pass - raise TypeError("could not construct PeriodDtype") + raise TypeError(f"Cannot construct a 'PeriodDtype' from '{string}'") def __str__(self) -> str_type: return self.name @@ -1054,6 +1054,7 @@ def construct_from_string(cls, string): return cls(string) msg = ( + f"Cannot construct a 'IntervalDtype' from '{string}'.\n\n" "Incorrectly formatted string passed to constructor. " "Valid formats include Interval or Interval[dtype] " "where dtype is numeric, datetime, or timedelta" diff --git a/pandas/tests/arrays/sparse/test_dtype.py b/pandas/tests/arrays/sparse/test_dtype.py index 3194498daf825..5e9e2d854f577 100644 --- a/pandas/tests/arrays/sparse/test_dtype.py +++ b/pandas/tests/arrays/sparse/test_dtype.py @@ -83,7 +83,7 @@ def test_not_equal(a, b): def test_construct_from_string_raises(): with pytest.raises( - TypeError, match="Could not construct SparseDtype from 'not a dtype'" + TypeError, match="Cannot construct a 'SparseDtype' from 'not a dtype'" ): SparseDtype.construct_from_string("not a dtype") diff --git a/pandas/tests/dtypes/test_dtypes.py b/pandas/tests/dtypes/test_dtypes.py index 6c6ff3272c012..bca78a1008d87 100644 --- a/pandas/tests/dtypes/test_dtypes.py +++ b/pandas/tests/dtypes/test_dtypes.py @@ -236,7 +236,7 @@ def test_compat(self): def test_construction_from_string(self): result = DatetimeTZDtype.construct_from_string("datetime64[ns, US/Eastern]") assert is_dtype_equal(self.dtype, result) - msg = "Could not construct DatetimeTZDtype from 'foo'" + msg = "Cannot construct a 'DatetimeTZDtype' from 'foo'" with pytest.raises(TypeError, match=msg): DatetimeTZDtype.construct_from_string("foo") @@ -244,7 +244,7 @@ def test_construct_from_string_raises(self): with pytest.raises(TypeError, match="notatz"): DatetimeTZDtype.construct_from_string("datetime64[ns, notatz]") - msg = "^Could not construct DatetimeTZDtype" + msg = "^Cannot construct a 'DatetimeTZDtype'" with pytest.raises(TypeError, match=msg): # list instead of string DatetimeTZDtype.construct_from_string(["datetime64[ns, notatz]"]) diff --git a/pandas/tests/extension/arrow/arrays.py b/pandas/tests/extension/arrow/arrays.py index a4554aca1325e..86e23b3264456 100644 --- a/pandas/tests/extension/arrow/arrays.py +++ b/pandas/tests/extension/arrow/arrays.py @@ -33,7 +33,7 @@ def construct_from_string(cls, string): if string == cls.name: return cls() else: - raise TypeError(f"Cannot construct a '{cls}' from '{string}'") + raise TypeError(f"Cannot construct a '{cls.__name__}' from '{string}'") @classmethod def construct_array_type(cls): diff --git a/pandas/tests/extension/base/dtype.py b/pandas/tests/extension/base/dtype.py index d1e1717225e15..9a442f346c19f 100644 --- a/pandas/tests/extension/base/dtype.py +++ b/pandas/tests/extension/base/dtype.py @@ -98,5 +98,8 @@ def test_eq(self, dtype): def test_construct_from_string(self, dtype): dtype_instance = type(dtype).construct_from_string(dtype.name) assert isinstance(dtype_instance, type(dtype)) - with pytest.raises(TypeError): + + def test_construct_from_string_another_type_raises(self, dtype): + msg = f"Cannot construct a '{type(dtype).__name__}' from 'another_type'" + with pytest.raises(TypeError, match=msg): type(dtype).construct_from_string("another_type") diff --git a/pandas/tests/extension/decimal/array.py b/pandas/tests/extension/decimal/array.py index 0c2f1e845909a..0b0865c424f34 100644 --- a/pandas/tests/extension/decimal/array.py +++ b/pandas/tests/extension/decimal/array.py @@ -40,7 +40,7 @@ def construct_from_string(cls, string): if string == cls.name: return cls() else: - raise TypeError(f"Cannot construct a '{cls}' from '{string}'") + raise TypeError(f"Cannot construct a '{cls.__name__}' from '{string}'") @property def _is_numeric(self): diff --git a/pandas/tests/extension/json/array.py b/pandas/tests/extension/json/array.py index b64ddbd6ac84d..28929d50718b6 100644 --- a/pandas/tests/extension/json/array.py +++ b/pandas/tests/extension/json/array.py @@ -44,7 +44,7 @@ def construct_from_string(cls, string): if string == cls.name: return cls() else: - raise TypeError("Cannot construct a '{}' from '{}'".format(cls, string)) + raise TypeError(f"Cannot construct a '{cls.__name__}' from '{string}'") class JSONArray(ExtensionArray):