Skip to content

Commit c5cb3e1

Browse files
author
Mayank
committed
Add comprehensive tests for iloc dictionary assignment fix (GH#62723)
- Tests verify iloc preserves dictionaries in object dtype Series - Covers edge cases: nested dicts, multiple assignments, consistency with direct assignment - Includes regression test for original bug scenario - All tests pass pre-commit checks
1 parent ed4c77f commit c5cb3e1

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
"""
2+
Tests for iloc dictionary assignment bug fix.
3+
4+
Regression test for GH#62723: Series.iloc assignment with dtype="object"
5+
incorrectly converts dictionary values to Series.
6+
"""
7+
import numpy as np
8+
import pytest
9+
10+
from pandas import (
11+
DataFrame,
12+
Series,
13+
)
14+
import pandas._testing as tm
15+
16+
17+
class TestIlocDictionaryAssignment:
18+
"""Tests for iloc dictionary assignment bug fix (GH#62723)."""
19+
20+
def test_iloc_preserves_dict_object_dtype(self):
21+
"""Test that iloc preserves dictionaries in object dtype Series."""
22+
# GH#62723
23+
s = Series(0, dtype="object")
24+
test_dict = {}
25+
26+
# Assign dictionary via iloc
27+
s.iloc[0] = test_dict
28+
29+
# Verify dictionary is preserved
30+
assert s[0] == test_dict
31+
assert isinstance(s[0], dict)
32+
33+
def test_iloc_preserves_complex_dict_object_dtype(self):
34+
"""Test that iloc preserves complex dictionaries in object dtype Series."""
35+
s = Series(0, dtype="object")
36+
test_dict = {
37+
'a': 1,
38+
'b': [1, 2, 3],
39+
'c': {'nested': True},
40+
'd': None,
41+
'e': 3.14
42+
}
43+
44+
s.iloc[0] = test_dict
45+
46+
assert s[0] == test_dict
47+
assert isinstance(s[0], dict)
48+
assert s[0]['a'] == 1
49+
assert s[0]['b'] == [1, 2, 3]
50+
assert s[0]['c'] == {'nested': True}
51+
assert s[0]['d'] is None
52+
assert s[0]['e'] == 3.14
53+
54+
def test_iloc_vs_loc_dict_assignment_consistency(self):
55+
"""Test that iloc and direct assignment behave consistently."""
56+
# Original bug: s[0] = {} works but s.iloc[0] = {} converts to Series
57+
s = Series(0, dtype="object")
58+
59+
# Direct assignment should work (baseline)
60+
s[0] = {}
61+
assert s[0] == {}
62+
assert isinstance(s[0], dict)
63+
64+
# Reset and test iloc
65+
s = Series(0, dtype="object")
66+
s.iloc[0] = {}
67+
assert s[0] == {}
68+
assert isinstance(s[0], dict)
69+
70+
def test_iloc_multiple_dict_assignments(self):
71+
"""Test iloc dictionary assignment to multiple positions."""
72+
s = Series([0, 1, 2], dtype="object")
73+
dict1 = {'first': 1}
74+
dict2 = {'second': 2}
75+
76+
s.iloc[0] = dict1
77+
s.iloc[2] = dict2
78+
79+
assert s.iloc[0] == dict1
80+
assert isinstance(s.iloc[0], dict)
81+
assert s.iloc[1] == 1 # unchanged
82+
assert s.iloc[2] == dict2
83+
assert isinstance(s.iloc[2], dict)
84+
85+
def test_iloc_dict_assignment_non_object_dtype_fails(self):
86+
"""Test that iloc dict assignment to non-object dtypes fails as expected."""
87+
s = Series([1, 2, 3], dtype="int64")
88+
89+
# This should fail for non-object dtypes
90+
with pytest.raises((ValueError, TypeError)):
91+
s.iloc[0] = {'key': 'value'}
92+
93+
def test_iloc_preserves_other_object_types(self):
94+
"""Test that iloc preserves other object types correctly."""
95+
s = Series([None] * 4, dtype="object")
96+
97+
# Test various object types
98+
test_list = [1, 2, 3]
99+
test_tuple = (1, 2, 3)
100+
test_set = {1, 2, 3}
101+
test_str = "test string"
102+
103+
s.iloc[0] = test_list
104+
s.iloc[1] = test_tuple
105+
s.iloc[2] = test_set
106+
s.iloc[3] = test_str
107+
108+
assert s.iloc[0] == test_list
109+
assert isinstance(s.iloc[0], list)
110+
assert s.iloc[1] == test_tuple
111+
assert isinstance(s.iloc[1], tuple)
112+
assert s.iloc[2] == test_set
113+
assert isinstance(s.iloc[2], set)
114+
assert s.iloc[3] == test_str
115+
assert isinstance(s.iloc[3], str)
116+
117+
def test_dataframe_iloc_dict_assignment_unaffected(self):
118+
"""Test that the fix doesn't break DataFrame iloc dict assignment."""
119+
df = DataFrame({'A': [0, 1], 'B': [2, 3]}, dtype="object")
120+
test_dict = {'frame': 'test'}
121+
122+
# DataFrame iloc should still work correctly
123+
df.iloc[0, 0] = test_dict
124+
125+
assert df.iloc[0, 0] == test_dict
126+
assert isinstance(df.iloc[0, 0], dict)
127+
128+
def test_nested_dict_assignment(self):
129+
"""Test iloc assignment with deeply nested dictionaries."""
130+
s = Series([None], dtype="object")
131+
nested_dict = {
132+
'level1': {
133+
'level2': {
134+
'level3': {
135+
'deep': 'value',
136+
'list': [1, 2, {'nested_in_list': True}]
137+
}
138+
}
139+
},
140+
'another_key': [{'dict_in_list': 'test'}]
141+
}
142+
143+
s.iloc[0] = nested_dict
144+
145+
assert s.iloc[0] == nested_dict
146+
assert isinstance(s.iloc[0], dict)
147+
assert s.iloc[0]['level1']['level2']['level3']['deep'] == 'value'
148+
assert s.iloc[0]['another_key'][0]['dict_in_list'] == 'test'
149+
150+
def test_original_bug_reproduction(self):
151+
"""Direct test of the original bug report scenario."""
152+
# This is the exact code from the bug report
153+
s = Series(0, dtype="object")
154+
155+
s[0] = {}
156+
assert s[0] == {} # This should pass
157+
158+
s.iloc[0] = {}
159+
assert s[0] == {} # This was failing before the fix
160+
161+
# Additional verification
162+
assert isinstance(s[0], dict)
163+
assert type(s[0]) == dict

0 commit comments

Comments
 (0)