Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEPR: Deprecate from_items #18529

Merged
merged 6 commits into from
Jan 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ Deprecations
- :func:`read_excel` has deprecated the ``skip_footer`` parameter. Use ``skipfooter`` instead (:issue:`18836`)
- The ``is_copy`` attribute is deprecated and will be removed in a future version (:issue:`18801`).
- ``IntervalIndex.from_intervals`` is deprecated in favor of the :class:`IntervalIndex` constructor (:issue:`19263`)

- :func:``DataFrame.from_items`` is deprecated. Use :func:``DataFrame.from_dict()`` instead, or :func:``DataFrame.from_dict(OrderedDict())`` if you wish to preserve the key order (:issue:`17320`)

.. _whatsnew_0230.prior_deprecations:

Expand Down
15 changes: 14 additions & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def _constructor(self):

_constructor_sliced = Series
_deprecations = NDFrame._deprecations | frozenset(
['sortlevel', 'get_value', 'set_value', 'from_csv'])
['sortlevel', 'get_value', 'set_value', 'from_csv', 'from_items'])

@property
def _constructor_expanddim(self):
Expand Down Expand Up @@ -1246,6 +1246,12 @@ def to_records(self, index=True, convert_datetime64=True):
@classmethod
def from_items(cls, items, columns=None, orient='columns'):
"""
.. deprecated:: 0.23.0
from_items is deprecated and will be removed in a
future version. Use :meth:`DataFrame.from_dict(dict())`
instead. :meth:`DataFrame.from_dict(OrderedDict(...))` may be used
to preserve the key order.

Convert (key, value) pairs to DataFrame. The keys will be the axis
index (usually the columns, but depends on the specified
orientation). The values should be arrays or Series.
Expand All @@ -1266,6 +1272,13 @@ def from_items(cls, items, columns=None, orient='columns'):
-------
frame : DataFrame
"""

warnings.warn("from_items is deprecated. Please use "
"DataFrame.from_dict(dict()) instead. "
"DataFrame.from_dict(OrderedDict()) may be used to "
"preserve the key order.",
FutureWarning, stacklevel=2)

keys, values = lzip(*items)

if orient == 'columns':
Expand Down
9 changes: 5 additions & 4 deletions pandas/io/stata.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import datetime
import struct
import sys
from collections import OrderedDict

import numpy as np
from dateutil.relativedelta import relativedelta
Expand Down Expand Up @@ -1571,7 +1572,7 @@ def read(self, nrows=None, convert_dates=None,
else:
data_formatted.append((col, data[col]))
if requires_type_conversion:
data = DataFrame.from_items(data_formatted)
data = DataFrame.from_dict(OrderedDict(data_formatted))
del data_formatted

self._do_convert_missing(data, convert_missing)
Expand Down Expand Up @@ -1609,7 +1610,7 @@ def read(self, nrows=None, convert_dates=None,
convert = True
retyped_data.append((col, data[col].astype(dtype)))
if convert:
data = DataFrame.from_items(retyped_data)
data = DataFrame.from_dict(OrderedDict(retyped_data))

if index_col is not None:
data = data.set_index(data.pop(index_col))
Expand Down Expand Up @@ -1722,7 +1723,7 @@ def _do_convert_categoricals(self, data, value_label_dict, lbllist,
cat_converted_data.append((col, cat_data))
else:
cat_converted_data.append((col, data[col]))
data = DataFrame.from_items(cat_converted_data)
data = DataFrame.from_dict(OrderedDict(cat_converted_data))
return data

def data_label(self):
Expand Down Expand Up @@ -1997,7 +1998,7 @@ def _prepare_categoricals(self, data):
data_formatted.append((col, values))
else:
data_formatted.append((col, data[col]))
return DataFrame.from_items(data_formatted)
return DataFrame.from_dict(OrderedDict(data_formatted))

def _replace_nans(self, data):
# return data
Expand Down
69 changes: 48 additions & 21 deletions pandas/tests/frame/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,7 @@ def __len__(self, n):
# GH 4297
# support Array
import array
result = DataFrame.from_items([('A', array.array('i', range(10)))])
result = DataFrame({'A': array.array('i', range(10))})
expected = DataFrame({'A': list(range(10))})
tm.assert_frame_equal(result, expected, check_dtype=False)

Expand Down Expand Up @@ -1175,44 +1175,55 @@ def test_constructor_manager_resize(self):

def test_constructor_from_items(self):
items = [(c, self.frame[c]) for c in self.frame.columns]
recons = DataFrame.from_items(items)
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
recons = DataFrame.from_items(items)
tm.assert_frame_equal(recons, self.frame)

# pass some columns
recons = DataFrame.from_items(items, columns=['C', 'B', 'A'])
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
recons = DataFrame.from_items(items, columns=['C', 'B', 'A'])
tm.assert_frame_equal(recons, self.frame.loc[:, ['C', 'B', 'A']])

# orient='index'

row_items = [(idx, self.mixed_frame.xs(idx))
for idx in self.mixed_frame.index]

recons = DataFrame.from_items(row_items,
columns=self.mixed_frame.columns,
orient='index')
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
recons = DataFrame.from_items(row_items,
columns=self.mixed_frame.columns,
orient='index')
tm.assert_frame_equal(recons, self.mixed_frame)
assert recons['A'].dtype == np.float64

with tm.assert_raises_regex(TypeError,
"Must pass columns with "
"orient='index'"):
DataFrame.from_items(row_items, orient='index')
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
DataFrame.from_items(row_items, orient='index')

# orient='index', but thar be tuples
arr = construct_1d_object_array_from_listlike(
[('bar', 'baz')] * len(self.mixed_frame))
self.mixed_frame['foo'] = arr
row_items = [(idx, list(self.mixed_frame.xs(idx)))
for idx in self.mixed_frame.index]
recons = DataFrame.from_items(row_items,
columns=self.mixed_frame.columns,
orient='index')
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
recons = DataFrame.from_items(row_items,
columns=self.mixed_frame.columns,
orient='index')
tm.assert_frame_equal(recons, self.mixed_frame)
assert isinstance(recons['foo'][0], tuple)

rs = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
orient='index',
columns=['one', 'two', 'three'])
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
rs = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
orient='index',
columns=['one', 'two', 'three'])
xp = DataFrame([[1, 2, 3], [4, 5, 6]], index=['A', 'B'],
columns=['one', 'two', 'three'])
tm.assert_frame_equal(rs, xp)
Expand All @@ -1222,12 +1233,28 @@ def test_constructor_from_items_scalars(self):
with tm.assert_raises_regex(ValueError,
r'The value in each \(key, value\) '
'pair must be an array, Series, or dict'):
DataFrame.from_items([('A', 1), ('B', 4)])
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
DataFrame.from_items([('A', 1), ('B', 4)])

with tm.assert_raises_regex(ValueError,
r'The value in each \(key, value\) '
'pair must be an array, Series, or dict'):
DataFrame.from_items([('A', 1), ('B', 2)], columns=['col1'],
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
DataFrame.from_items([('A', 1), ('B', 2)], columns=['col1'],
orient='index')

def test_from_items_deprecation(self):
# GH 17320
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])])

with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
columns=['col1', 'col2', 'col3'],
orient='index')

def test_constructor_mix_series_nonseries(self):
Expand Down Expand Up @@ -1256,13 +1283,13 @@ def test_constructor_column_duplicates(self):

tm.assert_frame_equal(df, edf)

idf = DataFrame.from_items(
[('a', [8]), ('a', [5])], columns=['a', 'a'])
idf = DataFrame.from_records([(8, 5)],
Copy link
Contributor Author

@reidy-p reidy-p Jan 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that some of the dataframe constructors don't allow duplicated columns while others do so I had to change the from_items in this test to from_records and from_dict(OrderedDict()) to get the test passing. But I'm not sure if it still tests for the original issue correctly (#2079)

All of the other tests in this file using from_items are directly testing from_items so I left the check for the deprecation warning rather than trying to replace from_items with a different constructor.

columns=['a', 'a'])

tm.assert_frame_equal(idf, edf)

pytest.raises(ValueError, DataFrame.from_items,
[('a', [8]), ('a', [5]), ('b', [6])],
columns=['b', 'a', 'a'])
pytest.raises(ValueError, DataFrame.from_dict,
OrderedDict([('b', 8), ('a', 5), ('a', 6)]))

def test_constructor_empty_with_string_dtype(self):
# GH 9428
Expand Down
7 changes: 4 additions & 3 deletions pandas/tests/frame/test_nonunique_indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,10 @@ def check(result, expected=None):
for index in [df.index, pd.Index(list('edcba'))]:
this_df = df.copy()
expected_ser = pd.Series(index.values, index=this_df.index)
expected_df = DataFrame.from_items([('A', expected_ser),
('B', this_df['B']),
('A', expected_ser)])
expected_df = DataFrame({'A': expected_ser,
'B': this_df['B'],
'A': expected_ser},
columns=['A', 'B', 'A'])
this_df['A'] = index
check(this_df, expected_df)

Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/io/parser/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
import sys
from datetime import datetime
from collections import OrderedDict

import pytest
import numpy as np
Expand Down Expand Up @@ -924,8 +925,9 @@ def test_float_parser(self):

def test_scientific_no_exponent(self):
# see gh-12215
df = DataFrame.from_items([('w', ['2e']), ('x', ['3E']),
('y', ['42e']), ('z', ['632E'])])
df = DataFrame.from_dict(OrderedDict([('w', ['2e']), ('x', ['3E']),
('y', ['42e']),
('z', ['632E'])]))
data = df.to_csv(index=False)
for prec in self.float_precision_choices:
df_roundtrip = self.read_csv(
Expand Down
58 changes: 28 additions & 30 deletions pandas/tests/io/test_excel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from distutils.version import LooseVersion
from functools import partial
from warnings import catch_warnings
from collections import OrderedDict

import numpy as np
import pytest
Expand Down Expand Up @@ -315,7 +316,7 @@ def test_excel_table(self):

def test_reader_special_dtypes(self):

expected = DataFrame.from_items([
expected = DataFrame.from_dict(OrderedDict([
("IntCol", [1, 2, -3, 4, 0]),
("FloatCol", [1.25, 2.25, 1.83, 1.92, 0.0000000005]),
("BoolCol", [True, False, True, True, False]),
Expand All @@ -325,8 +326,7 @@ def test_reader_special_dtypes(self):
("DateCol", [datetime(2013, 10, 30), datetime(2013, 10, 31),
datetime(1905, 1, 1), datetime(2013, 12, 14),
datetime(2015, 3, 14)])
])

]))
basename = 'test_types'

# should read in correctly and infer types
Expand Down Expand Up @@ -363,12 +363,12 @@ def test_reader_converters(self):

basename = 'test_converters'

expected = DataFrame.from_items([
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feel free to change some / most constructions with from items entirely (rather than catch the deprecation warning)

expected = DataFrame.from_dict(OrderedDict([
("IntCol", [1, 2, -3, -1000, 0]),
("FloatCol", [12.5, np.nan, 18.3, 19.2, 0.000000005]),
("BoolCol", ['Found', 'Found', 'Found', 'Not found', 'Found']),
("StrCol", ['1', np.nan, '3', '4', '5']),
])
]))

converters = {'IntCol': lambda x: int(x) if x != '' else -1000,
'FloatCol': lambda x: 10 * x if x else np.nan,
Expand Down Expand Up @@ -718,32 +718,30 @@ def test_reader_seconds(self):

if LooseVersion(xlrd.__VERSION__) >= LooseVersion("0.9.3"):
# Xlrd >= 0.9.3 can handle Excel milliseconds.
expected = DataFrame.from_items([("Time",
[time(1, 2, 3),
time(2, 45, 56, 100000),
time(4, 29, 49, 200000),
time(6, 13, 42, 300000),
time(7, 57, 35, 400000),
time(9, 41, 28, 500000),
time(11, 25, 21, 600000),
time(13, 9, 14, 700000),
time(14, 53, 7, 800000),
time(16, 37, 0, 900000),
time(18, 20, 54)])])
expected = DataFrame.from_dict({"Time": [time(1, 2, 3),
time(2, 45, 56, 100000),
time(4, 29, 49, 200000),
time(6, 13, 42, 300000),
time(7, 57, 35, 400000),
time(9, 41, 28, 500000),
time(11, 25, 21, 600000),
time(13, 9, 14, 700000),
time(14, 53, 7, 800000),
time(16, 37, 0, 900000),
time(18, 20, 54)]})
else:
# Xlrd < 0.9.3 rounds Excel milliseconds.
expected = DataFrame.from_items([("Time",
[time(1, 2, 3),
time(2, 45, 56),
time(4, 29, 49),
time(6, 13, 42),
time(7, 57, 35),
time(9, 41, 29),
time(11, 25, 22),
time(13, 9, 15),
time(14, 53, 8),
time(16, 37, 1),
time(18, 20, 54)])])
expected = DataFrame.from_dict({"Time": [time(1, 2, 3),
time(2, 45, 56),
time(4, 29, 49),
time(6, 13, 42),
time(7, 57, 35),
time(9, 41, 29),
time(11, 25, 22),
time(13, 9, 15),
time(14, 53, 8),
time(16, 37, 1),
time(18, 20, 54)]})

actual = self.get_exceldf('times_1900', 'Sheet1')
tm.assert_frame_equal(actual, expected)
Expand Down Expand Up @@ -1988,7 +1986,7 @@ def test_datetimes(self):
datetime(2013, 1, 13, 18, 20, 52)]

with ensure_clean(self.ext) as path:
write_frame = DataFrame.from_items([('A', datetimes)])
write_frame = DataFrame({'A': datetimes})
write_frame.to_excel(path, 'Sheet1')
read_frame = read_excel(path, 'Sheet1', header=0)

Expand Down
3 changes: 2 additions & 1 deletion pandas/tests/io/test_stata.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import warnings
from datetime import datetime
from distutils.version import LooseVersion
from collections import OrderedDict

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -945,7 +946,7 @@ def test_categorical_order(self, file):
cols.append((col, pd.Categorical.from_codes(codes, labels)))
else:
cols.append((col, pd.Series(labels, dtype=np.float32)))
expected = DataFrame.from_items(cols)
expected = DataFrame.from_dict(OrderedDict(cols))

# Read with and with out categoricals, ensure order is identical
file = getattr(self, file)
Expand Down