Python bindings for the opensomeip C++ SOME/IP (Scalable service-Oriented MiddlewarE over IP) stack.
- Full protocol coverage: types, serialization, transport (UDP/TCP), service discovery, RPC, events, transport protocol (TP), and E2E protection
- Pythonic API: dataclasses, enums, context managers, iterators, and async/await support
- Dual sync/async: every callback-based API also exposes an iterator/async-iterator
interface for use with
asyncioand frameworks like Jumpstarter - Native performance: when compiled with the C++ extension, all protocol operations delegate to the opensomeip C++ stack; pure-Python stubs are available for type checking and testing without compilation
- Type-safe: full type annotations with
py.typedmarker (PEP 561) - gRPC-friendly types: all public types are plain Python objects (dataclasses, bytes, enums) — no opaque C++ wrappers — enabling seamless serialization across gRPC
- Python >= 3.10
- CMake >= 3.20
- A C++17 compiler (GCC 10+, Clang 12+, MSVC 2019+)
- pybind11 >= 2.13
pip install opensomeipgit clone --recurse-submodules https://github.com/vtz/opensomeip-python.git
cd opensomeip-python
pip install -e ".[dev]"from opensomeip import SomeIpServer, ServerConfig, TransportMode
from opensomeip.transport import Endpoint
from opensomeip.sd import SdConfig, ServiceInstance
from opensomeip.message import Message
from opensomeip.types import MessageId
config = ServerConfig(
local_endpoint=Endpoint("192.168.1.10", 30490),
sd_config=SdConfig(
multicast_endpoint=Endpoint("239.1.1.1", 30490),
unicast_endpoint=Endpoint("192.168.1.10", 30490),
),
services=[ServiceInstance(service_id=0x1234, instance_id=0x0001)],
)
def echo_handler(request: Message) -> Message:
return Message(
message_id=request.message_id,
request_id=request.request_id,
payload=request.payload, # echo back
)
with SomeIpServer(config) as server:
server.register_method(MessageId(0x1234, 0x0001), echo_handler)
# Server is now offering service 0x1234 via SD and handling RPCsfrom opensomeip import SomeIpClient, ClientConfig
from opensomeip.transport import Endpoint
from opensomeip.sd import SdConfig, ServiceInstance
from opensomeip.types import MessageId
config = ClientConfig(
local_endpoint=Endpoint("192.168.1.20", 30491),
sd_config=SdConfig(
multicast_endpoint=Endpoint("239.1.1.1", 30490),
unicast_endpoint=Endpoint("192.168.1.20", 30491),
),
)
with SomeIpClient(config) as client:
# Find the service via Service Discovery
receiver = client.find(ServiceInstance(service_id=0x1234, instance_id=0x0001))
# Synchronous RPC call
response = client.call(MessageId(0x1234, 0x0001), payload=b"\x01\x02\x03")
print(response.payload)
# Subscribe to events
for notification in client.subscribe_events(eventgroup_id=1):
print(notification.payload)import asyncio
from opensomeip import SomeIpClient, ClientConfig
from opensomeip.transport import Endpoint
from opensomeip.sd import SdConfig
from opensomeip.types import MessageId
async def main():
config = ClientConfig(
local_endpoint=Endpoint("0.0.0.0", 30491),
sd_config=SdConfig(
multicast_endpoint=Endpoint("239.1.1.1", 30490),
unicast_endpoint=Endpoint("0.0.0.0", 30491),
),
)
async with SomeIpClient(config) as client:
response = await client.call_async(
MessageId(0x1234, 0x0001),
payload=b"\x01\x02\x03",
)
print(response.payload)
asyncio.run(main())from opensomeip.serialization import Serializer, Deserializer
# Serialize a payload
with Serializer() as s:
s.write_uint16(0x1234)
s.write_string("hello")
s.write_float32(3.14)
payload = s.to_bytes()
# Deserialize it back
d = Deserializer(payload)
value = d.read_uint16() # 0x1234
name = d.read_string() # "hello"
pi = d.read_float32() # 3.14The package has a two-layer architecture:
_opensomeip(compiled pybind11 extension): thin bindings to the C++ library with explicit GIL management for thread safetyopensomeip(pure Python package): Pythonic wrapper with dataclasses, context managers, async iterators, and logging integration
When the C++ extension is available, all wrapper classes automatically delegate to the native implementation. Without it, pure-Python stubs provide the same API for testing and type checking.
| Module | Purpose |
|---|---|
opensomeip.types |
Core types: MessageId, RequestId, MessageType, ReturnCode |
opensomeip.message |
Message dataclass with header fields and payload |
opensomeip.transport |
UdpTransport, TcpTransport, Endpoint |
opensomeip.sd |
SdServer, SdClient, ServiceInstance, SdConfig |
opensomeip.rpc |
RpcClient, RpcServer for remote procedure calls |
opensomeip.events |
EventPublisher, EventSubscriber for notifications |
opensomeip.serialization |
Serializer, Deserializer for payload encoding |
opensomeip.tp |
TpManager for large message segmentation/reassembly |
opensomeip.e2e |
E2EProtection, CRC functions for end-to-end safety |
opensomeip.server |
SomeIpServer — high-level server composing all components |
opensomeip.client |
SomeIpClient — high-level client composing all components |
opensomeip.receiver |
MessageReceiver — sync/async message iterator |
When installing from source on macOS (e.g. pip install opensomeip on a Python
version for which no pre-built wheel is available), the C++ extension may fail to
load at runtime with an error like:
ImportError: dlopen(…/_opensomeip.cpython-3xx-darwin.so, 0x0002):
symbol not found in flat namespace '__ZNSt3__113__hash_memoryEPKvm'
Cause: If Homebrew LLVM is installed
and its clang++ appears in PATH before /usr/bin/clang++, CMake will use it
during the build. Homebrew's compiler ships a newer libc++ than the one bundled
with macOS, so the compiled extension references symbols that don't exist in the
system library loaded at runtime.
Fix — rebuild with the system compiler:
CC=/usr/bin/clang CXX=/usr/bin/clang++ \
pip install --no-cache-dir --force-reinstall --no-binary=opensomeip opensomeipTip: Pre-built wheels (available for Python 3.10 – 3.14 on macOS, Linux, and Windows) are compiled in CI with the correct toolchain and don't have this issue. If a wheel exists for your platform you'll never hit this problem — it only occurs when pip falls back to building from the source distribution.
If the C++ extension fails to load, the library warns via Python's
warnings module and falls back to stub transport classes. These stubs
set is_running = True but do not open any network sockets. If your
server appears to start but lsof shows no listening socket, check for the
ImportWarning that opensomeip emits at import time:
python -W all your_script.pyIf you see the warning, follow the steps in the section above to fix the extension build.
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Lint and format
ruff check src/ tests/
ruff format src/ tests/
# Type check
mypy src/opensomeip/
# Build documentation
pip install -e ".[docs]"
cd docs && make htmlSee CONTRIBUTING.md for development setup, coding standards, and pull request guidelines.
Apache License 2.0. See LICENSE for details.