Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def create_job_configs_labels(
job_configs_labels = dict(job_configs_labels)

if api_methods and "bigframes-api" not in job_configs_labels:
api_methods = list(api_methods)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-rhetorical question: do we need this line of change? It alters the behavior of the original code, which alters the original list that was passed in at line 73.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this shallow copy is intentional as a safety guard. There are two reasons. (1) at line 73, del api_methods[0]
removes the primary API label. Creating a copy ensures this deletion stys local to the helper function and does not mutate the caller's original list if reused or logs elsewhere.
(2) api_methods may sometime pass in tuple. We have a unit test reate_job_configs_labels(labels, ("read_gbq_colab", "head")) will pass tuples to label. In this case, tuple is immutable. This copy is a guard to avoid errors for del api_methods[0].

job_configs_labels["bigframes-api"] = api_methods[0]
del api_methods[0]

Expand Down
3 changes: 2 additions & 1 deletion packages/bigframes/tests/unit/session/test_io_bigquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def test_add_and_trim_labels_length_limit_met():
for _ in range(52):
df.head()

io_bq.add_and_trim_labels(job_config=job_config)
io_bq.add_and_trim_labels(job_config=job_config, session=df._session)
assert job_config.labels is not None
assert len(job_config.labels) == 56
assert "dataframe-max" not in job_config.labels.values()
Expand Down Expand Up @@ -218,6 +218,7 @@ def test_start_query_with_job_labels_length_limit_met(
timeout=timeout,
metrics=None,
publisher=bigframes.core.events.Publisher(),
session=df._session,
)

assert job_config.labels is not None
Expand Down
30 changes: 30 additions & 0 deletions packages/bigframes/tests/unit/session/test_read_gbq_colab.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,36 @@ def test_read_gbq_colab_includes_label():
assert "session-read_gbq_colab" in label_values


def test_read_gbq_colab_includes_label_in_anywidget_mode():
"""Make sure read_gbq_colab label is preserved in recent-bigframes-api labels in anywidget mode."""
pytest.importorskip("anywidget")
pytest.importorskip("traitlets")

import bigframes
import bigframes.display.html as bf_html

bqclient = mock.create_autospec(bigquery.Client, instance=True)
bqclient.project = "proj"
session = mocks.create_bigquery_session(bqclient=bqclient)
df = session._read_gbq_colab("SELECT 'read-gbq-colab-test'")

with bigframes.option_context("display.render_mode", "anywidget"):
_ = bf_html.get_anywidget_bundle(df)

label_values = []
for kall in itertools.chain(
bqclient.query_and_wait.call_args_list,
bqclient._query_and_wait_bigframes.call_args_list,
bqclient.query.call_args_list,
):
job_config = kall.kwargs.get("job_config")
if job_config is None:
continue
label_values.extend(job_config.labels.values())

assert "session-read_gbq_colab" in label_values


@pytest.mark.parametrize("dry_run", [True, False])
def test_read_gbq_colab_includes_formatted_values_in_dry_run(monkeypatch, dry_run):
bqclient = mock.create_autospec(bigquery.Client, instance=True)
Expand Down
Loading