grpc-framework


Namegrpc-framework JSON
Version 0.1.5b0 PyPI version JSON
download
home_pageNone
SummaryEasy gRPC APIs Framework.
upload_time2025-10-27 08:32:14
maintainerNone
docs_urlNone
authorsurp1us
requires_python>=3.7
licenseMIT License Copyright (c) 2025 grpc-framework@surp1us Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords grpc framework grpcio
VCS
bugtrack_url
requirements grpcio grpcio-health-checking grpcio-reflection protobuf grpcio-tools pyyaml
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
  <img src="./docs/logo.png" alt="grpc-framework">
</p>
<p align="center">
    <em>gRPC Framework — a modern gRPC framework with Pythonic APIs</em>
</p>

<p align="center">
Language:
<a href="./README.md" target="_self">🌐 [English](en)</a> | <a href="./docs/README.CN.md" target="_self">🇨🇳 [简体中文](zh)</a> 
</p>

<p align="center">
Pressure Test:
<a href="./docs/PressureTest.EN.md" target="_self">🌐 [English](en)</a> | <a href="./docs/PressureTest.CN.md" target="_self">🇨🇳 [简体中文](zh)</a> 
</p>

---
**Source Code**: <a href="https://github.com/JokerCrying/grpc-framework" target="_blank">
https://github.com/JokerCrying/grpc-framework
</a>
---

gRPC-Framework is a modern, highly compatible, and more Pythonic gRPC framework for rapidly building gRPC projects and
writing gRPC APIs.

Key Features:

* **Pythonic**: Decorator-driven API design, comprehensive type annotations, multi-paradigm programming, native async
  support, and flexible extension mechanisms. It simplifies complex gRPC service development into elegant, Pythonic
  code, enabling developers to build high-performance gRPC projects in the most natural Python way.
* **Modern**: Embraces modern Python best practices, including native async/await, a complete typing system, domain data
  modeling, contextvars-based context management, and declarative API design via decorators — fully aligned with Python
  3.7+ features and design philosophy.
* **Performance**: Native asynchronous I/O, configurable thread pool executor, efficient middleware chaining, smart
  argument parsing cache, and a grpc.aio-based implementation deliver excellent concurrency and low latency, while
  keeping development convenient.
* **Compatibility/Adaptability**: Seamlessly interoperates with traditional protoc-generated service code via simple
  calls. Supports multiple configuration formats (YAML, JSON, INI, Python module), pluggable serializers and codecs, and
  flexible interceptors and middleware, enabling easy migration and broad tech stack compatibility.
* **Simplicity**: Clean decorator syntax, zero-config defaults, intuitive class-based and function-based views — build
  complete gRPC services with just a few lines of code, making complex distributed communication feel like writing
  regular Python functions.
* **gRPC Standards**: Fully compliant with gRPC standards, supporting all four standard interaction patterns, protobuf
  serialization, service reflection, health checks, interceptors, compression algorithms — ensuring full
  interoperability with any standard gRPC clients and servers.
* **Client Support**: Feature-complete client, including intelligent connection pool management (supports both async and
  sync modes), convenient methods for all four gRPC call patterns, automatic connection maintenance, and warm-up
  mechanisms.

## Dependencies

gRPC Framework is built using the following libraries:

* <a href="https://pypi.org/project/grpcio/" class="external-link" target="_blank">grpcio</a> — standard gRPC
  communication.
* <a href="https://pypi.org/project/grpcio-reflection/" class="external-link" target="_blank">grpcio-reflection</a> —
  standard gRPC reflection.
* <a href="https://pypi.org/project/grpcio-health-checking/" class="external-link" target="_blank">
  grpcio-health-checking</a> — standard gRPC health checking.
* <a href="https://pypi.org/project/protobuf/" class="external-link" target="_blank">protobuf</a> — ProtobufMessage type
  support and parsing.

## Installation

```bash
pip install --upgrade pip
pip install grpc-framework
```

## Configuration

gRPC Framework uses a dedicated configuration class and supports YAML, JSON, INI, and Python modules. You can create it via `GRPCFrameworkConfig.from_module`, `GRPCFrameworkConfig.from_file`, or by instantiating directly.

### Instantiate via Config Files or Python Modules

If your project uses YAML, JSON, INI files, or a Python module for configuration, 
you can build `GRPCFrameworkConfig` with helpers. For other formats (e.g., TOML), 
register a custom parser via `GRPCFrameworkConfig.add_config_parser`.

- Helpers: `GRPCFrameworkConfig.from_module('config')`, `GRPCFrameworkConfig.from_file('config.yaml')`.
- Custom parsers: Provide `filetype` and a `parser(filepath, options)` that returns a `Dict[str, Any]`. `options` is `ConfigParserOptions` with `ini_root_name` default.

```python
from grpc_framework import GRPCFrameworkConfig, ConfigParserOptions

# Using a Python module
config_from_module = GRPCFrameworkConfig.from_module('config')

# Using a config file
# Warning: when using from_file, parameters like serializer, codec, converter,
# executor, grpc_handlers, interceptors, grpc_compression are not supported yet.
config_from_file = GRPCFrameworkConfig.from_file('config.yaml')

# Add a custom parser (e.g., for TOML)
def from_toml_file(filepath: str, options: ConfigParserOptions):
    import tomllib
    with open(filepath, 'rb') as f:
        return tomllib.load(f)

GRPCFrameworkConfig.add_config_parser('toml', from_toml_file)
```

- package: Required. The package name that hosts the gRPC app. Default `grpc` (using exactly `grpc` is not allowed).
- name: Application name. Default `grpc-framework`.
- version: Application version, recommended format `x.x.x(.beta|alpha)`.
- host: Bind address. Use `[::]` to listen on all addresses.
- port: Service port. Default `50051`.
- serializer: Global serializer that orchestrates the Codec and Converter to process request data.
- codec: Global Codec that converts request bytes to transport objects. Default `ProtobufCodec`.
- converter: Global Converter that converts transport objects to domain models. Default `ProtobufConverter`.
- reflection: Enable gRPC reflection. Default `False`.
- app_service_name: Service name for function-based views under the app. Default `RootService`.
- executor: A Python `Executor` (e.g., `ThreadPoolExecutor` or `ProcessPoolExecutor`). Default `ThreadPoolExecutor(max_workers=os.cpu_count() * 2 - 1)`.
- grpc_handlers: Additional gRPC handlers. Default `None`.
- interceptors: gRPC interceptors. Default `None` (a request parsing interceptor is loaded during service setup).
- grpc_options: gRPC server options. Default `None` (converted to an empty dict during app init).
- maximum_concurrent_rpc: Max concurrent RPCs. Default `None` (unlimited).
- grpc_compression: gRPC compression type. Default `None`.

## Serializer

gRPC Framework provides a serializer that takes two parameters, a codec and a converter. Its main responsibility is
converting request data through the pipeline: request data (HTTP/2 data stream) <> transport object <> domain model.

Some built-in codecs and converters are available from `grpc_framework`:

* **JSONCodec**: Convert bytes into Dict/List
* **ProtobufCodec**: Convert bytes into ProtobufMessage
* **ORJSONCodec**: High-performance JSON codec powered by `orjson` (<span style="color: red;">*</span>requires
  installing `orjson`), leveraging its speed.
* **DataclassesCodec**: Convert bytes into Dict/List
* **ProtobufConverter**: Convert between ProtobufMessage and domain model (binary Protobuf data).
* **JsonProtobufConverter**: Bidirectional conversion between JSON and ProtobufMessage.
* **JsonConverter**: Convert between JSON strings and domain models.
* **DataclassesConverter**: Convert between Dataclass and Dict/List (using JSON bytes).

### Custom Data Conversion

If the data conversion provided by gRPC Framework does not meet your business needs, you can implement your own
serializer.
Implement either `grpc_framework.TransportCodec` or `grpc_framework.ModelConverter`:

#### Codec

* **decode(self, data: BytesLike, into: OptionalT = None) -> Any**: Implement `decode` to convert raw client bytes into
  a transport object.
* **encode(self, obj: Any) -> BytesLike**: Implement `encode` to convert the transport object back to bytes.

```python
class TransportCodec(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def decode(self, data: BytesLike, into: OptionalT = None) -> Any:
        """bytes -> transport object (e.g., protobuf.Message or dict)"""
        raise NotImplementedError

    @abc.abstractmethod
    def encode(self, obj: Any) -> BytesLike:
        """transport object -> bytes"""
        raise NotImplementedError
```

#### Converter

* **to_model(self, transport_obj: Any, model_type: TypeT) -> T**: Convert the transport object into a domain model.
* **from_model(self, model: T) -> Any**: Convert the domain model back into a transport object.

```python
class ModelConverter(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def to_model(self, transport_obj: Any, model_type: TypeT) -> T:
        """transport object -> domain model"""
        raise NotImplementedError

    @abc.abstractmethod
    def from_model(self, model: T) -> Any:
        """domain model -> transport object"""
        raise NotImplementedError
```

## Examples

<small><span style="color: red;">*</span>In the examples below, `JSONCodec` and `JSONConverter` are used.</small>

### Create and Run an Application

```python
from grpc_framework import GRPCFrameworkConfig, GRPCFramework

config = GRPCFrameworkConfig.from_module('config')

app = GRPCFramework(config=config)

if __name__ == '__main__':
    app.run()
```

### Function-Based Views

```python
from grpc_framework import GRPCFrameworkConfig, GRPCFramework, Request

config = GRPCFrameworkConfig.from_module('config')

app = GRPCFramework(config=config)


# Approach 1
@app.unary_unary
def IsServerAlive():
    return {"success": True}


# Approach 2
from grpc_framework import Service

some_service = Service("SomeService")


@some_service.unary_unary
def GetSomeData():
    # You can access the current request information
    request = Request.current()
    print(request.metadata)
    return {"success": True, "data": {"id": 1}}


app.add_service(some_service)
```

<details markdown="1">
<summary>Or use <code>async def</code>...</summary>

```python
from grpc_framework import GRPCFrameworkConfig, GRPCFramework, Request

config = GRPCFrameworkConfig.from_module('config')
app = GRPCFramework(config=config)


# Approach 1
@app.unary_unary
async def IsServerAlive():
    return {"success": True}


# Approach 2
from grpc_framework import Service

some_service = Service("SomeService")


@some_service.unary_unary
async def GetSomeData():
    # You can access the current request information
    request = Request.current()
    print(request.metadata)
    return {"success": True, "data": {"id": 1}}


app.add_service(some_service)
```

</details>

### Class-Based Views

```python
from grpc_framework import GRPCFrameworkConfig, GRPCFramework, Service, unary_unary, stream_unary, StreamRequest

config = GRPCFrameworkConfig.from_module('config')
app = GRPCFramework(config=config)


class SomeService(Service):
    @unary_unary
    def GetSomeData(self):
        # You can access the current request information
        print(self.request.metadata)
        return {"success": True}

    @stream_unary
    async def sum_counter(self, data: StreamRequest[dict]):
        result = 0
        async for item in data:
            result += data['count']
        return {'result': result}


app.add_service(SomeService)
```

<details markdown="1">
<summary>Or use <code>async def</code>...</summary>

```python
from grpc_framework import GRPCFrameworkConfig, GRPCFramework, Service, unary_unary, stream_unary, StreamRequest

config = GRPCFrameworkConfig.from_module('config')
app = GRPCFramework(config=config)


class SomeService(Service):
    @unary_unary
    async def GetSomeData(self):
        # You can access the current request information
        print(self.request.metadata)
        return {"success": True}

    @stream_unary
    async def sum_counter(self, data: StreamRequest[dict]):
        result = 0
        async for item in data:
            result += data['count']
        return {'result': result}


app.add_service(SomeService)
```

</details>

## Legacy Compatibility

gRPC Framework provides interfaces to be compatible with legacy projects compiled with protoc, 
allowing them to be seamlessly hosted within gRPC Framework. 
However, request context or middleware configured in the framework will not be available, 
as the legacy service is only hosted rather than fully managed.

### Example

```python
import example_pb2
import example_pb2_grpc


class Greeter(example_pb2_grpc.GreeterServicer):
    def say_hello(self, request):
        return example_pb2.HelloReply(message=f"Hello, {request.name}")

app.load_rpc_stub(Greeter(), example_pb2_grpc.add_GreeterServicer_to_server)
```

## Client Support

gRPC Framework provides a client that makes calling gRPC services simple. 
It supports both calling via generated stubs and by specifying method paths directly. 
It also includes a gRPC channel pool that supports both async ecosystem channels and default channels.

### Channel Pool Configuration

- pool_mode: Required. Supports `async` and `default` to manage async ecosystem channels and default channels.
- min_size: Minimum number of connections. Default `10`.
- max_size: Maximum number of connections. Default `20`.
- secure_mode: Whether to enable secure mode. Affects channel creation. Default `False`.
- credit: gRPC credentials. Required when `secure_mode=True`.
- maintenance_interval: Background task checks channel health at this interval. Default `5` seconds.
- auto_preheating: Whether to preheat the pool. Default `True`. When enabled, the pool warms up to `min_size` on instantiation.
- channel_options: Additional channel options.

### Client Usage

```python
from grpc_framework.client import GRPCChannelPool, GRPCClient, GRPCChannelPoolOptions

grpc_channel_pool = GRPCChannelPool(GRPCChannelPoolOptions(pool_mode='default'))

client = GRPCClient(
    channel_pool_manager=grpc_channel_pool,
    host='localhost',
    port=50051,
    request_serializer=lambda x: x,
    response_deserializer=lambda x: x,
    timeout=5,
)

# Stub-based call
import example_pb2_grpc as example_pb2_grpc
import example_pb2 as example_pb2

request = example_pb2.SimpleRequest(query='1', page_number=1, result_per_page=20)
channel = client.channel_pool_manager.get()
impl = example_pb2_grpc.SimpleServiceStub(channel)
resp = client.call_method(impl.GetSimpleResponse, request)
print(resp)

# Direct method call
response = client.call_method('/package.Service/Method', request_data=b'{"name":"jack"}')
print(response)
```

## Roadmap

| Status | Feature                       | Planned Version | Notes       |
|--------|-------------------------------|-----------------|-------------|
| ⬜      | Dependency collection         | v1.1.0          | Not started |
| ⬜      | Multi-loop support            | v1.1.0          | Not started |
| ⬜      | Version support               | v1.1.0          | Not started |
| ⬜      | Service-level codec/converter | v1.2.0          | Not started |
| ⬜      | Service-level request context | v1.2.0          | Not started |

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "grpc-framework",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "grpc, framework, grpcio",
    "author": "surp1us",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/3e/52/db04b4a48e4bef371d5db5b6fb4c9bf311332b5ef7619fce3feb9ec36552/grpc_framework-0.1.5b0.tar.gz",
    "platform": null,
    "description": "<p align=\"center\">\r\n  <img src=\"./docs/logo.png\" alt=\"grpc-framework\">\r\n</p>\r\n<p align=\"center\">\r\n    <em>gRPC Framework \u2014 a modern gRPC framework with Pythonic APIs</em>\r\n</p>\r\n\r\n<p align=\"center\">\r\nLanguage\uff1a\r\n<a href=\"./README.md\" target=\"_self\">\ud83c\udf10 [English](en)</a> | <a href=\"./docs/README.CN.md\" target=\"_self\">\ud83c\udde8\ud83c\uddf3 [\u7b80\u4f53\u4e2d\u6587](zh)</a> \r\n</p>\r\n\r\n<p align=\"center\">\r\nPressure Test\uff1a\r\n<a href=\"./docs/PressureTest.EN.md\" target=\"_self\">\ud83c\udf10 [English](en)</a> | <a href=\"./docs/PressureTest.CN.md\" target=\"_self\">\ud83c\udde8\ud83c\uddf3 [\u7b80\u4f53\u4e2d\u6587](zh)</a> \r\n</p>\r\n\r\n---\r\n**Source Code**: <a href=\"https://github.com/JokerCrying/grpc-framework\" target=\"_blank\">\r\nhttps://github.com/JokerCrying/grpc-framework\r\n</a>\r\n---\r\n\r\ngRPC-Framework is a modern, highly compatible, and more Pythonic gRPC framework for rapidly building gRPC projects and\r\nwriting gRPC APIs.\r\n\r\nKey Features:\r\n\r\n* **Pythonic**: Decorator-driven API design, comprehensive type annotations, multi-paradigm programming, native async\r\n  support, and flexible extension mechanisms. It simplifies complex gRPC service development into elegant, Pythonic\r\n  code, enabling developers to build high-performance gRPC projects in the most natural Python way.\r\n* **Modern**: Embraces modern Python best practices, including native async/await, a complete typing system, domain data\r\n  modeling, contextvars-based context management, and declarative API design via decorators \u2014 fully aligned with Python\r\n  3.7+ features and design philosophy.\r\n* **Performance**: Native asynchronous I/O, configurable thread pool executor, efficient middleware chaining, smart\r\n  argument parsing cache, and a grpc.aio-based implementation deliver excellent concurrency and low latency, while\r\n  keeping development convenient.\r\n* **Compatibility/Adaptability**: Seamlessly interoperates with traditional protoc-generated service code via simple\r\n  calls. Supports multiple configuration formats (YAML, JSON, INI, Python module), pluggable serializers and codecs, and\r\n  flexible interceptors and middleware, enabling easy migration and broad tech stack compatibility.\r\n* **Simplicity**: Clean decorator syntax, zero-config defaults, intuitive class-based and function-based views \u2014 build\r\n  complete gRPC services with just a few lines of code, making complex distributed communication feel like writing\r\n  regular Python functions.\r\n* **gRPC Standards**: Fully compliant with gRPC standards, supporting all four standard interaction patterns, protobuf\r\n  serialization, service reflection, health checks, interceptors, compression algorithms \u2014 ensuring full\r\n  interoperability with any standard gRPC clients and servers.\r\n* **Client Support**: Feature-complete client, including intelligent connection pool management (supports both async and\r\n  sync modes), convenient methods for all four gRPC call patterns, automatic connection maintenance, and warm-up\r\n  mechanisms.\r\n\r\n## Dependencies\r\n\r\ngRPC Framework is built using the following libraries:\r\n\r\n* <a href=\"https://pypi.org/project/grpcio/\" class=\"external-link\" target=\"_blank\">grpcio</a> \u2014 standard gRPC\r\n  communication.\r\n* <a href=\"https://pypi.org/project/grpcio-reflection/\" class=\"external-link\" target=\"_blank\">grpcio-reflection</a> \u2014\r\n  standard gRPC reflection.\r\n* <a href=\"https://pypi.org/project/grpcio-health-checking/\" class=\"external-link\" target=\"_blank\">\r\n  grpcio-health-checking</a> \u2014 standard gRPC health checking.\r\n* <a href=\"https://pypi.org/project/protobuf/\" class=\"external-link\" target=\"_blank\">protobuf</a> \u2014 ProtobufMessage type\r\n  support and parsing.\r\n\r\n## Installation\r\n\r\n```bash\r\npip install --upgrade pip\r\npip install grpc-framework\r\n```\r\n\r\n## Configuration\r\n\r\ngRPC Framework uses a dedicated configuration class and supports YAML, JSON, INI, and Python modules. You can create it via `GRPCFrameworkConfig.from_module`, `GRPCFrameworkConfig.from_file`, or by instantiating directly.\r\n\r\n### Instantiate via Config Files or Python Modules\r\n\r\nIf your project uses YAML, JSON, INI files, or a Python module for configuration, \r\nyou can build `GRPCFrameworkConfig` with helpers. For other formats (e.g., TOML), \r\nregister a custom parser via `GRPCFrameworkConfig.add_config_parser`.\r\n\r\n- Helpers: `GRPCFrameworkConfig.from_module('config')`, `GRPCFrameworkConfig.from_file('config.yaml')`.\r\n- Custom parsers: Provide `filetype` and a `parser(filepath, options)` that returns a `Dict[str, Any]`. `options` is `ConfigParserOptions` with `ini_root_name` default.\r\n\r\n```python\r\nfrom grpc_framework import GRPCFrameworkConfig, ConfigParserOptions\r\n\r\n# Using a Python module\r\nconfig_from_module = GRPCFrameworkConfig.from_module('config')\r\n\r\n# Using a config file\r\n# Warning: when using from_file, parameters like serializer, codec, converter,\r\n# executor, grpc_handlers, interceptors, grpc_compression are not supported yet.\r\nconfig_from_file = GRPCFrameworkConfig.from_file('config.yaml')\r\n\r\n# Add a custom parser (e.g., for TOML)\r\ndef from_toml_file(filepath: str, options: ConfigParserOptions):\r\n    import tomllib\r\n    with open(filepath, 'rb') as f:\r\n        return tomllib.load(f)\r\n\r\nGRPCFrameworkConfig.add_config_parser('toml', from_toml_file)\r\n```\r\n\r\n- package: Required. The package name that hosts the gRPC app. Default `grpc` (using exactly `grpc` is not allowed).\r\n- name: Application name. Default `grpc-framework`.\r\n- version: Application version, recommended format `x.x.x(.beta|alpha)`.\r\n- host: Bind address. Use `[::]` to listen on all addresses.\r\n- port: Service port. Default `50051`.\r\n- serializer: Global serializer that orchestrates the Codec and Converter to process request data.\r\n- codec: Global Codec that converts request bytes to transport objects. Default `ProtobufCodec`.\r\n- converter: Global Converter that converts transport objects to domain models. Default `ProtobufConverter`.\r\n- reflection: Enable gRPC reflection. Default `False`.\r\n- app_service_name: Service name for function-based views under the app. Default `RootService`.\r\n- executor: A Python `Executor` (e.g., `ThreadPoolExecutor` or `ProcessPoolExecutor`). Default `ThreadPoolExecutor(max_workers=os.cpu_count() * 2 - 1)`.\r\n- grpc_handlers: Additional gRPC handlers. Default `None`.\r\n- interceptors: gRPC interceptors. Default `None` (a request parsing interceptor is loaded during service setup).\r\n- grpc_options: gRPC server options. Default `None` (converted to an empty dict during app init).\r\n- maximum_concurrent_rpc: Max concurrent RPCs. Default `None` (unlimited).\r\n- grpc_compression: gRPC compression type. Default `None`.\r\n\r\n## Serializer\r\n\r\ngRPC Framework provides a serializer that takes two parameters, a codec and a converter. Its main responsibility is\r\nconverting request data through the pipeline: request data (HTTP/2 data stream) <> transport object <> domain model.\r\n\r\nSome built-in codecs and converters are available from `grpc_framework`:\r\n\r\n* **JSONCodec**: Convert bytes into Dict/List\r\n* **ProtobufCodec**: Convert bytes into ProtobufMessage\r\n* **ORJSONCodec**: High-performance JSON codec powered by `orjson` (<span style=\"color: red;\">*</span>requires\r\n  installing `orjson`), leveraging its speed.\r\n* **DataclassesCodec**: Convert bytes into Dict/List\r\n* **ProtobufConverter**: Convert between ProtobufMessage and domain model (binary Protobuf data).\r\n* **JsonProtobufConverter**: Bidirectional conversion between JSON and ProtobufMessage.\r\n* **JsonConverter**: Convert between JSON strings and domain models.\r\n* **DataclassesConverter**: Convert between Dataclass and Dict/List (using JSON bytes).\r\n\r\n### Custom Data Conversion\r\n\r\nIf the data conversion provided by gRPC Framework does not meet your business needs, you can implement your own\r\nserializer.\r\nImplement either `grpc_framework.TransportCodec` or `grpc_framework.ModelConverter`:\r\n\r\n#### Codec\r\n\r\n* **decode(self, data: BytesLike, into: OptionalT = None) -> Any**: Implement `decode` to convert raw client bytes into\r\n  a transport object.\r\n* **encode(self, obj: Any) -> BytesLike**: Implement `encode` to convert the transport object back to bytes.\r\n\r\n```python\r\nclass TransportCodec(metaclass=abc.ABCMeta):\r\n    @abc.abstractmethod\r\n    def decode(self, data: BytesLike, into: OptionalT = None) -> Any:\r\n        \"\"\"bytes -> transport object (e.g., protobuf.Message or dict)\"\"\"\r\n        raise NotImplementedError\r\n\r\n    @abc.abstractmethod\r\n    def encode(self, obj: Any) -> BytesLike:\r\n        \"\"\"transport object -> bytes\"\"\"\r\n        raise NotImplementedError\r\n```\r\n\r\n#### Converter\r\n\r\n* **to_model(self, transport_obj: Any, model_type: TypeT) -> T**: Convert the transport object into a domain model.\r\n* **from_model(self, model: T) -> Any**: Convert the domain model back into a transport object.\r\n\r\n```python\r\nclass ModelConverter(metaclass=abc.ABCMeta):\r\n    @abc.abstractmethod\r\n    def to_model(self, transport_obj: Any, model_type: TypeT) -> T:\r\n        \"\"\"transport object -> domain model\"\"\"\r\n        raise NotImplementedError\r\n\r\n    @abc.abstractmethod\r\n    def from_model(self, model: T) -> Any:\r\n        \"\"\"domain model -> transport object\"\"\"\r\n        raise NotImplementedError\r\n```\r\n\r\n## Examples\r\n\r\n<small><span style=\"color: red;\">*</span>In the examples below, `JSONCodec` and `JSONConverter` are used.</small>\r\n\r\n### Create and Run an Application\r\n\r\n```python\r\nfrom grpc_framework import GRPCFrameworkConfig, GRPCFramework\r\n\r\nconfig = GRPCFrameworkConfig.from_module('config')\r\n\r\napp = GRPCFramework(config=config)\r\n\r\nif __name__ == '__main__':\r\n    app.run()\r\n```\r\n\r\n### Function-Based Views\r\n\r\n```python\r\nfrom grpc_framework import GRPCFrameworkConfig, GRPCFramework, Request\r\n\r\nconfig = GRPCFrameworkConfig.from_module('config')\r\n\r\napp = GRPCFramework(config=config)\r\n\r\n\r\n# Approach 1\r\n@app.unary_unary\r\ndef IsServerAlive():\r\n    return {\"success\": True}\r\n\r\n\r\n# Approach 2\r\nfrom grpc_framework import Service\r\n\r\nsome_service = Service(\"SomeService\")\r\n\r\n\r\n@some_service.unary_unary\r\ndef GetSomeData():\r\n    # You can access the current request information\r\n    request = Request.current()\r\n    print(request.metadata)\r\n    return {\"success\": True, \"data\": {\"id\": 1}}\r\n\r\n\r\napp.add_service(some_service)\r\n```\r\n\r\n<details markdown=\"1\">\r\n<summary>Or use <code>async def</code>...</summary>\r\n\r\n```python\r\nfrom grpc_framework import GRPCFrameworkConfig, GRPCFramework, Request\r\n\r\nconfig = GRPCFrameworkConfig.from_module('config')\r\napp = GRPCFramework(config=config)\r\n\r\n\r\n# Approach 1\r\n@app.unary_unary\r\nasync def IsServerAlive():\r\n    return {\"success\": True}\r\n\r\n\r\n# Approach 2\r\nfrom grpc_framework import Service\r\n\r\nsome_service = Service(\"SomeService\")\r\n\r\n\r\n@some_service.unary_unary\r\nasync def GetSomeData():\r\n    # You can access the current request information\r\n    request = Request.current()\r\n    print(request.metadata)\r\n    return {\"success\": True, \"data\": {\"id\": 1}}\r\n\r\n\r\napp.add_service(some_service)\r\n```\r\n\r\n</details>\r\n\r\n### Class-Based Views\r\n\r\n```python\r\nfrom grpc_framework import GRPCFrameworkConfig, GRPCFramework, Service, unary_unary, stream_unary, StreamRequest\r\n\r\nconfig = GRPCFrameworkConfig.from_module('config')\r\napp = GRPCFramework(config=config)\r\n\r\n\r\nclass SomeService(Service):\r\n    @unary_unary\r\n    def GetSomeData(self):\r\n        # You can access the current request information\r\n        print(self.request.metadata)\r\n        return {\"success\": True}\r\n\r\n    @stream_unary\r\n    async def sum_counter(self, data: StreamRequest[dict]):\r\n        result = 0\r\n        async for item in data:\r\n            result += data['count']\r\n        return {'result': result}\r\n\r\n\r\napp.add_service(SomeService)\r\n```\r\n\r\n<details markdown=\"1\">\r\n<summary>Or use <code>async def</code>...</summary>\r\n\r\n```python\r\nfrom grpc_framework import GRPCFrameworkConfig, GRPCFramework, Service, unary_unary, stream_unary, StreamRequest\r\n\r\nconfig = GRPCFrameworkConfig.from_module('config')\r\napp = GRPCFramework(config=config)\r\n\r\n\r\nclass SomeService(Service):\r\n    @unary_unary\r\n    async def GetSomeData(self):\r\n        # You can access the current request information\r\n        print(self.request.metadata)\r\n        return {\"success\": True}\r\n\r\n    @stream_unary\r\n    async def sum_counter(self, data: StreamRequest[dict]):\r\n        result = 0\r\n        async for item in data:\r\n            result += data['count']\r\n        return {'result': result}\r\n\r\n\r\napp.add_service(SomeService)\r\n```\r\n\r\n</details>\r\n\r\n## Legacy Compatibility\r\n\r\ngRPC Framework provides interfaces to be compatible with legacy projects compiled with protoc, \r\nallowing them to be seamlessly hosted within gRPC Framework. \r\nHowever, request context or middleware configured in the framework will not be available, \r\nas the legacy service is only hosted rather than fully managed.\r\n\r\n### Example\r\n\r\n```python\r\nimport example_pb2\r\nimport example_pb2_grpc\r\n\r\n\r\nclass Greeter(example_pb2_grpc.GreeterServicer):\r\n    def say_hello(self, request):\r\n        return example_pb2.HelloReply(message=f\"Hello, {request.name}\")\r\n\r\napp.load_rpc_stub(Greeter(), example_pb2_grpc.add_GreeterServicer_to_server)\r\n```\r\n\r\n## Client Support\r\n\r\ngRPC Framework provides a client that makes calling gRPC services simple. \r\nIt supports both calling via generated stubs and by specifying method paths directly. \r\nIt also includes a gRPC channel pool that supports both async ecosystem channels and default channels.\r\n\r\n### Channel Pool Configuration\r\n\r\n- pool_mode: Required. Supports `async` and `default` to manage async ecosystem channels and default channels.\r\n- min_size: Minimum number of connections. Default `10`.\r\n- max_size: Maximum number of connections. Default `20`.\r\n- secure_mode: Whether to enable secure mode. Affects channel creation. Default `False`.\r\n- credit: gRPC credentials. Required when `secure_mode=True`.\r\n- maintenance_interval: Background task checks channel health at this interval. Default `5` seconds.\r\n- auto_preheating: Whether to preheat the pool. Default `True`. When enabled, the pool warms up to `min_size` on instantiation.\r\n- channel_options: Additional channel options.\r\n\r\n### Client Usage\r\n\r\n```python\r\nfrom grpc_framework.client import GRPCChannelPool, GRPCClient, GRPCChannelPoolOptions\r\n\r\ngrpc_channel_pool = GRPCChannelPool(GRPCChannelPoolOptions(pool_mode='default'))\r\n\r\nclient = GRPCClient(\r\n    channel_pool_manager=grpc_channel_pool,\r\n    host='localhost',\r\n    port=50051,\r\n    request_serializer=lambda x: x,\r\n    response_deserializer=lambda x: x,\r\n    timeout=5,\r\n)\r\n\r\n# Stub-based call\r\nimport example_pb2_grpc as example_pb2_grpc\r\nimport example_pb2 as example_pb2\r\n\r\nrequest = example_pb2.SimpleRequest(query='1', page_number=1, result_per_page=20)\r\nchannel = client.channel_pool_manager.get()\r\nimpl = example_pb2_grpc.SimpleServiceStub(channel)\r\nresp = client.call_method(impl.GetSimpleResponse, request)\r\nprint(resp)\r\n\r\n# Direct method call\r\nresponse = client.call_method('/package.Service/Method', request_data=b'{\"name\":\"jack\"}')\r\nprint(response)\r\n```\r\n\r\n## Roadmap\r\n\r\n| Status | Feature                       | Planned Version | Notes       |\r\n|--------|-------------------------------|-----------------|-------------|\r\n| \u2b1c      | Dependency collection         | v1.1.0          | Not started |\r\n| \u2b1c      | Multi-loop support            | v1.1.0          | Not started |\r\n| \u2b1c      | Version support               | v1.1.0          | Not started |\r\n| \u2b1c      | Service-level codec/converter | v1.2.0          | Not started |\r\n| \u2b1c      | Service-level request context | v1.2.0          | Not started |\r\n",
    "bugtrack_url": null,
    "license": "MIT License\r\n        \r\n        Copyright (c) 2025 grpc-framework@surp1us\r\n        \r\n        Permission is hereby granted, free of charge, to any person obtaining a copy\r\n        of this software and associated documentation files (the \"Software\"), to deal\r\n        in the Software without restriction, including without limitation the rights\r\n        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n        copies of the Software, and to permit persons to whom the Software is\r\n        furnished to do so, subject to the following conditions:\r\n        \r\n        The above copyright notice and this permission notice shall be included in all\r\n        copies or substantial portions of the Software.\r\n        \r\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n        SOFTWARE.",
    "summary": "Easy gRPC APIs Framework.",
    "version": "0.1.5b0",
    "project_urls": {
        "Bug Tracker": "https://github.com/JokerCrying/grpc-framework/issues",
        "Homepage": "https://github.com/JokerCrying/grpc-framework",
        "Repository": "https://github.com/JokerCrying/grpc-framework"
    },
    "split_keywords": [
        "grpc",
        " framework",
        " grpcio"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c79d88017cbaf546ce6a0f6f8d658f3194d200ad85c8baf2733c855a9b1d3f4c",
                "md5": "feb91c2475b48bd91b1082842abda4f3",
                "sha256": "8053432ce45ba1d597d5909776bea75a451e630785296b2affc454cb13fa6a56"
            },
            "downloads": -1,
            "filename": "grpc_framework-0.1.5b0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "feb91c2475b48bd91b1082842abda4f3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 43484,
            "upload_time": "2025-10-27T08:32:13",
            "upload_time_iso_8601": "2025-10-27T08:32:13.425388Z",
            "url": "https://files.pythonhosted.org/packages/c7/9d/88017cbaf546ce6a0f6f8d658f3194d200ad85c8baf2733c855a9b1d3f4c/grpc_framework-0.1.5b0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3e52db04b4a48e4bef371d5db5b6fb4c9bf311332b5ef7619fce3feb9ec36552",
                "md5": "f37d57e5650dfd5643bf145187b666df",
                "sha256": "9515d8b24622c2482a69e3a356ea9fa1ccf2d6c934ac0d83f4083e20d7b2b14f"
            },
            "downloads": -1,
            "filename": "grpc_framework-0.1.5b0.tar.gz",
            "has_sig": false,
            "md5_digest": "f37d57e5650dfd5643bf145187b666df",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 38132,
            "upload_time": "2025-10-27T08:32:14",
            "upload_time_iso_8601": "2025-10-27T08:32:14.682903Z",
            "url": "https://files.pythonhosted.org/packages/3e/52/db04b4a48e4bef371d5db5b6fb4c9bf311332b5ef7619fce3feb9ec36552/grpc_framework-0.1.5b0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-27 08:32:14",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "JokerCrying",
    "github_project": "grpc-framework",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "grpcio",
            "specs": [
                [
                    "==",
                    "1.73.1"
                ]
            ]
        },
        {
            "name": "grpcio-health-checking",
            "specs": [
                [
                    "==",
                    "1.73.1"
                ]
            ]
        },
        {
            "name": "grpcio-reflection",
            "specs": [
                [
                    "==",
                    "1.73.1"
                ]
            ]
        },
        {
            "name": "protobuf",
            "specs": [
                [
                    "==",
                    "6.31.1"
                ]
            ]
        },
        {
            "name": "grpcio-tools",
            "specs": [
                [
                    "==",
                    "1.73.1"
                ]
            ]
        },
        {
            "name": "pyyaml",
            "specs": [
                [
                    "==",
                    "6.0.3"
                ]
            ]
        }
    ],
    "lcname": "grpc-framework"
}
        
Elapsed time: 1.87369s