Skip to content

Commit 9d7c7f6

Browse files
committed
ENH: Allow to_sql to recognize single sql type pandas-dev#11886
ENH: support decimal option in PythonParser pandas-dev#12933 closes pandas-dev#12933 Author: Camilo Cota <[email protected]> Closes pandas-dev#13189 from camilocot/12933 and squashes the following commits: 465272e [Camilo Cota] Benchmark decimal option in read_csv for c engine 9f42d0c [Camilo Cota] double backticks around decimal and engine='python' dc8ca62 [Camilo Cota] fix test_empty_decimal_marker comment 49613fe [Camilo Cota] Assert read_csv error message in test_empty_decimal_marker d821052 [Camilo Cota] fix test_empty_decimal_marker comment f71509d [Camilo Cota] Include descritive what's new line 803356e [Camilo Cota] set nonnum regex in init method 1472d80 [Camilo Cota] Include the issue number in what's new b560fda [Camilo Cota] Fix what's new dc7acd1 [Camilo Cota] ENH: support decimal option in PythonParser pandas-dev#12933 ENH: Allow to_sql to recognize single sql type pandas-dev#11886 PEP pandas-dev#3
1 parent ae2ca83 commit 9d7c7f6

File tree

4 files changed

+58
-17
lines changed

4 files changed

+58
-17
lines changed

Diff for: doc/source/whatsnew/v0.18.2.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ Other enhancements
7474

7575
pd.Timestamp(year=2012, month=1, day=1, hour=8, minute=30)
7676

77+
- ``DataFrame.to_sql `` now allows a single value as the SQL type for all columns (:issue:`11886`).
78+
7779
- The ``pd.read_csv()`` with ``engine='python'`` has gained support for the ``decimal`` option (:issue:`12933`)
7880

7981
- ``Index.astype()`` now accepts an optional boolean argument ``copy``, which allows optional copying if the requirements on dtype are satisfied (:issue:`13209`)
@@ -89,7 +91,7 @@ Other enhancements
8991

9092
- ``pd.read_html()`` has gained support for the ``decimal`` option (:issue:`12907`)
9193

92-
94+
- ``DataFrame.to_sql `` now allows a single value as the SQL type for all columns (:issue:`11886`).
9395

9496
.. _whatsnew_0182.api:
9597

Diff for: pandas/io/sql.py

+16-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
string_types, text_type)
1919
from pandas.core.api import DataFrame, Series
2020
from pandas.core.common import isnull
21+
from pandas.core.generic import is_dictlike
2122
from pandas.core.base import PandasObject
2223
from pandas.types.api import DatetimeTZDtype
2324
from pandas.tseries.tools import to_datetime
@@ -550,9 +551,10 @@ def to_sql(frame, name, con, flavor='sqlite', schema=None, if_exists='fail',
550551
chunksize : int, default None
551552
If not None, then rows will be written in batches of this size at a
552553
time. If None, all rows will be written at once.
553-
dtype : dict of column name to SQL type, default None
554+
dtype : single SQLtype or dict of column name to SQL type, default None
554555
Optional specifying the datatype for columns. The SQL type should
555556
be a SQLAlchemy type, or a string for sqlite3 fallback connection.
557+
If all columns are of the same type, one single value can be used.
556558
557559
"""
558560
if if_exists not in ('fail', 'replace', 'append'):
@@ -1231,11 +1233,16 @@ def to_sql(self, frame, name, if_exists='fail', index=True,
12311233
chunksize : int, default None
12321234
If not None, then rows will be written in batches of this size at a
12331235
time. If None, all rows will be written at once.
1234-
dtype : dict of column name to SQL type, default None
1236+
dtype : single SQL type or dict of column name to SQL type, default
1237+
None
12351238
Optional specifying the datatype for columns. The SQL type should
1236-
be a SQLAlchemy type.
1239+
be a SQLAlchemy type. If all columns are of the same type, one
1240+
single value can be used.
12371241
12381242
"""
1243+
if dtype and not is_dictlike(dtype):
1244+
dtype = {col_name: dtype for col_name in frame}
1245+
12391246
if dtype is not None:
12401247
from sqlalchemy.types import to_instance, TypeEngine
12411248
for col, my_type in dtype.items():
@@ -1644,11 +1651,15 @@ def to_sql(self, frame, name, if_exists='fail', index=True,
16441651
chunksize : int, default None
16451652
If not None, then rows will be written in batches of this
16461653
size at a time. If None, all rows will be written at once.
1647-
dtype : dict of column name to SQL type, default None
1654+
dtype : single SQL type or dict of column name to SQL type, default
1655+
None
16481656
Optional specifying the datatype for columns. The SQL type should
1649-
be a string.
1657+
be a string. If all columns are of the same type, one single value
1658+
can be used.
16501659
16511660
"""
1661+
if dtype and not is_dictlike(dtype):
1662+
dtype = {col_name: dtype for col_name in frame}
16521663
if dtype is not None:
16531664
for col, my_type in dtype.items():
16541665
if not isinstance(my_type, str):

Diff for: pandas/io/tests/parser/common.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -1302,17 +1302,17 @@ def test_read_duplicate_names(self):
13021302

13031303
def test_inf_parsing(self):
13041304
data = """\
1305-
,A
1306-
a,inf
1307-
b,-inf
1308-
c,+Inf
1309-
d,-Inf
1310-
e,INF
1311-
f,-INF
1312-
g,+INf
1313-
h,-INf
1314-
i,inF
1315-
j,-inF"""
1305+
,A
1306+
a,inf
1307+
b,-inf
1308+
c,+Inf
1309+
d,-Inf
1310+
e,INF
1311+
f,-INF
1312+
g,+INf
1313+
h,-INf
1314+
i,inF
1315+
j,-inF"""
13161316
inf = float('inf')
13171317
expected = Series([inf, -inf] * 5)
13181318

Diff for: pandas/io/tests/test_sql.py

+28
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,19 @@ def test_dtype(self):
15521552
self.assertTrue(isinstance(sqltype, sqlalchemy.String))
15531553
self.assertEqual(sqltype.length, 10)
15541554

1555+
def test_to_sql_single_dtype(self):
1556+
cols = ['A', 'B']
1557+
data = [('a', 'b'),
1558+
('c', 'd')]
1559+
df = DataFrame(data, columns=cols)
1560+
df.to_sql('single_dtype_test', self.conn, dtype=sqlalchemy.TEXT)
1561+
meta = sqlalchemy.schema.MetaData(bind=self.conn)
1562+
meta.reflect()
1563+
sqltypea = meta.tables['single_dtype_test'].columns['A'].type
1564+
sqltypeb = meta.tables['single_dtype_test'].columns['B'].type
1565+
self.assertTrue(isinstance(sqltypea, sqlalchemy.TEXT))
1566+
self.assertTrue(isinstance(sqltypeb, sqlalchemy.TEXT))
1567+
15551568
def test_notnull_dtype(self):
15561569
cols = {'Bool': Series([True, None]),
15571570
'Date': Series([datetime(2012, 5, 1), None]),
@@ -2025,6 +2038,21 @@ def test_dtype(self):
20252038
self.assertRaises(ValueError, df.to_sql,
20262039
'error', self.conn, dtype={'B': bool})
20272040

2041+
def test_to_sql_single_dtype(self):
2042+
if self.flavor == 'mysql':
2043+
raise nose.SkipTest('Not applicable to MySQL legacy')
2044+
self.drop_table('single_dtype_test')
2045+
cols = ['A', 'B']
2046+
data = [('a', 'b'),
2047+
('c', 'd')]
2048+
df = DataFrame(data, columns=cols)
2049+
df.to_sql('single_dtype_test', self.conn, dtype='STRING')
2050+
self.assertEqual(
2051+
self._get_sqlite_column_type('single_dtype_test', 'A'), 'STRING')
2052+
self.assertEqual(
2053+
self._get_sqlite_column_type('single_dtype_test', 'B'), 'STRING')
2054+
self.drop_table('single_dtype_test')
2055+
20282056
def test_notnull_dtype(self):
20292057
if self.flavor == 'mysql':
20302058
raise nose.SkipTest('Not applicable to MySQL legacy')

0 commit comments

Comments
 (0)