Skip to content

Commit 5b4b250

Browse files
committed
render bigquery sent events
1 parent 70d8324 commit 5b4b250

File tree

2 files changed

+83
-78
lines changed

2 files changed

+83
-78
lines changed

bigframes/formatting_helpers.py

Lines changed: 83 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from __future__ import annotations
1818

1919
import datetime
20+
import html
2021
import random
2122
from typing import Any, Optional, Type, TYPE_CHECKING, Union
2223

@@ -26,7 +27,6 @@
2627
import humanize
2728
import IPython
2829
import IPython.display as display
29-
import ipywidgets as widgets
3030

3131
if TYPE_CHECKING:
3232
import bigframes.core.events
@@ -62,39 +62,6 @@ def create_exception_with_feedback_link(
6262
return exception(constants.FEEDBACK_LINK)
6363

6464

65-
def repr_query_job_html(query_job: Optional[bigquery.QueryJob]):
66-
"""Return query job in html format.
67-
Args:
68-
query_job (bigquery.QueryJob, Optional):
69-
The job representing the execution of the query on the server.
70-
Returns:
71-
Pywidget html table.
72-
"""
73-
if query_job is None:
74-
return display.HTML("No job information available")
75-
if query_job.dry_run:
76-
return display.HTML(
77-
f"Computation deferred. Computation will process {get_formatted_bytes(query_job.total_bytes_processed)}"
78-
)
79-
table_html = "<style> td {text-align: left;}</style>"
80-
table_html += "<table>"
81-
for key, value in query_job_prop_pairs.items():
82-
job_val = getattr(query_job, value)
83-
if job_val is not None:
84-
if key == "Job Id": # add link to job
85-
table_html += f"""<tr><td>{key}</td><td><a target="_blank" href="{get_job_url(query_job)}">{job_val}</a></td></tr>"""
86-
elif key == "Slot Time":
87-
table_html += (
88-
f"""<tr><td>{key}</td><td>{get_formatted_time(job_val)}</td></tr>"""
89-
)
90-
elif key == "Bytes Processed":
91-
table_html += f"""<tr><td>{key}</td><td>{get_formatted_bytes(job_val)}</td></tr>"""
92-
else:
93-
table_html += f"""<tr><td>{key}</td><td>{job_val}</td></tr>"""
94-
table_html += "</table>"
95-
return widgets.HTML(table_html)
96-
97-
9865
def repr_query_job(query_job: Optional[bigquery.QueryJob]):
9966
"""Return query job as a formatted string.
10067
Args:
@@ -113,7 +80,11 @@ def repr_query_job(query_job: Optional[bigquery.QueryJob]):
11380
if job_val is not None:
11481
res += "\n"
11582
if key == "Job Id": # add link to job
116-
res += f"""Job url: {get_job_url(query_job)}"""
83+
res += f"""Job url: {get_job_url(
84+
project_id=query_job.project,
85+
location=query_job.location,
86+
job_id=query_job.job_id,
87+
)}"""
11788
elif key == "Slot Time":
11889
res += f"""{key}: {get_formatted_time(job_val)}"""
11990
elif key == "Bytes Processed":
@@ -125,14 +96,14 @@ def repr_query_job(query_job: Optional[bigquery.QueryJob]):
12596

12697
current_display: Optional[display.HTML] = None
12798
current_display_id: Optional[str] = None
128-
previous_message: str = ""
99+
previous_display_html: str = ""
129100

130101

131102
def progress_callback(
132103
event: bigframes.core.events.Event,
133104
):
134105
"""Displays a progress bar while the query is running"""
135-
global current_display, current_display_id
106+
global current_display, current_display_id, previous_display_html
136107

137108
import bigframes._config
138109
import bigframes.core.events
@@ -148,28 +119,31 @@ def progress_callback(
148119
or current_display is None
149120
or current_display_id is None
150121
):
122+
previous_display_html = ""
151123
current_display_id = str(random.random())
152124
current_display = display.HTML("Starting execution.")
153125
display.display(
154126
current_display,
155127
display_id=current_display_id,
156128
)
157129

158-
if isinstance(event, bigframes.core.events.ExecutionRunning):
130+
if isinstance(event, bigframes.core.events.BigQuerySentEvent):
131+
previous_display_html = render_bqquery_sent_event_html(event)
159132
display.update_display(
160-
display.HTML("Execution happening."),
133+
display.HTML(previous_display_html),
161134
display_id=current_display_id,
162135
)
163136
elif isinstance(event, bigframes.core.events.ExecutionFinished):
164137
display.update_display(
165-
display.HTML(f"{previous_message} Execution done."),
138+
display.HTML(f"{previous_display_html} Execution done."),
166139
display_id=current_display_id,
167140
)
168141
elif progress_bar == "terminal":
169142
if isinstance(event, bigframes.core.events.ExecutionStarted):
170143
print("Starting execution.")
171-
elif isinstance(event, bigframes.core.events.ExecutionRunning):
172-
print("Execution happening.")
144+
elif isinstance(event, bigframes.core.events.BigQuerySentEvent):
145+
message = render_bqquery_sent_event_plaintext(event)
146+
print(message)
173147
elif isinstance(event, bigframes.core.events.ExecutionFinished):
174148
print("Execution done.")
175149

@@ -222,43 +196,84 @@ def wait_for_job(job: GenericJob, progress_bar: Optional[str] = None):
222196
raise
223197

224198

225-
def get_job_url(query_job: GenericJob):
199+
def get_job_url(
200+
*,
201+
project_id: Optional[str],
202+
location: Optional[str],
203+
job_id: Optional[str],
204+
):
226205
"""Return url to the query job in cloud console.
227-
Args:
228-
query_job (GenericJob):
229-
The job representing the execution of the query on the server.
206+
230207
Returns:
231208
String url.
232209
"""
233-
if (
234-
query_job.project is None
235-
or query_job.location is None
236-
or query_job.job_id is None
237-
):
210+
if project_id is None or location is None or job_id is None:
238211
return None
239-
return f"""https://console.cloud.google.com/bigquery?project={query_job.project}&j=bq:{query_job.location}:{query_job.job_id}&page=queryresults"""
212+
return f"""https://console.cloud.google.com/bigquery?project={project_id}&j=bq:{location}:{job_id}&page=queryresults"""
240213

241214

242-
def get_query_job_loading_html(query_job: bigquery.QueryJob):
215+
def render_bqquery_sent_event_html(
216+
event: bigframes.core.events.BigQuerySentEvent,
217+
) -> str:
243218
"""Return progress bar html string
244219
Args:
245220
query_job (bigquery.QueryJob):
246221
The job representing the execution of the query on the server.
247222
Returns:
248223
Html string.
249224
"""
250-
return f"""Query job {query_job.job_id} is {query_job.state}. {get_bytes_processed_string(query_job.total_bytes_processed)}<a target="_blank" href="{get_job_url(query_job)}">Open Job</a>"""
251225

226+
job_url = get_job_url(
227+
project_id=event.billing_project,
228+
location=event.location,
229+
job_id=event.job_id,
230+
)
231+
if job_url:
232+
job_link = f'<a target="_blank" href="{job_url}">Open Job</a>'
233+
else:
234+
job_link = ""
235+
236+
query_id = ""
237+
if event.job_id:
238+
query_id = f" with job ID {event.job_id}:{event.billing_project}.{event.job_id}"
239+
elif event.request_id:
240+
query_id = f" with request ID {event.job_id}:{event.billing_project}.{event.request_id}"
241+
242+
query_text_details = f"<details><summary>SQL</summary><pre>{html.escape(event.query)}</pre></details>"
243+
244+
return f"""
245+
Query started{query_id}.{job_link}{query_text_details}
246+
"""
252247

253-
def get_query_job_loading_string(query_job: bigquery.QueryJob):
254-
"""Return progress bar string
248+
249+
def render_bqquery_sent_event_plaintext(
250+
event: bigframes.core.events.BigQuerySentEvent,
251+
) -> str:
252+
"""Return progress bar html string
255253
Args:
256254
query_job (bigquery.QueryJob):
257255
The job representing the execution of the query on the server.
258256
Returns:
259-
String
257+
Html string.
260258
"""
261-
return f"""Query job {query_job.job_id} is {query_job.state}.{get_bytes_processed_string(query_job.total_bytes_processed)} \n{get_job_url(query_job)}"""
259+
260+
job_url = get_job_url(
261+
project_id=event.billing_project,
262+
location=event.location,
263+
job_id=event.job_id,
264+
)
265+
if job_url:
266+
job_link = f" Open job: {job_url}"
267+
else:
268+
job_link = ""
269+
270+
query_id = ""
271+
if event.job_id:
272+
query_id = f" with job ID {event.job_id}:{event.billing_project}.{event.job_id}"
273+
elif event.request_id:
274+
query_id = f" with request ID {event.job_id}:{event.billing_project}.{event.request_id}"
275+
276+
return f"Query started{query_id}.{job_link}"
262277

263278

264279
def get_base_job_loading_html(job: GenericJob):
@@ -269,7 +284,11 @@ def get_base_job_loading_html(job: GenericJob):
269284
Returns:
270285
Html string.
271286
"""
272-
return f"""{job.job_type.capitalize()} job {job.job_id} is {job.state}. <a target="_blank" href="{get_job_url(job)}">Open Job</a>"""
287+
return f"""{job.job_type.capitalize()} job {job.job_id} is {job.state}. <a target="_blank" href="{get_job_url(
288+
project_id=job.job_id,
289+
location=job.location,
290+
job_id=job.job_id,
291+
)}">Open Job</a>"""
273292

274293

275294
def get_base_job_loading_string(job: GenericJob):
@@ -280,7 +299,11 @@ def get_base_job_loading_string(job: GenericJob):
280299
Returns:
281300
String
282301
"""
283-
return f"""{job.job_type.capitalize()} job {job.job_id} is {job.state}. \n{get_job_url(job)}"""
302+
return f"""{job.job_type.capitalize()} job {job.job_id} is {job.state}. \n{get_job_url(
303+
project_id=job.job_id,
304+
location=job.location,
305+
job_id=job.job_id,
306+
)}"""
284307

285308

286309
def get_formatted_time(val):

tests/system/small/test_progress_bar.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,6 @@ def assert_loading_msg_exist(capystOut: str, pattern=job_load_message_regex):
115115
assert numLoadingMsg > 0
116116

117117

118-
def test_query_job_repr_html(penguins_df_default_index: bf.dataframe.DataFrame):
119-
with bf.option_context("display.progress_bar", "terminal"):
120-
penguins_df_default_index.to_pandas(allow_large_results=True)
121-
query_job_repr = formatting_helpers.repr_query_job_html(
122-
penguins_df_default_index.query_job
123-
).value
124-
125-
string_checks = [
126-
"Job Id",
127-
"Destination Table",
128-
"Slot Time",
129-
"Bytes Processed",
130-
"Cache hit",
131-
]
132-
for string in string_checks:
133-
assert string in query_job_repr
134-
135-
136118
def test_query_job_repr(penguins_df_default_index: bf.dataframe.DataFrame):
137119
penguins_df_default_index.to_pandas(allow_large_results=True)
138120
query_job_repr = formatting_helpers.repr_query_job(

0 commit comments

Comments
 (0)