From 904576a30efc4eca5691f9313b2c35e188ee6509 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Nov 2018 08:58:28 +0000 Subject: [PATCH 1/2] ENH: Improve error message for empty object array Improve the error message shown when an object array is empty closes #23572 --- pandas/io/stata.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 7e8ab002f7978..97b3beca5c245 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -1868,7 +1868,12 @@ def _dtype_to_default_stata_fmt(dtype, column, dta_version=114, inferred_dtype = infer_dtype(column.dropna()) if not (inferred_dtype in ('string', 'unicode') or len(column) == 0): - raise ValueError('Writing general object arrays is not supported') + raise ValueError('Only string-like object arrays containing all ' + 'strings or a mix of strings and None can be ' + 'exported. Object arrays containing only null ' + 'values are prohibited. Other object types' + 'cannot be exported and must first be converted ' + 'to one of the supported types.') itemsize = max_len_string_array(ensure_object(column.values)) if itemsize > max_str_len: if dta_version >= 117: From 527a1e3f8c3fb0b450f3fd3f2ff40489e025529e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Thu, 15 Nov 2018 13:59:40 +0000 Subject: [PATCH 2/2] TST: Add tests for all None Test exception is hit when all values in an object column are None Extend the test for strl conversion to ensure this case passes (as expected) --- pandas/io/stata.py | 6 ++++-- pandas/tests/io/test_stata.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 97b3beca5c245..d7beeb02a13c4 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -1868,12 +1868,14 @@ def _dtype_to_default_stata_fmt(dtype, column, dta_version=114, inferred_dtype = infer_dtype(column.dropna()) if not (inferred_dtype in ('string', 'unicode') or len(column) == 0): - raise ValueError('Only string-like object arrays containing all ' + raise ValueError('Column `{col}` cannot be exported.\n\nOnly ' + 'string-like object arrays containing all ' 'strings or a mix of strings and None can be ' 'exported. Object arrays containing only null ' 'values are prohibited. Other object types' 'cannot be exported and must first be converted ' - 'to one of the supported types.') + 'to one of the supported ' + 'types.'.format(col=column.name)) itemsize = max_len_string_array(ensure_object(column.values)) if itemsize > max_str_len: if dta_version >= 117: diff --git a/pandas/tests/io/test_stata.py b/pandas/tests/io/test_stata.py index 47293e8765d26..fb08af36e8325 100644 --- a/pandas/tests/io/test_stata.py +++ b/pandas/tests/io/test_stata.py @@ -1514,11 +1514,35 @@ def test_mixed_string_strl(self): {'mixed': None, 'number': 1} ] - output = pd.DataFrame(output) + output.number = output.number.astype('int32') + with tm.ensure_clean() as path: output.to_stata(path, write_index=False, version=117) reread = read_stata(path) expected = output.fillna('') - expected.number = expected.number.astype('int32') tm.assert_frame_equal(reread, expected) + + # Check strl supports all None (null) + output.loc[:, 'mixed'] = None + output.to_stata(path, write_index=False, convert_strl=['mixed'], + version=117) + reread = read_stata(path) + expected = output.fillna('') + tm.assert_frame_equal(reread, expected) + + @pytest.mark.parametrize('version', [114, 117]) + def test_all_none_exception(self, version): + output = [ + {'none': 'none', + 'number': 0}, + {'none': None, + 'number': 1} + ] + output = pd.DataFrame(output) + output.loc[:, 'none'] = None + with tm.ensure_clean() as path: + with pytest.raises(ValueError) as excinfo: + output.to_stata(path, version=version) + assert 'Only string-like' in excinfo.value.args[0] + assert 'Column `none`' in excinfo.value.args[0]