protodial 1.0.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.
- protodial-1.0.0/.gitignore +16 -0
- protodial-1.0.0/CHANGELOG.md +21 -0
- protodial-1.0.0/LICENSE +21 -0
- protodial-1.0.0/PKG-INFO +306 -0
- protodial-1.0.0/README.md +276 -0
- protodial-1.0.0/docs/diagnostics.md +107 -0
- protodial-1.0.0/examples/README.md +86 -0
- protodial-1.0.0/examples/call.sh +33 -0
- protodial-1.0.0/examples/deadlines/Dockerfile +27 -0
- protodial-1.0.0/examples/deadlines/call.sh +25 -0
- protodial-1.0.0/examples/deadlines/deadlines.proto +15 -0
- protodial-1.0.0/examples/deadlines/server.py +89 -0
- protodial-1.0.0/examples/errors/Dockerfile +27 -0
- protodial-1.0.0/examples/errors/call.sh +24 -0
- protodial-1.0.0/examples/errors/errors.proto +16 -0
- protodial-1.0.0/examples/errors/server.py +107 -0
- protodial-1.0.0/examples/formats/Dockerfile +27 -0
- protodial-1.0.0/examples/formats/call.sh +34 -0
- protodial-1.0.0/examples/formats/formats.proto +31 -0
- protodial-1.0.0/examples/formats/server.py +99 -0
- protodial-1.0.0/examples/hello/Dockerfile +27 -0
- protodial-1.0.0/examples/hello/call.sh +23 -0
- protodial-1.0.0/examples/hello/hello.proto +16 -0
- protodial-1.0.0/examples/hello/server.py +83 -0
- protodial-1.0.0/examples/lib.sh +30 -0
- protodial-1.0.0/examples/run.sh +157 -0
- protodial-1.0.0/examples/server_logging.py +75 -0
- protodial-1.0.0/examples/streaming/Dockerfile +27 -0
- protodial-1.0.0/examples/streaming/call.sh +26 -0
- protodial-1.0.0/examples/streaming/server.py +171 -0
- protodial-1.0.0/examples/streaming/streaming.proto +24 -0
- protodial-1.0.0/pyproject.toml +93 -0
- protodial-1.0.0/src/protodial/__init__.py +3 -0
- protodial-1.0.0/src/protodial/__main__.py +5 -0
- protodial-1.0.0/src/protodial/_rich_details.py +35 -0
- protodial-1.0.0/src/protodial/argument_parser/__init__.py +7 -0
- protodial-1.0.0/src/protodial/argument_parser/construction.py +406 -0
- protodial-1.0.0/src/protodial/argument_parser/parsing.py +115 -0
- protodial-1.0.0/src/protodial/argument_parser/resolution.py +162 -0
- protodial-1.0.0/src/protodial/argument_parser/target.py +227 -0
- protodial-1.0.0/src/protodial/argument_parser/validation.py +249 -0
- protodial-1.0.0/src/protodial/cli.py +662 -0
- protodial-1.0.0/src/protodial/commands/__init__.py +36 -0
- protodial-1.0.0/src/protodial/commands/models.py +131 -0
- protodial-1.0.0/src/protodial/commands/operations.py +29 -0
- protodial-1.0.0/src/protodial/errors.py +164 -0
- protodial-1.0.0/src/protodial/formats.py +14 -0
- protodial-1.0.0/src/protodial/message_io/__init__.py +61 -0
- protodial-1.0.0/src/protodial/message_io/dispatch.py +65 -0
- protodial-1.0.0/src/protodial/message_io/json_decoding.py +56 -0
- protodial-1.0.0/src/protodial/message_io/json_input.py +411 -0
- protodial-1.0.0/src/protodial/message_io/limits.py +59 -0
- protodial-1.0.0/src/protodial/message_io/models.py +90 -0
- protodial-1.0.0/src/protodial/message_io/output.py +94 -0
- protodial-1.0.0/src/protodial/message_io/protobuf_input.py +87 -0
- protodial-1.0.0/src/protodial/message_io/raw_input.py +125 -0
- protodial-1.0.0/src/protodial/message_io/text_input.py +114 -0
- protodial-1.0.0/src/protodial/presentation/__init__.py +51 -0
- protodial-1.0.0/src/protodial/presentation/_grapheme_data.py +1899 -0
- protodial-1.0.0/src/protodial/presentation/_graphemes.py +233 -0
- protodial-1.0.0/src/protodial/presentation/_truncation.py +198 -0
- protodial-1.0.0/src/protodial/presentation/descriptor.py +586 -0
- protodial-1.0.0/src/protodial/presentation/diagnostics/__init__.py +39 -0
- protodial-1.0.0/src/protodial/presentation/diagnostics/context.py +28 -0
- protodial-1.0.0/src/protodial/presentation/diagnostics/error_events.py +667 -0
- protodial-1.0.0/src/protodial/presentation/diagnostics/models.py +571 -0
- protodial-1.0.0/src/protodial/presentation/diagnostics/rendering.py +3161 -0
- protodial-1.0.0/src/protodial/presentation/rpc.py +195 -0
- protodial-1.0.0/src/protodial/presentation/sanitization.py +30 -0
- protodial-1.0.0/src/protodial/presentation/templates.py +131 -0
- protodial-1.0.0/src/protodial/py.typed +1 -0
- protodial-1.0.0/src/protodial/request_metadata/__init__.py +26 -0
- protodial-1.0.0/src/protodial/request_metadata/parsing.py +187 -0
- protodial-1.0.0/src/protodial/request_metadata/types.py +11 -0
- protodial-1.0.0/src/protodial/rich_status/__init__.py +36 -0
- protodial-1.0.0/src/protodial/rich_status/decoding.py +457 -0
- protodial-1.0.0/src/protodial/rich_status/models.py +43 -0
- protodial-1.0.0/src/protodial/rich_status/rendering.py +245 -0
- protodial-1.0.0/src/protodial/rpc.py +249 -0
- protodial-1.0.0/src/protodial/rpc_core/__init__.py +1 -0
- protodial-1.0.0/src/protodial/rpc_core/call.py +843 -0
- protodial-1.0.0/src/protodial/rpc_core/discovery.py +99 -0
- protodial-1.0.0/src/protodial/rpc_core/input.py +115 -0
- protodial-1.0.0/src/protodial/rpc_core/invoke.py +191 -0
- protodial-1.0.0/src/protodial/rpc_core/models.py +49 -0
- protodial-1.0.0/src/protodial/rpc_core/protocols.py +233 -0
- protodial-1.0.0/src/protodial/rpc_core/runtime.py +32 -0
- protodial-1.0.0/src/protodial/schema/__init__.py +1 -0
- protodial-1.0.0/src/protodial/schema/composition.py +95 -0
- protodial-1.0.0/src/protodial/schema/context.py +229 -0
- protodial-1.0.0/src/protodial/schema/contracts.py +170 -0
- protodial-1.0.0/src/protodial/schema/export.py +101 -0
- protodial-1.0.0/src/protodial/schema/factory.py +47 -0
- protodial-1.0.0/src/protodial/schema/local.py +607 -0
- protodial-1.0.0/src/protodial/schema/paths.py +54 -0
- protodial-1.0.0/src/protodial/schema/reflection.py +570 -0
- protodial-1.0.0/src/protodial/schema/registry.py +477 -0
- protodial-1.0.0/src/protodial/schema/source_locations.py +20 -0
- protodial-1.0.0/src/protodial/schema/source_protos.py +113 -0
- protodial-1.0.0/src/protodial/transport.py +103 -0
- protodial-1.0.0/src/protodial/transport_core/__init__.py +1 -0
- protodial-1.0.0/src/protodial/transport_core/channels.py +185 -0
- protodial-1.0.0/src/protodial/transport_core/insecure.py +584 -0
- protodial-1.0.0/src/protodial/transport_core/options.py +134 -0
- protodial-1.0.0/src/protodial/transport_core/protocols.py +82 -0
- protodial-1.0.0/src/protodial/transport_core/tls.py +335 -0
- protodial-1.0.0/tests/test_cli.py +1867 -0
- protodial-1.0.0/tests/test_cli_end_to_end.py +1580 -0
- protodial-1.0.0/tests/test_cli_io_security_edges.py +360 -0
- protodial-1.0.0/tests/test_diagnostics_metadata_status.py +710 -0
- protodial-1.0.0/tests/test_discovery.py +497 -0
- protodial-1.0.0/tests/test_examples.py +136 -0
- protodial-1.0.0/tests/test_messages.py +1077 -0
- protodial-1.0.0/tests/test_rpc_input_failures.py +229 -0
- protodial-1.0.0/tests/test_rpc_integration.py +385 -0
- protodial-1.0.0/tests/test_rpc_results.py +637 -0
- protodial-1.0.0/tests/test_schema_edge_cases.py +801 -0
- protodial-1.0.0/tests/test_schema_sources.py +1130 -0
- protodial-1.0.0/tests/test_structured_diagnostics.py +4021 -0
- protodial-1.0.0/tests/test_transport.py +722 -0
- protodial-1.0.0/tests/test_tunnel_lifecycle_edges.py +256 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 — 2026-10-25
|
|
4
|
+
|
|
5
|
+
Initial release.
|
|
6
|
+
|
|
7
|
+
- Invoke unary, client-streaming, server-streaming, and bidirectional gRPC methods.
|
|
8
|
+
- Discover services and protobuf symbols through server reflection, local
|
|
9
|
+
`.proto` files, or binary descriptor sets. Generate request templates and
|
|
10
|
+
export resolved descriptor sets.
|
|
11
|
+
- Read and write ProtoJSON, textproto, serialized protobuf, and raw bytes.
|
|
12
|
+
Stream requests from stdin and bind files to protobuf bytes fields.
|
|
13
|
+
- Configure TLS, custom CAs, mutual TLS, server identity, and HTTP/2 authority.
|
|
14
|
+
Support plaintext and explicit unverified TLS connections.
|
|
15
|
+
- Send shared or scoped request metadata. Inspect response headers, trailers,
|
|
16
|
+
status, and structured gRPC errors.
|
|
17
|
+
- Emit human-readable or versioned NDJSON diagnostics on stderr while keeping
|
|
18
|
+
response payloads on stdout.
|
|
19
|
+
- Configure deadlines, readiness checks, message limits, compression, and
|
|
20
|
+
keepalives. Support resolver URIs and Unix-socket targets.
|
|
21
|
+
- Provide a Python 3.10+ package, a `protodial` command, and a Docker image build.
|
protodial-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 félix
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
protodial-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: protodial
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Call gRPC services from the command line using reflection or local proto files
|
|
5
|
+
Project-URL: Repository, https://github.com/ocku/protodial
|
|
6
|
+
Project-URL: Issues, https://github.com/ocku/protodial/issues
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: cli,grpc,protobuf,reflection,rpc
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: System :: Networking
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: cryptography>=42
|
|
24
|
+
Requires-Dist: googleapis-common-protos>=1.63
|
|
25
|
+
Requires-Dist: grpcio-reflection>=1.62
|
|
26
|
+
Requires-Dist: grpcio-tools>=1.62
|
|
27
|
+
Requires-Dist: grpcio>=1.62
|
|
28
|
+
Requires-Dist: protobuf>=7
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# protodial
|
|
32
|
+
|
|
33
|
+
A Python command-line client for gRPC. Call methods, list services, inspect
|
|
34
|
+
protobuf definitions, and generate request templates using server reflection,
|
|
35
|
+
local `.proto` files, or descriptor sets. No generated client code is required.
|
|
36
|
+
|
|
37
|
+
Supports unary, client-streaming, server-streaming, and bidirectional RPCs.
|
|
38
|
+
Requests and responses can use ProtoJSON, textproto, serialized protobuf, or
|
|
39
|
+
raw bytes. Response payloads go to stdout; diagnostics go to stderr.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
Requires Python 3.10 or newer. Install the checkout with
|
|
44
|
+
[uv](https://docs.astral.sh/uv/):
|
|
45
|
+
|
|
46
|
+
```console
|
|
47
|
+
uv tool install .
|
|
48
|
+
protodial --version
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If the package is available on your package index, install version 1.0.0 with
|
|
52
|
+
`uv tool install protodial==1.0.0` or `python -m pip install protodial==1.0.0`.
|
|
53
|
+
You can also run it as `python -m protodial`.
|
|
54
|
+
|
|
55
|
+
## Quick start
|
|
56
|
+
|
|
57
|
+
Call a server with [reflection](https://grpc.io/docs/guides/reflection/) enabled:
|
|
58
|
+
|
|
59
|
+
```console
|
|
60
|
+
protodial -d '{"name":"Ada"}' \
|
|
61
|
+
grpc://localhost:50051/example.Greeter/SayHello
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The [hello example](examples/README.md) returns compact ProtoJSON:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{"message":"Hello, Ada!","requestId":"example-123"}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Use `grpc://` for plaintext and `grpcs://` for TLS. Bare targets and gRPC
|
|
71
|
+
resolver URIs use TLS by default. For resolver or Unix-socket targets, specify
|
|
72
|
+
`--method` separately:
|
|
73
|
+
|
|
74
|
+
```console
|
|
75
|
+
protodial --plaintext --method example.Greeter/SayHello dns:///localhost:50051
|
|
76
|
+
protodial --plaintext --method example.Greeter/SayHello unix:///tmp/example.sock
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
When reflection is unavailable, provide a schema:
|
|
80
|
+
|
|
81
|
+
```console
|
|
82
|
+
protodial --proto api.proto --proto-path protos -d @request.json \
|
|
83
|
+
grpcs://api.example.com:443/example.Greeter/SayHello
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Invocation options precede the target. Discovery options follow `list` or
|
|
87
|
+
`describe`. Run `protodial --help`, `protodial list --help`, or
|
|
88
|
+
`protodial describe --help` for the full option reference.
|
|
89
|
+
|
|
90
|
+
## Schema discovery
|
|
91
|
+
|
|
92
|
+
```console
|
|
93
|
+
# List services, then methods on a service.
|
|
94
|
+
protodial list grpc://localhost:50051
|
|
95
|
+
protodial list grpc://localhost:50051 example.Greeter
|
|
96
|
+
|
|
97
|
+
# Inspect a service, method, message, or field.
|
|
98
|
+
protodial describe grpc://localhost:50051 example.Greeter
|
|
99
|
+
protodial describe grpc://localhost:50051/example.Greeter/SayHello
|
|
100
|
+
protodial describe grpc://localhost:50051 example.HelloRequest.name
|
|
101
|
+
|
|
102
|
+
# Generate a ProtoJSON request template.
|
|
103
|
+
protodial describe --template \
|
|
104
|
+
grpc://localhost:50051/example.Greeter/SayHello
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Service names are sorted; methods retain declaration order. Reflection services
|
|
108
|
+
are hidden unless `--show-reflection` is set. Unique short or suffix names are
|
|
109
|
+
accepted; ambiguous names report the qualified candidates.
|
|
110
|
+
|
|
111
|
+
`describe --template` accepts a message or method. For methods, it uses the
|
|
112
|
+
request type. Templates include one repeated item and the first alternative
|
|
113
|
+
of each oneof. `--template-depth` limits nesting (default: 8).
|
|
114
|
+
|
|
115
|
+
### Local schemas and descriptor sets
|
|
116
|
+
|
|
117
|
+
```console
|
|
118
|
+
protodial list --proto api.proto --proto-path protos unused.example:443
|
|
119
|
+
protodial describe --protoset api.protoset \
|
|
120
|
+
unused.example:443 example.HelloRequest
|
|
121
|
+
protodial list --protoset-out schema.pb grpc://localhost:50051
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- Repeat `--proto` to compile multiple entrypoints or `--protoset` to combine
|
|
125
|
+
binary `FileDescriptorSet` files. Conflicting definitions of the same file
|
|
126
|
+
are rejected.
|
|
127
|
+
- Local schemas disable reflection by default. Add `--use-reflection` to resolve
|
|
128
|
+
missing symbols from the server.
|
|
129
|
+
- Local-only discovery does not contact the target, but still requires a target
|
|
130
|
+
operand.
|
|
131
|
+
- `--protoset-out` atomically exports the resolved schema and its dependencies.
|
|
132
|
+
- Repeat `--proto-path` for import roots. The default reusable schema directory
|
|
133
|
+
is `$XDG_DATA_HOME/protodial/protos`, falling back to
|
|
134
|
+
`$HOME/.local/share/protodial/protos`. It is not created automatically.
|
|
135
|
+
|
|
136
|
+
Invocation URL paths use `/SERVICE/METHOD`. Discovery URLs can contain
|
|
137
|
+
`/SERVICE` for `list`, or `/SYMBOL` or `/SERVICE/METHOD` for `describe`.
|
|
138
|
+
URL credentials, query strings, and fragments are not supported.
|
|
139
|
+
|
|
140
|
+
## Request and response formats
|
|
141
|
+
|
|
142
|
+
Select encodings independently with `--input-format` and `--output-format`.
|
|
143
|
+
Both default to `json`.
|
|
144
|
+
|
|
145
|
+
| Format | Unary | Streaming |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| `json` | One ProtoJSON value | Whitespace-separated values; output is NDJSON |
|
|
148
|
+
| `text` | One textproto document | Documents separated by a line containing `---` |
|
|
149
|
+
| `protobuf` | One serialized message | Four-byte unsigned big-endian length, then message bytes |
|
|
150
|
+
| `raw` | One top-level `bytes` field | Input byte chunks; concatenated output bytes |
|
|
151
|
+
|
|
152
|
+
Protobuf file framing is a protodial convention, not gRPC wire framing.
|
|
153
|
+
ProtoJSON `bytes` fields use base64 strings.
|
|
154
|
+
|
|
155
|
+
`-d` / `--data` accepts a literal value, `@path` for a file, or `-` / `@-` for
|
|
156
|
+
stdin. Without `--data`, unary calls send one empty message and client streams
|
|
157
|
+
send no messages, regardless of format.
|
|
158
|
+
|
|
159
|
+
JSON client streams are parsed incrementally. NDJSON, multiline values, and
|
|
160
|
+
consecutive whitespace-separated values are accepted. Responses are compact
|
|
161
|
+
JSON values, one per line:
|
|
162
|
+
|
|
163
|
+
```console
|
|
164
|
+
printf '%s\n' '{"value":1}' '{"value":2}' | \
|
|
165
|
+
protodial -d @- grpc://localhost:50051/example.Service/Upload
|
|
166
|
+
|
|
167
|
+
protodial -d '{"name":"Ada"}' \
|
|
168
|
+
grpc://localhost:50051/example.Greeter/SayHello | jq .
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Use `--allow-unknown-fields` to ignore unknown JSON input fields,
|
|
172
|
+
`--emit-defaults` to include default-valued output fields, and
|
|
173
|
+
`--max-input-buffer` to limit buffered parser input.
|
|
174
|
+
|
|
175
|
+
### Raw file input
|
|
176
|
+
|
|
177
|
+
Bind a file to a `bytes` field with `--field:file`; this selects raw input.
|
|
178
|
+
Use repeatable `--field` options for other top-level fields:
|
|
179
|
+
|
|
180
|
+
```console
|
|
181
|
+
protodial --field filename=video.bin --field:file content=video.bin \
|
|
182
|
+
grpc://localhost:50051/example.Service/Upload
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`--field` values are parsed as ProtoJSON values, or as strings if they are not
|
|
186
|
+
valid JSON. `--field:file content=-` reads bytes from stdin.
|
|
187
|
+
|
|
188
|
+
With `--input-format raw` or `--output-format raw`, the bytes field is inferred
|
|
189
|
+
if there is exactly one eligible field. Otherwise, select it with
|
|
190
|
+
`--input-field` or `--output-field`. Client-streaming raw input is split into
|
|
191
|
+
`--chunk-size` byte messages; `--field` values apply to every message.
|
|
192
|
+
|
|
193
|
+
Server streams flush each response as it arrives. Bidirectional calls send and
|
|
194
|
+
receive concurrently. Failed streams preserve partial stdout output and exit
|
|
195
|
+
nonzero. Ctrl-C and a closed output pipe cancel the active RPC. Interactive
|
|
196
|
+
prompting is not supported; use `-d @-` for streaming stdin.
|
|
197
|
+
|
|
198
|
+
## Metadata and diagnostics
|
|
199
|
+
|
|
200
|
+
```console
|
|
201
|
+
protodial -H 'authorization:Bearer token' --rpc-header 'x-request-id:1234' \
|
|
202
|
+
-i --show-trailers --show-status \
|
|
203
|
+
grpcs://api.example.com:443/example.Service/Call
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`-H` / `--header` metadata is sent to reflection and the application RPC.
|
|
207
|
+
`--reflect-header` and `--rpc-header` add scope-specific metadata without
|
|
208
|
+
replacing duplicate keys. Values for keys ending in `-bin` must be base64.
|
|
209
|
+
`--expand-headers` expands `$NAME` and `${NAME}` in values; `$$` is a literal
|
|
210
|
+
dollar sign. Expansion does not invoke a shell.
|
|
211
|
+
|
|
212
|
+
Diagnostics never share stdout with response data:
|
|
213
|
+
|
|
214
|
+
- `-i` / `--include`: response headers.
|
|
215
|
+
- `--show-trailers`: response trailers.
|
|
216
|
+
- `--show-status`: final status, message counts, and elapsed time.
|
|
217
|
+
- `--format-error`: decode `google.rpc.Status` and its detail messages.
|
|
218
|
+
- `-v`: response diagnostics, structured errors, and resolved method.
|
|
219
|
+
- `-vv`: also include connection, transport, schema, and RPC lifecycle events.
|
|
220
|
+
|
|
221
|
+
Human diagnostics use `*` for status, `>` for request metadata, and `<` for
|
|
222
|
+
response metadata. `--color auto|always|never` controls stderr color. Automatic
|
|
223
|
+
color requires a terminal and honors `NO_COLOR` and `TERM=dumb`.
|
|
224
|
+
|
|
225
|
+
For scripts, use NDJSON diagnostics rather than parsing human output:
|
|
226
|
+
|
|
227
|
+
```console
|
|
228
|
+
protodial -vv --diagnostic-format json \
|
|
229
|
+
grpc://localhost:50051/example.Greeter/SayHello \
|
|
230
|
+
>responses.ndjson 2>diagnostics.ndjson
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`PROTODIAL_DIAGNOSTIC_FORMAT=human|json` sets the default; the CLI option takes
|
|
234
|
+
precedence. See [the diagnostic schema](docs/diagnostics.md) for the
|
|
235
|
+
`protodial.diagnostic.v1` contract.
|
|
236
|
+
|
|
237
|
+
## TLS and connection controls
|
|
238
|
+
|
|
239
|
+
TLS is enabled by default. Use `--plaintext` or a `grpc://` URL to disable it.
|
|
240
|
+
|
|
241
|
+
| Option | Purpose |
|
|
242
|
+
| --- | --- |
|
|
243
|
+
| `--cacert FILE` | Trust a PEM CA bundle; repeatable |
|
|
244
|
+
| `--cert FILE --key FILE` | Present a client certificate and private key |
|
|
245
|
+
| `--key-password PASSWORD` | Decrypt an encrypted private key |
|
|
246
|
+
| `--servername NAME` | Set TLS SNI and the verified server identity |
|
|
247
|
+
| `--authority NAME` | Set HTTP/2 `:authority` |
|
|
248
|
+
| `-k` / `--insecure` | Disable TLS peer verification; unsafe |
|
|
249
|
+
|
|
250
|
+
`--cert` and `--key` are required together. Certificate options cannot be used
|
|
251
|
+
with `--plaintext`. A key password passed on the command line may be exposed
|
|
252
|
+
in shell history and the process list.
|
|
253
|
+
|
|
254
|
+
`--insecure` uses a local TLS relay and always emits a warning. On Unix, the
|
|
255
|
+
relay uses an owner-only temporary directory and a socket with mode `0600`.
|
|
256
|
+
The loopback TCP fallback on platforms without Unix sockets rejects client
|
|
257
|
+
certificates to prevent other local processes from using that identity.
|
|
258
|
+
Neither mode protects against remote man-in-the-middle attacks.
|
|
259
|
+
|
|
260
|
+
`--connect-timeout` bounds the channel-readiness check before schema discovery
|
|
261
|
+
or invocation. `-m` / `--max-time` sets the RPC deadline in seconds.
|
|
262
|
+
`--wait-for-ready` lets an RPC wait for an available channel within that
|
|
263
|
+
deadline; local-schema calls with this flag skip the readiness preflight.
|
|
264
|
+
Reflection still requires the preflight.
|
|
265
|
+
|
|
266
|
+
`--max-send-message-size` and `--max-recv-message-size` set gRPC message limits.
|
|
267
|
+
`--compression` accepts `none`, `gzip`, or `deflate`. `--keepalive-time` sets the
|
|
268
|
+
HTTP/2 keepalive interval in seconds; aggressive intervals may be rejected by
|
|
269
|
+
servers. `-A` / `--user-agent` sets the primary gRPC user agent.
|
|
270
|
+
|
|
271
|
+
## Exit codes
|
|
272
|
+
|
|
273
|
+
| Code | Meaning |
|
|
274
|
+
| ---: | --- |
|
|
275
|
+
| `0` | Success |
|
|
276
|
+
| `1` | Dependency, RPC, input, schema, or file error |
|
|
277
|
+
| `2` | Invalid CLI usage |
|
|
278
|
+
| `130` | Interrupted with Ctrl-C |
|
|
279
|
+
|
|
280
|
+
## Docker
|
|
281
|
+
|
|
282
|
+
```console
|
|
283
|
+
docker build -t protodial:1.0.0 .
|
|
284
|
+
docker run --rm protodial:1.0.0 --version
|
|
285
|
+
docker run --rm protodial:1.0.0 -d '{"name":"Ada"}' \
|
|
286
|
+
grpc://host.docker.internal:50051/example.Greeter/SayHello
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
On Docker Desktop, `host.docker.internal` addresses the host. On Linux, use
|
|
290
|
+
`--network host` with a localhost target when appropriate. Mount local schema,
|
|
291
|
+
request, and certificate files into the container; add `-i` when reading stdin.
|
|
292
|
+
|
|
293
|
+
## Development
|
|
294
|
+
|
|
295
|
+
```console
|
|
296
|
+
uv sync --dev
|
|
297
|
+
uv run protodial --help
|
|
298
|
+
uv run pytest
|
|
299
|
+
uv run ruff check .
|
|
300
|
+
uv run pyright
|
|
301
|
+
uv build
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
See [examples](examples/README.md) for runnable servers and calls, and
|
|
305
|
+
[CHANGELOG.md](CHANGELOG.md) for release notes. The CLI is the primary supported
|
|
306
|
+
interface; this README does not define a stable Python library API.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# protodial
|
|
2
|
+
|
|
3
|
+
A Python command-line client for gRPC. Call methods, list services, inspect
|
|
4
|
+
protobuf definitions, and generate request templates using server reflection,
|
|
5
|
+
local `.proto` files, or descriptor sets. No generated client code is required.
|
|
6
|
+
|
|
7
|
+
Supports unary, client-streaming, server-streaming, and bidirectional RPCs.
|
|
8
|
+
Requests and responses can use ProtoJSON, textproto, serialized protobuf, or
|
|
9
|
+
raw bytes. Response payloads go to stdout; diagnostics go to stderr.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Requires Python 3.10 or newer. Install the checkout with
|
|
14
|
+
[uv](https://docs.astral.sh/uv/):
|
|
15
|
+
|
|
16
|
+
```console
|
|
17
|
+
uv tool install .
|
|
18
|
+
protodial --version
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If the package is available on your package index, install version 1.0.0 with
|
|
22
|
+
`uv tool install protodial==1.0.0` or `python -m pip install protodial==1.0.0`.
|
|
23
|
+
You can also run it as `python -m protodial`.
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
Call a server with [reflection](https://grpc.io/docs/guides/reflection/) enabled:
|
|
28
|
+
|
|
29
|
+
```console
|
|
30
|
+
protodial -d '{"name":"Ada"}' \
|
|
31
|
+
grpc://localhost:50051/example.Greeter/SayHello
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The [hello example](examples/README.md) returns compact ProtoJSON:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{"message":"Hello, Ada!","requestId":"example-123"}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `grpc://` for plaintext and `grpcs://` for TLS. Bare targets and gRPC
|
|
41
|
+
resolver URIs use TLS by default. For resolver or Unix-socket targets, specify
|
|
42
|
+
`--method` separately:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
protodial --plaintext --method example.Greeter/SayHello dns:///localhost:50051
|
|
46
|
+
protodial --plaintext --method example.Greeter/SayHello unix:///tmp/example.sock
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
When reflection is unavailable, provide a schema:
|
|
50
|
+
|
|
51
|
+
```console
|
|
52
|
+
protodial --proto api.proto --proto-path protos -d @request.json \
|
|
53
|
+
grpcs://api.example.com:443/example.Greeter/SayHello
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Invocation options precede the target. Discovery options follow `list` or
|
|
57
|
+
`describe`. Run `protodial --help`, `protodial list --help`, or
|
|
58
|
+
`protodial describe --help` for the full option reference.
|
|
59
|
+
|
|
60
|
+
## Schema discovery
|
|
61
|
+
|
|
62
|
+
```console
|
|
63
|
+
# List services, then methods on a service.
|
|
64
|
+
protodial list grpc://localhost:50051
|
|
65
|
+
protodial list grpc://localhost:50051 example.Greeter
|
|
66
|
+
|
|
67
|
+
# Inspect a service, method, message, or field.
|
|
68
|
+
protodial describe grpc://localhost:50051 example.Greeter
|
|
69
|
+
protodial describe grpc://localhost:50051/example.Greeter/SayHello
|
|
70
|
+
protodial describe grpc://localhost:50051 example.HelloRequest.name
|
|
71
|
+
|
|
72
|
+
# Generate a ProtoJSON request template.
|
|
73
|
+
protodial describe --template \
|
|
74
|
+
grpc://localhost:50051/example.Greeter/SayHello
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Service names are sorted; methods retain declaration order. Reflection services
|
|
78
|
+
are hidden unless `--show-reflection` is set. Unique short or suffix names are
|
|
79
|
+
accepted; ambiguous names report the qualified candidates.
|
|
80
|
+
|
|
81
|
+
`describe --template` accepts a message or method. For methods, it uses the
|
|
82
|
+
request type. Templates include one repeated item and the first alternative
|
|
83
|
+
of each oneof. `--template-depth` limits nesting (default: 8).
|
|
84
|
+
|
|
85
|
+
### Local schemas and descriptor sets
|
|
86
|
+
|
|
87
|
+
```console
|
|
88
|
+
protodial list --proto api.proto --proto-path protos unused.example:443
|
|
89
|
+
protodial describe --protoset api.protoset \
|
|
90
|
+
unused.example:443 example.HelloRequest
|
|
91
|
+
protodial list --protoset-out schema.pb grpc://localhost:50051
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- Repeat `--proto` to compile multiple entrypoints or `--protoset` to combine
|
|
95
|
+
binary `FileDescriptorSet` files. Conflicting definitions of the same file
|
|
96
|
+
are rejected.
|
|
97
|
+
- Local schemas disable reflection by default. Add `--use-reflection` to resolve
|
|
98
|
+
missing symbols from the server.
|
|
99
|
+
- Local-only discovery does not contact the target, but still requires a target
|
|
100
|
+
operand.
|
|
101
|
+
- `--protoset-out` atomically exports the resolved schema and its dependencies.
|
|
102
|
+
- Repeat `--proto-path` for import roots. The default reusable schema directory
|
|
103
|
+
is `$XDG_DATA_HOME/protodial/protos`, falling back to
|
|
104
|
+
`$HOME/.local/share/protodial/protos`. It is not created automatically.
|
|
105
|
+
|
|
106
|
+
Invocation URL paths use `/SERVICE/METHOD`. Discovery URLs can contain
|
|
107
|
+
`/SERVICE` for `list`, or `/SYMBOL` or `/SERVICE/METHOD` for `describe`.
|
|
108
|
+
URL credentials, query strings, and fragments are not supported.
|
|
109
|
+
|
|
110
|
+
## Request and response formats
|
|
111
|
+
|
|
112
|
+
Select encodings independently with `--input-format` and `--output-format`.
|
|
113
|
+
Both default to `json`.
|
|
114
|
+
|
|
115
|
+
| Format | Unary | Streaming |
|
|
116
|
+
| --- | --- | --- |
|
|
117
|
+
| `json` | One ProtoJSON value | Whitespace-separated values; output is NDJSON |
|
|
118
|
+
| `text` | One textproto document | Documents separated by a line containing `---` |
|
|
119
|
+
| `protobuf` | One serialized message | Four-byte unsigned big-endian length, then message bytes |
|
|
120
|
+
| `raw` | One top-level `bytes` field | Input byte chunks; concatenated output bytes |
|
|
121
|
+
|
|
122
|
+
Protobuf file framing is a protodial convention, not gRPC wire framing.
|
|
123
|
+
ProtoJSON `bytes` fields use base64 strings.
|
|
124
|
+
|
|
125
|
+
`-d` / `--data` accepts a literal value, `@path` for a file, or `-` / `@-` for
|
|
126
|
+
stdin. Without `--data`, unary calls send one empty message and client streams
|
|
127
|
+
send no messages, regardless of format.
|
|
128
|
+
|
|
129
|
+
JSON client streams are parsed incrementally. NDJSON, multiline values, and
|
|
130
|
+
consecutive whitespace-separated values are accepted. Responses are compact
|
|
131
|
+
JSON values, one per line:
|
|
132
|
+
|
|
133
|
+
```console
|
|
134
|
+
printf '%s\n' '{"value":1}' '{"value":2}' | \
|
|
135
|
+
protodial -d @- grpc://localhost:50051/example.Service/Upload
|
|
136
|
+
|
|
137
|
+
protodial -d '{"name":"Ada"}' \
|
|
138
|
+
grpc://localhost:50051/example.Greeter/SayHello | jq .
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Use `--allow-unknown-fields` to ignore unknown JSON input fields,
|
|
142
|
+
`--emit-defaults` to include default-valued output fields, and
|
|
143
|
+
`--max-input-buffer` to limit buffered parser input.
|
|
144
|
+
|
|
145
|
+
### Raw file input
|
|
146
|
+
|
|
147
|
+
Bind a file to a `bytes` field with `--field:file`; this selects raw input.
|
|
148
|
+
Use repeatable `--field` options for other top-level fields:
|
|
149
|
+
|
|
150
|
+
```console
|
|
151
|
+
protodial --field filename=video.bin --field:file content=video.bin \
|
|
152
|
+
grpc://localhost:50051/example.Service/Upload
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`--field` values are parsed as ProtoJSON values, or as strings if they are not
|
|
156
|
+
valid JSON. `--field:file content=-` reads bytes from stdin.
|
|
157
|
+
|
|
158
|
+
With `--input-format raw` or `--output-format raw`, the bytes field is inferred
|
|
159
|
+
if there is exactly one eligible field. Otherwise, select it with
|
|
160
|
+
`--input-field` or `--output-field`. Client-streaming raw input is split into
|
|
161
|
+
`--chunk-size` byte messages; `--field` values apply to every message.
|
|
162
|
+
|
|
163
|
+
Server streams flush each response as it arrives. Bidirectional calls send and
|
|
164
|
+
receive concurrently. Failed streams preserve partial stdout output and exit
|
|
165
|
+
nonzero. Ctrl-C and a closed output pipe cancel the active RPC. Interactive
|
|
166
|
+
prompting is not supported; use `-d @-` for streaming stdin.
|
|
167
|
+
|
|
168
|
+
## Metadata and diagnostics
|
|
169
|
+
|
|
170
|
+
```console
|
|
171
|
+
protodial -H 'authorization:Bearer token' --rpc-header 'x-request-id:1234' \
|
|
172
|
+
-i --show-trailers --show-status \
|
|
173
|
+
grpcs://api.example.com:443/example.Service/Call
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`-H` / `--header` metadata is sent to reflection and the application RPC.
|
|
177
|
+
`--reflect-header` and `--rpc-header` add scope-specific metadata without
|
|
178
|
+
replacing duplicate keys. Values for keys ending in `-bin` must be base64.
|
|
179
|
+
`--expand-headers` expands `$NAME` and `${NAME}` in values; `$$` is a literal
|
|
180
|
+
dollar sign. Expansion does not invoke a shell.
|
|
181
|
+
|
|
182
|
+
Diagnostics never share stdout with response data:
|
|
183
|
+
|
|
184
|
+
- `-i` / `--include`: response headers.
|
|
185
|
+
- `--show-trailers`: response trailers.
|
|
186
|
+
- `--show-status`: final status, message counts, and elapsed time.
|
|
187
|
+
- `--format-error`: decode `google.rpc.Status` and its detail messages.
|
|
188
|
+
- `-v`: response diagnostics, structured errors, and resolved method.
|
|
189
|
+
- `-vv`: also include connection, transport, schema, and RPC lifecycle events.
|
|
190
|
+
|
|
191
|
+
Human diagnostics use `*` for status, `>` for request metadata, and `<` for
|
|
192
|
+
response metadata. `--color auto|always|never` controls stderr color. Automatic
|
|
193
|
+
color requires a terminal and honors `NO_COLOR` and `TERM=dumb`.
|
|
194
|
+
|
|
195
|
+
For scripts, use NDJSON diagnostics rather than parsing human output:
|
|
196
|
+
|
|
197
|
+
```console
|
|
198
|
+
protodial -vv --diagnostic-format json \
|
|
199
|
+
grpc://localhost:50051/example.Greeter/SayHello \
|
|
200
|
+
>responses.ndjson 2>diagnostics.ndjson
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`PROTODIAL_DIAGNOSTIC_FORMAT=human|json` sets the default; the CLI option takes
|
|
204
|
+
precedence. See [the diagnostic schema](docs/diagnostics.md) for the
|
|
205
|
+
`protodial.diagnostic.v1` contract.
|
|
206
|
+
|
|
207
|
+
## TLS and connection controls
|
|
208
|
+
|
|
209
|
+
TLS is enabled by default. Use `--plaintext` or a `grpc://` URL to disable it.
|
|
210
|
+
|
|
211
|
+
| Option | Purpose |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| `--cacert FILE` | Trust a PEM CA bundle; repeatable |
|
|
214
|
+
| `--cert FILE --key FILE` | Present a client certificate and private key |
|
|
215
|
+
| `--key-password PASSWORD` | Decrypt an encrypted private key |
|
|
216
|
+
| `--servername NAME` | Set TLS SNI and the verified server identity |
|
|
217
|
+
| `--authority NAME` | Set HTTP/2 `:authority` |
|
|
218
|
+
| `-k` / `--insecure` | Disable TLS peer verification; unsafe |
|
|
219
|
+
|
|
220
|
+
`--cert` and `--key` are required together. Certificate options cannot be used
|
|
221
|
+
with `--plaintext`. A key password passed on the command line may be exposed
|
|
222
|
+
in shell history and the process list.
|
|
223
|
+
|
|
224
|
+
`--insecure` uses a local TLS relay and always emits a warning. On Unix, the
|
|
225
|
+
relay uses an owner-only temporary directory and a socket with mode `0600`.
|
|
226
|
+
The loopback TCP fallback on platforms without Unix sockets rejects client
|
|
227
|
+
certificates to prevent other local processes from using that identity.
|
|
228
|
+
Neither mode protects against remote man-in-the-middle attacks.
|
|
229
|
+
|
|
230
|
+
`--connect-timeout` bounds the channel-readiness check before schema discovery
|
|
231
|
+
or invocation. `-m` / `--max-time` sets the RPC deadline in seconds.
|
|
232
|
+
`--wait-for-ready` lets an RPC wait for an available channel within that
|
|
233
|
+
deadline; local-schema calls with this flag skip the readiness preflight.
|
|
234
|
+
Reflection still requires the preflight.
|
|
235
|
+
|
|
236
|
+
`--max-send-message-size` and `--max-recv-message-size` set gRPC message limits.
|
|
237
|
+
`--compression` accepts `none`, `gzip`, or `deflate`. `--keepalive-time` sets the
|
|
238
|
+
HTTP/2 keepalive interval in seconds; aggressive intervals may be rejected by
|
|
239
|
+
servers. `-A` / `--user-agent` sets the primary gRPC user agent.
|
|
240
|
+
|
|
241
|
+
## Exit codes
|
|
242
|
+
|
|
243
|
+
| Code | Meaning |
|
|
244
|
+
| ---: | --- |
|
|
245
|
+
| `0` | Success |
|
|
246
|
+
| `1` | Dependency, RPC, input, schema, or file error |
|
|
247
|
+
| `2` | Invalid CLI usage |
|
|
248
|
+
| `130` | Interrupted with Ctrl-C |
|
|
249
|
+
|
|
250
|
+
## Docker
|
|
251
|
+
|
|
252
|
+
```console
|
|
253
|
+
docker build -t protodial:1.0.0 .
|
|
254
|
+
docker run --rm protodial:1.0.0 --version
|
|
255
|
+
docker run --rm protodial:1.0.0 -d '{"name":"Ada"}' \
|
|
256
|
+
grpc://host.docker.internal:50051/example.Greeter/SayHello
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
On Docker Desktop, `host.docker.internal` addresses the host. On Linux, use
|
|
260
|
+
`--network host` with a localhost target when appropriate. Mount local schema,
|
|
261
|
+
request, and certificate files into the container; add `-i` when reading stdin.
|
|
262
|
+
|
|
263
|
+
## Development
|
|
264
|
+
|
|
265
|
+
```console
|
|
266
|
+
uv sync --dev
|
|
267
|
+
uv run protodial --help
|
|
268
|
+
uv run pytest
|
|
269
|
+
uv run ruff check .
|
|
270
|
+
uv run pyright
|
|
271
|
+
uv build
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
See [examples](examples/README.md) for runnable servers and calls, and
|
|
275
|
+
[CHANGELOG.md](CHANGELOG.md) for release notes. The CLI is the primary supported
|
|
276
|
+
interface; this README does not define a stable Python library API.
|