Registry / http-networking / grpc-interceptor

grpc-interceptor

JSON →
library0.15.4pypypi✓ verified 29d ago

grpc-interceptor is a Python library that simplifies the implementation of gRPC interceptors. It provides base classes and utility interceptors that offer direct access to request, response, and service context objects, which are typically harder to access with standard `grpc` library interceptors. The library emphasizes a small, readable codebase and minimal dependencies, primarily `grpcio`. It is actively maintained with regular minor releases, currently at version 0.15.4.

pip install grpc-interceptor
INSTALL
IMPORT
SIG · GRPC-INTERCEPTOR
G
grpc-interceptor
http-networkingpythonv0.15.4
Install
2.9s avg
Import
271ms
Disk
37MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.9–3.13
musl
3.9–3.13
Install & Compatibility
Where this runs
tested against v0.15.4 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.284s · 40.3MB
glibc
py 3.10–3.910 runs
installs and imports cleanly · install 2.9s · import 0.259s · 39MB
37MB installed
● package 37MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

ServerInterceptor
✓ from grpc_interceptor import ServerInterceptor
✗ from grpc import ServerInterceptor
Do not confuse with the native `grpc.ServerInterceptor` class, which has a different API.
AsyncServerInterceptor
✓ from grpc_interceptor import AsyncServerInterceptor
ClientInterceptor
✓ from grpc_interceptor import ClientInterceptor
✗ from grpc import ClientInterceptor
Do not confuse with the native `grpc.ClientInterceptor` class, which has a different API.
ExceptionToStatusInterceptor
✓ from grpc_interceptor import ExceptionToStatusInterceptor
AsyncExceptionToStatusInterceptor
✓ from grpc_interceptor import AsyncExceptionToStatusInterceptor
GrpcException
✓ from grpc_interceptor.exceptions import GrpcException
NotFound
✓ from grpc_interceptor.exceptions import NotFound
A specific `GrpcException` subclass for NOT_FOUND status.

This quickstart demonstrates how to create a custom server interceptor using `grpc-interceptor` to handle exceptions and set gRPC status codes. It includes a basic `ServerInterceptor` subclass that catches `GrpcException` (like `NotFound`) and maps them to gRPC status codes. The example simulates a gRPC call flow to show both successful and error handling paths.

import grpc from concurrent import futures from grpc_interceptor import ServerInterceptor from grpc_interceptor.exceptions import GrpcException, NotFound # Assuming a generated protobuf service like my_pb2_grpc and my_pb2 # For demonstration, we'll mock these: class MockRequest: def __init__(self, name): self.name = name class MockResponse: def __init__(self, message): self.message = message class MockServicerContext: def __init__(self): self.code = grpc.StatusCode.OK self.details = '' def set_code(self, code): self.code = code def set_details(self, details): self.details = details def abort(self, code, details): self.set_code(code) self.set_details(details) raise GrpcException(code, details) class CustomExceptionInterceptor(ServerInterceptor): def intercept(self, method, request, context, method_name): try: return method(request, context) except GrpcException as e: context.set_code(e.status_code) context.set_details(e.details) raise # Re-raise to let gRPC handle it after context is set except Exception as e: # Catch other unexpected exceptions context.set_code(grpc.StatusCode.INTERNAL) context.set_details(f"An unexpected error occurred: {e}") raise class MyServiceServicer: def SayHello(self, request, context): if request.name == "Error": raise NotFound("Name not found!") return MockResponse(message=f"Hello, {request.name}!") def serve(): # In a real application, you'd use generated stubs and an actual gRPC server interceptors = [CustomExceptionInterceptor()] server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), interceptors=interceptors) # In a real app, you'd add your service here: # my_pb2_grpc.add_MyServiceServicer_to_server(MyServiceServicer(), server) # For this example, we'll simulate the service call through the interceptor service_instance = MyServiceServicer() print("Simulating RPC calls through the interceptor:") # Successful call req_success = MockRequest("World") ctx_success = MockServicerContext() try: res_success = interceptors[0].intercept(service_instance.SayHello, req_success, ctx_success, "/MyService/SayHello") print(f"Success: {res_success.message} (Status: {ctx_success.code.name})") except Exception as e: print(f"Unexpected error in successful call: {e}") # Error call req_error = MockRequest("Error") ctx_error = MockServicerContext() try: interceptors[0].intercept(service_instance.SayHello, req_error, ctx_error, "/MyService/SayHello") except GrpcException as e: print(f"Caught expected error: {ctx_error.details} (Status: {ctx_error.code.name})") except Exception as e: print(f"Caught unexpected error type: {e}") if __name__ == '__main__': serve()
Debug
Known issues
breakingVersion 0.15.0 and later dropped support for Python 3.6.0.
fix
Upgrade your Python environment to 3.7 or newer.
affects: >=0.15.0
breakingAsynchronous server interceptors (AsyncServerInterceptor and AsyncExceptionToStatusInterceptor) introduced in v0.15.0 require grpcio >= 1.32.0. Using older grpcio versions will prevent async features from working.
fix
Ensure `grpcio` is updated to version 1.32.0 or newer (e.g., `pip install --upgrade grpcio`).
affects: >=0.15.0
gotchaThe internal type of `MethodName` changed from a `NamedTuple` in version 0.14.1. Code relying on `MethodName` being iterable or having `NamedTuple`-specific behavior might break.
fix
Avoid relying on `MethodName`'s internal type; treat it as an opaque string or object with expected attributes rather than a `NamedTuple`.
affects: >=0.14.1
gotchaDo not confuse `grpc_interceptor.ServerInterceptor` or `grpc_interceptor.ClientInterceptor` with the native `grpc.ServerInterceptor` or `grpc.ClientInterceptor` classes. They have different APIs and intended usage.
fix
Always import interceptor base classes from `grpc_interceptor` (e.g., `from grpc_interceptor import ServerInterceptor`) when using this library.
affects: All versions
gotchaFor async server streaming RPCs, an alternate API was introduced where the RPC method might return `None` instead of an `async_generator`. If your interceptor logic expects an `async_generator` in all streaming cases, it may need adjustment.
fix
Check for the `__aiter__` attribute to determine if the result is an `async_generator`. For the alternate API, you may need to wrap the context object to capture `await context.write(...)` calls.
affects: >=0.15.0
gotchaPrior to v0.15.3, calling `context.abort` from an interceptor might have resulted in the wrong gRPC status code being set for the RPC. This was fixed in v0.15.3.
fix
Upgrade to `grpc-interceptor` v0.15.3 or newer to ensure correct status code propagation from `context.abort` calls.
affects: <0.15.3
gotchaAs of v0.15.4, interceptors will be skipped for RPC methods that are not registered in the gRPC server. Previous versions might have invoked interceptors even for unregistered methods, potentially leading to unexpected behavior.
fix
Be aware that interceptors will now correctly only apply to registered methods. If you relied on interceptors running for unregistered methods, adjust your logic accordingly, or upgrade to benefit from this fix.
affects: <0.15.4
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'grpc_interceptor'
The 'grpc-interceptor' library is not installed in the Python environment where the code is being executed.
fix
Run `pip install grpc-interceptor` in your terminal to install the library.
AttributeError: 'ServicerContext' object has no attribute 'my_custom_field'
This error occurs when attempting to assign custom attributes directly to the `grpc.ServicerContext` object within an interceptor, which is not supported by the underlying `grpcio` library. The `grpc-interceptor` library provides its own `ServiceContext` wrapper that allows this behavior for `ServerInterceptor` instances.
fix
Ensure your interceptor class inherits from `grpc_interceptor.ServerInterceptor` (or `AsyncServerInterceptor`). The `context` object passed to the `intercept` method of these base classes is a `grpc_interceptor.ServiceContext` instance, which supports custom attribute assignment.

```python
from grpc_interceptor import ServerInterceptor
import grpc

class MyCustomDataInterceptor(ServerInterceptor):
    def intercept(
        self,
        method: Callable,
        request_or_iterator: Any,
        context: grpc.ServicerContext,
        method_name: str,
    ) -> Any:
        context.my_custom_field = 'some_value' # This works with grpc-interceptor's ServiceContext
        return method(request_or_iterator, context)
```
TypeError: intercept() missing 1 required positional argument: 'method_name'
The `intercept` method in a custom interceptor inheriting from `grpc_interceptor.ServerInterceptor` (or `AsyncServerInterceptor`) has an incorrect or incomplete signature. The base class expects specific arguments for its `intercept` method.
fix
Adjust the signature of your `intercept` method to match the required arguments: `self`, `method`, `request_or_iterator`, `context`, and `method_name`.

```python
from grpc_interceptor import ServerInterceptor
from typing import Callable, Any
import grpc

class MyCorrectInterceptor(ServerInterceptor):
    def intercept(
        self,
        method: Callable, # The next interceptor or RPC method implementation
        request_or_iterator: Any, # The RPC request or iterator
        context: grpc.ServicerContext, # The ServicerContext
        method_name: str, # A string like '/package.Service/Method'
    ) -> Any:
        # Your interceptor logic here
        return method(request_or_iterator, context)
```
ImportError: cannot import name 'ServerInterceptor' from 'grpc_interceptor'
This error typically indicates that the `ServerInterceptor` class (or other core components like `ClientInterceptor`, `AsyncServerInterceptor`) is being imported incorrectly, either from a non-existent submodule or due to a naming conflict within the project. It could also point to a corrupted installation or an outdated version where the class structure has changed.
fix
Ensure that you are importing the interceptor base classes directly from the top-level `grpc_interceptor` package. If the error persists, try reinstalling the library to resolve any potential installation issues.

```python
# Correct imports for server-side interceptors
from grpc_interceptor import ServerInterceptor
from grpc_interceptor import AsyncServerInterceptor

# Correct import for client-side interceptors
from grpc_interceptor import ClientInterceptor
```
Upgrade
Version history
0.15.4latest on PyPI · released Nov 16, 2023
Audit
Dependencies
grpciorequiredCore dependency for gRPC functionality. Version >=1.32.0 is required for async features.
protobufoptionalIncluded with the testing framework extra.
Agent activity
24 hits · last 30 days
node
20
OpenAI (training)
2
Resources
grpc-interceptor — pip install grpc-interceptor · libregistry