Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 0d0bfd7

Browse files
authored
Merge branch 'main' into fix-request-serialization
2 parents c16dc5d + ae0a9e8 commit 0d0bfd7

21 files changed

Lines changed: 504 additions & 35 deletions

File tree

.librarian/state.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:68c7c79adf43af1be4c0527673342dd180aebebf652ea623614eaebff924ca27
22
libraries:
33
- id: gapic-generator
4-
version: 1.30.4
4+
version: 1.30.5
55
last_generated_commit: ""
66
apis: []
77
source_roots:

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
[1]: https://pypi.org/project/gapic-generator/#history
66

7+
## [1.30.5](https://github.com/googleapis/gapic-generator-python/compare/v1.30.4...v1.30.5) (2026-01-26)
8+
9+
10+
### Bug Fixes
11+
12+
* fix mypy for services with extended operations methods (#2536) ([84667d1b55a5dd895585ae40cbd32b2925ecf8e8](https://github.com/googleapis/gapic-generator-python/commit/84667d1b55a5dd895585ae40cbd32b2925ecf8e8))
13+
714
## [1.30.4](https://github.com/googleapis/gapic-generator-python/compare/v1.30.3...v1.30.4) (2026-01-20)
815

916

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{% macro sphinx_imports() -%}
2+
import logging
3+
from typing import Any
4+
{%- endmacro %}
5+
6+
{% macro sphinx_setup() -%}
7+
class UnexpectedUnindentFilter(logging.Filter):
8+
"""Filter out warnings about unexpected unindentation following bullet lists."""
9+
10+
def filter(self, record: logging.LogRecord) -> bool:
11+
"""Filter the log record.
12+
13+
Args:
14+
record (logging.LogRecord): The log record.
15+
16+
Returns:
17+
bool: False to suppress the warning, True to allow it.
18+
"""
19+
msg = record.getMessage()
20+
if "Bullet list ends without a blank line" in msg:
21+
return False
22+
return True
23+
24+
25+
def setup(app: Any) -> None:
26+
"""Setup the Sphinx application.
27+
28+
Args:
29+
app (Any): The Sphinx application.
30+
"""
31+
# Sphinx's logger is hierarchical. Adding a filter to the
32+
# root 'sphinx' logger will catch warnings from all sub-loggers.
33+
logger = logging.getLogger('sphinx')
34+
logger.addFilter(UnexpectedUnindentFilter())
35+
{%- endmacro %}

gapic/ads-templates/docs/conf.py.j2

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{% extends '_base.py.j2' %}
22

33
{% block content %}
4+
{% from "docs/common_setup.py.j2" import sphinx_imports, sphinx_setup %}
45

56
#
67
# {{ api.naming.warehouse_package_name }} documentation build configuration file
@@ -14,9 +15,11 @@
1415
# All configuration values have a default; values that are commented out
1516
# serve to show the default.
1617

17-
import sys
18+
import logging
1819
import os
1920
import shlex
21+
import sys
22+
{{ sphinx_imports() }}
2023

2124
# If extensions (or modules to document with autodoc) are in another directory,
2225
# add these directories to sys.path here. If the directory is relative to the
@@ -361,4 +364,7 @@ napoleon_use_admonition_for_references = False
361364
napoleon_use_ivar = False
362365
napoleon_use_param = True
363366
napoleon_use_rtype = True
367+
368+
# Setup for sphinx behaviors such as warning filters.
369+
{{ sphinx_setup() }}
364370
{% endblock %}

gapic/cli/generate.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from gapic import generator
2424
from gapic.schema import api
2525
from gapic.utils import Options
26+
from gapic.utils.cache import generation_cache_context
2627

2728

2829
@click.command()
@@ -56,15 +57,23 @@ def generate(request: typing.BinaryIO, output: typing.BinaryIO) -> None:
5657
[p.package for p in req.proto_file if p.name in req.file_to_generate]
5758
).rstrip(".")
5859

59-
# Build the API model object.
60-
# This object is a frozen representation of the whole API, and is sent
61-
# to each template in the rendering step.
62-
api_schema = api.API.build(req.proto_file, opts=opts, package=package)
60+
# Create the generation cache context.
61+
# This provides the shared storage for the @cached_proto_context decorator.
62+
# 1. Performance: Memoizes `with_context` calls, speeding up generation significantly.
63+
# 2. Safety: The decorator uses this storage to "pin" Proto objects in memory.
64+
# This prevents Python's Garbage Collector from deleting objects created during
65+
# `API.build` while `Generator.get_response` is still using their IDs.
66+
# (See `gapic.utils.cache.cached_proto_context` for the specific pinning logic).
67+
with generation_cache_context():
68+
# Build the API model object.
69+
# This object is a frozen representation of the whole API, and is sent
70+
# to each template in the rendering step.
71+
api_schema = api.API.build(req.proto_file, opts=opts, package=package)
6372

64-
# Translate into a protobuf CodeGeneratorResponse; this reads the
65-
# individual templates and renders them.
66-
# If there are issues, error out appropriately.
67-
res = generator.Generator(opts).get_response(api_schema, opts)
73+
# Translate into a protobuf CodeGeneratorResponse; this reads the
74+
# individual templates and renders them.
75+
# If there are issues, error out appropriately.
76+
res = generator.Generator(opts).get_response(api_schema, opts)
6877

6978
# Output the serialized response.
7079
output.write(res.SerializeToString())

gapic/schema/metadata.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from gapic.schema import imp
3636
from gapic.schema import naming
3737
from gapic.utils import cached_property
38+
from gapic.utils import cached_proto_context
3839
from gapic.utils import RESERVED_NAMES
3940

4041
# This class is a minor hack to optimize Address's __eq__ method.
@@ -359,6 +360,7 @@ def resolve(self, selector: str) -> str:
359360
return f'{".".join(self.package)}.{selector}'
360361
return selector
361362

363+
@cached_proto_context
362364
def with_context(self, *, collisions: Set[str]) -> "Address":
363365
"""Return a derivative of this address with the provided context.
364366
@@ -398,6 +400,7 @@ def doc(self):
398400
return "\n\n".join(self.documentation.leading_detached_comments)
399401
return ""
400402

403+
@cached_proto_context
401404
def with_context(self, *, collisions: Set[str]) -> "Metadata":
402405
"""Return a derivative of this metadata with the provided context.
403406

gapic/schema/wrappers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767

6868
from gapic import utils
6969
from gapic.schema import metadata
70+
from gapic.utils import cached_proto_context
7071
from gapic.utils import uri_sample
7172
from gapic.utils import make_private
7273

@@ -410,6 +411,7 @@ def type(self) -> Union["MessageType", "EnumType", "PrimitiveType"]:
410411
"This code should not be reachable; please file a bug."
411412
)
412413

414+
@cached_proto_context
413415
def with_context(
414416
self,
415417
*,
@@ -805,6 +807,7 @@ def get_field(
805807
# message.
806808
return cursor.message.get_field(*field_path[1:], collisions=collisions)
807809

810+
@cached_proto_context
808811
def with_context(
809812
self,
810813
*,
@@ -937,6 +940,7 @@ def ident(self) -> metadata.Address:
937940
"""Return the identifier data to be used in templates."""
938941
return self.meta.address
939942

943+
@cached_proto_context
940944
def with_context(self, *, collisions: Set[str]) -> "EnumType":
941945
"""Return a derivative of this enum with the provided context.
942946
@@ -1058,6 +1062,7 @@ class ExtendedOperationInfo:
10581062
request_type: MessageType
10591063
operation_type: MessageType
10601064

1065+
@cached_proto_context
10611066
def with_context(
10621067
self,
10631068
*,
@@ -1127,6 +1132,7 @@ class OperationInfo:
11271132
response_type: MessageType
11281133
metadata_type: MessageType
11291134

1135+
@cached_proto_context
11301136
def with_context(
11311137
self,
11321138
*,
@@ -1937,6 +1943,7 @@ def void(self) -> bool:
19371943
"""Return True if this method has no return value, False otherwise."""
19381944
return self.output.ident.proto == "google.protobuf.Empty"
19391945

1946+
@cached_proto_context
19401947
def with_context(
19411948
self,
19421949
*,
@@ -2357,6 +2364,7 @@ def operation_polling_method(self) -> Optional[Method]:
23572364
def is_internal(self) -> bool:
23582365
return any(m.is_internal for m in self.methods.values())
23592366

2367+
@cached_proto_context
23602368
def with_context(
23612369
self,
23622370
*,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{% macro sphinx_imports() -%}
2+
import logging
3+
from typing import Any
4+
{%- endmacro %}
5+
6+
{% macro sphinx_setup() -%}
7+
class UnexpectedUnindentFilter(logging.Filter):
8+
"""Filter out warnings about unexpected unindentation following bullet lists."""
9+
10+
def filter(self, record: logging.LogRecord) -> bool:
11+
"""Filter the log record.
12+
13+
Args:
14+
record (logging.LogRecord): The log record.
15+
16+
Returns:
17+
bool: False to suppress the warning, True to allow it.
18+
"""
19+
msg = record.getMessage()
20+
if "Bullet list ends without a blank line" in msg:
21+
return False
22+
return True
23+
24+
25+
def setup(app: Any) -> None:
26+
"""Setup the Sphinx application.
27+
28+
Args:
29+
app (Any): The Sphinx application.
30+
"""
31+
# Sphinx's logger is hierarchical. Adding a filter to the
32+
# root 'sphinx' logger will catch warnings from all sub-loggers.
33+
logger = logging.getLogger('sphinx')
34+
logger.addFilter(UnexpectedUnindentFilter())
35+
{%- endmacro %}

gapic/templates/docs/conf.py.j2

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% extends '_base.py.j2' %}
22

33
{% block content %}
4-
4+
{% from "docs/common_setup.py.j2" import sphinx_imports, sphinx_setup %}
55
#
66
# {{ api.naming.warehouse_package_name }} documentation build configuration file
77
#
@@ -14,9 +14,11 @@
1414
# All configuration values have a default; values that are commented out
1515
# serve to show the default.
1616

17-
import sys
17+
import logging
1818
import os
1919
import shlex
20+
import sys
21+
{{ sphinx_imports() }}
2022

2123
# If extensions (or modules to document with autodoc) are in another directory,
2224
# add these directories to sys.path here. If the directory is relative to the
@@ -372,4 +374,7 @@ napoleon_use_admonition_for_references = False
372374
napoleon_use_ivar = False
373375
napoleon_use_param = True
374376
napoleon_use_rtype = True
377+
378+
# Setup for sphinx behaviors such as warning filters.
379+
{{ sphinx_setup() }}
375380
{% endblock %}

gapic/utils/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
from gapic.utils.cache import cached_property
16+
from gapic.utils.cache import cached_proto_context
1617
from gapic.utils.case import to_snake_case
1718
from gapic.utils.case import to_camel_case
1819
from gapic.utils.checks import is_msg_field_pb
@@ -34,6 +35,7 @@
3435

3536
__all__ = (
3637
"cached_property",
38+
"cached_proto_context",
3739
"convert_uri_fieldnames",
3840
"doc",
3941
"empty",

0 commit comments

Comments
 (0)