diff --git a/pandas/core/construction.py b/pandas/core/construction.py index 78a7f1890b5de..ddb6473280a05 100644 --- a/pandas/core/construction.py +++ b/pandas/core/construction.py @@ -328,7 +328,7 @@ def array( elif inferred_dtype == "interval": try: return IntervalArray(data, copy=copy) - except ValueError: + except (ValueError, TypeError): # We may have a mixture of `closed` here. # We choose to return an ndarray, rather than raising. pass diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 12b343ab5d895..7c504edfe08d0 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -6327,13 +6327,6 @@ def _maybe_cast_data_without_dtype(subarr): converted : np.ndarray or ExtensionArray dtype : np.dtype or ExtensionDtype """ - # Runtime import needed bc IntervalArray imports Index - from pandas.core.arrays import ( - DatetimeArray, - IntervalArray, - PeriodArray, - TimedeltaArray, - ) assert subarr.dtype == object, subarr.dtype inferred = lib.infer_dtype(subarr, skipna=False) @@ -6356,38 +6349,10 @@ def _maybe_cast_data_without_dtype(subarr): data = np.asarray(subarr).astype(np.float64, copy=False) return data - elif inferred == "interval": - try: - data = IntervalArray._from_sequence(subarr, copy=False) - return data - except (ValueError, TypeError): - # GH27172: mixed closed Intervals --> object dtype - pass - elif inferred == "boolean": - # don't support boolean explicitly ATM - pass - elif inferred != "string": - if inferred.startswith("datetime"): - try: - data = DatetimeArray._from_sequence(subarr, copy=False) - return data - except (ValueError, OutOfBoundsDatetime): - # GH 27011 - # If we have mixed timezones, just send it - # down the base constructor - pass - - elif inferred.startswith("timedelta"): - tda = TimedeltaArray._from_sequence(subarr, copy=False) - return tda - elif inferred == "period": - try: - data = PeriodArray._from_sequence(subarr) - return data - except IncompatibleFrequency: - pass - - return subarr + else: + alt = sanitize_array(subarr, None) + alt = ensure_wrapped_if_datetimelike(alt) + return alt def _try_convert_to_int_array( diff --git a/pandas/tests/arrays/test_array.py b/pandas/tests/arrays/test_array.py index 5d2b7c43f6765..3e04fb3ceb40b 100644 --- a/pandas/tests/arrays/test_array.py +++ b/pandas/tests/arrays/test_array.py @@ -153,6 +153,16 @@ "category", pd.Categorical([pd.Period("2000", "D"), pd.Period("2001", "D")]), ), + # mixed-dtype intervals -> cast to object, dont raise TypeError + ( + [pd.Interval(0, 1), pd.Interval(pd.Timestamp(0), pd.Timestamp(1))], + None, + PandasArray( + np.array( + [pd.Interval(0, 1), pd.Interval(pd.Timestamp(0), pd.Timestamp(1))] + ) + ), + ), ], ) def test_array(data, dtype, expected): diff --git a/pandas/tests/indexes/test_index_new.py b/pandas/tests/indexes/test_index_new.py index 5937f43102190..38d8b36a0b137 100644 --- a/pandas/tests/indexes/test_index_new.py +++ b/pandas/tests/indexes/test_index_new.py @@ -1,6 +1,10 @@ """ Tests for the Index constructor conducting inference. """ +from datetime import ( + date, + datetime, +) from decimal import Decimal import numpy as np @@ -138,6 +142,24 @@ def test_constructor_mixed_nat_objs_infers_object(self, swap_objs): tm.assert_index_equal(Index(data), expected) tm.assert_index_equal(Index(np.array(data, dtype=object)), expected) + def test_constructor_datetime_inference(self): + # Index.__new__ inference to datetime matches Series + + # mixed str/datetime + data = ["2012-12-31", datetime(2013, 1, 1), datetime(2013, 1, 2)] + result = Index(data) + expected = DatetimeIndex([Timestamp(x) for x in data]) + tm.assert_index_equal(result, expected) + + # date objects cast to Timestamp + data = [date(2020, 1, 1), Timestamp("2020-01-02 00:00:00")] + result = Index(data) + expected = DatetimeIndex([Timestamp(x) for x in data]) + tm.assert_index_equal(result, expected) + + result = Index(data[::-1]) + tm.assert_index_equal(result, expected[::-1]) + class TestDtypeEnforced: # check we don't silently ignore the dtype keyword