openframe-protocol-grpc 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,220 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ *.lcov
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ # Pipfile.lock
97
+
98
+ # uv
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ # uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ # poetry.lock
110
+ # poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ # pdm.lock
117
+ # pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ # pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi/*
127
+ !.pixi/config.toml
128
+
129
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130
+ __pypackages__/
131
+
132
+ # Celery stuff
133
+ celerybeat-schedule*
134
+ celerybeat.pid
135
+
136
+ # Redis
137
+ *.rdb
138
+ *.aof
139
+ *.pid
140
+
141
+ # RabbitMQ
142
+ mnesia/
143
+ rabbitmq/
144
+ rabbitmq-data/
145
+
146
+ # ActiveMQ
147
+ activemq-data/
148
+
149
+ # SageMath parsed files
150
+ *.sage.py
151
+
152
+ # Environments
153
+ .env
154
+ .envrc
155
+ .venv
156
+ env/
157
+ venv/
158
+ ENV/
159
+ env.bak/
160
+ venv.bak/
161
+
162
+ # Spyder project settings
163
+ .spyderproject
164
+ .spyproject
165
+
166
+ # Rope project settings
167
+ .ropeproject
168
+
169
+ # mkdocs/Zensical documentation
170
+ /site
171
+
172
+ # mypy
173
+ .mypy_cache/
174
+ .dmypy.json
175
+ dmypy.json
176
+
177
+ # Pyre type checker
178
+ .pyre/
179
+
180
+ # pytype static type analyzer
181
+ .pytype/
182
+
183
+ # Cython debug symbols
184
+ cython_debug/
185
+
186
+ # PyCharm
187
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
188
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
189
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
190
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
191
+ # .idea/
192
+
193
+ # Abstra
194
+ # Abstra is an AI-powered process automation framework.
195
+ # Ignore directories containing user credentials, local state, and settings.
196
+ # Learn more at https://abstra.io/docs
197
+ .abstra/
198
+
199
+ # Visual Studio Code
200
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
201
+ # can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
202
+ # and can be added to the global gitignore or merged into this file. However, if you prefer, you
203
+ # could uncomment the following to ignore the entire vscode folder
204
+ # .vscode/
205
+ # Temporary file for partial code execution
206
+ tempCodeRunnerFile.py
207
+
208
+ # Ruff stuff:
209
+ .ruff_cache/
210
+
211
+ # PyPI configuration file
212
+ .pypirc
213
+
214
+ # Marimo
215
+ marimo/_static/
216
+ marimo/_lsp/
217
+ __marimo__/
218
+
219
+ # Streamlit
220
+ .streamlit/secrets.toml
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.5
2
+ Name: openframe-protocol-grpc
3
+ Version: 0.2.0
4
+ Summary: OpenFrame Microservice Suite - gRPC server and client binding for openframe.core.inbound/remote.
5
+ Project-URL: Homepage, https://github.com/Furious-Meteors/openframe-protocol
6
+ Project-URL: Documentation, https://furious-meteors.github.io/openframe-protocol/
7
+ Project-URL: Repository, https://github.com/Furious-Meteors/openframe-protocol
8
+ Project-URL: Changelog, https://github.com/Furious-Meteors/openframe-protocol/blob/production/.github/CHANGELOG.md
9
+ Project-URL: Bug Tracker, https://github.com/Furious-Meteors/openframe-protocol/issues
10
+ Author-email: Furious Meteors Engineering <engineering@furiousmeteors.dev>
11
+ Maintainer-email: Furious Meteors Engineering <engineering@furiousmeteors.dev>
12
+ License: MIT
13
+ Keywords: grpc,hexagonal,microservice,openframe,protocol
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: openframe-core<4,>=3.2.1
26
+ Requires-Dist: openframe-protocol-base<1,>=0.1
27
+ Provides-Extra: client
28
+ Requires-Dist: grpcio>=1.60; extra == 'client'
29
+ Provides-Extra: dev
30
+ Requires-Dist: grpcio-tools>=1.60; extra == 'dev'
31
+ Requires-Dist: grpcio>=1.60; extra == 'dev'
32
+ Requires-Dist: pydantic>=2.0; extra == 'dev'
33
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
34
+ Requires-Dist: pytest-mock>=3.14; extra == 'dev'
35
+ Requires-Dist: pytest>=8.0; extra == 'dev'
36
+ Provides-Extra: server
37
+ Requires-Dist: grpcio>=1.60; extra == 'server'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # openframe-protocol-grpc
41
+
42
+ gRPC server and client binding, the second transport (after HTTP) to prove
43
+ `openframe-protocol-base`'s conformance suites for real. Wires a
44
+ `QueryHandler`/`CommandHandler`/`UseCase` (`openframe.core.inbound`) to a
45
+ `grpc.aio.Server`, and provides `GrpcRemoteQueryClient`/
46
+ `GrpcRemoteCommandClient` for calling another service built on this
47
+ platform — through the same shared error mapper and `RequestContext`
48
+ builder `openframe-protocol-http` uses, not a parallel implementation.
49
+
50
+ One generic RPC (`GenericService.Call`, `{json_payload: string}` in both
51
+ directions) instead of one per route — the domain type travels as JSON
52
+ inside the payload, the gRPC equivalent of `-http`'s dynamic
53
+ `inspect.Signature` trick for avoiding a per-route message type.
54
+
55
+ Install the `[server]` extra for a server, `[client]` extra to call one —
56
+ both pull in `grpcio` (unlike HTTP, there's no separate client-only wire
57
+ library for gRPC, but the extras split is kept for symmetry with every
58
+ other `openframe-protocol-*` package).
59
+
60
+ ## Server-side wiring example
61
+
62
+ ```python
63
+ from openframe.protocol.grpc import bind_service
64
+
65
+ server = grpc.aio.server()
66
+
67
+ bind_service(
68
+ server, "get_item",
69
+ handler_factory=get_get_item_handler,
70
+ not_found_when=lambda item: item is None,
71
+ )
72
+ bind_service(
73
+ server, "create_item",
74
+ handler_factory=get_create_item_handler,
75
+ )
76
+
77
+ server.add_insecure_port("[::]:50051")
78
+ await server.start()
79
+ ```
80
+
81
+ ## Client-side wiring example
82
+
83
+ ```python
84
+ from openframe.protocol.grpc import GrpcRemoteQueryClient
85
+
86
+ get_item = GrpcRemoteQueryClient(target="items-service:50051", route="get_item")
87
+ item = await get_item.execute("abc-123")
88
+ ```
89
+
90
+ ## Status
91
+
92
+ Experimental, M4 of the project's own build plan. Both
93
+ `TransportConformanceTests` and `RemoteClientConformanceTests`
94
+ (`openframe-protocol-base`) pass against this package for real — the
95
+ point of building it: proving the architecture generalizes past HTTP,
96
+ not just adding a second transport for its own sake.
@@ -0,0 +1,57 @@
1
+ # openframe-protocol-grpc
2
+
3
+ gRPC server and client binding, the second transport (after HTTP) to prove
4
+ `openframe-protocol-base`'s conformance suites for real. Wires a
5
+ `QueryHandler`/`CommandHandler`/`UseCase` (`openframe.core.inbound`) to a
6
+ `grpc.aio.Server`, and provides `GrpcRemoteQueryClient`/
7
+ `GrpcRemoteCommandClient` for calling another service built on this
8
+ platform — through the same shared error mapper and `RequestContext`
9
+ builder `openframe-protocol-http` uses, not a parallel implementation.
10
+
11
+ One generic RPC (`GenericService.Call`, `{json_payload: string}` in both
12
+ directions) instead of one per route — the domain type travels as JSON
13
+ inside the payload, the gRPC equivalent of `-http`'s dynamic
14
+ `inspect.Signature` trick for avoiding a per-route message type.
15
+
16
+ Install the `[server]` extra for a server, `[client]` extra to call one —
17
+ both pull in `grpcio` (unlike HTTP, there's no separate client-only wire
18
+ library for gRPC, but the extras split is kept for symmetry with every
19
+ other `openframe-protocol-*` package).
20
+
21
+ ## Server-side wiring example
22
+
23
+ ```python
24
+ from openframe.protocol.grpc import bind_service
25
+
26
+ server = grpc.aio.server()
27
+
28
+ bind_service(
29
+ server, "get_item",
30
+ handler_factory=get_get_item_handler,
31
+ not_found_when=lambda item: item is None,
32
+ )
33
+ bind_service(
34
+ server, "create_item",
35
+ handler_factory=get_create_item_handler,
36
+ )
37
+
38
+ server.add_insecure_port("[::]:50051")
39
+ await server.start()
40
+ ```
41
+
42
+ ## Client-side wiring example
43
+
44
+ ```python
45
+ from openframe.protocol.grpc import GrpcRemoteQueryClient
46
+
47
+ get_item = GrpcRemoteQueryClient(target="items-service:50051", route="get_item")
48
+ item = await get_item.execute("abc-123")
49
+ ```
50
+
51
+ ## Status
52
+
53
+ Experimental, M4 of the project's own build plan. Both
54
+ `TransportConformanceTests` and `RemoteClientConformanceTests`
55
+ (`openframe-protocol-base`) pass against this package for real — the
56
+ point of building it: proving the architecture generalizes past HTTP,
57
+ not just adding a second transport for its own sake.
@@ -0,0 +1,67 @@
1
+ """
2
+ openframe.protocol.grpc
3
+ ==========================
4
+ gRPC binding, both directions, same two-file schema `-http` established:
5
+
6
+ - `bind_service` (`server.py`, needs the `[server]` extra) — wire a
7
+ `QueryHandler`/`CommandHandler`/`UseCase` to a `grpc.aio.Server` through
8
+ the shared error mapper and `RequestContext` builder in
9
+ `openframe.protocol.base`.
10
+ - `GrpcRemoteQueryClient`/`GrpcRemoteCommandClient` (`client.py`, needs
11
+ the `[client]` extra) — call another service built on this platform,
12
+ the outbound counterpart.
13
+
14
+ Unlike `-http`, both extras pull in the same underlying dependency
15
+ (`grpcio`) — there is no separate client-only wire library the way httpx
16
+ is separate from FastAPI. The `[server]`/`[client]` split is kept anyway,
17
+ for the same reason `-http` has it: so a package that only ever calls out
18
+ (never serves) doesn't need to reason about why a server dependency is
19
+ present, even if today that dependency happens to be identical.
20
+
21
+ Lazily imported (PEP 562, `__getattr__` below), matching `-http`'s own
22
+ `__init__.py` exactly — not because the dependency differs here, but
23
+ because the *schema* is the point: every future `openframe-protocol-*`
24
+ package follows this same lazy-import shape regardless of whether a given
25
+ transport's own extras happen to overlap.
26
+
27
+ `generic_pb2`/`generic_pb2_grpc` (the compiled `.proto` stubs) are
28
+ re-exported too, but not lazily — they need `grpcio` either way, the same
29
+ as everything else in this package, so there is no extras boundary for
30
+ them to respect.
31
+
32
+ .. stability: experimental
33
+ """
34
+ from __future__ import annotations
35
+
36
+ from typing import TYPE_CHECKING
37
+
38
+ from openframe.protocol.grpc import generic_pb2, generic_pb2_grpc
39
+
40
+ if TYPE_CHECKING:
41
+ from openframe.protocol.grpc.client import GrpcRemoteCommandClient, GrpcRemoteQueryClient
42
+ from openframe.protocol.grpc.server import ROUTE_METADATA_KEY, bind_service, create_server
43
+
44
+ __all__ = [
45
+ "bind_service",
46
+ "ROUTE_METADATA_KEY",
47
+ "create_server",
48
+ "GrpcRemoteQueryClient",
49
+ "GrpcRemoteCommandClient",
50
+ "generic_pb2",
51
+ "generic_pb2_grpc",
52
+ ]
53
+
54
+ _FROM_SERVER = {"bind_service", "ROUTE_METADATA_KEY", "create_server"}
55
+ _FROM_CLIENT = {"GrpcRemoteQueryClient", "GrpcRemoteCommandClient"}
56
+
57
+
58
+ def __getattr__(name: str):
59
+ if name in _FROM_SERVER:
60
+ from openframe.protocol.grpc import server
61
+
62
+ return getattr(server, name)
63
+ if name in _FROM_CLIENT:
64
+ from openframe.protocol.grpc import client
65
+
66
+ return getattr(client, name)
67
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,121 @@
1
+ """
2
+ openframe/protocol/grpc/client.py
3
+ =====================================
4
+ `GrpcRemoteQueryClient`/`GrpcRemoteCommandClient` — gRPC implementations
5
+ of `openframe.core.remote`'s `RemoteQueryClient`/`RemoteCommandClient`,
6
+ the gRPC counterpart of `-http`'s `HttpRemoteQueryClient`/
7
+ `HttpRemoteCommandClient`.
8
+
9
+ No `RequestSpec`-equivalent needed — simpler than the HTTP client's
10
+ `build_request` hook, not a weaker version of it. gRPC has no path/query/
11
+ body split: a request is just one message (`GenericRequest`), so the
12
+ handler's input value is JSON-encoded into `json_payload` directly, no
13
+ hook required to decide where each piece of it goes.
14
+
15
+ Lifecycle, per draft 8's D10 (same reasoning as `-http`'s client.py):
16
+ no `BasePort`/`PluginRegistry` involvement. Each client owns (or borrows)
17
+ a plain `grpc.aio.Channel` and exposes `aclose()` for a caller's own
18
+ lifespan to manage directly.
19
+
20
+ Dependency order:
21
+ protocol/grpc/client → protocol/base (errors, for the reverse mapping), protocol/grpc (generic_pb2*)
22
+ """
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ from typing import Any, Generic, TypeVar
27
+
28
+ import grpc
29
+
30
+ from openframe.core.inbound import RequestContext
31
+ from openframe.protocol.base.errors import ErrorCategory, ErrorEnvelope, raise_for_envelope
32
+ from openframe.protocol.grpc import generic_pb2, generic_pb2_grpc
33
+ from openframe.protocol.grpc.server import ROUTE_METADATA_KEY
34
+
35
+ __all__ = ["GrpcRemoteQueryClient", "GrpcRemoteCommandClient"]
36
+
37
+ TInput = TypeVar("TInput")
38
+ TOutput = TypeVar("TOutput")
39
+
40
+ _STATUS_CODE_TO_CATEGORY: dict[grpc.StatusCode, ErrorCategory] = {
41
+ grpc.StatusCode.NOT_FOUND: ErrorCategory.NOT_FOUND,
42
+ grpc.StatusCode.INVALID_ARGUMENT: ErrorCategory.INVALID,
43
+ grpc.StatusCode.DEADLINE_EXCEEDED: ErrorCategory.TIMEOUT,
44
+ grpc.StatusCode.UNAVAILABLE: ErrorCategory.UNAVAILABLE,
45
+ }
46
+
47
+
48
+ class _GrpcRemoteCallMixin:
49
+ """Shared machinery both client classes below use — not public itself."""
50
+
51
+ def __init__(
52
+ self,
53
+ *,
54
+ target: str | None = None,
55
+ route: str,
56
+ channel: "grpc.aio.Channel | None" = None,
57
+ remote_name: str | None = None,
58
+ ) -> None:
59
+ if channel is None and target is None:
60
+ raise ValueError("Either target or an existing channel must be provided.")
61
+ self._channel = channel if channel is not None else grpc.aio.insecure_channel(target)
62
+ self._owns_channel = channel is None
63
+ self._stub = generic_pb2_grpc.GenericServiceStub(self._channel)
64
+ self._route = route
65
+ self._remote_name = remote_name or f"grpc:{route}"
66
+
67
+ async def aclose(self) -> None:
68
+ """Close the underlying channel — only if this instance created it."""
69
+ if self._owns_channel:
70
+ await self._channel.close()
71
+
72
+ async def _call(self, value: Any, context: RequestContext | None) -> Any:
73
+ metadata: list[tuple[str, str]] = [(ROUTE_METADATA_KEY, self._route)]
74
+ if context is not None:
75
+ metadata.append(("x-correlation-id", context.correlation_id))
76
+
77
+ request = generic_pb2.GenericRequest(json_payload=json.dumps(value))
78
+
79
+ try:
80
+ response = await self._stub.Call(request, metadata=tuple(metadata))
81
+ except grpc.aio.AioRpcError as exc:
82
+ category = _STATUS_CODE_TO_CATEGORY.get(exc.code(), ErrorCategory.INTERNAL)
83
+ details = exc.details() or ""
84
+ try:
85
+ body = json.loads(details)
86
+ error = body.get("error", body)
87
+ except (json.JSONDecodeError, AttributeError):
88
+ error = {}
89
+ envelope = ErrorEnvelope(
90
+ code=error.get("code", "unknown"),
91
+ message=error.get("message", details or f"{self._remote_name} failed with {exc.code()}"),
92
+ retryable=error.get("retryable", False),
93
+ correlation_id=error.get("correlation_id", ""),
94
+ )
95
+ raise_for_envelope(category, envelope, remote_name=self._remote_name)
96
+
97
+ if not response.json_payload:
98
+ return None
99
+ return json.loads(response.json_payload)
100
+
101
+
102
+ class GrpcRemoteQueryClient(_GrpcRemoteCallMixin, Generic[TInput, TOutput]):
103
+ """
104
+ `RemoteQueryClient` over gRPC. Satisfies
105
+ `openframe.core.remote.RemoteQueryClient` structurally.
106
+
107
+ Args: see `_GrpcRemoteCallMixin.__init__`.
108
+ """
109
+
110
+ async def execute(self, query: TInput, context: RequestContext | None = None) -> TOutput:
111
+ return await self._call(query, context)
112
+
113
+
114
+ class GrpcRemoteCommandClient(_GrpcRemoteCallMixin, Generic[TInput]):
115
+ """
116
+ `RemoteCommandClient` over gRPC. Satisfies
117
+ `openframe.core.remote.RemoteCommandClient` structurally.
118
+ """
119
+
120
+ async def execute(self, command: TInput, context: RequestContext | None = None) -> None:
121
+ await self._call(command, context)
@@ -0,0 +1,18 @@
1
+ syntax = "proto3";
2
+ package openframe.protocol.grpc;
3
+
4
+ // One generic message pair instead of one per route — mirrors server.py's
5
+ // own inspect.Signature trick for HTTP: the wire schema doesn't need to
6
+ // know the domain type, only that a JSON-encoded payload travels inside it.
7
+ // The actual domain type is JSON-encoded inside json_payload.
8
+ message GenericRequest {
9
+ string json_payload = 1;
10
+ }
11
+
12
+ message GenericResponse {
13
+ string json_payload = 1;
14
+ }
15
+
16
+ service GenericService {
17
+ rpc Call(GenericRequest) returns (GenericResponse);
18
+ }
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: generic.proto
5
+ # Protobuf Python Version: 7.35.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 7,
15
+ 35,
16
+ 1,
17
+ '',
18
+ 'generic.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+
26
+
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rgeneric.proto\x12\x17openframe.protocol.grpc\"&\n\x0eGenericRequest\x12\x14\n\x0cjson_payload\x18\x01 \x01(\t\"\'\n\x0fGenericResponse\x12\x14\n\x0cjson_payload\x18\x01 \x01(\t2k\n\x0eGenericService\x12Y\n\x04\x43\x61ll\x12\'.openframe.protocol.grpc.GenericRequest\x1a(.openframe.protocol.grpc.GenericResponseb\x06proto3')
28
+
29
+ _globals = globals()
30
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'generic_pb2', _globals)
32
+ if not _descriptor._USE_C_DESCRIPTORS:
33
+ DESCRIPTOR._loaded_options = None
34
+ _globals['_GENERICREQUEST']._serialized_start=42
35
+ _globals['_GENERICREQUEST']._serialized_end=80
36
+ _globals['_GENERICRESPONSE']._serialized_start=82
37
+ _globals['_GENERICRESPONSE']._serialized_end=121
38
+ _globals['_GENERICSERVICE']._serialized_start=123
39
+ _globals['_GENERICSERVICE']._serialized_end=230
40
+ # @@protoc_insertion_point(module_scope)