From 055784c28e87803309c68e31f55073e62275562d Mon Sep 17 00:00:00 2001 From: Wayne Manselle Date: Wed, 22 Nov 2023 19:35:22 -0800 Subject: [PATCH] Pretty printers working --- src/grpc_requests/client.py | 9 +++-- src/grpc_requests/utils.py | 55 ++++++++++++++++++++--------- src/tests/reflection_client_test.py | 16 +++++++-- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/grpc_requests/client.py b/src/grpc_requests/client.py index b39bcf3..6dbb8b7 100644 --- a/src/grpc_requests/client.py +++ b/src/grpc_requests/client.py @@ -308,12 +308,15 @@ def get_service_descriptor(self, service): return self._desc_pool.FindServiceByName(service) def describe_method_request(self, service, method): - warnings.warn("This function is deprecated, and will be removed in a future release. Use describe_request() instead.", DeprecationWarning) + warnings.warn( + "This function is deprecated, and will be removed in a future release. Use describe_request() instead.", + DeprecationWarning + ) return describe_request(self.get_method_descriptor(service, method)) - + def describe_request(self, service, method): return describe_descriptor(self.get_method_descriptor(service, method).input_type) - + def describe_response(self, service, method): return describe_descriptor(self.get_method_descriptor(service, method).output_type) diff --git a/src/grpc_requests/utils.py b/src/grpc_requests/utils.py index 26573d8..41e3607 100644 --- a/src/grpc_requests/utils.py +++ b/src/grpc_requests/utils.py @@ -1,5 +1,5 @@ from pathlib import Path -from google.protobuf.descriptor import Descriptor, MethodDescriptor +from google.protobuf.descriptor import Descriptor, EnumDescriptor, MethodDescriptor, OneofDescriptor import warnings @@ -37,38 +37,61 @@ def describe_request(method_descriptor: MethodDescriptor) -> dict: :param method_descriptor: MethodDescriptor :return: dict - a mapping of field names to their types """ - warnings.warn("This function is deprecated, and will be removed in a future release. Use describe_descriptor() instead.", DeprecationWarning) + warnings.warn( + "This function is deprecated, and will be removed in a future release. Use describe_descriptor() instead.", + DeprecationWarning + ) description = {} for field in method_descriptor.input_type.fields: description[field.name] = FIELD_TYPES[field.type-1] return description -def describe_descriptor(descriptor: Descriptor) -> str: +def describe_descriptor(descriptor: Descriptor, indent: int = 0) -> str: """ Prints a human readable description of a protobuf descriptor. :param descriptor: Descriptor - a protobuf descriptor :return: str - a human readable description of the descriptor """ - description = descriptor.full_name + description = descriptor.name + padding = "\t" * indent if descriptor.enum_types: - description += "\nEnums:" + description += f"\n{padding}Enums:" for enum in descriptor.enum_types: - description += f"\n{enum.name}: {enum.values}" + description += describe_enum_descriptor(enum, indent+1) if descriptor.fields: - description += "\nFields:" + description += f"\n{padding}Fields:" for field in descriptor.fields: - description += f"\n{field.name}: {FIELD_TYPES[field.type-1]}" - - if descriptor.nested_types: - description += "\nNested Types:" - for nested_type in descriptor.nested_types: - description += f"\n{nested_type.name}" + description += f"\n\t{padding}{field.name}: {FIELD_TYPES[field.type-1]}" if descriptor.oneofs: - description += "\nOneofs:" + description += f"\n{padding}Oneofs:" for oneof in descriptor.oneofs: - description += f"\n{oneof.name}" + description += describe_oneof_descriptor(oneof, indent+1) + + return description + +def describe_enum_descriptor(enum_descriptor: EnumDescriptor, indent: int = 0) -> str: + """ + Prints a human readable description of a protobuf enum descriptor. + :param enum_descriptor: EnumDescriptor - a protobuf enum descriptor + :return: str - a human readable description of the enum descriptor + """ + padding = "\t" * indent + description = f"\n{padding}{enum_descriptor.name}:" + for value in enum_descriptor.values: + description += f"\n{padding}{value.name} = {value.number}" + return description - return description \ No newline at end of file +def describe_oneof_descriptor(oneof_descriptor: OneofDescriptor, indent: int = 0) -> str: + """ + Prints a human readable description of a protobuf oneof descriptor. + :param oneof_descriptor: OneofDescriptor - a protobuf oneof descriptor + :return: str - a human readable description of the oneof descriptor + """ + padding = "\t" * indent + description = f"\n{padding}{oneof_descriptor.name}:" + for field in oneof_descriptor.fields: + description += f"\n{padding}{field.name}: {FIELD_TYPES[field.type-1]}" + return description diff --git a/src/tests/reflection_client_test.py b/src/tests/reflection_client_test.py index 833b621..adc1d2f 100644 --- a/src/tests/reflection_client_test.py +++ b/src/tests/reflection_client_test.py @@ -50,12 +50,24 @@ def test_describe_method_request(client_tester_reflection_client): def test_describe_request(client_tester_reflection_client): request_description = \ client_tester_reflection_client.describe_request('client_tester.ClientTester', 'TestUnaryUnary') - assert request_description == 'client_tester.ClientTester.TestUnaryUnaryRequest' + expected_request_description = """TestRequest +Fields: +\tfactor: INT32 +\treadings: FLOAT +\tuuid: UINT64 +\tsample_flag: BOOL +\trequest_name: STRING +\textra_data: BYTES""" + assert request_description == expected_request_description def test_describe_response(client_tester_reflection_client): request_description = \ client_tester_reflection_client.describe_response('client_tester.ClientTester', 'TestUnaryUnary') - assert request_description == 'client_tester.ClientTester.TestUnaryUnaryResponse' + expected_response_description = """TestResponse +Fields: +\taverage: DOUBLE +\tfeedback: STRING""" + assert request_description == expected_response_description def test_empty_body_request(helloworld_reflection_client): response = helloworld_reflection_client.request('helloworld.Greeter', 'SayHello', {})