Skip to content

Commit 8bc43e5

Browse files
authored
Merge pull request #4442 from anmyachev/fix-column-names
Fix usage of `column_names` which is part of Interchange protocol
2 parents 63b9ac5 + e7bfc7c commit 8bc43e5

File tree

3 files changed

+24
-10
lines changed

3 files changed

+24
-10
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
99
- Fix issue with creating dendrogram in subplots [[#4411](https://github.com/plotly/plotly.py/pull/4411)],
1010
- Fix issue with px.line not accepting "spline" line shape [[#2812](https://github.com/plotly/plotly.py/issues/2812)]
1111
- Fix KeyError when using column of `pd.Categorical` dtype with unobserved categories [[#4437](https://github.com/plotly/plotly.py/pull/4437)]
12+
- Fix dataframe interchange in case `column_names` returns an unmaterialized object: generator, iterator, etc. [[#4442]](https://github.com/plotly/plotly.py/pull/4442)
1213

1314
## [5.18.0] - 2023-10-25
1415

Diff for: packages/python/plotly/plotly/express/_core.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,11 @@ def build_dataframe(args, constructor):
13271327

13281328
df_not_pandas = args["data_frame"]
13291329
args["data_frame"] = df_not_pandas.__dataframe__()
1330-
columns = args["data_frame"].column_names()
1330+
# According interchange protocol: `def column_names(self) -> Iterable[str]:`
1331+
# so this function can return for example a generator.
1332+
# The easiest way is to convert `columns` to `pandas.Index` so that the
1333+
# type is similar to the types in other code branches.
1334+
columns = pd.Index(args["data_frame"].column_names())
13311335
needs_interchanging = True
13321336
elif hasattr(args["data_frame"], "to_pandas"):
13331337
args["data_frame"] = args["data_frame"].to_pandas()

Diff for: packages/python/plotly/plotly/tests/test_optional/test_px/test_px_input.py

+18-9
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
@pytest.fixture
1515
def add_interchange_module_for_old_pandas():
1616
if not hasattr(pd.api, "interchange"):
17-
pd.api.interchange = mock.MagicMock()
18-
# to make the following import work: `import pandas.api.interchange`
19-
with mock.patch.dict(
20-
"sys.modules", {"pandas.api.interchange": pd.api.interchange}
21-
):
22-
yield
17+
with mock.patch.object(pd.api, "interchange", mock.MagicMock(), create=True):
18+
# to make the following import work: `import pandas.api.interchange`
19+
with mock.patch.dict(
20+
"sys.modules", {"pandas.api.interchange": pd.api.interchange}
21+
):
22+
yield
2323
else:
2424
yield
2525

@@ -250,15 +250,24 @@ def test_build_df_with_index():
250250
assert_frame_equal(tips.reset_index()[out["data_frame"].columns], out["data_frame"])
251251

252252

253+
@pytest.mark.parametrize("column_names_as_generator", [False, True])
253254
def test_build_df_using_interchange_protocol_mock(
254-
add_interchange_module_for_old_pandas,
255+
add_interchange_module_for_old_pandas, column_names_as_generator
255256
):
256257
class InterchangeDataFrame:
257258
def __init__(self, columns):
258259
self._columns = columns
259260

260-
def column_names(self):
261-
return self._columns
261+
if column_names_as_generator:
262+
263+
def column_names(self):
264+
for col in self._columns:
265+
yield col
266+
267+
else:
268+
269+
def column_names(self):
270+
return self._columns
262271

263272
interchange_dataframe = InterchangeDataFrame(
264273
["petal_width", "sepal_length", "sepal_width"]

0 commit comments

Comments
 (0)