Im working on a gRPC microservice.
Because every method has to load a JSON string from the request
argument first – and then in the end dump it again, I want to use a decorator on the methods of the class, so that the method itself besides the return
only contains the ... more stuff to do ...
below:
class VPPSetupService(SetupService_pb2_grpc.VPPSetupServiceServicer):
...
def method(self, request, context):
request = json.loads(request.context)
request = request["request"]
header = request["headers"]
... more stuff to do ...
response = json.dumps(response)
return SetupService_pb2.JsonContextResponse(context=response)
So I wrote a decorator function. However, I could not find a solution for this error:
request = json.loads(request.context)
UnboundLocalError: local variable 'request' referenced before assignment
The error is produced by this: (Just as an example, the real thing is a bit more complex)
from functools import wraps
def json_and_error(func):
@wraps(func)
def args_wrapper(*args, **kwargs): # Problem: This
request = json.loads(request.context) <<# variable is referenced
request = request["request"] # before assignment
header = request["headers"]
func(*args, **kwargs)
return func(*args, **kwargs)
return args_wrapper
class VPPSetupService(SetupService_pb2_grpc.VPPSetupServiceServicer):
...
@json_and_error
def method(self, request, context):
... more stuff to do ...
return SetupService_pb2.JsonContextResponse(context=response)
I tried using request = json.loads(args[1].context)
instead. But then I get this error:
if request["source_machine"] and request["dest_machine"]: TypeError:
'JsonContextRequest' object is not subscriptable
The input given as request
argument is an object of type <class 'SetupService_pb2.JsonContextRequest'>
The JSON String in the request would be accessible through the request.context
attribute.
I'm thinking the problem is related to how the decorator function is being called. I suppose if it was called at runtime of the class method the variable request should already have been assigned the request object.
But maybe I'm completely wrong here. So how would you solve this?
There are few errors in your code:
def args_wrapper(*args, **kwargs):
request = json.loads(request.context)
You're using request.context
while request
variable is undefined (it will be defined only after json.loads(request.context)
will be executed). You tried to fix it using request = json.loads(args[1].context)
, but got JsonContextRequest object is not subscriptable
in wrapped function. Look at this line closer:
return func(*args, **kwargs)
You decorator returns wrapped function called with the same params, so this code result isn't used, you don't pass request and header to wrapped function:
request = json.loads(request.context)
request = request["request"]
header = request["headers"]
Also you shouldn't call wrapped function:
func(*args, **kwargs)
I guess you want to do something like this:
def json_and_error(func):
def args_wrapper(this, request):
context = request.context
request = json.loads(context)
request = request["request"]
return func(this, request, context)
return args_wrapper