stinger-ipc 0.11.0.dev1__tar.gz → 0.11.0.dev2__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.
- {stinger_ipc-0.11.0.dev1/stinger_ipc.egg-info → stinger_ipc-0.11.0.dev2}/PKG-INFO +1 -1
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/pyproject.toml +1 -1
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2/stinger_ipc.egg-info}/PKG-INFO +1 -1
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/components.py +8 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/cpp_symb.py +11 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/payload.py +11 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/protobuf_compiler.py +70 -8
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/python_symb.py +10 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/rust_symb.py +34 -1
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/schema/0.3/schema.yaml +5 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/codec.jinja2 +5 -4
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/partials/codec.jinja2 +2 -2
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/Cargo.toml.jinja2 +3 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/examples/server_demo.rs.jinja2 +1 -1
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/partials/codec.jinja2 +4 -4
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/server.rs.jinja2 +3 -3
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/tools/generic_generator.py +24 -8
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_protobuf_payloads.py +91 -1
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/LICENSE +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/README.md +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/setup.cfg +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stinger_ipc.egg-info/SOURCES.txt +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stinger_ipc.egg-info/dependency_links.txt +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stinger_ipc.egg-info/entry_points.txt +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stinger_ipc.egg-info/requires.txt +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stinger_ipc.egg-info/top_level.txt +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/__init__.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/arg_datatypes.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/arg_models.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/args.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/asyncapi.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/config.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/connection.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/exceptions.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/filtering.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/interface.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/ipc_command.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/ipc_method.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/ipc_property.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/ipc_signal.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/lang_symb.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/loading.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/markdown_symb.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/models.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/schema/0.1/schema.yaml +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/schema/0.2/schema.yaml +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/symbols/__init__.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/symbols/protobuf.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/CMakeLists.txt.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/cmake/config.cmake.in.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/examples/client_main.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/examples/discovery_example.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/examples/discovery_publisher.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/examples/server_main.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/client.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/command_payloads.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/constants.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/discovery.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/enums.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/method_payloads.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/property_structs.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/server.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/signal_payloads.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/structs.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/wire.hpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/args.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/deserialize.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/properties.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/serialize.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/validate.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/client.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/command_payloads.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/discovery.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/method_payloads.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/property_structs.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/server.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/signal_payloads.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/structs.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/tests/test_client.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/tests/test_serialization.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/tests/test_server.cpp.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/markdown/index.md.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/protobuf/{{stinger.name|snake_case}}.proto.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/Taskfile.yml.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/docs/api.rst.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/docs/conf.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/docs/examples.rst.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/docs/index.rst.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/examples/client_demo.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/examples/client_demo_classes.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/examples/server_demo.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/mypy.ini.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/partials/docstrings.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/partials/imports.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/partials/payloads.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/pyproject.toml.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/__init__.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/client.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/constants.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/discovery.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/interface_types.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/lwt.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/method_codes.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/property.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/semver.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/src/{{stinger.python.package_directory}}/server.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/tests/test_client.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/tests/test_server.py.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/Cargo.lock.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/README.md.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/docs/client.md.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/docs/overview.md.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/docs/server.md.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/examples/client_demo.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/partials/payloads.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/client.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/constants.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/discovery.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/interface.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/lib.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/lwt.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/message.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/payloads.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/property.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/serde_formats.rs.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/web/app.js.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/web/index.html.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/web/styles.css.jinja2 +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/tools/__init__.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/tools/cli.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/topic_template.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/topic_util.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_args.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_enum.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_example_values.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_examples.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_interface.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_ipc_command.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_ipc_method.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_ipc_property.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_ipc_signal.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_struct.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_topic_template.py +0 -0
- {stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/tests/test_topic_util.py +0 -0
|
@@ -257,6 +257,14 @@ class StingerSpec:
|
|
|
257
257
|
"""True if any payload in the interface is a protobuf message."""
|
|
258
258
|
return any(payload.is_protobuf for payload in self.all_payloads())
|
|
259
259
|
|
|
260
|
+
def uses_well_known_protobuf(self) -> bool:
|
|
261
|
+
"""True if any payload is one of protobuf's well-known types.
|
|
262
|
+
|
|
263
|
+
Those come from the protobuf runtime rather than from this interface's own
|
|
264
|
+
.proto files, and some languages need an extra dependency to reach them.
|
|
265
|
+
"""
|
|
266
|
+
return any(ref.is_well_known for ref in self.all_protobuf_refs())
|
|
267
|
+
|
|
260
268
|
def uses_json(self) -> bool:
|
|
261
269
|
"""True if any payload in the interface is a JSON argument list."""
|
|
262
270
|
return any(not payload.is_protobuf for payload in self.all_payloads())
|
|
@@ -444,6 +444,17 @@ class CppProtobufRefSymbols(CppSymbols):
|
|
|
444
444
|
"""The C++ namespace protoc puts this message in, from its protobuf package."""
|
|
445
445
|
return "::".join(p for p in self._ref.package.split(".") if p)
|
|
446
446
|
|
|
447
|
+
@property
|
|
448
|
+
def include(self) -> str:
|
|
449
|
+
"""The ``#include`` argument, brackets and all, for this message's header.
|
|
450
|
+
|
|
451
|
+
A well-known type's header ships with libprotobuf and is found on the
|
|
452
|
+
include path; the interface's own headers protoc wrote into the generated
|
|
453
|
+
library are quoted and relative to it.
|
|
454
|
+
"""
|
|
455
|
+
header = self._ref.proto_file.replace(".proto", ".pb.h")
|
|
456
|
+
return f"<{header}>" if self._ref.is_well_known else f'"proto/{header}"'
|
|
457
|
+
|
|
447
458
|
@property
|
|
448
459
|
def qualified_name(self) -> str:
|
|
449
460
|
"""How generated C++ code names this message, e.g. ``::weather::v1::CurrentConditions``."""
|
|
@@ -67,6 +67,17 @@ class ProtobufMessageRef(BaseModel):
|
|
|
67
67
|
"""True once the reference has been matched to a message in the .proto sources."""
|
|
68
68
|
return self._descriptor is not None
|
|
69
69
|
|
|
70
|
+
@property
|
|
71
|
+
def is_well_known(self) -> bool:
|
|
72
|
+
"""True for one of protobuf's own well-known types, e.g. ``google.protobuf.Empty``.
|
|
73
|
+
|
|
74
|
+
These are declared by the protobuf project rather than by this interface,
|
|
75
|
+
so they are neither found in the interface's .proto directory nor compiled
|
|
76
|
+
alongside it: every language's protobuf runtime already ships them, and
|
|
77
|
+
generated code reaches for that copy instead.
|
|
78
|
+
"""
|
|
79
|
+
return self.package == "google.protobuf"
|
|
80
|
+
|
|
70
81
|
@property
|
|
71
82
|
def proto_file(self) -> str:
|
|
72
83
|
"""The .proto file that declares this message, relative to the source directory."""
|
|
@@ -9,11 +9,16 @@ is what the generated code needs in order to import it.
|
|
|
9
9
|
Matching is done from a descriptor set produced by ``protoc`` rather than by
|
|
10
10
|
parsing ``.proto`` text, so imports, packages and nested messages resolve exactly
|
|
11
11
|
the way the protobuf compiler resolves them.
|
|
12
|
+
|
|
13
|
+
Protobuf's own well-known types -- ``google.protobuf.Empty`` and its siblings --
|
|
14
|
+
are resolvable without appearing in the interface's sources at all, since they
|
|
15
|
+
are declared by the protobuf project and shipped with every language's runtime.
|
|
12
16
|
"""
|
|
13
17
|
|
|
14
18
|
from __future__ import annotations
|
|
15
19
|
|
|
16
20
|
import difflib
|
|
21
|
+
import importlib
|
|
17
22
|
import shutil
|
|
18
23
|
import subprocess
|
|
19
24
|
import tempfile
|
|
@@ -87,6 +92,49 @@ def _message_names(proto_file: FileDescriptorProto) -> list[tuple[str, Descripto
|
|
|
87
92
|
return found
|
|
88
93
|
|
|
89
94
|
|
|
95
|
+
# The .proto files the protobuf project ships as its "well-known types". Every
|
|
96
|
+
# protobuf runtime carries them, so a message from one of these resolves without
|
|
97
|
+
# the interface declaring anything, and nothing here is ever copied or compiled
|
|
98
|
+
# into the generated output. Listed by module rather than discovered, because the
|
|
99
|
+
# set is fixed by the protobuf specification and reading it from the runtime's
|
|
100
|
+
# descriptor pool would only report whichever modules happened to be imported.
|
|
101
|
+
_WELL_KNOWN_MODULES = (
|
|
102
|
+
"any_pb2",
|
|
103
|
+
"api_pb2",
|
|
104
|
+
"duration_pb2",
|
|
105
|
+
"empty_pb2",
|
|
106
|
+
"field_mask_pb2",
|
|
107
|
+
"source_context_pb2",
|
|
108
|
+
"struct_pb2",
|
|
109
|
+
"timestamp_pb2",
|
|
110
|
+
"type_pb2",
|
|
111
|
+
"wrappers_pb2",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
_well_known_index: Optional[dict[str, tuple[str, DescriptorProto]]] = None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def well_known_message_index() -> dict[str, tuple[str, DescriptorProto]]:
|
|
118
|
+
"""Fully-qualified name -> (declaring file, descriptor) for the well-known types.
|
|
119
|
+
|
|
120
|
+
Read out of the protobuf runtime that stinger itself imports, so the messages
|
|
121
|
+
match the ones the generated code will use, and no protoc invocation is needed
|
|
122
|
+
to know they exist.
|
|
123
|
+
"""
|
|
124
|
+
global _well_known_index
|
|
125
|
+
if _well_known_index is None:
|
|
126
|
+
index: dict[str, tuple[str, DescriptorProto]] = {}
|
|
127
|
+
for module_name in _WELL_KNOWN_MODULES:
|
|
128
|
+
module = importlib.import_module(f"google.protobuf.{module_name}")
|
|
129
|
+
file_descriptor = module.DESCRIPTOR
|
|
130
|
+
file_proto = FileDescriptorProto()
|
|
131
|
+
file_descriptor.CopyToProto(file_proto)
|
|
132
|
+
for full_name, descriptor in _message_names(file_proto):
|
|
133
|
+
index[full_name] = (file_descriptor.name, descriptor)
|
|
134
|
+
_well_known_index = index
|
|
135
|
+
return _well_known_index
|
|
136
|
+
|
|
137
|
+
|
|
90
138
|
class ProtobufSources:
|
|
91
139
|
"""The ``.proto`` files an interface draws its messages from."""
|
|
92
140
|
|
|
@@ -102,6 +150,16 @@ class ProtobufSources:
|
|
|
102
150
|
raise ProtobufError(f"Protobuf source directory not found: {self.proto_dir}")
|
|
103
151
|
return sorted(self.proto_dir.rglob("*.proto"))
|
|
104
152
|
|
|
153
|
+
@property
|
|
154
|
+
def has_sources(self) -> bool:
|
|
155
|
+
"""True when the directory exists and holds at least one .proto file.
|
|
156
|
+
|
|
157
|
+
An interface whose only protobuf payloads are well-known types declares no
|
|
158
|
+
.proto files of its own, so the absence of sources is not an error until
|
|
159
|
+
something actually needs to be compiled.
|
|
160
|
+
"""
|
|
161
|
+
return self.proto_dir.is_dir() and any(self.proto_dir.rglob("*.proto"))
|
|
162
|
+
|
|
105
163
|
def run(self, *flags: str) -> None:
|
|
106
164
|
"""Run protoc over every source file with the given flags."""
|
|
107
165
|
files = self.proto_files
|
|
@@ -125,9 +183,10 @@ class ProtobufSources:
|
|
|
125
183
|
"""Fully-qualified message name -> (declaring file, descriptor), compiled once."""
|
|
126
184
|
if self._index is None:
|
|
127
185
|
index: dict[str, tuple[str, DescriptorProto]] = {}
|
|
128
|
-
|
|
129
|
-
for
|
|
130
|
-
|
|
186
|
+
if self.has_sources:
|
|
187
|
+
for proto_file in self.descriptor_set().file:
|
|
188
|
+
for full_name, descriptor in _message_names(proto_file):
|
|
189
|
+
index[full_name] = (proto_file.name, descriptor)
|
|
131
190
|
self._index = index
|
|
132
191
|
return self._index
|
|
133
192
|
|
|
@@ -139,16 +198,19 @@ class ProtobufSources:
|
|
|
139
198
|
def resolve(self, ref: ProtobufMessageRef) -> None:
|
|
140
199
|
"""Match a reference to a message in the sources, filling in its descriptor.
|
|
141
200
|
|
|
142
|
-
|
|
143
|
-
|
|
201
|
+
A well-known type is matched against the protobuf runtime instead of the
|
|
202
|
+
sources, since it is not the interface's to declare. Otherwise this raises
|
|
203
|
+
with the closest matching names, since a typo in a fully-qualified name is
|
|
204
|
+
tedious to spot.
|
|
144
205
|
"""
|
|
145
|
-
index = self._message_index()
|
|
206
|
+
index = well_known_message_index() if ref.is_well_known else self._message_index()
|
|
146
207
|
found = index.get(ref.full_name)
|
|
147
208
|
if found is None:
|
|
148
|
-
known =
|
|
209
|
+
known = sorted(index)
|
|
149
210
|
suggestions = difflib.get_close_matches(ref.full_name, known, n=3)
|
|
150
211
|
hint = f" Did you mean: {', '.join(suggestions)}?" if suggestions else f" Available messages: {', '.join(known) or '(none)'}"
|
|
151
|
-
|
|
212
|
+
where = "protobuf's well-known types" if ref.is_well_known else str(self.proto_dir)
|
|
213
|
+
raise ProtobufError(f"Protobuf message '{ref.full_name}' was not found in {where}.{hint}")
|
|
152
214
|
proto_file, descriptor = found
|
|
153
215
|
ref._proto_file = proto_file
|
|
154
216
|
ref._descriptor = descriptor
|
|
@@ -499,6 +499,16 @@ class PythonProtobufRefSymbols(PythonSymbols):
|
|
|
499
499
|
stem = stem[: -len(".proto")]
|
|
500
500
|
return f"{stem}_pb2"
|
|
501
501
|
|
|
502
|
+
@property
|
|
503
|
+
def import_statement(self) -> str:
|
|
504
|
+
"""The import that brings this message's module into a generated module.
|
|
505
|
+
|
|
506
|
+
A well-known type comes from the installed protobuf runtime; everything
|
|
507
|
+
else from the bindings protoc wrote beside the generated package.
|
|
508
|
+
"""
|
|
509
|
+
package = "google.protobuf" if self._ref.is_well_known else ".proto"
|
|
510
|
+
return f"from {package} import {self.module}"
|
|
511
|
+
|
|
502
512
|
@property
|
|
503
513
|
def qualified_name(self) -> str:
|
|
504
514
|
"""How generated Python code names this message, e.g. ``weather_pb2.CurrentConditions``."""
|
|
@@ -389,6 +389,26 @@ class RustPayloadSymbols(RustSymbols):
|
|
|
389
389
|
return self.struct_name
|
|
390
390
|
|
|
391
391
|
|
|
392
|
+
# How prost names protobuf's well-known types. prost never generates code for
|
|
393
|
+
# them: it substitutes a ready-made type, which for most is the `prost-types`
|
|
394
|
+
# struct of the same name, but for `Empty` and the wrapper messages is a plain
|
|
395
|
+
# Rust type instead. Mirrored here because generated code has to spell the
|
|
396
|
+
# message the same way prost does, and these exceptions are not derivable from
|
|
397
|
+
# the name. Kept in step with prost-build's `ExternPaths::new`.
|
|
398
|
+
_RUST_WELL_KNOWN_EXCEPTIONS = {
|
|
399
|
+
"Empty": "()",
|
|
400
|
+
"BoolValue": "bool",
|
|
401
|
+
"BytesValue": "::prost::alloc::vec::Vec<u8>",
|
|
402
|
+
"DoubleValue": "f64",
|
|
403
|
+
"FloatValue": "f32",
|
|
404
|
+
"Int32Value": "i32",
|
|
405
|
+
"Int64Value": "i64",
|
|
406
|
+
"StringValue": "::prost::alloc::string::String",
|
|
407
|
+
"UInt32Value": "u32",
|
|
408
|
+
"UInt64Value": "u64",
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
|
|
392
412
|
class RustProtobufRefSymbols(RustSymbols):
|
|
393
413
|
"""Rust symbols for a :class:`ProtobufMessageRef`."""
|
|
394
414
|
|
|
@@ -403,12 +423,21 @@ class RustProtobufRefSymbols(RustSymbols):
|
|
|
403
423
|
prost writes one file per protobuf package with the messages at its top
|
|
404
424
|
level, and those files are included into a single ``proto`` module, so the
|
|
405
425
|
package does not reappear in the Rust path.
|
|
426
|
+
|
|
427
|
+
A well-known type is the exception: prost generates nothing for one,
|
|
428
|
+
substituting the ready-made definition in ``prost-types``.
|
|
406
429
|
"""
|
|
430
|
+
if self._ref.is_well_known:
|
|
431
|
+
return "::prost_types"
|
|
407
432
|
return "crate::proto"
|
|
408
433
|
|
|
409
434
|
@property
|
|
410
435
|
def qualified_name(self) -> str:
|
|
411
436
|
"""How generated Rust code names this message, fully qualified from the crate root."""
|
|
437
|
+
if self._ref.is_well_known:
|
|
438
|
+
substitute = _RUST_WELL_KNOWN_EXCEPTIONS.get(self._ref.message_name)
|
|
439
|
+
if substitute is not None:
|
|
440
|
+
return substitute
|
|
412
441
|
return f"{self.module_path}::{self._ref.message_name}"
|
|
413
442
|
|
|
414
443
|
@property
|
|
@@ -416,6 +445,10 @@ class RustProtobufRefSymbols(RustSymbols):
|
|
|
416
445
|
"""How code outside the library names this message.
|
|
417
446
|
|
|
418
447
|
Examples and integration tests are separate crates, so they import the
|
|
419
|
-
library's ``proto`` module rather than reaching through ``crate::``.
|
|
448
|
+
library's ``proto`` module rather than reaching through ``crate::``. A
|
|
449
|
+
well-known type is spelled the same way everywhere, since it comes from
|
|
450
|
+
neither.
|
|
420
451
|
"""
|
|
452
|
+
if self._ref.is_well_known:
|
|
453
|
+
return self.qualified_name
|
|
421
454
|
return f"proto::{self._ref.message_name}"
|
|
@@ -259,6 +259,11 @@ $defs:
|
|
|
259
259
|
|
|
260
260
|
protobufPayload:
|
|
261
261
|
type: string
|
|
262
|
+
description: >-
|
|
263
|
+
The fully-qualified name of a protobuf message carrying this payload, e.g.
|
|
264
|
+
'weather.v1.Forecast'. Resolved against the .proto sources configured for
|
|
265
|
+
the interface, or, for a name in the 'google.protobuf' package, against
|
|
266
|
+
protobuf's own well-known types, which every protobuf runtime ships.
|
|
262
267
|
|
|
263
268
|
enumValueDescription:
|
|
264
269
|
type: string
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/codec.jinja2
RENAMED
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
{%- endmacro -%}
|
|
22
22
|
|
|
23
23
|
{#
|
|
24
|
-
The
|
|
25
|
-
|
|
24
|
+
The headers this interface's protobuf payloads come from -- protoc-generated
|
|
25
|
+
for the interface's own messages, shipped with libprotobuf for the well-known
|
|
26
|
+
types. Emitted once per header, and nothing at all when no payload is protobuf.
|
|
26
27
|
#}
|
|
27
28
|
{%- macro imports(stinger) -%}
|
|
28
|
-
{%- for
|
|
29
|
-
#include
|
|
29
|
+
{%- for include in stinger.protobuf_messages() | map(attribute='cpp.include') | unique | sort %}
|
|
30
|
+
#include {{ include }}
|
|
30
31
|
{%- endfor -%}
|
|
31
32
|
{%- endmacro -%}
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
all for an interface that uses no protobuf messages.
|
|
27
27
|
#}
|
|
28
28
|
{%- macro imports(stinger) -%}
|
|
29
|
-
{%- for
|
|
30
|
-
|
|
29
|
+
{%- for import_statement in stinger.protobuf_messages() | map(attribute='python.import_statement') | unique | sort %}
|
|
30
|
+
{{ import_statement }}
|
|
31
31
|
{%- endfor -%}
|
|
32
32
|
{%- endmacro -%}
|
|
33
33
|
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/Cargo.toml.jinja2
RENAMED
|
@@ -39,6 +39,9 @@ jsonschema = "0.46" # Only needed because this interface declares JSON schema co
|
|
|
39
39
|
{%- if stinger.uses_protobuf() %}
|
|
40
40
|
prost = "0.13" # Only needed because this interface carries protobuf payloads.
|
|
41
41
|
{%- endif %}
|
|
42
|
+
{%- if stinger.uses_well_known_protobuf() %}
|
|
43
|
+
prost-types = "0.13" # Only needed because this interface carries protobuf well-known types.
|
|
44
|
+
{%- endif %}
|
|
42
45
|
{%- if stinger.uses_binary() %}
|
|
43
46
|
base64 = "0.22.1" # Only needed because this interface has binary fields.
|
|
44
47
|
{%- endif %}
|
|
@@ -56,7 +56,7 @@ impl {{stinger.name | UpperCamelCase }}MethodHandlers<MqttierClient> for {{sting
|
|
|
56
56
|
async fn handle_{{method_name|snake_case}}(&self, {%if method.request_payload.is_protobuf%}_payload: {{method.request_payload.protobuf.rust.external_name}}{%else%}{%for arg in method.arg_list%}_{{arg.name|snake_case}}: {{arg.rust.type}}{%if not loop.last%}, {%endif%}{%endfor%}{%endif%}) -> Result<{%if method.response_payload.is_protobuf%}{{method.response_payload.protobuf.rust.external_name}}{%else%}{{method.rust.return_value_type}}{%endif%}, MethodReturnCode> {
|
|
57
57
|
println!("Handling {{method_name}}");
|
|
58
58
|
{%- if method.response_payload.is_protobuf %}
|
|
59
|
-
Ok({{method.response_payload.protobuf.rust.external_name}}
|
|
59
|
+
Ok(<{{method.response_payload.protobuf.rust.external_name}} as Default>::default())
|
|
60
60
|
{%- elif method.return_value_type == 'struct'%}
|
|
61
61
|
let rv = {{method.return_value.rust.temp_type}} {
|
|
62
62
|
{%for arg in method.return_value.values-%}
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/partials/codec.jinja2
RENAMED
|
@@ -217,7 +217,7 @@ let data = {{ payload.rust.struct_name }} {
|
|
|
217
217
|
#}
|
|
218
218
|
{%- macro example_payload(payload, arg_list) -%}
|
|
219
219
|
{%- if payload.is_protobuf -%}
|
|
220
|
-
{{ payload.protobuf.rust.external_name }}
|
|
220
|
+
<{{ payload.protobuf.rust.external_name }} as Default>::default()
|
|
221
221
|
{%- else -%}
|
|
222
222
|
{%- for arg in arg_list %}{{ arg.get_random_example_value(lang="rust") }}{% if not loop.last %}, {% endif %}{% endfor -%}
|
|
223
223
|
{%- endif -%}
|
|
@@ -229,7 +229,7 @@ let data = {{ payload.rust.struct_name }} {
|
|
|
229
229
|
#}
|
|
230
230
|
{%- macro example_payload_local(payload, arg_list) -%}
|
|
231
231
|
{%- if payload.is_protobuf -%}
|
|
232
|
-
{{ payload.rust.struct_name }}
|
|
232
|
+
<{{ payload.rust.struct_name }} as Default>::default()
|
|
233
233
|
{%- else -%}
|
|
234
234
|
{%- for arg in arg_list %}{{ arg.get_random_example_value(lang="rust") }}{% if not loop.last %}, {% endif %}{% endfor -%}
|
|
235
235
|
{%- endif -%}
|
|
@@ -267,7 +267,7 @@ let data = {{ payload.rust.struct_name }} {
|
|
|
267
267
|
{# An example value for a property, for demos and generated tests. #}
|
|
268
268
|
{%- macro property_example(prop) -%}
|
|
269
269
|
{%- if prop.payload.is_protobuf -%}
|
|
270
|
-
{{ prop.payload.rust.struct_name }}
|
|
270
|
+
<{{ prop.payload.rust.struct_name }} as Default>::default()
|
|
271
271
|
{%- else -%}
|
|
272
272
|
{{ prop.value.get_random_example_value(lang="rust") }}
|
|
273
273
|
{%- endif -%}
|
|
@@ -276,7 +276,7 @@ let data = {{ payload.rust.struct_name }} {
|
|
|
276
276
|
{# Like `property_example`, but for code outside the library (demos, integration tests). #}
|
|
277
277
|
{%- macro property_example_external(prop) -%}
|
|
278
278
|
{%- if prop.payload.is_protobuf -%}
|
|
279
|
-
{{ prop.payload.protobuf.rust.external_name }}
|
|
279
|
+
<{{ prop.payload.protobuf.rust.external_name }} as Default>::default()
|
|
280
280
|
{%- else -%}
|
|
281
281
|
{{ prop.value.get_random_example_value(lang="rust") }}
|
|
282
282
|
{%- endif -%}
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/server.rs.jinja2
RENAMED
|
@@ -906,7 +906,7 @@ mod tests {
|
|
|
906
906
|
Ok(rv)
|
|
907
907
|
{%endif%}
|
|
908
908
|
{%elif method.response_payload.is_protobuf %}
|
|
909
|
-
Ok({{method.response_payload.rust.struct_name}}
|
|
909
|
+
Ok(<{{method.response_payload.rust.struct_name}} as Default>::default())
|
|
910
910
|
{%elif method.return_value_type is not false %}
|
|
911
911
|
Ok({{method.return_value.get_random_example_value(lang="rust")}})
|
|
912
912
|
{%else%}
|
|
@@ -986,7 +986,7 @@ mod tests {
|
|
|
986
986
|
|
|
987
987
|
// Just to get this test working faster, we're copy-pasting test code from payloads.rs to generate example property payloads.
|
|
988
988
|
{%- if prop.payload.is_protobuf %}
|
|
989
|
-
let payload = {{prop.payload.rust.struct_name}}
|
|
989
|
+
let payload = <{{prop.payload.rust.struct_name}} as Default>::default();
|
|
990
990
|
{%- else %}
|
|
991
991
|
let json_str = r#"{ "{{prop.value.name}}": {{prop.value.get_random_example_value(lang="json")}} }"#;
|
|
992
992
|
let payload: {{prop.payload.rust.class_name}} = serde_json::from_str(json_str).unwrap();
|
|
@@ -1021,7 +1021,7 @@ mod tests {
|
|
|
1021
1021
|
|
|
1022
1022
|
// Example values always satisfy any schema constraint declared on the argument,
|
|
1023
1023
|
// so this payload reaches the channel.
|
|
1024
|
-
let payload = {%if cmd.payload.is_protobuf%}{{cmd.payload.rust.struct_name}}
|
|
1024
|
+
let payload = {%if cmd.payload.is_protobuf%}<{{cmd.payload.rust.struct_name}} as Default>::default(){%else%}{{cmd.rust.payload_struct_name}} {
|
|
1025
1025
|
{%-for arg in cmd.arg_list%}
|
|
1026
1026
|
{{arg.name|snake_case}}: {{arg.get_random_example_value(lang="rust")}},
|
|
1027
1027
|
{%-endfor%}
|
|
@@ -14,7 +14,7 @@ from stingeripc.loading import parse_yaml_file
|
|
|
14
14
|
from stevedore import ExtensionManager
|
|
15
15
|
from stingeripc import StingerInterface, __version__, topic_util
|
|
16
16
|
from stingeripc.filtering import filter_by_consumer
|
|
17
|
-
from stingeripc.config import load_config, StingerConfig
|
|
17
|
+
from stingeripc.config import load_config, ProtobufConfig, StingerConfig
|
|
18
18
|
from stingeripc.exceptions import ProtobufError
|
|
19
19
|
from stingeripc.protobuf_compiler import ProtobufSources
|
|
20
20
|
|
|
@@ -68,8 +68,13 @@ def emit_protobuf_bindings(template_dir: Path, outdir: Path, stinger, config_obj
|
|
|
68
68
|
}
|
|
69
69
|
recipe = tomllib.loads(recipe_path.read_text())
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
sources = protobuf_sources(config_obj, inname)
|
|
72
|
+
# An interface whose protobuf payloads are all well-known types has no .proto
|
|
73
|
+
# files of its own; those messages come from the language's protobuf runtime,
|
|
74
|
+
# so there is nothing to copy and nothing to compile.
|
|
75
|
+
if not sources.has_sources:
|
|
76
|
+
print("🧬 PROTO: no .proto sources to compile (well-known types only)")
|
|
77
|
+
return
|
|
73
78
|
|
|
74
79
|
# The .proto files travel with the generated code, so the output is
|
|
75
80
|
# self-contained and can be regenerated for another language later.
|
|
@@ -109,6 +114,20 @@ def emit_protobuf_bindings(template_dir: Path, outdir: Path, stinger, config_obj
|
|
|
109
114
|
target.write_text(content.format(**placeholders))
|
|
110
115
|
|
|
111
116
|
|
|
117
|
+
def protobuf_sources(config_obj, inname: Path) -> ProtobufSources:
|
|
118
|
+
"""The .proto sources for an interface, relative to the interface file.
|
|
119
|
+
|
|
120
|
+
Resolved relative to the .stinger.yaml so a definition and its .proto files
|
|
121
|
+
travel together regardless of where the generator is invoked from. The
|
|
122
|
+
protobuf configuration is optional: an interface that names only well-known
|
|
123
|
+
types needs no .proto directory, and the default one simply turns out to be
|
|
124
|
+
empty.
|
|
125
|
+
"""
|
|
126
|
+
protobuf_config = config_obj.protobuf or ProtobufConfig()
|
|
127
|
+
proto_dir = (inname.parent / protobuf_config.path).resolve()
|
|
128
|
+
return ProtobufSources(proto_dir, protobuf_config.protoc, python37=config_obj.python.python37)
|
|
129
|
+
|
|
130
|
+
|
|
112
131
|
def resolve_protobuf_messages(stinger, config_obj, inname: Path) -> None:
|
|
113
132
|
"""Match every protobuf message the interface names against the .proto sources.
|
|
114
133
|
|
|
@@ -121,11 +140,8 @@ def resolve_protobuf_messages(stinger, config_obj, inname: Path) -> None:
|
|
|
121
140
|
if not refs:
|
|
122
141
|
return
|
|
123
142
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
proto_dir = (inname.parent / config_obj.protobuf.path).resolve()
|
|
127
|
-
print(f"🧬 [bold cyan]PROTOS:[/bold cyan] {proto_dir}")
|
|
128
|
-
sources = ProtobufSources(proto_dir, config_obj.protobuf.protoc, python37=config_obj.python.python37)
|
|
143
|
+
sources = protobuf_sources(config_obj, inname)
|
|
144
|
+
print(f"🧬 [bold cyan]PROTOS:[/bold cyan] {sources.proto_dir}")
|
|
129
145
|
sources.resolve_all(refs)
|
|
130
146
|
for ref in stinger.protobuf_messages():
|
|
131
147
|
print(f"🧬 MSG: {ref.full_name} ({ref.proto_file})")
|
|
@@ -15,8 +15,11 @@ from google.protobuf.descriptor_pb2 import FileDescriptorSet
|
|
|
15
15
|
from stingeripc.components import StingerSpec
|
|
16
16
|
from stingeripc.config import ProtobufConfig, StingerConfig
|
|
17
17
|
from stingeripc.exceptions import InvalidStingerStructure, ProtobufError
|
|
18
|
+
from stingeripc.cpp_symb import CppProtobufRefSymbols
|
|
18
19
|
from stingeripc.payload import PayloadRole, ProtobufMessageRef
|
|
19
|
-
from stingeripc.protobuf_compiler import ProtobufSources, find_protoc
|
|
20
|
+
from stingeripc.protobuf_compiler import ProtobufSources, find_protoc, well_known_message_index
|
|
21
|
+
from stingeripc.python_symb import PythonProtobufRefSymbols
|
|
22
|
+
from stingeripc.rust_symb import RustProtobufRefSymbols
|
|
20
23
|
|
|
21
24
|
FIXTURES = Path(__file__).parent / "fixtures"
|
|
22
25
|
|
|
@@ -90,6 +93,93 @@ class TestResolution(unittest.TestCase):
|
|
|
90
93
|
)
|
|
91
94
|
|
|
92
95
|
|
|
96
|
+
|
|
97
|
+
class TestWellKnownTypes(unittest.TestCase):
|
|
98
|
+
"""Protobuf's own types resolve without the interface declaring them."""
|
|
99
|
+
|
|
100
|
+
def _resolved(self, full_name: str) -> ProtobufMessageRef:
|
|
101
|
+
ref = ProtobufMessageRef(full_name=full_name)
|
|
102
|
+
_sources().resolve(ref)
|
|
103
|
+
return ref
|
|
104
|
+
|
|
105
|
+
def test_recognises_the_google_protobuf_package(self):
|
|
106
|
+
self.assertTrue(ProtobufMessageRef(full_name="google.protobuf.Empty").is_well_known)
|
|
107
|
+
self.assertFalse(ProtobufMessageRef(full_name="weather.v1.Forecast").is_well_known)
|
|
108
|
+
self.assertFalse(
|
|
109
|
+
ProtobufMessageRef(full_name="google.protobuf.nested.Thing").is_well_known,
|
|
110
|
+
"only the well-known package itself, not anything beneath it",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def test_resolves_without_any_local_sources(self):
|
|
114
|
+
ref = self._resolved("google.protobuf.Empty")
|
|
115
|
+
self.assertTrue(ref.is_resolved)
|
|
116
|
+
self.assertEqual(ref.proto_file, "google/protobuf/empty.proto")
|
|
117
|
+
|
|
118
|
+
def test_resolves_with_no_proto_directory_at_all(self):
|
|
119
|
+
"""An interface using only well-known types needs no .proto sources."""
|
|
120
|
+
sources = ProtobufSources(FIXTURES / "no_such_directory")
|
|
121
|
+
self.assertFalse(sources.has_sources)
|
|
122
|
+
ref = ProtobufMessageRef(full_name="google.protobuf.Empty")
|
|
123
|
+
sources.resolve(ref)
|
|
124
|
+
self.assertTrue(ref.is_resolved)
|
|
125
|
+
|
|
126
|
+
def test_index_covers_the_whole_well_known_set(self):
|
|
127
|
+
index = well_known_message_index()
|
|
128
|
+
for name in ("Empty", "Timestamp", "Duration", "Any", "Struct", "FieldMask", "StringValue"):
|
|
129
|
+
self.assertIn(f"google.protobuf.{name}", index)
|
|
130
|
+
|
|
131
|
+
def test_unknown_well_known_type_is_reported_against_the_right_place(self):
|
|
132
|
+
ref = ProtobufMessageRef(full_name="google.protobuf.Emty")
|
|
133
|
+
with self.assertRaises(ProtobufError) as caught:
|
|
134
|
+
_sources().resolve(ref)
|
|
135
|
+
message = str(caught.exception)
|
|
136
|
+
self.assertIn("well-known types", message)
|
|
137
|
+
self.assertIn("google.protobuf.Empty", message, "a near miss is suggested")
|
|
138
|
+
|
|
139
|
+
def test_interface_reports_that_it_uses_them(self):
|
|
140
|
+
spec = _spec({"commands": {"c": {"protobuf": "google.protobuf.Empty"}}})
|
|
141
|
+
self.assertTrue(spec.uses_protobuf())
|
|
142
|
+
self.assertTrue(spec.uses_well_known_protobuf())
|
|
143
|
+
|
|
144
|
+
def test_interface_of_its_own_messages_only_does_not(self):
|
|
145
|
+
spec = _spec({"commands": {"c": {"protobuf": "weather.v1.Forecast"}}})
|
|
146
|
+
self.assertTrue(spec.uses_protobuf())
|
|
147
|
+
self.assertFalse(spec.uses_well_known_protobuf())
|
|
148
|
+
|
|
149
|
+
def test_python_imports_from_the_installed_runtime(self):
|
|
150
|
+
symbols = PythonProtobufRefSymbols(self._resolved("google.protobuf.Empty"))
|
|
151
|
+
self.assertEqual(symbols.import_statement, "from google.protobuf import empty_pb2")
|
|
152
|
+
self.assertEqual(symbols.qualified_name, "empty_pb2.Empty")
|
|
153
|
+
|
|
154
|
+
def test_python_imports_the_interfaces_own_messages_from_its_package(self):
|
|
155
|
+
symbols = PythonProtobufRefSymbols(self._resolved("weather.v1.Forecast"))
|
|
156
|
+
self.assertEqual(symbols.import_statement, "from .proto import weather_pb2")
|
|
157
|
+
|
|
158
|
+
def test_cpp_includes_the_libprotobuf_header(self):
|
|
159
|
+
symbols = CppProtobufRefSymbols(self._resolved("google.protobuf.Empty"))
|
|
160
|
+
self.assertEqual(symbols.include, "<google/protobuf/empty.pb.h>")
|
|
161
|
+
self.assertEqual(symbols.qualified_name, "::google::protobuf::Empty")
|
|
162
|
+
|
|
163
|
+
def test_cpp_includes_the_interfaces_own_headers_relatively(self):
|
|
164
|
+
symbols = CppProtobufRefSymbols(self._resolved("weather.v1.Forecast"))
|
|
165
|
+
self.assertEqual(symbols.include, '"proto/weather.pb.h"')
|
|
166
|
+
|
|
167
|
+
def test_rust_uses_the_substitute_prost_gives_empty(self):
|
|
168
|
+
symbols = RustProtobufRefSymbols(self._resolved("google.protobuf.Empty"))
|
|
169
|
+
self.assertEqual(symbols.qualified_name, "()", "prost maps Empty onto the unit type")
|
|
170
|
+
self.assertEqual(symbols.external_name, "()")
|
|
171
|
+
|
|
172
|
+
def test_rust_uses_prost_types_for_the_rest(self):
|
|
173
|
+
symbols = RustProtobufRefSymbols(self._resolved("google.protobuf.Timestamp"))
|
|
174
|
+
self.assertEqual(symbols.qualified_name, "::prost_types::Timestamp")
|
|
175
|
+
self.assertEqual(symbols.external_name, "::prost_types::Timestamp")
|
|
176
|
+
|
|
177
|
+
def test_rust_still_reaches_the_interfaces_own_messages_through_the_crate(self):
|
|
178
|
+
symbols = RustProtobufRefSymbols(self._resolved("weather.v1.Forecast"))
|
|
179
|
+
self.assertEqual(symbols.qualified_name, "crate::proto::Forecast")
|
|
180
|
+
self.assertEqual(symbols.external_name, "proto::Forecast")
|
|
181
|
+
|
|
182
|
+
|
|
93
183
|
class TestFindProtoc(unittest.TestCase):
|
|
94
184
|
def test_prefers_protoc_on_path(self):
|
|
95
185
|
with mock.patch("shutil.which", side_effect=lambda name: "/usr/bin/protoc" if name == "protoc" else None):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stinger_ipc.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/CMakeLists.txt.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/include/wire.hpp.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/partials/args.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/client.cpp.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/server.cpp.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/cpp/src/structs.cpp.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/markdown/index.md.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/Taskfile.yml.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/docs/api.rst.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/docs/conf.py.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/python/mypy.ini.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/Cargo.lock.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/README.md.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/docs/client.md.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/docs/server.md.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/client.rs.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/lib.rs.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/lwt.rs.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/message.rs.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/payloads.rs.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/rust/src/property.rs.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/web/index.html.jinja2
RENAMED
|
File without changes
|
{stinger_ipc-0.11.0.dev1 → stinger_ipc-0.11.0.dev2}/stingeripc/templates/web/styles.css.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|