diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 7e8ab002f7978..d7beeb02a13c4 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -1868,7 +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('Writing general object arrays is not supported') + 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.'.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]