Skip to content

Commit 216f051

Browse files
committed
Merge branch 'master' of github.com:pydata/pandas into fix-index-dict-assign
2 parents 99aabee + f8ca3b7 commit 216f051

File tree

7 files changed

+132
-17
lines changed

7 files changed

+132
-17
lines changed

doc/source/whatsnew/v0.16.1.txt

+5
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Bug Fixes
9595
- Fixed bug (:issue:`9542`) where labels did not appear properly in legend of ``DataFrame.plot()``. Passing ``label=`` args also now works, and series indices are no longer mutated.
9696
- Bug in json serialization when frame has length zero.(:issue:`9805`)
9797
- Bug in `read_csv` where missing trailing delimiters would cause segfault. (:issue:`5664`)
98+
- Bug in retaining index name on appending (:issue:`9862`)
9899

99100

100101
- Bug in ``scatter_matrix`` draws unexpected axis ticklabels (:issue:`5662`)
@@ -106,6 +107,8 @@ Bug Fixes
106107

107108
- Bug in ``equals`` causing false negatives when block order differed (:issue:`9330`)
108109

110+
- Bug in ``read_sql_table`` error when reading postgres table with timezone (:issue:`7139`)
111+
109112
- Bug in ``DataFrame`` slicing may not retain metadata (:issue:`9776`)
110113
- Bug where ``TimdeltaIndex`` were not properly serialized in fixed ``HDFStore`` (:issue:`9635`)
111114

@@ -134,3 +137,5 @@ Bug Fixes
134137
- Bug in unequal comparisons between categorical data and a scalar, which was not in the categories (e.g. ``Series(Categorical(list("abc"), ordered=True)) > "d"``. This returned ``False`` for all elements, but now raises a ``TypeError``. Equality comparisons also now return ``False`` for ``==`` and ``True`` for ``!=``. (:issue:`9848`)
135138

136139
- Bug in DataFrame ``__setitem__`` when right hand side is a dictionary (:issue:`9874`)
140+
141+
- Bug in ``MultiIndex.sortlevel()`` results in unicode level name breaks (:issue:`9875`)

pandas/core/index.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,9 @@ def append(self, other):
976976
to_concat.append(other)
977977

978978
for obj in to_concat:
979-
if isinstance(obj, Index) and obj.name != name:
979+
if (isinstance(obj, Index) and
980+
obj.name != name and
981+
obj.name is not None):
980982
name = None
981983
break
982984

@@ -4023,7 +4025,7 @@ def sortlevel(self, level=0, ascending=True, sort_remaining=True):
40234025
labels = list(self.labels)
40244026
shape = list(self.levshape)
40254027

4026-
if isinstance(level, (str, int)):
4028+
if isinstance(level, (compat.string_types, int)):
40274029
level = [level]
40284030
level = [self._get_level_number(lev) for lev in level]
40294031

pandas/io/sql.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ def _handle_date_column(col, format=None):
8383
return to_datetime(col, **format)
8484
else:
8585
if format in ['D', 's', 'ms', 'us', 'ns']:
86-
return to_datetime(col, coerce=True, unit=format)
86+
return to_datetime(col, coerce=True, unit=format, utc=True)
8787
elif (issubclass(col.dtype.type, np.floating)
8888
or issubclass(col.dtype.type, np.integer)):
8989
# parse dates as timestamp
9090
format = 's' if format is None else format
91-
return to_datetime(col, coerce=True, unit=format)
91+
return to_datetime(col, coerce=True, unit=format, utc=True)
9292
else:
93-
return to_datetime(col, coerce=True, format=format)
93+
return to_datetime(col, coerce=True, format=format, utc=True)
9494

9595

9696
def _parse_date_columns(data_frame, parse_dates):
@@ -318,6 +318,10 @@ def read_sql_table(table_name, con, schema=None, index_col=None,
318318
-------
319319
DataFrame
320320
321+
Notes
322+
-----
323+
Any datetime values with time zone information will be converted to UTC
324+
321325
See also
322326
--------
323327
read_sql_query : Read SQL query into a DataFrame.
@@ -390,6 +394,11 @@ def read_sql_query(sql, con, index_col=None, coerce_float=True, params=None,
390394
-------
391395
DataFrame
392396
397+
Notes
398+
-----
399+
Any datetime values with time zone information parsed via the `parse_dates`
400+
parameter will be converted to UTC
401+
393402
See also
394403
--------
395404
read_sql_table : Read SQL database table into a DataFrame
@@ -451,7 +460,8 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
451460
This function is a convenience wrapper around ``read_sql_table`` and
452461
``read_sql_query`` (and for backward compatibility) and will delegate
453462
to the specific function depending on the provided input (database
454-
table name or sql query).
463+
table name or sql query). The delegated function might have more specific
464+
notes about their functionality not listed here.
455465
456466
See also
457467
--------

pandas/io/tests/test_packers.py

+4
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ def test_compression_zlib(self):
476476
assert_frame_equal(self.frame[k], i_rec[k])
477477

478478
def test_compression_blosc(self):
479+
try:
480+
import blosc
481+
except ImportError:
482+
raise nose.SkipTest('no blosc')
479483
i_rec = self.encode_decode(self.frame, compress='blosc')
480484
for k in self.frame.keys():
481485
assert_frame_equal(self.frame[k], i_rec[k])

pandas/io/tests/test_sql.py

+67-10
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from datetime import datetime, date, time
3030

3131
from pandas import DataFrame, Series, Index, MultiIndex, isnull, concat
32-
from pandas import date_range, to_datetime, to_timedelta
32+
from pandas import date_range, to_datetime, to_timedelta, Timestamp
3333
import pandas.compat as compat
3434
from pandas.compat import StringIO, range, lrange, string_types
3535
from pandas.core.datetools import format as date_format
@@ -100,6 +100,7 @@
100100
'postgresql': """CREATE TABLE types_test_data (
101101
"TextCol" TEXT,
102102
"DateCol" TIMESTAMP,
103+
"DateColWithTz" TIMESTAMP WITH TIME ZONE,
103104
"IntDateCol" INTEGER,
104105
"FloatCol" DOUBLE PRECISION,
105106
"IntCol" INTEGER,
@@ -109,18 +110,36 @@
109110
)"""
110111
},
111112
'insert_test_types': {
112-
'sqlite': """
113+
'sqlite': {
114+
'query': """
113115
INSERT INTO types_test_data
114116
VALUES(?, ?, ?, ?, ?, ?, ?, ?)
115117
""",
116-
'mysql': """
118+
'fields': (
119+
'TextCol', 'DateCol', 'IntDateCol', 'FloatCol',
120+
'IntCol', 'BoolCol', 'IntColWithNull', 'BoolColWithNull'
121+
)
122+
},
123+
'mysql': {
124+
'query': """
117125
INSERT INTO types_test_data
118126
VALUES("%s", %s, %s, %s, %s, %s, %s, %s)
119127
""",
120-
'postgresql': """
128+
'fields': (
129+
'TextCol', 'DateCol', 'IntDateCol', 'FloatCol',
130+
'IntCol', 'BoolCol', 'IntColWithNull', 'BoolColWithNull'
131+
)
132+
},
133+
'postgresql': {
134+
'query': """
121135
INSERT INTO types_test_data
122-
VALUES(%s, %s, %s, %s, %s, %s, %s, %s)
123-
"""
136+
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s)
137+
""",
138+
'fields': (
139+
'TextCol', 'DateCol', 'DateColWithTz', 'IntDateCol', 'FloatCol',
140+
'IntCol', 'BoolCol', 'IntColWithNull', 'BoolColWithNull'
141+
)
142+
},
124143
},
125144
'read_parameters': {
126145
'sqlite': "SELECT * FROM iris WHERE Name=? AND SepalLength=?",
@@ -218,11 +237,36 @@ def _load_raw_sql(self):
218237
self._get_exec().execute(SQL_STRINGS['create_test_types'][self.flavor])
219238
ins = SQL_STRINGS['insert_test_types'][self.flavor]
220239

221-
data = [(
222-
'first', '2000-01-03 00:00:00', 535852800, 10.10, 1, False, 1, False),
223-
('first', '2000-01-04 00:00:00', 1356998400, 10.10, 1, False, None, None)]
240+
data = [
241+
{
242+
'TextCol': 'first',
243+
'DateCol': '2000-01-03 00:00:00',
244+
'DateColWithTz': '2000-01-01 00:00:00-08:00',
245+
'IntDateCol': 535852800,
246+
'FloatCol': 10.10,
247+
'IntCol': 1,
248+
'BoolCol': False,
249+
'IntColWithNull': 1,
250+
'BoolColWithNull': False,
251+
},
252+
{
253+
'TextCol': 'first',
254+
'DateCol': '2000-01-04 00:00:00',
255+
'DateColWithTz': '2000-06-01 00:00:00-07:00',
256+
'IntDateCol': 1356998400,
257+
'FloatCol': 10.10,
258+
'IntCol': 1,
259+
'BoolCol': False,
260+
'IntColWithNull': None,
261+
'BoolColWithNull': None,
262+
},
263+
]
264+
224265
for d in data:
225-
self._get_exec().execute(ins, d)
266+
self._get_exec().execute(
267+
ins['query'],
268+
[d[field] for field in ins['fields']]
269+
)
226270

227271
def _count_rows(self, table_name):
228272
result = self._get_exec().execute(
@@ -1512,6 +1556,19 @@ def test_schema_support(self):
15121556
res2 = pdsql.read_table('test_schema_other2')
15131557
tm.assert_frame_equal(res1, res2)
15141558

1559+
def test_datetime_with_time_zone(self):
1560+
# Test to see if we read the date column with timezones that
1561+
# the timezone information is converted to utc and into a
1562+
# np.datetime64 (GH #7139)
1563+
df = sql.read_sql_table("types_test_data", self.conn)
1564+
self.assertTrue(issubclass(df.DateColWithTz.dtype.type, np.datetime64),
1565+
"DateColWithTz loaded with incorrect type")
1566+
1567+
# "2000-01-01 00:00:00-08:00" should convert to "2000-01-01 08:00:00"
1568+
self.assertEqual(df.DateColWithTz[0], Timestamp('2000-01-01 08:00:00'))
1569+
1570+
# "2000-06-01 00:00:00-07:00" should convert to "2000-06-01 07:00:00"
1571+
self.assertEqual(df.DateColWithTz[1], Timestamp('2000-06-01 07:00:00'))
15151572

15161573
#------------------------------------------------------------------------------
15171574
#--- Test Sqlite / MySQL fallback

pandas/tests/test_frame.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from pandas.compat import(
1818
map, zip, range, long, lrange, lmap, lzip,
19-
OrderedDict, u, StringIO
19+
OrderedDict, u, StringIO, string_types
2020
)
2121
from pandas import compat
2222

@@ -12428,6 +12428,30 @@ def test_unstack_bool(self):
1242812428
['c', 'l']]))
1242912429
assert_frame_equal(rs, xp)
1243012430

12431+
def test_unstack_level_binding(self):
12432+
# GH9856
12433+
mi = pd.MultiIndex(
12434+
levels=[[u'foo', u'bar'], [u'one', u'two'], [u'a', u'b']],
12435+
labels=[[0, 0, 1, 1], [0, 1, 0, 1], [1, 0, 1, 0]],
12436+
names=[u'first', u'second', u'third'])
12437+
s = pd.Series(0, index=mi)
12438+
result = s.unstack([1, 2]).stack(0)
12439+
12440+
expected_mi = pd.MultiIndex(
12441+
levels=[['foo', 'bar'], ['one', 'two']],
12442+
labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
12443+
names=['first', 'second'])
12444+
12445+
expected = pd.DataFrame(np.array([[np.nan, 0],
12446+
[0, np.nan],
12447+
[np.nan, 0],
12448+
[0, np.nan]],
12449+
dtype=np.float64),
12450+
index=expected_mi,
12451+
columns=pd.Index(['a', 'b'], name='third'))
12452+
12453+
self.assert_frame_equal(result, expected)
12454+
1243112455
def test_unstack_to_series(self):
1243212456
# check reversibility
1243312457
data = self.frame.unstack()

pandas/tests/test_index.py

+13
Original file line numberDiff line numberDiff line change
@@ -4075,6 +4075,19 @@ def test_groupby(self):
40754075
exp = dict((key, [key]) for key in self.index)
40764076
tm.assert_dict_equal(groups, exp)
40774077

4078+
def test_index_name_retained(self):
4079+
# GH9857
4080+
result = pd.DataFrame({'x': [1, 2, 6],
4081+
'y': [2, 2, 8],
4082+
'z': [-5, 0, 5]})
4083+
result = result.set_index('z')
4084+
result.loc[10] = [9, 10]
4085+
df_expected = pd.DataFrame({'x': [1, 2, 6, 9],
4086+
'y': [2, 2, 8, 10],
4087+
'z': [-5, 0, 5, 10]})
4088+
df_expected = df_expected.set_index('z')
4089+
tm.assert_frame_equal(result, df_expected)
4090+
40784091

40794092
def test_get_combined_index():
40804093
from pandas.core.index import _get_combined_index

0 commit comments

Comments
 (0)