Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions packages/gapic-generator/gapic/schema/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,12 @@ def resource_messages(self) -> Mapping[str, wrappers.MessageType]:
if msg.options.Extensions[resource_pb2.resource].type
)
return collections.OrderedDict(
itertools.chain(
file_resource_messages,
resource_messages,
sorted(
Comment thread
ohmayr marked this conversation as resolved.
itertools.chain(
file_resource_messages,
resource_messages,
),
key=lambda item: item[0]
)
)

Expand Down
11 changes: 9 additions & 2 deletions packages/gapic-generator/gapic/schema/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2278,7 +2278,7 @@ 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."""

Expand All @@ -2301,7 +2301,7 @@ def gen_indirect_resources_used(message):
if resource:
yield resource

return frozenset(
unique_messages = frozenset(
msg
for method in self.methods.values()
for msg in chain(
Expand All @@ -2316,6 +2316,13 @@ def gen_indirect_resources_used(message):
)
)

sorted_messages = sorted(
Comment thread
ohmayr marked this conversation as resolved.
unique_messages,
key=lambda m: m.resource_type_full_path or m.name
)
Comment on lines +2321 to +2324
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current sorting key m.resource_type_full_path or m.name may not guarantee deterministic ordering if multiple messages share the same resource type path or if a message name conflicts with a resource type path. Since the input is a frozenset (which is unordered), any tie in the sort key will result in non-deterministic output order across different runs.

Consider using a tuple as a sort key to provide a consistent tie-breaker, such as (m.resource_type_full_path or "", m.name).

Suggested change
sorted_messages = sorted(
unique_messages,
key=lambda m: m.resource_type_full_path or m.name
)
sorted_messages = sorted(
unique_messages,
key=lambda m: (m.resource_type_full_path or "", m.name)
)
References
  1. To ensure dictionary keys remain sorted without manual effort, programmatically sort the dictionary before returning it instead of relying on manual ordering in the code.


return tuple(sorted_messages)

@utils.cached_property
def resource_messages_dict(self) -> Dict[str, MessageType]:
"""Returns a dict from resource reference to
Expand Down
16 changes: 8 additions & 8 deletions packages/gapic-generator/tests/unit/schema/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1740,17 +1740,17 @@ def test_file_level_resources():
expected = collections.OrderedDict(
(
(
"nomenclature.linnaen.com/Species",
"nomenclature.linnaen.com/Phylum",
wrappers.CommonResource(
type_name="nomenclature.linnaen.com/Species",
pattern="families/{family}/genera/{genus}/species/{species}",
type_name="nomenclature.linnaen.com/Phylum",
pattern="kingdoms/{kingdom}/phyla/{phylum}",
).message_type,
),
(
"nomenclature.linnaen.com/Phylum",
"nomenclature.linnaen.com/Species",
wrappers.CommonResource(
type_name="nomenclature.linnaen.com/Phylum",
pattern="kingdoms/{kingdom}/phyla/{phylum}",
type_name="nomenclature.linnaen.com/Species",
pattern="families/{family}/genera/{genus}/species/{species}",
).message_type,
),
)
Expand All @@ -1767,7 +1767,7 @@ def test_file_level_resources():
# The service doesn't own any method that owns a message that references
# Phylum, so the service doesn't count it among its resource messages.
expected.pop("nomenclature.linnaen.com/Phylum")
expected = frozenset(expected.values())
expected = tuple(expected.values())
actual = service.resource_messages

assert actual == expected
Expand Down Expand Up @@ -1822,7 +1822,7 @@ def test_resources_referenced_but_not_typed(reference_attr="type"):
name_resource_opts.child_type = species_resource_opts.type

api_schema = api.API.build([fdp], package="nomenclature.linneaen.v1")
expected = {api_schema.messages["nomenclature.linneaen.v1.Species"]}
expected = (api_schema.messages["nomenclature.linneaen.v1.Species"],)
actual = api_schema.services[
"nomenclature.linneaen.v1.SpeciesService"
].resource_messages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,12 @@ def test_resource_messages():
),
)

expected = {
squid_resource,
expected = (
clam_resource,
whelk_resource,
squamosa_message,
}
squid_resource,
whelk_resource,
)
actual = service.resource_messages
assert expected == actual

Expand Down Expand Up @@ -557,7 +557,7 @@ def test_resource_response():
),
)

expected = {squid_resource, clam_resource}
expected = (clam_resource, squid_resource)
actual = mollusc_service.resource_messages
assert expected == actual

Expand Down
Loading