From b636bb0c86cfde82b4fa2d597090e5dfe368e1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Swe=C3=B1a=20=28Swast=29?= Date: Fri, 6 Feb 2026 09:24:46 -0600 Subject: [PATCH 1/4] feat: remove redundant "started." messages from progress output Follow-up to https://github.com/googleapis/python-bigquery-dataframes/pull/2419 --- bigframes/formatting_helpers.py | 80 +++++++++++++-------------------- 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/bigframes/formatting_helpers.py b/bigframes/formatting_helpers.py index 1e3cdabdaf..5b6d36e0ac 100644 --- a/bigframes/formatting_helpers.py +++ b/bigframes/formatting_helpers.py @@ -134,16 +134,14 @@ def repr_query_job_html(query_job: Optional[bigquery.QueryJob]): return res -current_display: Optional[display.HTML] = None current_display_id: Optional[str] = None -previous_display_html: str = "" def progress_callback( event: bigframes.core.events.Event, ): """Displays a progress bar while the query is running""" - global current_display, current_display_id, previous_display_html + global current_display_id try: import bigframes._config @@ -162,59 +160,43 @@ def progress_callback( if progress_bar == "notebook": import IPython.display as display - if ( - isinstance(event, bigframes.core.events.ExecutionStarted) - or current_display is None - or current_display_id is None - ): - previous_display_html = "" - current_display_id = str(random.random()) - current_display = display.HTML("Starting.") - display.display( - current_display, - display_id=current_display_id, - ) + display_html = None + + if isinstance(event, bigframes.core.events.ExecutionStarted): + # Start a new context for progress output. + current_display_id = None + + elif isinstance(event, bigframes.core.events.BigQuerySentEvent): + display_html = render_bqquery_sent_event_html(event) - if isinstance(event, bigframes.core.events.BigQuerySentEvent): - previous_display_html = render_bqquery_sent_event_html(event) - display.update_display( - display.HTML(previous_display_html), - display_id=current_display_id, - ) elif isinstance(event, bigframes.core.events.BigQueryRetryEvent): - previous_display_html = render_bqquery_retry_event_html(event) - display.update_display( - display.HTML(previous_display_html), - display_id=current_display_id, - ) + display_html = render_bqquery_retry_event_html(event) + elif isinstance(event, bigframes.core.events.BigQueryReceivedEvent): - previous_display_html = render_bqquery_received_event_html(event) - display.update_display( - display.HTML(previous_display_html), - display_id=current_display_id, - ) + display_html = render_bqquery_received_event_html(event) + elif isinstance(event, bigframes.core.events.BigQueryFinishedEvent): - previous_display_html = render_bqquery_finished_event_html(event) - display.update_display( - display.HTML(previous_display_html), - display_id=current_display_id, - ) - elif isinstance(event, bigframes.core.events.ExecutionFinished): - if previous_display_html: + display_html = render_bqquery_finished_event_html(event) + + elif isinstance(event, bigframes.core.events.SessionClosed): + display_html = f"Session {event.session_id} closed."), + + if display_html: + if current_display_id: display.update_display( - display.HTML(f"✅ Completed. {previous_display_html}"), + display.HTML(display_html), display_id=current_display_id, ) - - elif isinstance(event, bigframes.core.events.SessionClosed): - display.update_display( - display.HTML(f"Session {event.session_id} closed."), - display_id=current_display_id, - ) + else: + display.display( + display.HTML(display_html), + display_id=current_display_id, + ) + elif progress_bar == "terminal": - if isinstance(event, bigframes.core.events.ExecutionStarted): - print("Starting execution.") - elif isinstance(event, bigframes.core.events.BigQuerySentEvent): + message = None + + if isinstance(event, bigframes.core.events.BigQuerySentEvent): message = render_bqquery_sent_event_plaintext(event) print(message) elif isinstance(event, bigframes.core.events.BigQueryRetryEvent): @@ -226,8 +208,6 @@ def progress_callback( elif isinstance(event, bigframes.core.events.BigQueryFinishedEvent): message = render_bqquery_finished_event_plaintext(event) print(message) - elif isinstance(event, bigframes.core.events.ExecutionFinished): - print("Execution done.") def wait_for_job(job: GenericJob, progress_bar: Optional[str] = None): From 1507c89fa010881a9531aec412d5a34d8bcf4e10 Mon Sep 17 00:00:00 2001 From: Tim Swena Date: Fri, 6 Feb 2026 15:34:43 +0000 Subject: [PATCH 2/4] chore: syntax error, oops --- bigframes/formatting_helpers.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bigframes/formatting_helpers.py b/bigframes/formatting_helpers.py index 5b6d36e0ac..639eae82c1 100644 --- a/bigframes/formatting_helpers.py +++ b/bigframes/formatting_helpers.py @@ -27,8 +27,6 @@ import humanize if TYPE_CHECKING: - from IPython import display - import bigframes.core.events GenericJob = Union[ @@ -179,7 +177,7 @@ def progress_callback( display_html = render_bqquery_finished_event_html(event) elif isinstance(event, bigframes.core.events.SessionClosed): - display_html = f"Session {event.session_id} closed."), + display_html = f"Session {event.session_id} closed." if display_html: if current_display_id: @@ -192,7 +190,7 @@ def progress_callback( display.HTML(display_html), display_id=current_display_id, ) - + elif progress_bar == "terminal": message = None From b8b143425ea82cd7d77a7b6d058a293a3b8493dc Mon Sep 17 00:00:00 2001 From: Tim Swena Date: Fri, 6 Feb 2026 15:41:24 +0000 Subject: [PATCH 3/4] chore: fix issue where I forgot to set the display id --- bigframes/formatting_helpers.py | 1 + notebooks/getting_started/magics.ipynb | 217 +++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 notebooks/getting_started/magics.ipynb diff --git a/bigframes/formatting_helpers.py b/bigframes/formatting_helpers.py index 639eae82c1..094493818d 100644 --- a/bigframes/formatting_helpers.py +++ b/bigframes/formatting_helpers.py @@ -186,6 +186,7 @@ def progress_callback( display_id=current_display_id, ) else: + current_display_id = str(random.random()) display.display( display.HTML(display_html), display_id=current_display_id, diff --git a/notebooks/getting_started/magics.ipynb b/notebooks/getting_started/magics.ipynb new file mode 100644 index 0000000000..05a8f00e5c --- /dev/null +++ b/notebooks/getting_started/magics.ipynb @@ -0,0 +1,217 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "id": "98cd0489", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The bigframes extension is already loaded. To reload it, use:\n", + " %reload_ext bigframes\n" + ] + } + ], + "source": [ + "%load_ext bigframes" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "269c5862", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " Query processed 0 Bytes. [Job bigframes-dev:US.job_HiiqKoJVBj9_EYqkrjVsmzkVZCb5 details]\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c6fbeec6762f4a3fa0c9d3e71ca4c00d", + "version_major": 2, + "version_minor": 1 + }, + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
stategenderyearnamenumber
0HIF1999Ariana10
1HIF2002Jordyn10
2HIF2006Mya10
3HIF2010Jordyn10
4HIM1921Nobuo10
5HIM1925Ralph10
6HIM1926Hisao10
7HIM1927Moses10
8HIM1933Larry10
9HIM1933Alfredo10
\n", + "

10 rows × 5 columns

\n", + "
[5552452 rows x 5 columns in total]" + ], + "text/plain": [ + "state gender year name number\n", + " HI F 1999 Ariana 10\n", + " HI F 2002 Jordyn 10\n", + " HI F 2006 Mya 10\n", + " HI F 2010 Jordyn 10\n", + " HI M 1921 Nobuo 10\n", + " HI M 1925 Ralph 10\n", + " HI M 1926 Hisao 10\n", + " HI M 1927 Moses 10\n", + " HI M 1933 Larry 10\n", + " HI M 1933 Alfredo 10\n", + "...\n", + "\n", + "[5552452 rows x 5 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%bqsql\n", + "SELECT * FROM `bigquery-public-data.usa_names.usa_1910_2013`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30bb6327", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 8945693aa115932513cf05bad8f6e7bf352a1619 Mon Sep 17 00:00:00 2001 From: Tim Swena Date: Fri, 6 Feb 2026 15:47:52 +0000 Subject: [PATCH 4/4] docs: add sample notebook for magics --- notebooks/getting_started/magics.ipynb | 219 +++++++++++++++++++++++-- 1 file changed, 204 insertions(+), 15 deletions(-) diff --git a/notebooks/getting_started/magics.ipynb b/notebooks/getting_started/magics.ipynb index 05a8f00e5c..1f2cf7a409 100644 --- a/notebooks/getting_started/magics.ipynb +++ b/notebooks/getting_started/magics.ipynb @@ -1,27 +1,38 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "91edcf7b", + "metadata": {}, + "source": [ + "# %%bqsql cell magics\n", + "\n", + "The BigQuery DataFrames (aka BigFrames) package provides a `%%bqsql` cell magics for Jupyter environments.\n", + "\n", + "To use it, first activate the extension:" + ] + }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "id": "98cd0489", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The bigframes extension is already loaded. To reload it, use:\n", - " %reload_ext bigframes\n" - ] - } - ], + "outputs": [], "source": [ "%load_ext bigframes" ] }, + { + "cell_type": "markdown", + "id": "f18fdc63", + "metadata": {}, + "source": [ + "Now, use the magics by including SQL in the body." + ] + }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "id": "269c5862", "metadata": {}, "outputs": [ @@ -29,7 +40,7 @@ "data": { "text/html": [ "\n", - " Query processed 0 Bytes. [Job bigframes-dev:US.job_HiiqKoJVBj9_EYqkrjVsmzkVZCb5 details]\n", + " Query processed 0 Bytes. [Job bigframes-dev:US.job_UVe7FsupxF3CbYuLcLT7fpw9dozg details]\n", " " ], "text/plain": [ @@ -42,7 +53,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c6fbeec6762f4a3fa0c9d3e71ca4c00d", + "model_id": "1e2fb7b019754d31b11323a054f97f47", "version_major": 2, "version_minor": 1 }, @@ -184,11 +195,189 @@ "SELECT * FROM `bigquery-public-data.usa_names.usa_1910_2013`" ] }, + { + "cell_type": "markdown", + "id": "8771e10f", + "metadata": {}, + "source": [ + "The output DataFrame can be saved to a variable." + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "30bb6327", "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " Query processed 0 Bytes. [Job bigframes-dev:US.c142adf3-cd95-42da-bbdc-c176b36b934f details]\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%bqsql mydf\n", + "SELECT * FROM `bigquery-public-data.usa_names.usa_1910_2013`" + ] + }, + { + "cell_type": "markdown", + "id": "533e2e9e", + "metadata": {}, + "source": [ + "You can chain cells together using format strings. DataFrame objects are automatically turned into table expressions." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "6a8a8123", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " Query processed 88.1 MB in a moment of slot time.\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c4889de9296440428de90defb5c58070", + "version_major": 2, + "version_minor": 1 + }, + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
total_countname
0304036Tracy
1293876Travis
2203784Troy
3150127Trevor
496397Tristan
589996Tracey
665546Trinity
750112Traci
849657Trenton
945692Trent
\n", + "

10 rows × 2 columns

\n", + "
[238 rows x 2 columns in total]" + ], + "text/plain": [ + " total_count name\n", + "0 304036 Tracy\n", + "1 293876 Travis\n", + "2 203784 Troy\n", + "3 150127 Trevor\n", + "4 96397 Tristan\n", + "5 89996 Tracey\n", + "6 65546 Trinity\n", + "7 50112 Traci\n", + "8 49657 Trenton\n", + "9 45692 Trent\n", + "...\n", + "\n", + "[238 rows x 2 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%bqsql\n", + "SELECT sum(number) as total_count, name\n", + "FROM {mydf}\n", + "WHERE name LIKE 'Tr%'\n", + "GROUP BY name\n", + "ORDER BY total_count DESC" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2a17078", + "metadata": {}, "outputs": [], "source": [] }