Skip to content

Commit f549481

Browse files
committed
BIG: Enforce correc encoding in stata
Ensure StataReader and StataWriter have the correct encoding. Standardized default encoding to 'latin-1' closes pandas-dev#15723
1 parent 1e753d7 commit f549481

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

doc/source/whatsnew/v0.20.0.txt

+3
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,8 @@ Bug Fixes
917917
- Avoid use of ``np.finfo()`` during ``import pandas`` removed to mitigate deadlock on Python GIL misuse (:issue:`14641`)
918918

919919
- Bug in ``DataFrame.to_stata()`` and ``StataWriter`` which produces incorrectly formatted files to be produced for some locales (:issue:`13856`)
920+
- Bug in ``StataReader`` and ``StataWriter`` which allows invalid encodings (:issue:`15723`)
921+
920922
- Bug in ``pd.concat()`` in which concatting with an empty dataframe with ``join='inner'`` was being improperly handled (:issue:`15328`)
921923
- Bug in ``groupby.agg()`` incorrectly localizing timezone on ``datetime`` (:issue:`15426`, :issue:`10668`, :issue:`13046`)
922924

@@ -931,3 +933,4 @@ Bug Fixes
931933
- Bug in ``pd.melt()`` where passing a tuple value for ``value_vars`` caused a ``TypeError`` (:issue:`15348`)
932934
- Bug in ``.eval()`` which caused multiline evals to fail with local variables not on the first line (:issue:`15342`)
933935
- Bug in ``pd.read_msgpack`` which did not allow to load dataframe with an index of type ``CategoricalIndex`` (:issue:`15487`)
936+

pandas/io/stata.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
from pandas._libs.lib import max_len_string_array, infer_dtype
3434
from pandas._libs.tslib import NaT, Timestamp
3535

36+
VALID_ENCODINGS = ('ascii', 'us-ascii', 'latin-1', 'latin_1', 'iso-8859-1',
37+
'iso8859-1', '8859', 'cp819', 'latin', 'latin1', 'L1')
38+
3639
_version_error = ("Version of given Stata file is not 104, 105, 108, "
3740
"111 (Stata 7SE), 113 (Stata 8/9), 114 (Stata 10/11), "
3841
"115 (Stata 12), 117 (Stata 13), or 118 (Stata 14)")
@@ -45,7 +48,7 @@
4548

4649
_encoding_params = """\
4750
encoding : string, None or encoding
48-
Encoding used to parse the files. None defaults to iso-8859-1."""
51+
Encoding used to parse the files. None defaults to latin-1."""
4952

5053
_statafile_processing_params2 = """\
5154
index : identifier of index column
@@ -153,7 +156,7 @@
153156

154157
@Appender(_read_stata_doc)
155158
def read_stata(filepath_or_buffer, convert_dates=True,
156-
convert_categoricals=True, encoding=None, index=None,
159+
convert_categoricals=True, encoding='latin-1', index=None,
157160
convert_missing=False, preserve_dtypes=True, columns=None,
158161
order_categoricals=True, chunksize=None, iterator=False):
159162

@@ -816,9 +819,14 @@ def get_base_missing_value(cls, dtype):
816819

817820

818821
class StataParser(object):
819-
_default_encoding = 'iso-8859-1'
822+
_default_encoding = 'latin-1'
823+
824+
def __init__(self, encoding='latin-1'):
825+
826+
if encoding not in VALID_ENCODINGS:
827+
raise ValueError('Unknown encoding. Only latin-1 and ascii '
828+
'supported.')
820829

821-
def __init__(self, encoding):
822830
self._encoding = encoding
823831

824832
# type code.
@@ -936,7 +944,7 @@ def __init__(self, path_or_buf, convert_dates=True,
936944
convert_categoricals=True, index=None,
937945
convert_missing=False, preserve_dtypes=True,
938946
columns=None, order_categoricals=True,
939-
encoding='iso-8859-1', chunksize=None):
947+
encoding='latin-1', chunksize=None):
940948
super(StataReader, self).__init__(encoding)
941949
self.col_sizes = ()
942950

@@ -949,6 +957,9 @@ def __init__(self, path_or_buf, convert_dates=True,
949957
self._preserve_dtypes = preserve_dtypes
950958
self._columns = columns
951959
self._order_categoricals = order_categoricals
960+
if encoding not in VALID_ENCODINGS:
961+
raise ValueError('Unknown encoding. Only latin-1 and ascii '
962+
'supported.')
952963
self._encoding = encoding
953964
self._chunksize = chunksize
954965

@@ -1855,7 +1866,7 @@ class StataWriter(StataParser):
18551866
write_index : bool
18561867
Write the index to Stata dataset.
18571868
encoding : str
1858-
Default is latin-1. Unicode is not supported
1869+
Default is latin-1. Only latin-1 and ascii are supported.
18591870
byteorder : str
18601871
Can be ">", "<", "little", or "big". default is `sys.byteorder`
18611872
time_stamp : datetime

pandas/tests/io/test_stata.py

+6
Original file line numberDiff line numberDiff line change
@@ -1276,3 +1276,9 @@ def test_out_of_range_float(self):
12761276
original.to_stata(path)
12771277
tm.assertTrue('ColumnTooBig' in cm.exception)
12781278
tm.assertTrue('infinity' in cm.exception)
1279+
1280+
def test_invalid_encoding(self):
1281+
original = self.read_csv(self.csv3)
1282+
with tm.assertRaises(ValueError):
1283+
with tm.ensure_clean() as path:
1284+
original.to_stata(path, encoding='utf-8')

0 commit comments

Comments
 (0)