Skip to content

Commit 78e4a81

Browse files
fangchenlifeefladder
authored andcommitted
BUG: fix is_named_tuple for objects that are not subclass of tuple pandas-dev#40682 (pandas-dev#43253)
1 parent b78791c commit 78e4a81

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ I/O
376376
- Bug in :func:`read_csv` with multi-header input and arguments referencing column names as tuples (:issue:`42446`)
377377
- Bug in :func:`read_fwf`, where difference in lengths of ``colspecs`` and ``names`` was not raising ``ValueError`` (:issue:`40830`)
378378
- Bug in :func:`Series.to_json` and :func:`DataFrame.to_json` where some attributes were skipped when serialising plain Python objects to JSON (:issue:`42768`, :issue:`33043`)
379+
- Column headers are dropped when constructing a :class:`DataFrame` from a sqlalchemy's ``Row`` object (:issue:`40682`)
379380
-
380381

381382
Period

pandas/core/dtypes/inference.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ def is_named_tuple(obj) -> bool:
315315
>>> is_named_tuple((1, 2))
316316
False
317317
"""
318-
return isinstance(obj, tuple) and hasattr(obj, "_fields")
318+
return isinstance(obj, abc.Sequence) and hasattr(obj, "_fields")
319319

320320

321321
def is_hashable(obj) -> bool:

pandas/tests/io/test_sql.py

+38
Original file line numberDiff line numberDiff line change
@@ -2189,6 +2189,44 @@ def test_bigint_warning(self):
21892189
with tm.assert_produces_warning(None):
21902190
sql.read_sql_table("test_bigintwarning", self.conn)
21912191

2192+
def test_row_object_is_named_tuple(self):
2193+
# GH 40682
2194+
# Test for the is_named_tuple() function
2195+
# Placed here due to its usage of sqlalchemy
2196+
2197+
from sqlalchemy import (
2198+
Column,
2199+
Integer,
2200+
String,
2201+
)
2202+
from sqlalchemy.orm import sessionmaker
2203+
2204+
if _gt14():
2205+
from sqlalchemy.orm import declarative_base
2206+
else:
2207+
from sqlalchemy.ext.declarative import declarative_base
2208+
2209+
BaseModel = declarative_base()
2210+
2211+
class Test(BaseModel):
2212+
__tablename__ = "test_frame"
2213+
id = Column(Integer, primary_key=True)
2214+
foo = Column(String(50))
2215+
2216+
BaseModel.metadata.create_all(self.conn)
2217+
Session = sessionmaker(bind=self.conn)
2218+
session = Session()
2219+
2220+
df = DataFrame({"id": [0, 1], "foo": ["hello", "world"]})
2221+
df.to_sql("test_frame", con=self.conn, index=False, if_exists="replace")
2222+
2223+
session.commit()
2224+
foo = session.query(Test.id, Test.foo)
2225+
df = DataFrame(foo)
2226+
session.close()
2227+
2228+
assert list(df.columns) == ["id", "foo"]
2229+
21922230

21932231
class _TestMySQLAlchemy:
21942232
"""

0 commit comments

Comments
 (0)