Skip to content

Commit c6ef52c

Browse files
authored
chore: add experimental series.blob.display() function (#1232)
1 parent 9dc166a commit c6ef52c

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

bigframes/core/compile/scalar_op_compiler.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,8 +1212,13 @@ def json_extract_string_array_op_impl(
12121212

12131213
# Blob Ops
12141214
@scalar_op_compiler.register_unary_op(ops.obj_fetch_metadata_op)
1215-
def obj_fetch_metadata_op_impl(x: ibis_types.Value):
1216-
return obj_fetch_metadata(obj_ref=x)
1215+
def obj_fetch_metadata_op_impl(obj_ref: ibis_types.Value):
1216+
return obj_fetch_metadata(obj_ref=obj_ref)
1217+
1218+
1219+
@scalar_op_compiler.register_unary_op(ops.ObjGetAccessUrl, pass_op=True)
1220+
def obj_get_access_url_op_impl(obj_ref: ibis_types.Value, op: ops.ObjGetAccessUrl):
1221+
return obj_get_access_url(obj_ref=obj_ref, mode=op.mode)
12171222

12181223

12191224
### Binary Ops
@@ -1917,3 +1922,8 @@ def obj_fetch_metadata(obj_ref: _OBJ_REF_IBIS_DTYPE) -> _OBJ_REF_IBIS_DTYPE: #
19171922
@ibis_udf.scalar.builtin(name="OBJ.MAKE_REF")
19181923
def obj_make_ref(uri: str, authorizer: str) -> _OBJ_REF_IBIS_DTYPE: # type: ignore
19191924
"""Make ObjectRef Struct from uri and connection."""
1925+
1926+
1927+
@ibis_udf.scalar.builtin(name="OBJ.GET_ACCESS_URL")
1928+
def obj_get_access_url(obj_ref: _OBJ_REF_IBIS_DTYPE, mode: ibis_dtypes.String) -> ibis_dtypes.JSON: # type: ignore
1929+
"""Get access url (as ObjectRefRumtime JSON) from ObjectRef."""

bigframes/operations/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,16 @@ def output_type(self, *input_types):
740740
)
741741

742742

743+
## Blob Ops
744+
@dataclasses.dataclass(frozen=True)
745+
class ObjGetAccessUrl(UnaryOp):
746+
name: typing.ClassVar[str] = "obj_get_access_url"
747+
mode: str # access mode, e.g. R read, W write, RW read & write
748+
749+
def output_type(self, *input_types):
750+
return dtypes.JSON_DTYPE
751+
752+
743753
# Binary Ops
744754
fillna_op = create_binary_op(name="fillna", type_signature=op_typing.COERCE)
745755
maximum_op = create_binary_op(name="maximum", type_signature=op_typing.COERCE)

bigframes/operations/blob.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414

1515
from __future__ import annotations
1616

17-
import bigframes
17+
import IPython.display as ipy_display
18+
import requests
19+
1820
from bigframes.operations import base
1921
import bigframes.operations as ops
22+
import bigframes.series
2023

2124

2225
class BlobAccessor(base.SeriesMethods):
@@ -26,7 +29,7 @@ def __init__(self, *args, **kwargs):
2629

2730
super().__init__(*args, **kwargs)
2831

29-
def metadata(self):
32+
def metadata(self) -> bigframes.series.Series:
3033
"""Retrive the metadata of the Blob.
3134
3235
.. note::
@@ -37,7 +40,29 @@ def metadata(self):
3740
details_json = self._apply_unary_op(ops.obj_fetch_metadata_op).struct.field(
3841
"details"
3942
)
40-
4143
import bigframes.bigquery as bbq
4244

4345
return bbq.json_extract(details_json, "$.gcs_metadata")
46+
47+
def display(self, n: int = 3):
48+
"""Display the blob content in the IPython Notebook environment. Only works for image type now.
49+
50+
.. note::
51+
BigFrames Blob is still under experiments. It may not work and subject to change in the future.
52+
53+
Args:
54+
n (int, default 3): number of sample blob objects to display.
55+
"""
56+
import bigframes.bigquery as bbq
57+
58+
s = bigframes.series.Series(self._block).head(n)
59+
60+
obj_ref_runtime = s._apply_unary_op(ops.ObjGetAccessUrl(mode="R"))
61+
read_urls = bbq.json_extract(
62+
obj_ref_runtime, json_path="$.access_urls.read_url"
63+
)
64+
65+
for read_url in read_urls:
66+
read_url = str(read_url).strip('"')
67+
response = requests.get(read_url)
68+
ipy_display.display(ipy_display.Image(response.content))

0 commit comments

Comments
 (0)