gapic-generator-python
gapic-generator-python copied to clipboard
samplegen maximum recursion error when recursive message in oneof
To reproduce with version 1.11.9:
- Add the following to
tests/fragments
:
# tests/fragments/test_recursive_messages_oneof.proto
syntax = "proto3";
package google.fragment;
import "google/api/client.proto";
service MyService {
option (google.api.default_host) = "my.example.com";
rpc MyMethod(MethodRequest) returns (MethodResponse) {}
}
message MethodRequest {
oneof request {
MethodRequest child = 1;
string data = 2;
}
}
message MethodResponse {}
- Run
nox -s fragment-3.7 -- tests/fragments/test_recursive_messages_oneof.proto
. - The test fails with
RecursionError: maximum recursion depth exceeded while calling a Python object
. The recursion happens at this line: https://github.com/googleapis/gapic-generator-python/blob/v1.11.9/gapic/samplegen/samplegen.py#L992, around which the previous maintainer of samplegen.py included a warning and a possible solution.
The error only occurs when there is a oneof
whose first field is recursive. Variants of the fragment proto that do not result in the same error:
- If there is no
oneof
. - If there is no recursion.
- If there are mutual/multiple recursions where at least one recursion is not the first field in a
oneof
. - If the recursion does not occur in the first field belonging to the
oneof
. Here "first" refers to the proto file's represenation, and not the field ID number.
Another way the same issue occurs is when a recursive message is marked REQUIRED
:
# tests/fragments/test_recursive_messages_required.proto
syntax = "proto3";
package google.fragment;
import "google/api/client.proto";
import "google/api/field_behavior.proto";
service MyService {
option (google.api.default_host) = "my.example.com";
rpc MyMethod(MethodRequest) returns (MethodResponse) {}
}
message MethodRequest {
MethodRequest child = 1 [(google.api.field_behavior) = REQUIRED];
}
message MethodResponse {}
To be sure, this proto fragment is unusable since a MethodRequest
message (that conforms to the field_behavior
) can never be constructed.
In both cases (oneof
and REQUIRED
), the issue is that the same message type could recursively appear in request_fields
(https://github.com/googleapis/gapic-generator-python/blob/v1.11.11/gapic/samplegen/samplegen.py#L965). The fix should be to exclude message types that have already appeared when populating the sample request message used in the generated snippets.