Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: V1.2 DataFrame.to_csv() fails to write a file with codecs #39247

Closed
2 of 3 tasks
Kazzz-S opened this issue Jan 18, 2021 · 9 comments · Fixed by #39253 or #39440
Closed
2 of 3 tasks

BUG: V1.2 DataFrame.to_csv() fails to write a file with codecs #39247

Kazzz-S opened this issue Jan 18, 2021 · 9 comments · Fixed by #39253 or #39440
Labels
Bug IO Data IO issues that don't fit into a more specific label Regression Functionality that used to work in a prior pandas version
Milestone

Comments

@Kazzz-S
Copy link

Kazzz-S commented Jan 18, 2021

  • I have checked that this issue has not already been reported.

  • I have confirmed this bug exists on the latest version of pandas.

  • (optional) I have confirmed this bug exists on the master branch of pandas.


Note: Please read this guide detailing how to provide the necessary information for us to reproduce your bug.

Code Sample, a copy-pastable example

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import pandas as pd
import codecs

x    = [ 1, 2, 3, 4, 5  ]
y    = [ 6, 7, 8, 9, 10 ]
z    = [ 'a', 'b', 'c', 'd', 'e' ]
data = { "X": x, "Y":y, "Z":z }
df   = pd.DataFrame( data, columns=[ "X", "Y", "Z" ] )
print( "Pandas version = %s" % pd.__version__ )
print(df)

fp = codecs.open( "out-testPD12.csv", "w", "utf-8" )
fp.write( "Pandas version = %s\n" % pd.__version__  )
df.to_csv( fp, index=False, header=True )
fp.close()

Problem description

When saving the file, TypeError: utf_8_encode() argument 1 must be str, not bytes flags on.

Expected Output

The output below has been obtained by downgrading and pinned Pandas to V1.1.5.
V1.1.2 is also tested OK.

Pandas version = 1.1.5
X,Y,Z
1,6,a
2,7,b
3,8,c
4,9,d
5,10,e

Output of pd.show_versions()

INSTALLED VERSIONS

commit : 3e89b4c
python : 3.8.2.final.0
python-bits : 64
OS : Darwin
OS-release : 19.6.0
Version : Darwin Kernel Version 19.6.0: Tue Nov 10 00:10:30 PST 2020; root:xnu-6153.141.10~1/RELEASE_X86_64
machine : x86_64
processor : i386
byteorder : little
LC_ALL : None
LANG : None
LOCALE : None.UTF-8

pandas : 1.2.0
numpy : 1.19.2
pytz : 2020.5
dateutil : 2.8.1
pip : 20.3.3
setuptools : 51.1.2.post20210112
Cython : 0.29.21
pytest : 6.2.1
hypothesis : None
sphinx : 3.4.3
blosc : None
feather : None
xlsxwriter : 1.3.7
lxml.etree : 4.6.2
html5lib : 1.1
pymysql : None
psycopg2 : None
jinja2 : 2.11.2
IPython : 7.19.0
pandas_datareader: None
bs4 : 4.9.3
bottleneck : 1.3.2
fsspec : 0.8.3
fastparquet : None
gcsfs : None
matplotlib : 3.3.2
numexpr : 2.7.2
odfpy : None
openpyxl : 3.0.6
pandas_gbq : None
pyarrow : None
pyxlsb : None
s3fs : None
scipy : 1.5.2
sqlalchemy : 1.3.21
tables : 3.6.1
tabulate : None
xarray : None
xlrd : 2.0.1
xlwt : 1.3.0
numba : 0.51.2

(base) Catalina1{kazzz-s} temp (1)% python testPD12.py 
Pandas version = 1.2.0
   X   Y  Z
0  1   6  a
1  2   7  b
2  3   8  c
3  4   9  d
4  5  10  e
Traceback (most recent call last):
  File "testPD12.py", line 52, in <module>
    df.to_csv( fp, index=False, header=True )
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/site-packages/pandas/core/generic.py", line 3384, in to_csv
    return DataFrameRenderer(formatter).to_csv(
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/site-packages/pandas/io/formats/format.py", line 1083, in to_csv
    csv_formatter.save()
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/site-packages/pandas/io/formats/csvs.py", line 248, in save
    self._save()
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/site-packages/pandas/io/common.py", line 104, in __exit__
    self.close()
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/site-packages/pandas/io/common.py", line 89, in close
    self.handle.flush()
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/codecs.py", line 721, in write
    return self.writer.write(data)
  File "/Users/kazzz-s/opt/anaconda3/lib/python3.8/codecs.py", line 377, in write
    data, consumed = self.encode(object, self.errors)
TypeError: utf_8_encode() argument 1 must be str, not bytes
@Kazzz-S Kazzz-S added Bug Needs Triage Issue that has not been reviewed by a pandas team member labels Jan 18, 2021
@twoertwein
Copy link
Member

thank you for the report and your minimal examples! Yes, that is a regression.

Unfortunately it seems that codecs.open( ..., mode="w", encoding="utf-8" ).mode is "wb". So pandas 1.2 tries to write bytes to it. Interestingly codecs.open( ..., mode="w" ).mode is "w" and should therefore work with pandas 1.2.

@twoertwein twoertwein added IO Data IO issues that don't fit into a more specific label Regression Functionality that used to work in a prior pandas version and removed Needs Triage Issue that has not been reviewed by a pandas team member labels Jan 18, 2021
@jorisvandenbossche jorisvandenbossche added this to the 1.2.2 milestone Jan 18, 2021
simonjayhawkins added a commit to simonjayhawkins/pandas that referenced this issue Jan 18, 2021
@simonjayhawkins simonjayhawkins modified the milestones: 1.2.2, 1.2.1 Jan 18, 2021
@simonjayhawkins
Copy link
Member

The output below has been obtained by downgrading and pinned Pandas to V1.1.5.

d75eb5b...ff1cd78

https://github.com/simonjayhawkins/pandas/runs/1723695416?check_suite_focus=true

perhaps #36997

@tgs
Copy link

tgs commented Jan 26, 2021

Hello, we still seem to be getting this issue in Pandas 1.2.1, but with another text IO class:

>>> import codecs
>>> import pandas
>>> df = pandas.DataFrame({'a': [1,2,3]})
>>> f = codecs.getwriter('utf-8')(open('blah', 'wb'))
>>> df.to_csv(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "env/lib/python3.7/site-packages/pandas/core/generic.py", line 3402, in to_csv
    storage_options=storage_options,
  File "env/lib/python3.7/site-packages/pandas/io/formats/format.py", line 1083, in to_csv
    csv_formatter.save()
  File "env/lib/python3.7/site-packages/pandas/io/formats/csvs.py", line 248, in save
    self._save()
  File "env/lib/python3.7/site-packages/pandas/io/common.py", line 105, in __exit__
    self.close()
  File "env/lib/python3.7/site-packages/pandas/io/common.py", line 90, in close
    self.handle.flush()
  File "env/lib/python3.7/codecs.py", line 377, in write
    data, consumed = self.encode(object, self.errors)
TypeError: utf_8_encode() argument 1 must be str, not bytes

The class that codecs.getwriter('utf-8') returns on my system is encodings.utf_8.StreamWriter.

@twoertwein
Copy link
Member

oh my, I think there are three directions how to address this:

  1. go back to the pre-1.2 behavior: assume text mode except for a growing list of binary classes

  2. try to infer it with .mode (as done in 1.2) and a growing list of common text/byte classes

  3. make sure that read_/to_ have a mode keyword: force the user to specify the correct mode

(3) would probably not be okay for 1.2.*

@jreback what do you think is the best short/long-term solution?

@tgs
Copy link

tgs commented Jan 26, 2021

It looks like all of the results of codecs.getwriter(...) are subclasses of codecs.StreamWriter ... so far as I can tell.

@jreback
Copy link
Contributor

jreback commented Jan 27, 2021

@twoertwein 2) sgtm

@tgs
Copy link

tgs commented Jan 27, 2021

It could also be helpful to be able to pass 'wt' as the mode argument of to_csv, to force text mode in case it wasn't detected?

@twoertwein
Copy link
Member

@tgs it should work on master now and will work in 1.2.2:

  1. codecs.StreamWriter is assumed to take strings
  2. if you specify a mode (like "wt" or "wb") then no auto-detection takes place. Unfortunately not all to_/read_ functions have a mode argument.

@tgs
Copy link

tgs commented Jan 28, 2021

Thank you! We really appreciate the quick fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug IO Data IO issues that don't fit into a more specific label Regression Functionality that used to work in a prior pandas version
Projects
None yet
6 participants