Repository URL to install this package:
|
Version:
0.9.1 ▾
|
namara-python
/
method_generator.py
|
|---|
from namara_python.utils import to_camel_case
import namara_python.classes as cl
from namara_python.rpc.organizations.organizations_pb2_twirp import OrganizationsServiceClient
from namara_python.rpc.catalog.catalog_pb2_twirp import CatalogServiceClient
from namara_python.rpc.category.category_pb2_twirp import CategoryServiceClient
from namara_python.rpc.grants.grants_pb2_twirp import GrantsServiceClient
from namara_python.rpc.sources.sources_pb2_twirp import SourcesServiceClient
from namara_python.rpc.references.references_pb2_twirp import ReferencesServiceClient
# must import these so that they are available to the symbol database which
# registers all the rpc objects, which is required before method generation begins
import namara_python.rpc.organizations.organizations_pb2
import namara_python.rpc.catalog.catalog_pb2
import namara_python.rpc.category.category_pb2
import namara_python.rpc.grants.grants_pb2
import namara_python.rpc.sources.sources_pb2
import namara_python.rpc.references.references_pb2
import inspect
import json
from typing import Callable, Any
from google.protobuf.json_format import MessageToJson
from google.protobuf import symbol_database as _symbol_database
_sym_db = _symbol_database.Default()
RPC_CLIENT_TO_LIB_CLS_MAPPING = {
OrganizationsServiceClient: cl.Organization,
CatalogServiceClient: cl.Catalog,
CategoryServiceClient: cl.Category,
GrantsServiceClient: cl.Grant,
SourcesServiceClient: cl.Source,
ReferencesServiceClient: cl.Reference
}
TWIRP_FUNCTION = Callable[[Any, Any], Any]
def serialize_input(twirp_func:TWIRP_FUNCTION) -> TWIRP_FUNCTION:
def wrapper(self, *args, **kwargs):
input_obj_name = _get_input_object_name(twirp_func, self)
serialized_input_obj = _sym_db.GetSymbol(input_obj_name)(**kwargs)
# here self is an instance of NamaraPython.<class>, which all have
# `rpc_client` as an instance variable which points to the Twirp generated
# client object
return twirp_func(self.rpc_client, serialized_input_obj)
return wrapper
def deserialize_output(twirp_func:TWIRP_FUNCTION) -> TWIRP_FUNCTION:
def wrapper(self, *args, **kwargs):
resp = twirp_func(self, *args, **kwargs)
return json.loads(MessageToJson(resp))
return wrapper
def _get_input_object_name(twirp_func, namara_lib_instance):
''' This funtion will return a string of the form `<service_name>.<function_input_object>`
ie. `organizations.GetOrganizationReqeust`
It relies on _name_ of the second parameter of `twirp_func`.
This depends on parameter names being the same as the actual protofbuf objects
i.e get_organization_request, which camelized will give
GetOrganizationRequest, which is the correct input proto object for
`get_organization` method.
This will work as long the python twirp client generates the function
signatures in this manner (which is stable and shouldn't be a problem)
'''
input_obj_name = inspect.getargspec(twirp_func).args[1]
proper_input_name = to_camel_case(input_obj_name)
cls_name = type(namara_lib_instance.rpc_client).__name__
internal_var_name = '_' + cls_name + '__service_name'
service_name = getattr(namara_lib_instance.rpc_client, internal_var_name).split('.')[0]
return service_name + '.' + proper_input_name
# METHOD GENERATOR
for rpc_client, lib_cls in RPC_CLIENT_TO_LIB_CLS_MAPPING.items():
for func_name, twirp_func in rpc_client.__dict__.items():
if func_name.startswith('_'):
continue
# create decorators around the existing twirp functions to handle input
# and output in a pythonic way (ie. using python objects rather than Twirp objects)
new_func = deserialize_output(serialize_input(twirp_func))
setattr(lib_cls, func_name, new_func)