Skip to content

Commit 85ea899

Browse files
JanKomarekNXPMichalPrincNXP
authored andcommitted
[RPSDK-1347] Improve eRPC python implementation
Signed-off-by: Michal Princ <michal.princ@nxp.com>
1 parent 4f4d8fb commit 85ea899

File tree

10 files changed

+448
-391
lines changed

10 files changed

+448
-391
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
### Fixed
13+
- Python code of the eRPC infrastructure was updated to match the proper python code style, add type annotations and improve readability.
14+
1015
## [1.14.0]
1116

1217
### Added

erpc_python/erpc/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#!/usr/bin/env python
22

3-
# Copyright 2016 NXP
4-
# All rights reserved.
3+
# Copyright 2016-2025 NXP
54
#
65
# SPDX-License-Identifier: BSD-3-Clause
76

87
import os
9-
import typing
8+
from typing import Any
109
# Yocto and python27 combination
1110
if "IS_YOCTO" in os.environ:
1211
from . import erpc_version
@@ -20,12 +19,11 @@
2019
from . import simple_server
2120
from . import transport
2221

23-
2422
class Reference(object):
2523
""" Simple container class used for pass by reference.
2624
"""
2725

28-
def __init__(self, value: typing.Any = None):
26+
def __init__(self, value: Any = None):
2927
# Read/write attribute holding the referent.
3028
self.value = value
3129

erpc_python/erpc/arbitrator.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,59 @@
11
#!/usr/bin/env python
22

3-
# Copyright 2016 NXP
3+
# Copyright 2016-2025 NXP
44
# All rights reserved.
55
#
66
# SPDX-License-Identifier: BSD-3-Clause
77

88
import threading
9+
import dataclasses
10+
from typing import Optional, TYPE_CHECKING
911

10-
from .codec import MessageType
12+
from .codec import MessageType, Codec
1113
from .transport import Transport
12-
from .client import RequestContext
14+
from .client import RequestError
1315

16+
if TYPE_CHECKING:
17+
from .client import RequestContext
1418

19+
20+
@dataclasses.dataclass
1521
class ClientInfo:
16-
event = None
17-
msg = None
22+
event: threading.Event
23+
message: Optional[bytearray] = None
1824

1925

2026
class TransportArbitrator(Transport):
21-
""" Shares a transport between a server and multiple clients.
27+
""" Shares transport between a server and multiple clients.
2228
2329
Args:
2430
Transport (_type_): Inherit and define transport interface methods
2531
"""
2632

27-
def __init__(self, sharedTransport=None, codec=None):
33+
def __init__(self, sharedTransport: Optional[Transport] = None, codec: Optional[Codec] = None):
34+
super().__init__()
2835
self._transport = sharedTransport
2936
self._codec = codec
30-
self._pending_clients = {}
37+
self._pending_clients: dict[int, ClientInfo] = {}
3138
self._lock = threading.Lock()
3239

3340
@property
34-
def shared_transport(self):
41+
def shared_transport(self) -> Optional[Transport]:
3542
return self._transport
3643

3744
@shared_transport.setter
38-
def shared_transport(self, transport):
45+
def shared_transport(self, transport: Transport):
3946
self._transport = transport
4047

4148
@property
42-
def codec(self):
49+
def codec(self) -> Optional[Codec]:
4350
return self._codec
4451

4552
@codec.setter
46-
def codec(self, theCodec):
53+
def codec(self, theCodec: Codec):
4754
self._codec = theCodec
4855

49-
def send(self, message):
56+
def send(self, message: bytes):
5057
assert self._transport is not None, "No shared transport was set"
5158
self._transport.send(message)
5259

@@ -77,13 +84,13 @@ def receive(self):
7784
client = self._pending_clients[info.sequence]
7885
finally:
7986
self._lock.release()
80-
client.msg = msg
87+
client.message = msg
8188
client.event.set()
8289
except KeyError:
8390
# No client was found, unexpected sequence number!
8491
pass
8592

86-
def prepare_client_receive(self, requestContext: RequestContext):
93+
def prepare_client_receive(self, requestContext: "RequestContext"):
8794
""" Add a client request to the client list.
8895
8996
This call is made by the client thread prior to sending the invocation to the server. It
@@ -98,10 +105,9 @@ def prepare_client_receive(self, requestContext: RequestContext):
98105
"""
99106

100107
# Create pending client info.
101-
info = ClientInfo()
102-
info.event = threading.Event()
108+
info = ClientInfo(threading.Event())
103109

104-
# Add this client to the pending clients dict.
110+
# Add this client to the pending clients' dict.
105111
try:
106112
self._lock.acquire()
107113
self._pending_clients[requestContext.sequence] = info
@@ -110,10 +116,10 @@ def prepare_client_receive(self, requestContext: RequestContext):
110116

111117
return requestContext.sequence
112118

113-
def client_receive(self, token: int):
119+
def client_receive(self, token: int) -> bytearray:
114120
""" Receive method for the client.
115121
116-
Blocks until the a reply message is received with the expected sequence number that is
122+
Blocks until the reply message is received with the expected sequence number that is
117123
associated with @a token. The client must have called prepare_client_receive() previously.
118124
119125
Args:
@@ -133,14 +139,15 @@ def client_receive(self, token: int):
133139
# Wait for the reply to be received.
134140
client.event.wait()
135141

136-
# Remove this client from the pending clients dict.
142+
# Remove this client from the pending clients' dict.
137143
try:
138144
self._lock.acquire()
139145
del self._pending_clients[token]
140146
finally:
141147
self._lock.release()
142148

143149
# Return the received message.
144-
return client.msg
150+
assert client.message # Message should be available at this moment
151+
return client.message
145152
except KeyError:
146-
pass
153+
raise RequestError(f"Pending client with token '{token}' not found")

erpc_python/erpc/basic_codec.py

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#!/usr/bin/env python
22

33
# Copyright (c) 2015 Freescale Semiconductor, Inc.
4-
# Copyright 2016-2017 NXP
5-
# All rights reserved.
4+
# Copyright 2016-2025 NXP
65
#
76
# SPDX-License-Identifier: BSD-3-Clause
87

98
import struct
10-
from .codec import (MessageType, MessageInfo, Codec, CodecError)
9+
from typing import Any
10+
11+
from .codec import MessageType, MessageInfo, Codec, CodecError
1112

1213

1314
class BasicCodec(Codec):
@@ -19,68 +20,68 @@ class BasicCodec(Codec):
1920

2021
BASIC_CODEC_VERSION = 1
2122

22-
def start_write_message(self, msgInfo):
23+
def start_write_message(self, msgInfo: MessageInfo):
2324
header = (self.BASIC_CODEC_VERSION << 24) \
24-
| ((msgInfo.service & 0xff) << 16) \
25-
| ((msgInfo.request & 0xff) << 8) \
26-
| (msgInfo.type.value & 0xff)
25+
| ((msgInfo.service & 0xff) << 16) \
26+
| ((msgInfo.request & 0xff) << 8) \
27+
| (msgInfo.type.value & 0xff)
2728
self.write_uint32(header)
2829
self.write_uint32(msgInfo.sequence)
2930

30-
def _write(self, fmt, value):
31+
def _write(self, fmt: str, value: Any):
3132
self._buffer += struct.pack(fmt, value)
3233
self._cursor += struct.calcsize(fmt)
3334

34-
def write_bool(self, value):
35+
def write_bool(self, value: bool):
3536
self._write('<?', value)
3637

37-
def write_int8(self, value):
38+
def write_int8(self, value: int):
3839
self._write('<b', value)
3940

40-
def write_int16(self, value):
41+
def write_int16(self, value: int):
4142
self._write('<h', value)
4243

43-
def write_int32(self, value):
44+
def write_int32(self, value: int):
4445
self._write('<i', value)
4546

46-
def write_int64(self, value):
47+
def write_int64(self, value: int):
4748
self._write('<q', value)
4849

49-
def write_uint8(self, value):
50+
def write_uint8(self, value: int):
5051
self._write('<B', value)
5152

52-
def write_uint16(self, value):
53+
def write_uint16(self, value: int):
5354
self._write('<H', value)
5455

55-
def write_uint32(self, value):
56+
def write_uint32(self, value: int):
5657
self._write('<I', value)
5758

58-
def write_uint64(self, value):
59+
def write_uint64(self, value: int):
5960
self._write('<Q', value)
6061

61-
def write_float(self, value):
62+
def write_float(self, value: float):
6263
self._write('<f', value)
6364

64-
def write_double(self, value):
65+
def write_double(self, value: float):
6566
self._write('<d', value)
6667

67-
def write_string(self, value):
68+
def write_string(self, value: str):
6869
self.write_binary(value.encode())
6970

70-
def write_binary(self, value):
71+
def write_binary(self, value: bytes):
7172
self.write_uint32(len(value))
7273
self._buffer += value
7374

74-
def start_write_list(self, length):
75+
def start_write_list(self, length: int):
7576
self.write_uint32(length)
7677

77-
def start_write_union(self, discriminator):
78+
def start_write_union(self, discriminator: int):
7879
self.write_uint32(discriminator)
7980

80-
def write_null_flag(self, flag):
81+
def write_null_flag(self, flag: int):
8182
self.write_uint8(1 if flag else 0)
8283

83-
def start_read_message(self):
84+
def start_read_message(self) -> MessageInfo:
8485
""" Returns 4-tuple of msgType, service, request, sequence.
8586
8687
Raises:
@@ -96,71 +97,71 @@ def start_read_message(self):
9697
raise CodecError("unsupported codec version %d" % version)
9798
service = (header >> 16) & 0xff
9899
request = (header >> 8) & 0xff
99-
msgType = MessageType(header & 0xff)
100-
return MessageInfo(type=msgType, service=service, request=request, sequence=sequence)
100+
msg_type = MessageType(header & 0xff)
101+
return MessageInfo(type=msg_type, service=service, request=request, sequence=sequence)
101102

102-
def _read(self, fmt):
103+
def _read(self, fmt: str):
103104
result = struct.unpack_from(fmt, self._buffer, self._cursor)
104105
self._cursor += struct.calcsize(fmt)
105106
return result[0]
106107

107-
def read_bool(self):
108+
def read_bool(self) -> bool:
108109
return self._read('<?')
109110

110-
def read_int8(self):
111+
def read_int8(self) -> int:
111112
return self._read('<b')
112113

113-
def read_int16(self):
114+
def read_int16(self) -> int:
114115
return self._read('<h')
115116

116-
def read_int32(self):
117+
def read_int32(self) -> int:
117118
return self._read('<i')
118119

119-
def read_int64(self):
120+
def read_int64(self) -> int:
120121
return self._read('<q')
121122

122-
def read_uint8(self):
123+
def read_uint8(self) -> int:
123124
return self._read('<B')
124125

125-
def read_uint16(self):
126+
def read_uint16(self) -> int:
126127
return self._read('<H')
127128

128-
def read_uint32(self):
129+
def read_uint32(self) -> int:
129130
return self._read('<I')
130131

131-
def read_uint64(self):
132+
def read_uint64(self) -> int:
132133
return self._read('<Q')
133134

134-
def read_float(self):
135+
def read_float(self) -> float:
135136
return self._read('<f')
136137

137-
def read_double(self):
138+
def read_double(self) -> float:
138139
return self._read('<d')
139140

140-
def read_string(self):
141+
def read_string(self) -> str:
141142
return self.read_binary().decode()
142143

143-
def read_binary(self):
144+
def read_binary(self) -> bytearray:
144145
length = self.read_uint32()
145-
data = self._buffer[self._cursor:self._cursor+length]
146+
data = self._buffer[self._cursor:self._cursor + length]
146147
self._cursor += length
147148
return data
148149

149-
def start_read_list(self):
150+
def start_read_list(self) -> int:
150151
""" Function which should be called on list de-serialization.
151152
152153
Returns:
153154
int: Int of list length.
154155
"""
155156
return self.read_uint32()
156157

157-
def start_read_union(self):
158+
def start_read_union(self) -> int:
158159
""" Function which should be called on union de-serialization.
159160
160161
Returns:
161162
int: Int of union discriminator.
162163
"""
163164
return self.read_int32()
164165

165-
def read_null_flag(self):
166+
def read_null_flag(self) -> int:
166167
return self.read_uint8()

0 commit comments

Comments
 (0)