Skip to content

Commit d4219df

Browse files
committed
MAINT: refactor from_items() using from_dict(). Fixes pandas-dev#21850
This removes the deprecation warnings introduced in pandas-dev#18262, by reimplementing DataFrame.from_items() in the recommended way using DataFrame.from_dict() and collections.OrderedDict. This eliminates the maintenance burden of separate code for from_items(), while allowing existing uses to keep working. A small cleanup can be done once pandas-dev#8425 is fixed.
1 parent dfd58e8 commit d4219df

File tree

2 files changed

+28
-97
lines changed

2 files changed

+28
-97
lines changed

pandas/core/frame.py

+11-49
Original file line numberDiff line numberDiff line change
@@ -1445,17 +1445,13 @@ def to_records(self, index=True, convert_datetime64=None):
14451445
def from_items(cls, items, columns=None, orient='columns'):
14461446
"""Construct a dataframe from a list of tuples
14471447
1448-
.. deprecated:: 0.23.0
1449-
`from_items` is deprecated and will be removed in a future version.
1450-
Use :meth:`DataFrame.from_dict(dict(items)) <DataFrame.from_dict>`
1451-
instead.
1452-
:meth:`DataFrame.from_dict(OrderedDict(items)) <DataFrame.from_dict>`
1453-
may be used to preserve the key order.
1454-
14551448
Convert (key, value) pairs to DataFrame. The keys will be the axis
14561449
index (usually the columns, but depends on the specified
14571450
orientation). The values should be arrays or Series.
14581451
1452+
`from_items(items)` is equivalent to
1453+
:meth:`DataFrame.from_dict(OrderedDict(items)) <DataFrame.from_dict>`.
1454+
14591455
Parameters
14601456
----------
14611457
items : sequence of (key, value) pairs
@@ -1473,57 +1469,23 @@ def from_items(cls, items, columns=None, orient='columns'):
14731469
frame : DataFrame
14741470
"""
14751471

1476-
warnings.warn("from_items is deprecated. Please use "
1477-
"DataFrame.from_dict(dict(items), ...) instead. "
1478-
"DataFrame.from_dict(OrderedDict(items)) may be used to "
1479-
"preserve the key order.",
1480-
FutureWarning, stacklevel=2)
1481-
1482-
keys, values = lzip(*items)
1472+
odict = collections.OrderedDict(items)
14831473

14841474
if orient == 'columns':
14851475
if columns is not None:
1486-
columns = ensure_index(columns)
1487-
1488-
idict = dict(items)
1489-
if len(idict) < len(items):
1490-
if not columns.equals(ensure_index(keys)):
1491-
raise ValueError('With non-unique item names, passed '
1492-
'columns must be identical')
1493-
arrays = values
1494-
else:
1495-
arrays = [idict[k] for k in columns if k in idict]
1476+
return cls.from_dict(odict).reindex(columns=columns)
14961477
else:
1497-
columns = ensure_index(keys)
1498-
arrays = values
1499-
1500-
# GH 17312
1501-
# Provide more informative error msg when scalar values passed
1502-
try:
1503-
return cls._from_arrays(arrays, columns, None)
1504-
1505-
except ValueError:
1506-
if not is_nested_list_like(values):
1507-
raise ValueError('The value in each (key, value) pair '
1508-
'must be an array, Series, or dict')
1478+
return cls.from_dict(odict, orient)
15091479

15101480
elif orient == 'index':
15111481
if columns is None:
1482+
# we can produce a DataFrame even in this case,
1483+
# but raise for consistency with previous versions
15121484
raise TypeError("Must pass columns with orient='index'")
15131485

1514-
keys = ensure_index(keys)
1515-
1516-
# GH 17312
1517-
# Provide more informative error msg when scalar values passed
1518-
try:
1519-
arr = np.array(values, dtype=object).T
1520-
data = [lib.maybe_convert_objects(v) for v in arr]
1521-
return cls._from_arrays(data, columns, keys)
1522-
1523-
except TypeError:
1524-
if not is_nested_list_like(values):
1525-
raise ValueError('The value in each (key, value) pair '
1526-
'must be an array, Series, or dict')
1486+
# reindex will not be needed once GH 8425 is fixed
1487+
idx = odict.keys()
1488+
return cls.from_dict(odict, orient, columns=columns).reindex(idx)
15271489

15281490
else: # pragma: no cover
15291491
raise ValueError("'orient' must be either 'columns' or 'index'")

pandas/tests/frame/test_constructors.py

+17-48
Original file line numberDiff line numberDiff line change
@@ -1283,87 +1283,56 @@ def test_constructor_manager_resize(self):
12831283

12841284
def test_constructor_from_items(self):
12851285
items = [(c, self.frame[c]) for c in self.frame.columns]
1286-
with tm.assert_produces_warning(FutureWarning,
1287-
check_stacklevel=False):
1288-
recons = DataFrame.from_items(items)
1286+
recons = DataFrame.from_items(items)
12891287
tm.assert_frame_equal(recons, self.frame)
12901288

12911289
# pass some columns
1292-
with tm.assert_produces_warning(FutureWarning,
1293-
check_stacklevel=False):
1294-
recons = DataFrame.from_items(items, columns=['C', 'B', 'A'])
1290+
recons = DataFrame.from_items(items, columns=['C', 'B', 'A'])
12951291
tm.assert_frame_equal(recons, self.frame.loc[:, ['C', 'B', 'A']])
12961292

12971293
# orient='index'
12981294

12991295
row_items = [(idx, self.mixed_frame.xs(idx))
13001296
for idx in self.mixed_frame.index]
1301-
with tm.assert_produces_warning(FutureWarning,
1302-
check_stacklevel=False):
1303-
recons = DataFrame.from_items(row_items,
1304-
columns=self.mixed_frame.columns,
1305-
orient='index')
1297+
recons = DataFrame.from_items(row_items,
1298+
columns=self.mixed_frame.columns,
1299+
orient='index')
13061300
tm.assert_frame_equal(recons, self.mixed_frame)
13071301
assert recons['A'].dtype == np.float64
13081302

13091303
with tm.assert_raises_regex(TypeError,
13101304
"Must pass columns with "
13111305
"orient='index'"):
1312-
with tm.assert_produces_warning(FutureWarning,
1313-
check_stacklevel=False):
1314-
DataFrame.from_items(row_items, orient='index')
1306+
DataFrame.from_items(row_items, orient='index')
13151307

13161308
# orient='index', but thar be tuples
13171309
arr = construct_1d_object_array_from_listlike(
13181310
[('bar', 'baz')] * len(self.mixed_frame))
13191311
self.mixed_frame['foo'] = arr
13201312
row_items = [(idx, list(self.mixed_frame.xs(idx)))
13211313
for idx in self.mixed_frame.index]
1322-
with tm.assert_produces_warning(FutureWarning,
1323-
check_stacklevel=False):
1324-
recons = DataFrame.from_items(row_items,
1325-
columns=self.mixed_frame.columns,
1326-
orient='index')
1314+
recons = DataFrame.from_items(row_items,
1315+
columns=self.mixed_frame.columns,
1316+
orient='index')
13271317
tm.assert_frame_equal(recons, self.mixed_frame)
13281318
assert isinstance(recons['foo'][0], tuple)
13291319

1330-
with tm.assert_produces_warning(FutureWarning,
1331-
check_stacklevel=False):
1332-
rs = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
1333-
orient='index',
1334-
columns=['one', 'two', 'three'])
1320+
rs = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
1321+
orient='index',
1322+
columns=['one', 'two', 'three'])
13351323
xp = DataFrame([[1, 2, 3], [4, 5, 6]], index=['A', 'B'],
13361324
columns=['one', 'two', 'three'])
13371325
tm.assert_frame_equal(rs, xp)
13381326

13391327
def test_constructor_from_items_scalars(self):
13401328
# GH 17312
13411329
with tm.assert_raises_regex(ValueError,
1342-
r'The value in each \(key, value\) '
1343-
'pair must be an array, Series, or dict'):
1344-
with tm.assert_produces_warning(FutureWarning,
1345-
check_stacklevel=False):
1346-
DataFrame.from_items([('A', 1), ('B', 4)])
1347-
1348-
with tm.assert_raises_regex(ValueError,
1349-
r'The value in each \(key, value\) '
1350-
'pair must be an array, Series, or dict'):
1351-
with tm.assert_produces_warning(FutureWarning,
1352-
check_stacklevel=False):
1353-
DataFrame.from_items([('A', 1), ('B', 2)], columns=['col1'],
1354-
orient='index')
1355-
1356-
def test_from_items_deprecation(self):
1357-
# GH 17320
1358-
with tm.assert_produces_warning(FutureWarning,
1359-
check_stacklevel=False):
1360-
DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])])
1330+
r'If using all scalar values, '
1331+
'you must pass an index'):
1332+
DataFrame.from_items([('A', 1), ('B', 4)])
13611333

1362-
with tm.assert_produces_warning(FutureWarning,
1363-
check_stacklevel=False):
1364-
DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
1365-
columns=['col1', 'col2', 'col3'],
1366-
orient='index')
1334+
DataFrame.from_items([('A', 1), ('B', 2)], columns=['col1'],
1335+
orient='index')
13671336

13681337
def test_constructor_mix_series_nonseries(self):
13691338
df = DataFrame({'A': self.frame['A'],

0 commit comments

Comments
 (0)