Prevent generated RPC methods from being shadowed by ServiceStub parameters#225
Open
gaoflow wants to merge 1 commit into
Open
Prevent generated RPC methods from being shadowed by ServiceStub parameters#225gaoflow wants to merge 1 commit into
gaoflow wants to merge 1 commit into
Conversation
A generated RPC method is a class-level method on the ServiceStub subclass.
When its snake_cased name collides with a base __init__ parameter (e.g. an
RPC named Metadata -> metadata), the base class stored that parameter as an
instance attribute, which takes precedence over the class method on lookup.
Calling the RPC then raised TypeError ('dict'/'NoneType' object is not
callable).
Store channel/timeout/deadline/metadata under private names and expose them
through read-only properties. A subclass RPC method now overrides the base
property in the MRO, while non-colliding access still returns the parameter.
Fixes betterproto#224.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #224.
Problem
Generated RPC methods are class-level methods on the
ServiceStubsubclass.ServiceStub.__init__stored itschannel/timeout/deadline/metadataparameters as plain instance attributes. When a generated RPC's snake_cased name collides with one of those names — e.g. an RPC literally namedMetadatabecomesmetadata— the instance attribute shadows the class method, since instance attributes take precedence over class methods during attribute lookup. Calling the RPC then fails withTypeError: 'dict' object is not callable(or'NoneType' object is not callablewhen no metadata was passed).Fix
Store the four constructor parameters under private names (
self._channel, etc.) and expose them through read-only@propertyaccessors. A subclass method now overrides the base property in the MRO, so a colliding RPC method is reachable again. Non-colliding access (stub.channel,stub.metadata, …) still returns the parameter value exactly as before, so this is backwards compatible for normal reads. The properties are read-only; the parameters were never reassigned after__init__, so nothing in the codebase relied on writing to them.Tests
Added
tests/grpc/test_service_stub_attributes.py:test_rpc_method_not_shadowed_by_constructor_param— aServiceStubsubclass defining an asyncmetadatamethod (the colliding RPC); asserts the method is still callable and returns its own result. Fails before the change (metadataresolves to the dict), passes after.test_constructor_params_exposed_as_properties— assertschannel/timeout/deadline/metadataproperties return the values passed to__init__.