Repository navigation
Description
Description
Table.from_df fails on any pandas DataFrame that has a string-like column with a
missing value represented as pd.NA. That includes the common case of a pandas
string dtype column (dtype="string", either the python or pyarrow storage) with a
missing entry:
TypeError: must be real number, not NAType
The cause is the check in astropy/table/_dataframes.py that decides whether an
object column can be converted to a native NumPy string array:
if all((x is None) or isinstance(x, ts) or math.isnan(x) for x in data):math.isnan(pd.NA) raises a TypeError instead of returning False. Only None and
float NaN are accepted as missing values.
Table.from_pandas does not raise for the same input, because its version of the
check uses x is np.nan. However, it does not recognize pd.NA as missing either. The
column stays a MaskedColumn of dtype object, with pd.NA stored under the mask. The
same data with np.nan for the missing value becomes a <U1 column.
This came up while reviewing #20599, which moves the check into the
_get_string_fill_value helper but keeps the same behavior.
Expected behavior
pd.NA in a string-like column should be treated as a missing value, the same way as
None and NaN. Both Table.from_df and Table.from_pandas should then return a
MaskedColumn with a native string dtype (<U1 in the example below) and that entry
masked.
At a minimum, Table.from_df should not raise. If a column can't be converted, it
could fall back to an object column, as from_pandas does.
How to Reproduce
import numpy as np
import pandas as pd
from astropy.table import Table
df = pd.DataFrame({"s": ["a", None]}, dtype="string") # None is stored as pd.NA
Table.from_df(df)
# TypeError: must be real number, not NAType
t = Table.from_pandas(df)
t["s"].dtype, t["s"].mask.tolist()
# (dtype('O'), [False, True]) -- pd.NA kept in an object column
# For comparison, np.nan as the missing value works with both methods:
df2 = pd.DataFrame({"s": ["a", np.nan]}, dtype=object)
Table.from_df(df2)["s"].dtype # dtype('<U1')
Table.from_pandas(df2)["s"].dtype # dtype('<U1')Results for other ways of holding the missing value:
| DataFrame column | from_df |
from_pandas |
|---|---|---|
dtype="string" with None (becomes pd.NA) |
TypeError |
object column |
dtype="string[pyarrow]" with None |
TypeError |
object column |
dtype=object with pd.NA |
TypeError |
object column |
dtype=object with None |
<U1 column |
object column |
dtype=object with np.nan |
<U1 column |
<U1 column |
Full traceback for Table.from_df(df):
Traceback (most recent call last):
File "astropy/table/table.py", line 4368, in from_df
return from_df(cls, df, index=index, units=units)
File "astropy/table/_dataframes.py", line 391, in from_df
if all((x is None) or isinstance(x, ts) or math.isnan(x) for x in data):
File "astropy/table/_dataframes.py", line 391, in <genexpr>
if all((x is None) or isinstance(x, ts) or math.isnan(x) for x in data):
~~~~~~~~~~^^^
TypeError: must be real number, not NAType
Versions
import astropy
astropy.system_info()platform
--------
platform.platform() = 'macOS-26.6.2-arm64-arm-64bit-Mach-O'
platform.version() = 'Darwin Kernel Version 25.6.0: Fri Jul 31 19:18:48 PDT 2026; root:xnu-12377.161.14~5/RELEASE_ARM64_T6020'
platform.python_version() = '3.13.2'
packages
--------
astropy 8.1.0.dev423+g1d2de44a7
numpy 2.2.3
scipy 1.15.1
matplotlib 3.10.0
pandas 2.3.3
pyerfa 2.0.1.5
(The astropy line is from the editable install metadata; the source tree was main at
984804c.)
Activity
codeNstruct commentedon Oct 30, 2026
Hi! I'd like to work on this issue as my first code contribution to Astropy. I understand that the problem occurs when
Table.from_df()processes pandas string columns containingpd.NA. I'd like to investigate the missing-value handling and add regression tests along with a fix. Is this issue still available for contribution? Thank you!