-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[WIP] Experiment deterministic resource names #16569
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
base: main
Are you sure you want to change the base?
Changes from 6 commits
84ee2f3
c5aa36d
627e377
19bc3e3
380ce06
b69d1e4
8249847
840b265
42e0527
5849780
3551fc7
46146df
80d0dd9
4f36ef0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "id": "google-cloud-dialogflow", | ||
| "version": "2.47.0", | ||
| "apis": [ | ||
| { | ||
| "path": "google/cloud/dialogflow/v2beta1", | ||
| "service_config": "dialogflow_v2beta1.yaml" | ||
| }, | ||
| { | ||
| "path": "google/cloud/dialogflow/v2", | ||
| "service_config": "dialogflow_v2.yaml" | ||
| } | ||
| ], | ||
| "source_roots": [ | ||
| "packages/google-cloud-dialogflow" | ||
| ], | ||
| "preserve_regex": [ | ||
| "packages/google-cloud-dialogflow/CHANGELOG.md", | ||
| "docs/CHANGELOG.md" | ||
| ], | ||
| "remove_regex": [ | ||
| "packages/google-cloud-dialogflow/" | ||
| ], | ||
| "tag_format": "{id}-v{version}" | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -157,7 +157,7 @@ def messages(self) -> Mapping[str, wrappers.MessageType]: | |||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @cached_property | ||||||||||||||||||||||||||||||||
| def resource_messages(self) -> Mapping[str, wrappers.MessageType]: | ||||||||||||||||||||||||||||||||
| """Return the file level resources of the proto.""" | ||||||||||||||||||||||||||||||||
| """Return the file level resources of the proto in a deterministic order.""" | ||||||||||||||||||||||||||||||||
| file_resource_messages = ( | ||||||||||||||||||||||||||||||||
| (res.type, wrappers.CommonResource.build(res).message_type) | ||||||||||||||||||||||||||||||||
| for res in self.file_pb2.options.Extensions[ | ||||||||||||||||||||||||||||||||
|
|
@@ -169,10 +169,12 @@ def resource_messages(self) -> Mapping[str, wrappers.MessageType]: | |||||||||||||||||||||||||||||||
| for msg in self.messages.values() | ||||||||||||||||||||||||||||||||
| if msg.options.Extensions[resource_pb2.resource].type | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # Sort the chained generator by the resource path (item[0]) to ensure determinism | ||||||||||||||||||||||||||||||||
| return collections.OrderedDict( | ||||||||||||||||||||||||||||||||
| itertools.chain( | ||||||||||||||||||||||||||||||||
| file_resource_messages, | ||||||||||||||||||||||||||||||||
| resource_messages, | ||||||||||||||||||||||||||||||||
| sorted( | ||||||||||||||||||||||||||||||||
| itertools.chain(file_resource_messages, resource_messages), | ||||||||||||||||||||||||||||||||
| key=lambda item: item[0] | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
Comment on lines
172
to
180
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In modern Python (3.7+), the standard
Suggested change
References
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2240,6 +2240,46 @@ def oauth_scopes(self) -> Sequence[str]: | |
| for i in self.options.Extensions[client_pb2.oauth_scopes].split(",") | ||
| if i | ||
| ) | ||
|
|
||
| @utils.cached_property | ||
| def deterministic_resource_messages(self) -> Sequence[MessageType]: | ||
| """Returns a sorted sequence of resource messages to guarantee deterministic output order.""" | ||
| return tuple( | ||
| sorted( | ||
| self.resource_messages, | ||
| key=lambda r: r.resource_type_full_path or r.name | ||
| ) | ||
| ) | ||
|
||
|
|
||
| @utils.cached_property | ||
| def resource_path_method_names(self) -> Dict[str, str]: | ||
| """Returns a mapping of resource_type_full_path to its disambiguated Python method base name.""" | ||
| import collections | ||
| from gapic import utils | ||
|
||
|
|
||
| type_counts = collections.Counter( | ||
| r.resource_type for r in self.resource_messages_dict.values() if r.resource_type | ||
| ) | ||
|
|
||
| method_names = {} | ||
| for full_path, resource in self.resource_messages_dict.items(): | ||
| if not resource.resource_type: | ||
| continue | ||
|
|
||
| base_name = utils.to_snake_case(resource.resource_type) | ||
|
|
||
| # Collision detection | ||
| if type_counts[resource.resource_type] > 1: | ||
| domain = full_path.split(".")[0] | ||
|
|
||
| # THE MAGIC FIX: Only prefix if the resource belongs to a foreign API | ||
| if domain != self.shortname: | ||
| domain_prefix = domain.replace("-", "_") | ||
| base_name = f"{domain_prefix}_{base_name}" | ||
|
|
||
| method_names[full_path] = base_name | ||
|
|
||
| return method_names | ||
|
|
||
| @property | ||
| def module_name(self) -> str: | ||
|
|
@@ -2278,14 +2318,13 @@ def names(self) -> FrozenSet[str]: | |
| return frozenset(answer) | ||
|
|
||
| @utils.cached_property | ||
| def resource_messages(self) -> FrozenSet[MessageType]: | ||
| def resource_messages(self) -> Sequence[MessageType]: | ||
| """Returns all the resource message types used in all | ||
| request and response fields in the service.""" | ||
| request and response fields in the service in a deterministic order.""" | ||
|
|
||
| def gen_resources(message): | ||
| if message.resource_path: | ||
| yield message | ||
|
|
||
| for type_ in message.recursive_field_types: | ||
| if type_.resource_path: | ||
| yield type_ | ||
|
|
@@ -2294,14 +2333,12 @@ def gen_indirect_resources_used(message): | |
| for field in message.recursive_resource_fields: | ||
| resource = field.options.Extensions[resource_pb2.resource_reference] | ||
| resource_type = resource.type or resource.child_type | ||
| # The resource may not be visible if the resource type is one of | ||
| # the common_resources (see the class var in class definition) | ||
| # or if it's something unhelpful like '*'. | ||
| resource = self.visible_resources.get(resource_type) | ||
| if resource: | ||
| yield resource | ||
|
|
||
| return frozenset( | ||
| # Collect all resources into an unordered set to remove duplicates | ||
| unsorted_resources = set( | ||
| msg | ||
| for method in self.methods.values() | ||
| for msg in chain( | ||
|
|
@@ -2315,6 +2352,14 @@ def gen_indirect_resources_used(message): | |
| ), | ||
| ) | ||
| ) | ||
|
|
||
| # Return them deterministically sorted by their full path | ||
| return tuple( | ||
| sorted( | ||
| unsorted_resources, | ||
| key=lambda r: r.resource_type_full_path or r.name | ||
| ) | ||
| ) | ||
|
|
||
| @utils.cached_property | ||
| def resource_messages_dict(self) -> Dict[str, MessageType]: | ||
|
|
||
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.
The use of a hardcoded local absolute path (
-e /usr/local/google/...) will break the build for other developers and in CI/CD environments. Please revert this to a versioned dependency or a relative path if necessary for the experiment.