Skip to content

Commit ac785fd

Browse files
committed
Merge branch 'main' into shuowei-gbq-delegation-telemetry-mvp
2 parents 814400e + 5d3ca44 commit ac785fd

318 files changed

Lines changed: 116493 additions & 14729 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/import-profiler.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@ jobs:
3232
TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref }}
3333
TEST_TYPE: import_profile
3434
PY_VERSION: "3.15"
35+
# Workaround: Allows libcst to compile on Python 3.15+ while PyO3 catches up
36+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
3537
run: |
3638
ci/run_conditional_tests.sh

librarian.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ version: v0.26.0
1616
repo: googleapis/google-cloud-python
1717
sources:
1818
googleapis:
19-
commit: 99f54e6513f09d8df1707a6c553b0a3c6ef9b5fb
20-
sha256: 7cee15fe1ae76a16aaf70425c4380a3a0fcbfeb4ea8e30c934c43f5cd54b9657
19+
commit: fe04226e3d76435acbfd3ffb51f6771740e1fb5b
20+
sha256: e99c641a9c5525394de43c762b9db50c3ada1f219d6dbdba594ae992fbe1d838
2121
default:
2222
output: packages
2323
tag_format: '{name}-v{version}'

packages/bigframes/tests/unit/display/test_anywidget.py

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ def test_navigation_to_invalid_page_resets_to_valid_page_without_deadlock():
4545
mock_df._block = mock_block
4646

4747
# We mock _initial_load to avoid complex setup
48-
with mock.patch.object(TableWidget, "_initial_load"):
49-
with bigframes.option_context(
48+
with (
49+
mock.patch.object(TableWidget, "_initial_load"),
50+
bigframes.option_context(
5051
"display.render_mode", "anywidget", "display.max_rows", 10
51-
):
52-
widget = TableWidget(mock_df)
52+
),
53+
):
54+
widget = TableWidget(mock_df)
5355

5456
# Simulate "loaded data but unknown total rows" state
5557
widget.page_size = 10
@@ -179,11 +181,11 @@ def test_page_size_change_resets_sort(mock_df):
179181

180182
def test_cell_execution_count_propagation(mock_df):
181183
"""Test that the captured cell_execution_count is propagated to to_pandas_batches."""
182-
with mock.patch(
183-
"bigframes.core.utils.get_ipython_execution_count", return_value=42
184+
with (
185+
mock.patch("bigframes.core.utils.get_ipython_execution_count", return_value=42),
186+
bigframes.option_context("display.render_mode", "anywidget"),
184187
):
185-
with bigframes.option_context("display.render_mode", "anywidget"):
186-
widget = TableWidget(mock_df)
188+
widget = TableWidget(mock_df)
187189

188190
assert widget._cell_execution_count == 42
189191

@@ -274,19 +276,23 @@ def __init__(self):
274276

275277

276278
def test_init_raises_if_anywidget_not_installed():
277-
with mock.patch("bigframes.display.anywidget._ANYWIDGET_INSTALLED", False):
278-
with pytest.raises(ImportError):
279-
from bigframes.display.anywidget import TableWidget
279+
with (
280+
mock.patch("bigframes.display.anywidget._ANYWIDGET_INSTALLED", False),
281+
pytest.raises(ImportError),
282+
):
283+
from bigframes.display.anywidget import TableWidget
280284

281-
TableWidget(mock.Mock())
285+
TableWidget(mock.Mock())
282286

283287

284288
def test_init_initializes_attributes(mock_df_deferred):
285289
from bigframes.display.anywidget import TableWidget
286290

287-
with bigframes.option_context("display.render_mode", "anywidget"):
288-
with mock.patch.object(TableWidget, "_initial_load"):
289-
widget = TableWidget(mock_df_deferred)
291+
with (
292+
bigframes.option_context("display.render_mode", "anywidget"),
293+
mock.patch.object(TableWidget, "_initial_load"),
294+
):
295+
widget = TableWidget(mock_df_deferred)
290296

291297
assert widget._dataframe is mock_df_deferred
292298
assert widget.page == 0
@@ -328,19 +334,21 @@ def test_validate_page_clamping(mock_df_deferred):
328334
def test_validate_page_size(mock_df_deferred):
329335
from bigframes.display.anywidget import TableWidget
330336

331-
with bigframes.option_context("display.render_mode", "anywidget"):
332-
with mock.patch.object(TableWidget, "_initial_load"):
333-
widget = TableWidget(mock_df_deferred)
337+
with (
338+
bigframes.option_context("display.render_mode", "anywidget"),
339+
mock.patch.object(TableWidget, "_initial_load"),
340+
):
341+
widget = TableWidget(mock_df_deferred)
334342

335-
widget.page_size = 50
336-
assert widget.page_size == 50
343+
widget.page_size = 50
344+
assert widget.page_size == 50
337345

338-
original_size = widget.page_size
339-
widget.page_size = -5
340-
assert widget.page_size == original_size
346+
original_size = widget.page_size
347+
widget.page_size = -5
348+
assert widget.page_size == original_size
341349

342-
widget.page_size = 10000
343-
assert widget.page_size == 1000
350+
widget.page_size = 10000
351+
assert widget.page_size == 1000
344352

345353

346354
def test_page_size_change_resets_page_and_sort(mock_df_deferred):
@@ -373,14 +381,16 @@ def test_page_size_change_resets_batches(mock_df_deferred):
373381
def test_sort_change_resets_batches(mock_df_deferred):
374382
from bigframes.display.anywidget import TableWidget
375383

376-
with bigframes.option_context("display.render_mode", "anywidget"):
377-
with mock.patch.object(TableWidget, "_initial_load"):
378-
widget = TableWidget(mock_df_deferred)
379-
widget._initial_load_complete = True
384+
with (
385+
bigframes.option_context("display.render_mode", "anywidget"),
386+
mock.patch.object(TableWidget, "_initial_load"),
387+
):
388+
widget = TableWidget(mock_df_deferred)
389+
widget._initial_load_complete = True
380390

381-
mock_df_deferred.to_pandas_batches.reset_mock()
391+
mock_df_deferred.to_pandas_batches.reset_mock()
382392

383-
widget.sort_context = [{"column": "B", "ascending": False}]
393+
widget.sort_context = [{"column": "B", "ascending": False}]
384394

385395
assert mock_df_deferred.to_pandas_batches.call_count >= 1
386396

@@ -510,22 +520,24 @@ def test_deferred_mode_execution_in_colab(mock_deferred_df, mock_df_deferred):
510520
batches.total_rows = 1
511521
mock_df_deferred.to_pandas_batches.return_value = batches
512522

513-
with mock.patch.dict(sys.modules, {"google.colab": mock.MagicMock()}):
514-
with bigframes.option_context("display.render_mode", "anywidget"):
515-
widget = TableWidget(mock_deferred_df)
516-
widget.is_deferred_mode = True
523+
with (
524+
mock.patch.dict(sys.modules, {"google.colab": mock.MagicMock()}),
525+
bigframes.option_context("display.render_mode", "anywidget"),
526+
):
527+
widget = TableWidget(mock_deferred_df)
528+
widget.is_deferred_mode = True
517529

518-
widget.start_execution = True
530+
widget.start_execution = True
519531

520-
thread = getattr(widget, "_execution_thread", None)
521-
if thread is not None:
522-
thread.join(timeout=5)
532+
thread = getattr(widget, "_execution_thread", None)
533+
if thread is not None:
534+
thread.join(timeout=5)
523535

524-
assert widget.is_deferred_mode is True
525-
assert widget.table_html == ""
536+
assert widget.is_deferred_mode is True
537+
assert widget.table_html == ""
526538

527-
# Simulate frontend ping callback
528-
widget.ping = 1
539+
# Simulate frontend ping callback
540+
widget.ping = 1
529541

530-
assert widget.is_deferred_mode is False
531-
assert widget.table_html != ""
542+
assert widget.is_deferred_mode is False
543+
assert widget.table_html != ""

packages/bigframes/tests/unit/display/test_html.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -203,19 +203,20 @@ def test_repr_mimebundle_head():
203203
)
204204

205205
# Mock _get_obj_metadata
206-
with patch("bigframes.display.html._get_obj_metadata", return_value=(False, False)):
207-
# Mock create_html_representation and create_text_representation
208-
with patch(
206+
with (
207+
patch("bigframes.display.html._get_obj_metadata", return_value=(False, False)),
208+
patch(
209209
"bigframes.display.html.create_html_representation", return_value="<html>"
210-
) as mock_create_html:
211-
with patch(
212-
"bigframes.display.plaintext.create_text_representation",
213-
return_value="text",
214-
) as mock_create_text:
215-
bundle = bf_html.repr_mimebundle_head(mock_df)
216-
217-
assert bundle == {"text/html": "<html>", "text/plain": "text"}
218-
mock_df._prepare_display_df.assert_called_once()
219-
mock_df._block.retrieve_repr_request_results.assert_called_once()
220-
mock_create_html.assert_called_once()
221-
mock_create_text.assert_called_once()
210+
) as mock_create_html,
211+
patch(
212+
"bigframes.display.plaintext.create_text_representation",
213+
return_value="text",
214+
) as mock_create_text,
215+
):
216+
bundle = bf_html.repr_mimebundle_head(mock_df)
217+
218+
assert bundle == {"text/html": "<html>", "text/plain": "text"}
219+
mock_df._prepare_display_df.assert_called_once()
220+
mock_df._block.retrieve_repr_request_results.assert_called_once()
221+
mock_create_html.assert_called_once()
222+
mock_create_text.assert_called_once()

packages/bigframes/tests/unit/display/test_render_mode.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
import unittest.mock as mock
1616

17+
import pytest
18+
1719
import bigframes.display.html as bf_html
1820
import bigframes.pandas as bpd
1921

@@ -62,7 +64,10 @@ def test_repr_mimebundle_selection_logic():
6264

6365
# Test fallback to static deferred repr when anywidget fails
6466
mock_anywidget.side_effect = Exception("Anywidget failed")
65-
with bpd.option_context("display.repr_mode", "deferred"):
67+
with (
68+
bpd.option_context("display.repr_mode", "deferred"),
69+
pytest.warns(UserWarning, match="Anywidget mode is not available"),
70+
):
6671
bundle = bf_html.repr_mimebundle(mock_obj)
6772
assert bundle == {"text/plain": "deferred"}
6873
mock_deferred.assert_called_once()

packages/google-api-core/google/api_core/operations_v1/__init__.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,68 @@
1414

1515
"""Package for interacting with the google.longrunning.operations meta-API."""
1616

17-
from google.api_core.operations_v1.abstract_operations_client import AbstractOperationsClient
18-
from google.api_core.operations_v1.operations_async_client import OperationsAsyncClient
19-
from google.api_core.operations_v1.operations_client import OperationsClient
20-
from google.api_core.operations_v1.transports.rest import OperationsRestTransport
17+
import importlib.util
18+
from typing import Set
19+
20+
try:
21+
_has_async_rest = (
22+
importlib.util.find_spec("google.auth.aio.transport.sessions") is not None
23+
)
24+
except ModuleNotFoundError:
25+
_has_async_rest = False
26+
27+
# PEP 0810: Explicit Lazy Imports
28+
# Python 3.15+ natively intercepts and defers these imports.
29+
# Developers can disable this behavior and force eager imports.
30+
# For more information, see:
31+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
32+
# Older Python versions safely ignore this variable.
33+
# NOTE: We statically define all modules here (including async ones) to ensure
34+
# static analysis tools (mypy, pyright, Ruff) can easily parse them. If async
35+
# support is not present, the imports are ignored, making their presence safe.
36+
__lazy_modules__: Set[str] = {
37+
"google.api_core.operations_v1.abstract_operations_client",
38+
"google.api_core.operations_v1.operations_async_client",
39+
"google.api_core.operations_v1.operations_client",
40+
"google.api_core.operations_v1.transports.rest",
41+
"google.api_core.operations_v1.transports.rest_asyncio",
42+
"google.api_core.operations_v1.operations_rest_client_async",
43+
}
2144

2245
__all__ = [
2346
"AbstractOperationsClient",
2447
"OperationsAsyncClient",
2548
"OperationsClient",
26-
"OperationsRestTransport"
49+
"OperationsRestTransport",
2750
]
2851

29-
try:
30-
from google.api_core.operations_v1.transports.rest_asyncio import (
31-
AsyncOperationsRestTransport,
32-
)
33-
from google.api_core.operations_v1.operations_rest_client_async import AsyncOperationsRestClient
34-
35-
__all__ += ["AsyncOperationsRestClient", "AsyncOperationsRestTransport"]
36-
except ImportError:
37-
# This import requires the `async_rest` extra.
38-
# Don't raise an exception if `AsyncOperationsRestTransport` cannot be imported
39-
# as other transports are still available.
40-
pass
52+
53+
from google.api_core.operations_v1.abstract_operations_client import ( # noqa: E402
54+
AbstractOperationsClient,
55+
)
56+
from google.api_core.operations_v1.operations_async_client import ( # noqa: E402
57+
OperationsAsyncClient,
58+
)
59+
from google.api_core.operations_v1.operations_client import ( # noqa: E402
60+
OperationsClient,
61+
)
62+
from google.api_core.operations_v1.transports.rest import ( # noqa: E402
63+
OperationsRestTransport,
64+
)
65+
66+
if _has_async_rest:
67+
try:
68+
# On Python 3.15+, PEP 0810 lazy loading means these imports will succeed
69+
# instantly (returning a lazy proxy). Any actual ImportErrors (e.g., due to
70+
# missing aiohttp/auth dependencies) are deferred until the proxies are accessed.
71+
from google.api_core.operations_v1.transports.rest_asyncio import ( # noqa: E402, F401
72+
AsyncOperationsRestTransport,
73+
)
74+
from google.api_core.operations_v1.operations_rest_client_async import ( # noqa: E402, F401
75+
AsyncOperationsRestClient,
76+
)
77+
78+
__all__.extend(["AsyncOperationsRestClient", "AsyncOperationsRestTransport"])
79+
except ImportError:
80+
# Fallback for older python/environments when importlib find_spec succeeds but actual import fails
81+
pass

packages/google-apps-chat/google/apps/chat/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
UploadAttachmentRequest,
4444
UploadAttachmentResponse,
4545
)
46+
from google.apps.chat_v1.types.audience import Audience
4647
from google.apps.chat_v1.types.availability import (
4748
Availability,
4849
CustomStatus,
@@ -199,6 +200,7 @@
199200
"GetAttachmentRequest",
200201
"UploadAttachmentRequest",
201202
"UploadAttachmentResponse",
203+
"Audience",
202204
"Availability",
203205
"CustomStatus",
204206
"DoNotDisturbMetadata",

packages/google-apps-chat/google/apps/chat_v1/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
UploadAttachmentRequest,
4646
UploadAttachmentResponse,
4747
)
48+
from .types.audience import Audience
4849
from .types.availability import (
4950
Availability,
5051
CustomStatus,
@@ -271,6 +272,7 @@ def _get_version(dependency_name):
271272
"AttachedGif",
272273
"Attachment",
273274
"AttachmentDataRef",
275+
"Audience",
274276
"Availability",
275277
"CalendarEventLinkData",
276278
"CardWithId",

packages/google-apps-chat/google/apps/chat_v1/services/chat_service/async_client.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,27 @@ async def sample_update_space():
25352535
``access_settings.audience`` is not supported with
25362536
``useAdminAccess``.
25372537
2538+
``access_settings.access_permission_settings``: Updates
2539+
the `access permission
2540+
settings <https://support.google.com/chat/answer/11971020>`__
2541+
of who can discover and join the space where
2542+
``spaceType`` field is ``SPACE``. Principals allowed to
2543+
join the space must also be allowed to discover it. To
2544+
update access permission settings for a space, the
2545+
authenticating user must be a space manager or assistant
2546+
manager and omit all other field masks in the request.
2547+
You can't update this field if the space is in `import
2548+
mode <https://developers.google.com/workspace/chat/import-data-overview>`__.
2549+
To learn more, see `Make a space discoverable to
2550+
specific
2551+
users <https://developers.google.com/workspace/chat/space-target-audience>`__.
2552+
``access_settings.access_permission_settings`` is not
2553+
supported with ``useAdminAccess``. The supported field
2554+
masks include:
2555+
2556+
- ``access_settings.access_permission_settings.discoverSpaceSetting``
2557+
- ``access_settings.access_permission_settings.joinSpaceSetting``
2558+
25382559
``permission_settings``: Supports changing the
25392560
`permission
25402561
settings <https://support.google.com/chat/answer/13340792>`__

0 commit comments

Comments
 (0)