-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add support for reading selective GAPIC generation methods from service YAML #2272
base: main
Are you sure you want to change the base?
Conversation
8f9db43
to
2274254
Compare
2274254
to
55d0cca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but holding off on formal approval until tomorrow after the next release is shipped
Requesting review from @vchudnov-g as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is looking good, but I have some questions/suggestions. PTAL.
gapic/schema/api.py
Outdated
@@ -237,6 +237,69 @@ def disambiguate(self, string: str) -> str: | |||
return self.disambiguate(f'_{string}') | |||
return string | |||
|
|||
def build_address_allowlist_for_selective_gapic(self, *, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In our code base (including comments), I would use a clearer name that "selective GAPIC"; I find it a bit of a misnomer. We're not selecting the GAPIC; we're selecting the RPCs to create a custom (non-standard) GAPIC. So I would have us choose one of selective_generation
or custom_gapic
and use that as the affix consistently everywhere, instead of selective_gapic
.
gapic/schema/api.py
Outdated
@@ -237,6 +237,69 @@ def disambiguate(self, string: str) -> str: | |||
return self.disambiguate(f'_{string}') | |||
return string | |||
|
|||
def build_address_allowlist_for_selective_gapic(self, *, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I've not seen the word address
used in this context and I wish we weren't using it, but I see it's prior art already in use. Oh, well)
gapic/schema/api.py
Outdated
} | ||
|
||
# For messages and enums we should only be pruning them from all_messages if they | ||
# are proto plus types. This should apply to the Protos we are pruning from, but might |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"but might not in the future."
WDYM? This seems cryptic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we trying to move away from proto plus types? I'll remove the "in the future part" regardless
|
||
# We only prune services/messages/enums from protos that are not depepdencies. | ||
for name, proto in api.all_protos.items(): | ||
if name not in api.protos: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it mean for a proto to be in api.all_protos
but not in api.protos
? (I'm not familiar with this part of the codebase)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definition here:
gapic-generator-python/gapic/schema/api.py
Lines 406 to 417 in e050f4e
def protos(self) -> Mapping[str, Proto]: | |
"""Return a map of all protos specific to this API. | |
This property excludes imported protos that are dependencies | |
of this API but not being directly generated. | |
""" | |
view = self.subpackage_view | |
return collections.OrderedDict([ | |
(k, v) for k, v in self.all_protos.items() | |
if v.file_to_generate and | |
v.meta.address.subpackage[:len(view)] == view | |
]) |
Here I'm trying to prune only the proto objects corresponding to the files in this API package.
gapic/schema/wrappers.py
Outdated
if self.extended_lro: | ||
# We need to add the service/method pointed to by self.operation_service to | ||
# the allowlist, as it might not have been specified by selective_gapic_generation. | ||
# We assume that the operation service lives in the same proto as this one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a good assumption? (I honestly don't know.) Will it work with operation mixins?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to make this assumption, otherwise the lookups won't work. The precedent for this is here where the Proto
object is built:
gapic-generator-python/gapic/schema/api.py
Lines 1238 to 1250 in e050f4e
def _maybe_get_extended_lro( | |
self, | |
service_address: metadata.Address, | |
meth_pb: descriptor_pb2.MethodDescriptorProto, | |
) -> Optional[wrappers.ExtendedOperationInfo]: | |
op_service_name = meth_pb.options.Extensions[ex_ops_pb2.operation_service] | |
if not op_service_name: | |
return None | |
# Manual lookups because services and methods haven't been loaded. | |
# Note: this assumes that the operation service lives in the same proto file. | |
# This is a reasonable assumption as of March '22, but it may (unlikely) | |
# change in the future. |
for method in self.methods.values(): | ||
if method.ident.proto in method_names: | ||
# Include this service if there are any types/methods in selective gapic for this service. | ||
address_allowlist.add(self.meta.address) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this allow-listing this service it it has any methods at all, not just allowlisted ones?
Should the logic be something like this pseudocode?
for method in self.methods.values():
if method in allowlist:
allowlist.add(self)
allowlist.add(method)
method.build_allowlist()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method_names
is the allowlist. I'll make that clearer by renaming it to method_allowlist
or method_names_allowlist
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this file, it seems to me that the build_address_allowlist
name is descriptive for the method you're adding to the Service
class, but the other classes should have their new methods names something like add_to_address_allowlist
, to emphasize that they themselves are not checking for the RPC allowlist in the YAML, but are being included transitively. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me.
Co-authored-by: Victor Chudnovsky <[email protected]>
Co-authored-by: Victor Chudnovsky <[email protected]>
Co-authored-by: Victor Chudnovsky <[email protected]>
This PR implements Selective GAPIC generation for Python. For more details, see:
Overall design doc: go/selective-gapic-generation
Implementation doc for Python: go/selective-gapic-gen-python