Skip to content

Commit 179b3e6

Browse files
authored
BUG: DataFrame(frozenset) should raise (#40163)
1 parent dd2e721 commit 179b3e6

File tree

5 files changed

+40
-17
lines changed

5 files changed

+40
-17
lines changed

doc/source/whatsnew/v1.3.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ Conversion
405405
- Bug in :meth:`Series.to_dict` with ``orient='records'`` now returns python native types (:issue:`25969`)
406406
- Bug in :meth:`Series.view` and :meth:`Index.view` when converting between datetime-like (``datetime64[ns]``, ``datetime64[ns, tz]``, ``timedelta64``, ``period``) dtypes (:issue:`39788`)
407407
- Bug in creating a :class:`DataFrame` from an empty ``np.recarray`` not retaining the original dtypes (:issue:`40121`)
408+
- Bug in :class:`DataFrame` failing to raise ``TypeError`` when constructing from a ``frozenset`` (:issue:`40163`)
408409
-
409410

410411
Strings

pandas/core/construction.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -518,9 +518,9 @@ def sanitize_array(
518518

519519
elif isinstance(data, (list, tuple, abc.Set, abc.ValuesView)) and len(data) > 0:
520520
# TODO: deque, array.array
521-
if isinstance(data, set):
521+
if isinstance(data, (set, frozenset)):
522522
# Raise only for unordered sets, e.g., not for dict_keys
523-
raise TypeError("Set type is unordered")
523+
raise TypeError(f"'{type(data).__name__}' type is unordered")
524524
data = list(data)
525525

526526
if dtype is not None:

pandas/core/series.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -375,10 +375,8 @@ def __init__(
375375
"`index` argument. `copy` must be False."
376376
)
377377

378-
elif is_extension_array_dtype(data):
378+
elif isinstance(data, ExtensionArray):
379379
pass
380-
elif isinstance(data, (set, frozenset)):
381-
raise TypeError(f"'{type(data).__name__}' type is unordered")
382380
else:
383381
data = com.maybe_iterable_to_list(data)
384382

pandas/tests/frame/test_constructors.py

+19-4
Original file line numberDiff line numberDiff line change
@@ -377,26 +377,31 @@ def test_constructor_dict(self):
377377
with pytest.raises(ValueError, match=msg):
378378
DataFrame({"A": {"a": "a", "b": "b"}, "B": ["a", "b", "c"]})
379379

380+
def test_constructor_dict_length1(self):
380381
# Length-one dict micro-optimization
381382
frame = DataFrame({"A": {"1": 1, "2": 2}})
382383
tm.assert_index_equal(frame.index, Index(["1", "2"]))
383384

385+
def test_constructor_dict_with_index(self):
384386
# empty dict plus index
385387
idx = Index([0, 1, 2])
386388
frame = DataFrame({}, index=idx)
387389
assert frame.index is idx
388390

391+
def test_constructor_dict_with_index_and_columns(self):
389392
# empty dict with index and columns
390393
idx = Index([0, 1, 2])
391394
frame = DataFrame({}, index=idx, columns=idx)
392395
assert frame.index is idx
393396
assert frame.columns is idx
394397
assert len(frame._series) == 3
395398

399+
def test_constructor_dict_of_empty_lists(self):
396400
# with dict of empty list and Series
397401
frame = DataFrame({"A": [], "B": []}, columns=["A", "B"])
398402
tm.assert_index_equal(frame.index, RangeIndex(0), exact=True)
399403

404+
def test_constructor_dict_with_none(self):
400405
# GH 14381
401406
# Dict with None value
402407
frame_none = DataFrame({"a": None}, index=[0])
@@ -405,6 +410,7 @@ def test_constructor_dict(self):
405410
assert frame_none_list._get_value(0, "a") is None
406411
tm.assert_frame_equal(frame_none, frame_none_list)
407412

413+
def test_constructor_dict_errors(self):
408414
# GH10856
409415
# dict with scalar values should raise error, even if columns passed
410416
msg = "If using all scalar values, you must pass an index"
@@ -560,7 +566,7 @@ def test_constructor_error_msgs(self):
560566
with pytest.raises(ValueError, match=msg):
561567
DataFrame({"a": False, "b": True})
562568

563-
def test_constructor_subclass_dict(self, float_frame, dict_subclass):
569+
def test_constructor_subclass_dict(self, dict_subclass):
564570
# Test for passing dict subclass to constructor
565571
data = {
566572
"col1": dict_subclass((x, 10.0 * x) for x in range(10)),
@@ -574,6 +580,7 @@ def test_constructor_subclass_dict(self, float_frame, dict_subclass):
574580
df = DataFrame(data)
575581
tm.assert_frame_equal(refdf, df)
576582

583+
def test_constructor_defaultdict(self, float_frame):
577584
# try with defaultdict
578585
from collections import defaultdict
579586

@@ -608,6 +615,7 @@ def test_constructor_dict_cast(self):
608615
assert frame["B"].dtype == np.object_
609616
assert frame["A"].dtype == np.float64
610617

618+
def test_constructor_dict_cast2(self):
611619
# can't cast to float
612620
test_data = {
613621
"A": dict(zip(range(20), tm.makeStringIndex(20))),
@@ -623,6 +631,7 @@ def test_constructor_dict_dont_upcast(self):
623631
df = DataFrame(d)
624632
assert isinstance(df["Col1"]["Row2"], float)
625633

634+
def test_constructor_dict_dont_upcast2(self):
626635
dm = DataFrame([[1, 2], ["a", "b"]], index=[1, 2], columns=[1, 2])
627636
assert isinstance(dm[1][1], int)
628637

@@ -1195,6 +1204,7 @@ def __len__(self, n):
11951204
expected = DataFrame([[1, "a"], [2, "b"]], columns=columns)
11961205
tm.assert_frame_equal(result, expected, check_dtype=False)
11971206

1207+
def test_constructor_stdlib_array(self):
11981208
# GH 4297
11991209
# support Array
12001210
import array
@@ -2427,11 +2437,16 @@ def test_from_2d_ndarray_with_dtype(self):
24272437
expected = DataFrame(array_dim2).astype("datetime64[ns, UTC]")
24282438
tm.assert_frame_equal(df, expected)
24292439

2430-
def test_construction_from_set_raises(self):
2440+
@pytest.mark.parametrize("typ", [set, frozenset])
2441+
def test_construction_from_set_raises(self, typ):
24312442
# https://github.com/pandas-dev/pandas/issues/32582
2432-
msg = "Set type is unordered"
2443+
values = typ({1, 2, 3})
2444+
msg = f"'{typ.__name__}' type is unordered"
24332445
with pytest.raises(TypeError, match=msg):
2434-
DataFrame({"a": {1, 2, 3}})
2446+
DataFrame({"a": values})
2447+
2448+
with pytest.raises(TypeError, match=msg):
2449+
Series(values)
24352450

24362451

24372452
def get1(obj):

pandas/tests/series/test_constructors.py

+17-8
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class TestSeriesConstructors:
6969
],
7070
)
7171
def test_empty_constructor(self, constructor, check_index_type):
72+
# TODO: share with frame test of the same name
7273
with tm.assert_produces_warning(DeprecationWarning, check_stacklevel=False):
7374
expected = Series()
7475
result = constructor()
@@ -310,6 +311,7 @@ def test_constructor_generator(self):
310311
exp = Series(range(10))
311312
tm.assert_series_equal(result, exp)
312313

314+
# same but with non-default index
313315
gen = (i for i in range(10))
314316
result = Series(gen, index=range(10, 20))
315317
exp.index = range(10, 20)
@@ -323,6 +325,7 @@ def test_constructor_map(self):
323325
exp = Series(range(10))
324326
tm.assert_series_equal(result, exp)
325327

328+
# same but with non-default index
326329
m = map(lambda x: x, range(10))
327330
result = Series(m, index=range(10, 20))
328331
exp.index = range(10, 20)
@@ -386,6 +389,7 @@ def test_constructor_categorical_with_coercion(self):
386389
str(df.values)
387390
str(df)
388391

392+
def test_constructor_categorical_with_coercion2(self):
389393
# GH8623
390394
x = DataFrame(
391395
[[1, "John P. Doe"], [2, "Jane Dove"], [1, "John P. Doe"]],
@@ -747,6 +751,7 @@ def test_constructor_datelike_coercion(self):
747751
assert s.iloc[1] == "NOV"
748752
assert s.dtype == object
749753

754+
def test_constructor_datelike_coercion2(self):
750755
# the dtype was being reset on the slicing and re-inferred to datetime
751756
# even thought the blocks are mixed
752757
belly = "216 3T19".split()
@@ -798,6 +803,7 @@ def test_constructor_dtype_datetime64(self):
798803
assert isna(s[1])
799804
assert s.dtype == "M8[ns]"
800805

806+
def test_constructor_dtype_datetime64_10(self):
801807
# GH3416
802808
dates = [
803809
np.datetime64(datetime(2013, 1, 1)),
@@ -850,18 +856,21 @@ def test_constructor_dtype_datetime64(self):
850856
expected = Series(dts.astype(np.int64))
851857
tm.assert_series_equal(result, expected)
852858

859+
def test_constructor_dtype_datetime64_9(self):
853860
# invalid dates can be help as object
854861
result = Series([datetime(2, 1, 1)])
855862
assert result[0] == datetime(2, 1, 1, 0, 0)
856863

857864
result = Series([datetime(3000, 1, 1)])
858865
assert result[0] == datetime(3000, 1, 1, 0, 0)
859866

867+
def test_constructor_dtype_datetime64_8(self):
860868
# don't mix types
861869
result = Series([Timestamp("20130101"), 1], index=["a", "b"])
862870
assert result["a"] == Timestamp("20130101")
863871
assert result["b"] == 1
864872

873+
def test_constructor_dtype_datetime64_7(self):
865874
# GH6529
866875
# coerce datetime64 non-ns properly
867876
dates = date_range("01-Jan-2015", "01-Dec-2015", freq="M")
@@ -887,6 +896,7 @@ def test_constructor_dtype_datetime64(self):
887896
tm.assert_numpy_array_equal(series1.values, dates2)
888897
assert series1.dtype == object
889898

899+
def test_constructor_dtype_datetime64_6(self):
890900
# these will correctly infer a datetime
891901
s = Series([None, NaT, "2013-08-05 15:30:00.000001"])
892902
assert s.dtype == "datetime64[ns]"
@@ -897,6 +907,7 @@ def test_constructor_dtype_datetime64(self):
897907
s = Series([NaT, np.nan, "2013-08-05 15:30:00.000001"])
898908
assert s.dtype == "datetime64[ns]"
899909

910+
def test_constructor_dtype_datetime64_5(self):
900911
# tz-aware (UTC and other tz's)
901912
# GH 8411
902913
dr = date_range("20130101", periods=3)
@@ -906,18 +917,21 @@ def test_constructor_dtype_datetime64(self):
906917
dr = date_range("20130101", periods=3, tz="US/Eastern")
907918
assert str(Series(dr).iloc[0].tz) == "US/Eastern"
908919

920+
def test_constructor_dtype_datetime64_4(self):
909921
# non-convertible
910922
s = Series([1479596223000, -1479590, NaT])
911923
assert s.dtype == "object"
912924
assert s[2] is NaT
913925
assert "NaT" in str(s)
914926

927+
def test_constructor_dtype_datetime64_3(self):
915928
# if we passed a NaT it remains
916929
s = Series([datetime(2010, 1, 1), datetime(2, 1, 1), NaT])
917930
assert s.dtype == "object"
918931
assert s[2] is NaT
919932
assert "NaT" in str(s)
920933

934+
def test_constructor_dtype_datetime64_2(self):
921935
# if we passed a nan it remains
922936
s = Series([datetime(2010, 1, 1), datetime(2, 1, 1), np.nan])
923937
assert s.dtype == "object"
@@ -980,6 +994,7 @@ def test_constructor_with_datetime_tz(self):
980994
result = DatetimeIndex(s, freq="infer")
981995
tm.assert_index_equal(result, dr)
982996

997+
def test_constructor_with_datetime_tz4(self):
983998
# inference
984999
s = Series(
9851000
[
@@ -990,6 +1005,7 @@ def test_constructor_with_datetime_tz(self):
9901005
assert s.dtype == "datetime64[ns, US/Pacific]"
9911006
assert lib.infer_dtype(s, skipna=True) == "datetime64"
9921007

1008+
def test_constructor_with_datetime_tz3(self):
9931009
s = Series(
9941010
[
9951011
Timestamp("2013-01-01 13:00:00-0800", tz="US/Pacific"),
@@ -999,6 +1015,7 @@ def test_constructor_with_datetime_tz(self):
9991015
assert s.dtype == "object"
10001016
assert lib.infer_dtype(s, skipna=True) == "datetime"
10011017

1018+
def test_constructor_with_datetime_tz2(self):
10021019
# with all NaT
10031020
s = Series(NaT, index=[0, 1], dtype="datetime64[ns, US/Eastern]")
10041021
expected = Series(DatetimeIndex(["NaT", "NaT"], tz="US/Eastern"))
@@ -1231,14 +1248,6 @@ def test_constructor_dict_of_tuples(self):
12311248
expected = Series([3, 6], index=MultiIndex.from_tuples([(1, 2), (None, 5)]))
12321249
tm.assert_series_equal(result, expected)
12331250

1234-
def test_constructor_set(self):
1235-
values = {1, 2, 3, 4, 5}
1236-
with pytest.raises(TypeError, match="'set' type is unordered"):
1237-
Series(values)
1238-
values = frozenset(values)
1239-
with pytest.raises(TypeError, match="'frozenset' type is unordered"):
1240-
Series(values)
1241-
12421251
# https://github.com/pandas-dev/pandas/issues/22698
12431252
@pytest.mark.filterwarnings("ignore:elementwise comparison:FutureWarning")
12441253
def test_fromDict(self):

0 commit comments

Comments
 (0)