Skip to content
2 changes: 1 addition & 1 deletion pandas/core/dtypes/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ def is_named_tuple(obj) -> bool:
>>> is_named_tuple((1, 2))
False
"""
return isinstance(obj, tuple) and hasattr(obj, "_fields")
return isinstance(obj, abc.Sequence) and hasattr(obj, "_fields")


def is_hashable(obj) -> bool:
Expand Down
39 changes: 39 additions & 0 deletions pandas/tests/io/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -2189,6 +2189,45 @@ def test_bigint_warning(self):
with tm.assert_produces_warning(None):
sql.read_sql_table("test_bigintwarning", self.conn)

def test_row_object_is_named_tuple(self):
# GH 40682
# Test for the is_named_tuple() function
# Placed here due to its usage of sqlalchemy

from sqlalchemy import (
Column,
Integer,
String,
)
from sqlalchemy.orm import sessionmaker

if _gt14():
from sqlalchemy.orm import declarative_base
else:
from sqlalchemy.ext.declarative import declarative_base

BaseModel = declarative_base()

class Test(BaseModel):
__tablename__ = "test_Frame"
id = Column(Integer, primary_key=True)
foo = Column(String(50))

BaseModel.metadata.create_all(self.conn)
Session = sessionmaker(bind=self.conn)
session = Session()

df = DataFrame({"id": [0, 1], "foo": ["hello", "world"]})
df.to_sql("test_Frame", con=self.conn, index=False, if_exists="replace")

session.commit()
foo = session.query(Test.id, Test.foo)
print(foo)
df = DataFrame(foo)
session.close()

assert list(df.columns) == ["id", "foo"]


class _TestMySQLAlchemy:
"""
Expand Down