Summary
DisciplineServer.GetInfo is written as a generator (yield), but the proto declares GetInfo as a unary RPC. gRPC cannot serialize a generator into a DisciplineProperties, so the call fails for every caller — including Philote-Python's own client.
Reproduction
from concurrent import futures
import grpc, philote_mdo.general as pmdo
from philote_mdo.examples import Paraboloid
server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
pmdo.ExplicitServer(discipline=Paraboloid()).attach_to_server(server)
server.add_insecure_port("[::]:50079"); server.start()
client = pmdo.ExplicitClient(channel=grpc.insecure_channel("localhost:50079"))
client.get_discipline_info()
Actual:
StatusCode.INTERNAL | Failed to serialize response!
Expected: the discipline's properties, with _is_continuous / _is_differentiable / _provides_gradients populated on the client.
Cause
The proto declares a unary response:
// proto/disciplines.proto:36
rpc GetInfo(google.protobuf.Empty) returns (philote.DisciplineProperties) {}
The servicer yields instead of returning, so gRPC receives a generator object where it expects a message:
# philote_mdo/general/discipline_server.py:67
def GetInfo(self, request, context):
yield data.DisciplineProperties( # <-- should be `return`
continuous=self._discipline._is_continuous,
...
)
The client mirrors the same misunderstanding and indexes the response as if it were a stream:
# philote_mdo/general/discipline_client.py:79
response = self._disc_stub.GetInfo(empty.Empty())
self._is_continuous = response[0].continuous # <-- should be response.continuous
Both sides need changing together: with the server fixed, response[0] raises TypeError: 'DisciplineProperties' object is not subscriptable.
Why CI doesn't catch this
tests/test_discipline_client.py:67 patches the stub and hands back a list, so the test asserts against the mock's shape rather than the server's:
mock_stub.GetInfo.return_value = [
data.DisciplineProperties(continuous=True, differentiable=True, provides_gradients=True)
]
Nothing exercises GetInfo against a real server. examples/parabaloid_client.py and examples/quadratic_client.py never call get_discipline_info(), which is why the examples all pass.
Suggested fix
discipline_server.py:67 — yield → return.
discipline_client.py:79-81 — drop the [0] indexing.
- Update the mock in
tests/test_discipline_client.py:72 to return the message rather than a list, and ideally add an end-to-end check against a real server so the two sides can't drift again.
Related
Also worth noting: DisciplineProperties.name and .version are never populated by the server, so even once this is fixed a client gets empty strings for both.
Found while implementing Philote-Rust against the same proto; a spec-conforming unary client hits this immediately on connect.
Environment: Philote-Python 0.8.0 @ 1f3baf6, proto v0.8.0.
Summary
DisciplineServer.GetInfois written as a generator (yield), but the proto declaresGetInfoas a unary RPC. gRPC cannot serialize a generator into aDisciplineProperties, so the call fails for every caller — including Philote-Python's own client.Reproduction
Actual:
Expected: the discipline's properties, with
_is_continuous/_is_differentiable/_provides_gradientspopulated on the client.Cause
The proto declares a unary response:
// proto/disciplines.proto:36 rpc GetInfo(google.protobuf.Empty) returns (philote.DisciplineProperties) {}The servicer yields instead of returning, so gRPC receives a generator object where it expects a message:
The client mirrors the same misunderstanding and indexes the response as if it were a stream:
Both sides need changing together: with the server fixed,
response[0]raisesTypeError: 'DisciplineProperties' object is not subscriptable.Why CI doesn't catch this
tests/test_discipline_client.py:67patches the stub and hands back a list, so the test asserts against the mock's shape rather than the server's:Nothing exercises
GetInfoagainst a real server.examples/parabaloid_client.pyandexamples/quadratic_client.pynever callget_discipline_info(), which is why the examples all pass.Suggested fix
discipline_server.py:67—yield→return.discipline_client.py:79-81— drop the[0]indexing.tests/test_discipline_client.py:72to return the message rather than a list, and ideally add an end-to-end check against a real server so the two sides can't drift again.Related
Also worth noting:
DisciplineProperties.nameand.versionare never populated by the server, so even once this is fixed a client gets empty strings for both.Found while implementing Philote-Rust against the same proto; a spec-conforming unary client hits this immediately on connect.
Environment: Philote-Python 0.8.0 @
1f3baf6, proto v0.8.0.