Pandas version checks

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

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

  • [ ] I have confirmed this bug exists on the main branch of pandas. (I am working on compiling and testing this.)

Reproducible Example

import pandas as pd

excel_file = "string_list.xlsx"

df_openpyxl = pd.read_excel(excel_file, engine="openpyxl")
df_calamine = pd.read_excel(excel_file, engine="calamine")

print("openpyxl engine")
print("===============")
print(df_openpyxl)

print("calamine engine")
print("===============")
print(df_calamine)

Issue Description

The attached excel file string_list.xlsx contains the following data:

  Header
0  Alone
1   Bone
2   None
3   Cone
4   Done

It looks like this:

Image

When read with read_excel() using either the openpyxl or calamine engine it converts the string cell "None" to a NaN. The output from the above program is:

openpyxl engine
===============
  Header
0  Alone
1   Bone
2    NaN
3   Cone
4   Done
calamine engine
===============
  Header
0  Alone
1   Bone
2    NaN
3   Cone
4   Done

Note that "None" has changed to NaN.

Sample file:

string_list.xlsx

I checked openpyxl, calamine and python-calamine outside of Pandas and they each print the expected string "None".

Expected Behavior

The string "None" from an Excel file shouldn't be interpreted as Python None and/or converted to NaN.

Installed Versions

INSTALLED VERSIONS ------------------ commit : 2cc37625532045f4ac55b27176454bbbc9baf213 python : 3.11.1 python-bits : 64 OS : Darwin OS-release : 24.5.0 Version : Darwin Kernel Version 24.5.0: Tue Apr 22 19:53:26 PDT 2025; root:xnu-11417.121.6~2/RELEASE_X86_64 machine : x86_64 processor : i386 byteorder : little LC_ALL : None LANG : en_US.UTF-8 LOCALE : en_US.UTF-8 pandas : 2.3.0 numpy : 2.1.3 pytz : 2024.2 dateutil : 2.9.0.post0 pip : 25.1.1 Cython : None sphinx : None IPython : None adbc-driver-postgresql: None adbc-driver-sqlite : None bs4 : None blosc : None bottleneck : None dataframe-api-compat : None fastparquet : None fsspec : None html5lib : None hypothesis : None gcsfs : None jinja2 : 3.1.4 lxml.etree : None matplotlib : None numba : None numexpr : None odfpy : None openpyxl : 3.1.5 pandas_gbq : None psycopg2 : None pymysql : None pyarrow : 20.0.0 pyreadstat : None pytest : None python-calamine : None pyxlsb : None s3fs : None scipy : None sqlalchemy : None tables : None tabulate : None xarray : None xlrd : None xlsxwriter : 3.2.5 zstandard : None tzdata : 2024.2 qtpy : None pyqt5 : None

Comment From: lsgordon

I can look into this

Comment From: asishm

Haven't investigated, but it's likely due to the na_values / keep_default_na parameters of read_excel. I'd try with setting keep_default_na=False

Comment From: lsgordon

Looks like that is the issue:

keep_default_na : bool, default True
    Whether or not to include the default NaN values when parsing the data.
    Depending on whether ``na_values`` is passed in, the behavior is as follows:

    * If ``keep_default_na`` is True, and ``na_values`` are specified,
      ``na_values`` is appended to the default NaN values used for parsing.
    * If ``keep_default_na`` is True, and ``na_values`` are not specified, only
      the default NaN values are used for parsing.
    * If ``keep_default_na`` is False, and ``na_values`` are specified, only
      the NaN values specified ``na_values`` are used for parsing.
    * If ``keep_default_na`` is False, and ``na_values`` are not specified, no
      strings will be parsed as NaN.

Yup, None is in there Image Turning that to False should resolve the issue.

Comment From: jmcnamara

Thanks, I can confirm that add keep_default_na=False make it work as expected.

df_openpyxl = pd.read_excel(excel_file, engine="openpyxl", keep_default_na=False)
df_calamine = pd.read_excel(excel_file, engine="calamine", keep_default_na=False)
openpyxl engine
===============
  Header
0  Alone
1   Bone
2   None
3   Cone
4   Done
calamine engine
===============
  Header
0  Alone
1   Bone
2   None
3   Cone
4   Done

So, to be clear, are you saying that this is expected behaviour and not a bug?

Comment From: asishm

Yes, this is expected behavior.

Comment From: jmcnamara

Yes, this is expected behavior.

Thanks. Then I will close.