13

I am just getting started with gRPC and have tried to implement a simple python service after going through the starter guides. But when I invoke my client call python is asking for a context argument to be provided. Why does my code need to supply a context object when it was not needed in the examples?

P.S. I started trying to create my own concrete context subclass but wasn't sure how it should be implemented. I've added my start to it but if possible would really appreciate an example to work from

Thanks!

Protofile

syntax = "proto2";

package parsefile;

service ParseFile {
  rpc SendFile (File) returns (Empty) {}
}

message File {

  message MetaData {
    optional string file_name = 1;
    optional string file_path = 2 [default = '.'];
    optional string mime_type = 3 [default = 'application/pdf'];
  }

  message Source {
    optional string title = 1;
    optional int32 id = 2;
  }

  optional MetaData document = 1;
  optional Source supplier = 2;
}

message Empty {
}

Server

from concurrent import futures
import time

import grpc

import parsefile_pb2_grpc
import parsefile_pb2

_ONE_DAY_IN_SECONDS = 60 * 60 * 24

class ParseFileServicer(parsefile_pb2_grpc.ParseFileServicer):

    def SendFile(self, request, context):
        supplier = request.supplier.title
        file_name = request.document.file_name
        print('Received {} from {}'.format(file_name, supplier))
        return parsefile_pb2.Empty()

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=2))
    parsefile_pb2_grpc.add_ParseFileServicer_to_server(
        ParseFileServicer, server)
    server.add_insecure_port('[::]:50051')
    server.start()
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        server.stop(0)

if __name__ == '__main__':
    serve()

Client

import grpc

import parsefile_pb2_grpc
import parsefile_pb2

def get_file_info():
    return parsefile_pb2.File(
        document = parsefile_pb2.File.MetaData(
            file_name = 'example.txt'
        ),
        supplier = parsefile_pb2.File.Source(
            title = 'Example Supplier'
        )
    )

def run():
    channel = grpc.insecure_channel('localhost:50051')
    stub = parsefile_pb2_grpc.ParseFileStub(channel)
    context = RequestContext()
    print('object created')
    response = stub.SendFile(get_file_info())
    print('File info sent to server')

if __name__ == '__main__':
    run()

Error Trace

Traceback (most recent call last):   File "parse_client.py", line 60, in <module>
    run()   File "parse_client.py", line 56, in run
    response = stub.SendFile(get_file_info(), 2)   File "/Users/davidbowe/.virtualenvs/post/lib/python3.6/site-packages/grpc/_channel.py", line 507, in __call__
    return _end_unary_response_blocking(state, call, False, deadline)   File "/Users/davidbowe/.virtualenvs/post/lib/python3.6/site-packages/grpc/_channel.py", line 455, in _end_unary_response_bl ocking
    raise _Rendezvous(state, None, None, deadline) grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with (StatusCode.UNKNOWN, Exception calling application: SendF ile() missing 1 required positional argument: 'context')>
user7815551
  • 206
  • 1
  • 2
  • 6
  • 1
    Can you provide the exact error that you are seeing? – murgatroid99 Apr 04 '17 at 22:54
  • 2
    In `parsefile_pb2_grpc.add_ParseFileServicer_to_server(ParseFileServicer, server)` I think it's a mistake that you're passing the ParseFileServicer class object rather than a ParseFileServicer instance. Consider changing that to `parsefile_pb2_grpc.add_ParseFileServicer_to_server(ParseFileServicer(), server)`? – Nathaniel Manista At Google Apr 05 '17 at 16:36
  • 1
    Can't believe that was it! Thanks a lot @NathanielManistaAtGoogle. I've updated the question to show the error trace for anyone interested. – user7815551 Apr 06 '17 at 07:55
  • Also, would you be able to point me towards an example implementation of a context subclass? I'll keep looking through the docs but it would be nice to work off a template. Thanks! – user7815551 Apr 06 '17 at 07:57
  • I can't point you towards such an example because the `ServicerContext` interface is intended to be implemented by gRPC Python, not by applications. If an application ever thinks it should implement the `ServicerContext` interface, or thinks it is being required to do so, something really weird that we hadn't imagined at all is going on. – Nathaniel Manista At Google Apr 06 '17 at 23:10
  • I'm curious how one could get the context at the client side -- where or what does `RequestContext()` constitute? – Mo Kanj Jun 12 '22 at 17:59

2 Answers2

32

In your server code you are missing the brackets to instatiate the servicer object. You've written...

parsefile_pb2_grpc.add_ParseFileServicer_to_server(ParseFileServicer, server)

It should be:

parsefile_pb2_grpc.add_ParseFileServicer_to_server(ParseFileServicer(), server)
Tiki
  • 463
  • 4
  • 9
  • 6
    I know this answer is a year old, but you just saved me quite a lot of headache! Thanks! – ekl Jun 18 '20 at 15:37
  • 3
    I know this answer is two years old, but you saved me from wasting more time (current_waste: 3 hours) – Kenan Sep 24 '21 at 18:06
0

You don't need to create the context parameter, it is created by grpc automatically.

ospider
  • 9,334
  • 3
  • 46
  • 46
  • I am trying to do unit tests on grpc service side, I want to use a mock context. Any idea on that? – RufusVS Jul 13 '21 at 15:11