Skip to content

Commit d1f7343

Browse files
authored
Merge branch 'main' into owl-bot-update-lock-04c35dc5f49f0f503a306397d6d043685f8d2bb822ab515818c4208d7fb2db3a
2 parents 9c716d9 + 3a1a91c commit d1f7343

File tree

73 files changed

+23660
-12
lines changed

Some content is hidden

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

73 files changed

+23660
-12
lines changed

DEVELOPMENT.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,6 @@ Execute unit tests by running one of the sessions prefixed with `unit-`.
6060
bazel run //tests/integration:eventarc_update
6161
bazel run //tests/integration:logging_update
6262
bazel run //tests/integration:redis_update
63+
bazel run //tests/integration:redis_selective_update
6364
```
6465

gapic/schema/api.py

Lines changed: 151 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import os
2525
import sys
2626
from types import MappingProxyType
27-
from typing import Callable, Container, Dict, FrozenSet, Mapping, Optional, Sequence, Set, Tuple
27+
from typing import Callable, Container, Dict, FrozenSet, Iterable, Mapping, Optional, Sequence, Set, Tuple
2828
import yaml
2929

3030
from google.api_core import exceptions
@@ -237,6 +237,95 @@ def disambiguate(self, string: str) -> str:
237237
return self.disambiguate(f'_{string}')
238238
return string
239239

240+
def add_to_address_allowlist(self, *,
241+
address_allowlist: Set['metadata.Address'],
242+
method_allowlist: Set[str],
243+
resource_messages: Dict[str, 'wrappers.MessageType'],
244+
) -> None:
245+
"""Adds to the set of Addresses of wrapper objects to be included in selective GAPIC generation.
246+
247+
This method is used to create an allowlist of addresses to be used to filter out unneeded
248+
services, methods, messages, and enums at a later step.
249+
250+
Args:
251+
address_allowlist (Set[metadata.Address]): A set of allowlisted metadata.Address
252+
objects to add to. Only the addresses of the allowlisted methods, the services
253+
containing these methods, and messages/enums those methods use will be part of the
254+
final address_allowlist. The set may be modified during this call.
255+
method_allowlist (Set[str]): An allowlist of fully-qualified method names.
256+
resource_messages (Dict[str, wrappers.MessageType]): A dictionary mapping the unified
257+
resource type name of a resource message to the corresponding MessageType object
258+
representing that resource message. Only resources with a message representation
259+
should be included in the dictionary.
260+
Returns:
261+
None
262+
"""
263+
# The method.operation_service for an extended LRO is not fully qualified, so we
264+
# truncate the service names accordingly so they can be found in
265+
# method.add_to_address_allowlist
266+
services_in_proto = {
267+
service.name: service for service in self.services.values()
268+
}
269+
for service in self.services.values():
270+
service.add_to_address_allowlist(address_allowlist=address_allowlist,
271+
method_allowlist=method_allowlist,
272+
resource_messages=resource_messages,
273+
services_in_proto=services_in_proto)
274+
275+
def prune_messages_for_selective_generation(self, *,
276+
address_allowlist: Set['metadata.Address']) -> Optional['Proto']:
277+
"""Returns a truncated version of this Proto.
278+
279+
Only the services, messages, and enums contained in the allowlist
280+
of visited addresses are included in the returned object. If there
281+
are no services, messages, or enums left, and no file level resources,
282+
return None.
283+
284+
Args:
285+
address_allowlist (Set[metadata.Address]): A set of allowlisted metadata.Address
286+
objects to filter against. Objects with addresses not the allowlist will be
287+
removed from the returned Proto.
288+
Returns:
289+
Optional[Proto]: A truncated version of this proto. If there are no services, messages,
290+
or enums left after the truncation process and there are no file level resources,
291+
returns None.
292+
"""
293+
# Once the address allowlist has been created, it suffices to only
294+
# prune items at 2 different levels to truncate the Proto object:
295+
#
296+
# 1. At the Proto level, we remove unnecessary services, messages,
297+
# and enums.
298+
# 2. For allowlisted services, at the Service level, we remove
299+
# non-allowlisted methods.
300+
services = {
301+
k: v.prune_messages_for_selective_generation(
302+
address_allowlist=address_allowlist)
303+
for k, v in self.services.items()
304+
if v.meta.address in address_allowlist
305+
}
306+
307+
all_messages = {
308+
k: v
309+
for k, v in self.all_messages.items()
310+
if v.ident in address_allowlist
311+
}
312+
313+
all_enums = {
314+
k: v
315+
for k, v in self.all_enums.items()
316+
if v.ident in address_allowlist
317+
}
318+
319+
if not services and not all_messages and not all_enums:
320+
return None
321+
322+
return dataclasses.replace(
323+
self,
324+
services=services,
325+
all_messages=all_messages,
326+
all_enums=all_enums
327+
)
328+
240329

241330
@dataclasses.dataclass(frozen=True)
242331
class API:
@@ -365,10 +454,52 @@ def disambiguate_keyword_sanitize_fname(
365454
ignore_unknown_fields=True
366455
)
367456

368-
# Done; return the API.
369-
return cls(naming=naming,
370-
all_protos=protos,
371-
service_yaml_config=service_yaml_config)
457+
# Third pass for various selective GAPIC settings; these require
458+
# settings in the service.yaml and so we build the API object
459+
# before doing another pass.
460+
api = cls(naming=naming,
461+
all_protos=protos,
462+
service_yaml_config=service_yaml_config)
463+
464+
if package in api.all_library_settings:
465+
selective_gapic_methods = set(
466+
api.all_library_settings[package].python_settings.common.selective_gapic_generation.methods
467+
)
468+
if selective_gapic_methods:
469+
470+
all_resource_messages = collections.ChainMap(
471+
*(proto.resource_messages for proto in protos.values())
472+
)
473+
474+
# Prepare a list of addresses to include in selective generation,
475+
# then prune each Proto object. We look at metadata.Addresses, not objects, because
476+
# objects that refer to the same thing in the proto are different Python objects
477+
# in memory.
478+
address_allowlist: Set['metadata.Address'] = set([])
479+
for proto in api.protos.values():
480+
proto.add_to_address_allowlist(address_allowlist=address_allowlist,
481+
method_allowlist=selective_gapic_methods,
482+
resource_messages=all_resource_messages)
483+
484+
# The list of explicitly allow-listed protos to generate, plus all
485+
# the proto dependencies regardless of the allow-list.
486+
new_all_protos = {}
487+
488+
# We only prune services/messages/enums from protos that are not dependencies.
489+
for name, proto in api.all_protos.items():
490+
if name not in api.protos:
491+
new_all_protos[name] = proto
492+
else:
493+
proto_to_generate = proto.prune_messages_for_selective_generation(
494+
address_allowlist=address_allowlist)
495+
if proto_to_generate:
496+
new_all_protos[name] = proto_to_generate
497+
498+
api = cls(naming=naming,
499+
all_protos=new_all_protos,
500+
service_yaml_config=service_yaml_config)
501+
502+
return api
372503

373504
@cached_property
374505
def enums(self) -> Mapping[str, wrappers.EnumType]:
@@ -743,6 +874,21 @@ def enforce_valid_library_settings(
743874
continue
744875
versions_seen.add(library_settings.version)
745876

877+
# Check to see if selective gapic generation methods are valid.
878+
selective_gapic_errors = {}
879+
for method_name in library_settings.python_settings.common.selective_gapic_generation.methods:
880+
if method_name not in self.all_methods:
881+
selective_gapic_errors[method_name] = "Method does not exist."
882+
elif not method_name.startswith(library_settings.version):
883+
selective_gapic_errors[method_name] = "Mismatched version for method."
884+
885+
if selective_gapic_errors:
886+
all_errors[library_settings.version] = [
887+
{
888+
"selective_gapic_generation": selective_gapic_errors,
889+
}
890+
]
891+
746892
if all_errors:
747893
raise ClientLibrarySettingsError(yaml.dump(all_errors))
748894

0 commit comments

Comments
 (0)