socketwrapper 0.0.1__tar.gz → 0.0.3__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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketwrapper
3
- Version: 0.0.1
4
- Summary: high level socket and pipe wrapper
3
+ Version: 0.0.3
4
+ Summary: high level socket and pipe wrappers
5
5
  Author: Felipe A Hernandez
6
6
  Author-email: ergoithz@gmail.com
7
7
  License: MIT License
@@ -27,6 +27,7 @@ License: MIT License
27
27
  SOFTWARE.
28
28
 
29
29
  Project-URL: homepage, https://gitlab.com/ergoithz/socketwrapper
30
+ Project-URL: repository, https://gitlab.com/ergoithz/socketwrapper
30
31
  Project-URL: issue-tracker, https://gitlab.com/ergoithz/socketwrapper/-/issues
31
32
  Project-URL: release-notes, https://gitlab.com/ergoithz/socketwrapper/-/releases
32
33
  Project-URL: issue-new, https://gitlab.com/ergoithz/socketwrapper/-/issues/new
@@ -41,9 +42,12 @@ Classifier: Topic :: System :: Networking
41
42
  Requires-Python: >=3.12
42
43
  Description-Content-Type: text/markdown
43
44
  License-File: LICENSE
44
- Requires-Dist: typing-extensions>=4.15; python_version < "3.13"
45
+ Requires-Dist: typing-extensions>=4.6; python_version < "3.13"
46
+ Provides-Extra: msgpack
47
+ Requires-Dist: msgpack; extra == "msgpack"
45
48
  Provides-Extra: dev
46
49
  Requires-Dist: coverage; extra == "dev"
50
+ Requires-Dist: msgpack; extra == "dev"
47
51
  Requires-Dist: ruff; extra == "dev"
48
52
  Requires-Dist: wheel; extra == "dev"
49
53
  Requires-Dist: yapf; extra == "dev"
@@ -52,24 +56,26 @@ Dynamic: license-file
52
56
  # socketwrapper
53
57
 
54
58
  This package provides high level wrappers for sockets and pipes:
55
- - Thread-safe within both and between threads and asyncio realms.
56
- - Managed sync recv and send operations with timeouts.
57
- - Native asyncio recv_async and send_async operations.
58
- - Pluggable message protocol (headered variable length data) supporting
59
- header parsing, serialization and deserialization.
60
- - Pluggable I/O protocol (file descriptor still required due asyncio).
61
59
 
62
- ## Motivation
60
+ - Thread-safe within both threads and asyncio realms, and between them.
61
+ - Managed sync `recv` and `send` operations with timeouts.
62
+ - Native asyncio `recv_async` and `send_async` operations.
63
+ - Pluggable message protocol (headered variable length data) supporting variable-length header parsing, payload serialization and deserialization.
64
+ - Pluggable I/O protocol (OS file descriptor still required).
63
65
 
64
- There aren't a ton of high level asyncio socket wrappers out there providing
65
- all we need for IPC: header/payload logic and support for both sockets and pipes.
66
+ Builtin message protocols (framing):
66
67
 
67
- Most implementations either don't have pluggable messaging protocols or it
68
- doesn't support variable-size headers.
68
+ - `socketwrapper.framing.VarIntBytes`: varint-headered bytes (default with `framing=True`).
69
+ - `socketwrapper.framing.MultiprocessingBytes` (if platform is supported): [multiprocessing.connection.Connection](https://docs.python.org/3.14/library/multiprocessing.html#connection-objects) bytes.
70
+ - `socketwrapper.framing.Multiprocessing` (if platform is supported): [multiprocessing.connection.Connection](https://docs.python.org/3.14/library/multiprocessing.html#connection-objects) pickled data.
71
+ - `socketwrapper.framing.MsgPack` (if `msgpack` is available): unheadered [msgpack](https://pypi.org/project/msgpack/) data stream.
69
72
 
70
- No other implementation is thread-safe across both asyncio and threading realms.
73
+ ## Motivation
71
74
 
72
- No other implementation directly supports wrapping multiprocessing Connections.
75
+ - There aren't a ton of high level asyncio socket wrappers out there providing all we need for IPC: header/payload message logic and support for both sockets and pipes.
76
+ - Most implementations got either hardcoded messaging protocols or require a fixed-size header.
77
+ - No implementation was thread-safe between both asyncio and threading realms.
78
+ - No implementation directly supported wrapping multiprocessing Connections into an asyncio-native interface.
73
79
 
74
80
  ## Installation
75
81
 
@@ -77,18 +83,35 @@ No other implementation directly supports wrapping multiprocessing Connections.
77
83
  uv pip install socketwrapper
78
84
  ```
79
85
 
86
+ Or with optional [msgpack](https://pypi.org/project/msgpack/) support.
87
+ ```sh
88
+ uv pip install 'socketwrapper[msgpack]'
89
+ ```
90
+
91
+ ## Changelog
92
+
93
+ ### 0.0.3 - 2025.11.08
94
+
95
+ - New: optional support for `recv_into` in socket-like objects.
96
+ - Optimization: recv operations will now use `sock.recv_into` (if available) to reduce memory allocation overhead.
97
+
98
+ ### 0.0.2 - 2025.11.05
99
+
100
+ - Breaking: `MessageFraming.frames` and `MessageFraming.loads` now receive `io.BytesIO` instead of `bytearray`.
101
+ - New: optional msgpack support (`msgpack` extra).
102
+ - Fix: busy reads no longer blocking asyncio event loop.
103
+ - Typing: expose `SizedBuffer` and deprecate `SendPayload` (removal expected in `0.1.0`).
104
+ - Typing: `SocketWriter.send` and `SocketWriter.send_async` data is now `SizedBuffer`.
105
+
80
106
  ## Documentation
81
107
 
82
- None other than this README, life's too short and I'm too busy with real life,
83
- if you need better documentation consider donating to
84
- [my ko-fi](https://ko-fi.com/s26me) stating that as the tip message,
85
- check out how my docs look like at [mstache docs](https://mstache.readthedocs.io/en/latest/)
86
- and [uactor docs](https://mstache.readthedocs.io/en/latest/).
108
+ None other than this README, life's too short and I'm too busy with real life, if you need better documentation consider donating to [my ko-fi](https://ko-fi.com/s26me) stating that as a tip message, check out how my docs look like at [mstache docs](https://mstache.readthedocs.io/en/latest/) and [uactor docs](https://mstache.readthedocs.io/en/latest/).
87
109
 
88
110
  ### Puggable I/O: SocketLike protocol
89
111
 
90
- The `socketwrapper.SocketLike` protocol, an small subset the socket interface,
91
- is all what's required for any object to be wrap-able by `socketwrapper`.
112
+ The `protocols.SocketLike` protocol, a small subset the socket interface, is all what's required for any object to be wrap-able by `socketwrapper`.
113
+
114
+ Additional methods defined in `protocols.OptionalSocketLike` can be optionally implemented enabling optimized code paths.
92
115
 
93
116
  ```py
94
117
  @typing.runtime_checkable
@@ -100,18 +123,19 @@ class SocketLike(typing.Protocol):
100
123
  def recv(self, bufsize: int, /) -> bytes: ...
101
124
  def settimeout(self, timeout: float | None, /) -> None: ...
102
125
  def close(self) -> None: ...
126
+
127
+
128
+ @typing.runtime_checkable
129
+ class OptionalSocketLike(SocketLike, typing.Protocol):
130
+ """Protocol for optional socket-like object methods accepted by socketwrapper socket classes."""
131
+
132
+ def recv_into(self, buffer: collections.abc.Buffer, /) -> bytes: ...
133
+
103
134
  ```
104
135
 
105
136
  Special attention to:
106
- - [fileno](https://docs.python.org/3.14/library/socket.html#socket.socket.fileno)
107
- has to be a valid OS file descriptor.
108
- - [settimeout](https://docs.python.org/3.14/library/socket.html#socket.socket.settimeout)
109
- only requires support for `settimeout(.0)` (
110
- [non-blocking semantics](https://docs.python.org/3.14/library/socket.html#notes-on-socket-timeouts)
111
- ), raising [ValueError](https://docs.python.org/3.14/library/exceptions.html#ValueError)
112
- for any other value is fully supported in which case
113
- [selectors.DefaultSelector](https://docs.python.org/3.14/library/selectors.html#selectors.DefaultSelector)
114
- will be used for synchronous operations.
137
+ - [fileno](https://docs.python.org/3.14/library/socket.html#socket.socket.fileno) has to be a valid OS file descriptor.
138
+ - [settimeout](https://docs.python.org/3.14/library/socket.html#socket.socket.settimeout) must support `settimeout(.0)` ([non-blocking semantics](https://docs.python.org/3.14/library/socket.html#notes-on-socket-timeouts)), raising [ValueError](https://docs.python.org/3.14/library/exceptions.html#ValueError) for any other value will be handled, relying on [selectors.DefaultSelector](https://docs.python.org/3.14/library/selectors.html#selectors.DefaultSelector) for synchronous operations.
115
139
 
116
140
  ## Usage
117
141
 
@@ -131,11 +155,31 @@ with socketwrapper.pipe(framing=True) as (parent_reader, child_writer):
131
155
  else:
132
156
  child_writer.send(b'Hello world!')
133
157
  ```
134
-
135
158
  ```
136
159
  Message b'Hello world!' received
137
160
  ```
138
161
 
162
+ ### Simple IPC with pipe using msgpack
163
+
164
+ ```python
165
+ import os
166
+ import socketwrapper
167
+ import socketwrapper.framing as framing
168
+
169
+ with socketwrapper.pipe(framing=framing.MsgPack()) as (parent_reader, child_writer):
170
+ child_writer.inheritable = True
171
+ child_pid = os.fork() # replace with your own process fork/spawn logic
172
+ child_writer.inheritable = False # important, prevent socket leaks!
173
+
174
+ if child_pid:
175
+ print(f'Message {parent_reader.recv()!r} received')
176
+ else:
177
+ child_writer.send({'data': b'Hello world!'})
178
+ ```
179
+ ```
180
+ Message {'data': b'Hello world!'} received
181
+ ```
182
+
139
183
  ### Simple asyncio IPC with pipe
140
184
 
141
185
  ```python
@@ -156,7 +200,6 @@ with socketwrapper.pipe(framing=True) as (parent_reader, child_writer):
156
200
 
157
201
  asyncio.run(parent(parent_reader) if child_pid else child(child_writer))
158
202
  ```
159
-
160
203
  ```
161
204
  Message b'Hello world!' received
162
205
  ```
@@ -180,7 +223,6 @@ with socketwrapper.socketpair(framing=True) as (parent_duplex, child_duplex):
180
223
  print(f'Message {child_duplex.recv()!r} received in child')
181
224
  child_duplex.send(b'Hello parent!')
182
225
  ```
183
-
184
226
  ```
185
227
  Message b'Hello child!' received in child
186
228
  Message b'Hello parent!' received in parent
@@ -204,25 +246,46 @@ def child(conn: multiprocessing.connection.Connection) -> None:
204
246
 
205
247
  asyncio.run(main())
206
248
 
207
- parent_conn, child_conn = multiprocessing.Pipe()
208
- with parent_conn, child_conn:
209
- child_process = multiprocessing.Process(target=child, args=(child_conn,))
210
- child_process.start()
249
+ if __name__ == '__main__':
250
+ parent_conn, child_conn = multiprocessing.Pipe()
251
+ with parent_conn, child_conn:
252
+ child_process = multiprocessing.Process(target=child, args=(child_conn,))
253
+ child_process.start()
211
254
 
212
- parent_conn.send_bytes(b'Hello child!')
213
- print(f'Message {parent_conn.recv_bytes()!r} received in parent')
214
- child_process.join(1)
255
+ parent_conn.send_bytes(b'Hello child!')
256
+ print(f'Message {parent_conn.recv_bytes()!r} received in parent')
257
+ child_process.join(1)
215
258
  ```
216
-
217
259
  ```
218
260
  Message b'Hello child!' received in child
219
261
  Message b'Hello parent!' received in parent
220
262
  ```
221
263
 
264
+ ### Socketwrapper for cross-interpreter communication
265
+
266
+ ```py
267
+ import concurrent.futures
268
+ import socketwrapper
269
+
270
+ def child(child_fileno: int) -> None:
271
+ child_writer = socketwrapper.MessageWriter(child_fileno)
272
+ child_writer.send(b'Hello World')
273
+
274
+ if __name__ == '__main__':
275
+ with (socketwrapper.pipe(framing=True) as (parent_reader, child_writer),
276
+ concurrent.futures.InterpreterPoolExecutor() as pool):
277
+ pool.submit(child, child_writer.fileno())
278
+ print(f'Message {parent_reader.recv()!r} received')
279
+ ```
280
+ ```
281
+ Message b'Hello World' received
282
+ ```
283
+
222
284
  ### Custom socketwrapper framing with progress
223
285
 
224
286
  ```py
225
287
  import collections.abc
288
+ import io
226
289
  import itertools
227
290
  import os
228
291
  import socketwrapper
@@ -246,7 +309,7 @@ def progress(arrow: str, size: int, min_chunk: int = 1024) -> collections.abc.Ge
246
309
  class ProgressFraming(socketwrapper.framing.VarIntBytes):
247
310
 
248
311
  @classmethod
249
- def frames(cls, buffer: bytearray) -> collections.abc.Generator[int, None, None]:
312
+ def frames(cls, buffer: io.BytesIO) -> collections.abc.Generator[int, None, None]:
250
313
  frames = super().frames(buffer)
251
314
  yield from itertools.islice(frames, 2)
252
315
  yield from progress('>', next(frames))
@@ -1,24 +1,26 @@
1
1
  # socketwrapper
2
2
 
3
3
  This package provides high level wrappers for sockets and pipes:
4
- - Thread-safe within both and between threads and asyncio realms.
5
- - Managed sync recv and send operations with timeouts.
6
- - Native asyncio recv_async and send_async operations.
7
- - Pluggable message protocol (headered variable length data) supporting
8
- header parsing, serialization and deserialization.
9
- - Pluggable I/O protocol (file descriptor still required due asyncio).
10
4
 
11
- ## Motivation
5
+ - Thread-safe within both threads and asyncio realms, and between them.
6
+ - Managed sync `recv` and `send` operations with timeouts.
7
+ - Native asyncio `recv_async` and `send_async` operations.
8
+ - Pluggable message protocol (headered variable length data) supporting variable-length header parsing, payload serialization and deserialization.
9
+ - Pluggable I/O protocol (OS file descriptor still required).
12
10
 
13
- There aren't a ton of high level asyncio socket wrappers out there providing
14
- all we need for IPC: header/payload logic and support for both sockets and pipes.
11
+ Builtin message protocols (framing):
15
12
 
16
- Most implementations either don't have pluggable messaging protocols or it
17
- doesn't support variable-size headers.
13
+ - `socketwrapper.framing.VarIntBytes`: varint-headered bytes (default with `framing=True`).
14
+ - `socketwrapper.framing.MultiprocessingBytes` (if platform is supported): [multiprocessing.connection.Connection](https://docs.python.org/3.14/library/multiprocessing.html#connection-objects) bytes.
15
+ - `socketwrapper.framing.Multiprocessing` (if platform is supported): [multiprocessing.connection.Connection](https://docs.python.org/3.14/library/multiprocessing.html#connection-objects) pickled data.
16
+ - `socketwrapper.framing.MsgPack` (if `msgpack` is available): unheadered [msgpack](https://pypi.org/project/msgpack/) data stream.
18
17
 
19
- No other implementation is thread-safe across both asyncio and threading realms.
18
+ ## Motivation
20
19
 
21
- No other implementation directly supports wrapping multiprocessing Connections.
20
+ - There aren't a ton of high level asyncio socket wrappers out there providing all we need for IPC: header/payload message logic and support for both sockets and pipes.
21
+ - Most implementations got either hardcoded messaging protocols or require a fixed-size header.
22
+ - No implementation was thread-safe between both asyncio and threading realms.
23
+ - No implementation directly supported wrapping multiprocessing Connections into an asyncio-native interface.
22
24
 
23
25
  ## Installation
24
26
 
@@ -26,18 +28,35 @@ No other implementation directly supports wrapping multiprocessing Connections.
26
28
  uv pip install socketwrapper
27
29
  ```
28
30
 
31
+ Or with optional [msgpack](https://pypi.org/project/msgpack/) support.
32
+ ```sh
33
+ uv pip install 'socketwrapper[msgpack]'
34
+ ```
35
+
36
+ ## Changelog
37
+
38
+ ### 0.0.3 - 2025.11.08
39
+
40
+ - New: optional support for `recv_into` in socket-like objects.
41
+ - Optimization: recv operations will now use `sock.recv_into` (if available) to reduce memory allocation overhead.
42
+
43
+ ### 0.0.2 - 2025.11.05
44
+
45
+ - Breaking: `MessageFraming.frames` and `MessageFraming.loads` now receive `io.BytesIO` instead of `bytearray`.
46
+ - New: optional msgpack support (`msgpack` extra).
47
+ - Fix: busy reads no longer blocking asyncio event loop.
48
+ - Typing: expose `SizedBuffer` and deprecate `SendPayload` (removal expected in `0.1.0`).
49
+ - Typing: `SocketWriter.send` and `SocketWriter.send_async` data is now `SizedBuffer`.
50
+
29
51
  ## Documentation
30
52
 
31
- None other than this README, life's too short and I'm too busy with real life,
32
- if you need better documentation consider donating to
33
- [my ko-fi](https://ko-fi.com/s26me) stating that as the tip message,
34
- check out how my docs look like at [mstache docs](https://mstache.readthedocs.io/en/latest/)
35
- and [uactor docs](https://mstache.readthedocs.io/en/latest/).
53
+ None other than this README, life's too short and I'm too busy with real life, if you need better documentation consider donating to [my ko-fi](https://ko-fi.com/s26me) stating that as a tip message, check out how my docs look like at [mstache docs](https://mstache.readthedocs.io/en/latest/) and [uactor docs](https://mstache.readthedocs.io/en/latest/).
36
54
 
37
55
  ### Puggable I/O: SocketLike protocol
38
56
 
39
- The `socketwrapper.SocketLike` protocol, an small subset the socket interface,
40
- is all what's required for any object to be wrap-able by `socketwrapper`.
57
+ The `protocols.SocketLike` protocol, a small subset the socket interface, is all what's required for any object to be wrap-able by `socketwrapper`.
58
+
59
+ Additional methods defined in `protocols.OptionalSocketLike` can be optionally implemented enabling optimized code paths.
41
60
 
42
61
  ```py
43
62
  @typing.runtime_checkable
@@ -49,18 +68,19 @@ class SocketLike(typing.Protocol):
49
68
  def recv(self, bufsize: int, /) -> bytes: ...
50
69
  def settimeout(self, timeout: float | None, /) -> None: ...
51
70
  def close(self) -> None: ...
71
+
72
+
73
+ @typing.runtime_checkable
74
+ class OptionalSocketLike(SocketLike, typing.Protocol):
75
+ """Protocol for optional socket-like object methods accepted by socketwrapper socket classes."""
76
+
77
+ def recv_into(self, buffer: collections.abc.Buffer, /) -> bytes: ...
78
+
52
79
  ```
53
80
 
54
81
  Special attention to:
55
- - [fileno](https://docs.python.org/3.14/library/socket.html#socket.socket.fileno)
56
- has to be a valid OS file descriptor.
57
- - [settimeout](https://docs.python.org/3.14/library/socket.html#socket.socket.settimeout)
58
- only requires support for `settimeout(.0)` (
59
- [non-blocking semantics](https://docs.python.org/3.14/library/socket.html#notes-on-socket-timeouts)
60
- ), raising [ValueError](https://docs.python.org/3.14/library/exceptions.html#ValueError)
61
- for any other value is fully supported in which case
62
- [selectors.DefaultSelector](https://docs.python.org/3.14/library/selectors.html#selectors.DefaultSelector)
63
- will be used for synchronous operations.
82
+ - [fileno](https://docs.python.org/3.14/library/socket.html#socket.socket.fileno) has to be a valid OS file descriptor.
83
+ - [settimeout](https://docs.python.org/3.14/library/socket.html#socket.socket.settimeout) must support `settimeout(.0)` ([non-blocking semantics](https://docs.python.org/3.14/library/socket.html#notes-on-socket-timeouts)), raising [ValueError](https://docs.python.org/3.14/library/exceptions.html#ValueError) for any other value will be handled, relying on [selectors.DefaultSelector](https://docs.python.org/3.14/library/selectors.html#selectors.DefaultSelector) for synchronous operations.
64
84
 
65
85
  ## Usage
66
86
 
@@ -80,11 +100,31 @@ with socketwrapper.pipe(framing=True) as (parent_reader, child_writer):
80
100
  else:
81
101
  child_writer.send(b'Hello world!')
82
102
  ```
83
-
84
103
  ```
85
104
  Message b'Hello world!' received
86
105
  ```
87
106
 
107
+ ### Simple IPC with pipe using msgpack
108
+
109
+ ```python
110
+ import os
111
+ import socketwrapper
112
+ import socketwrapper.framing as framing
113
+
114
+ with socketwrapper.pipe(framing=framing.MsgPack()) as (parent_reader, child_writer):
115
+ child_writer.inheritable = True
116
+ child_pid = os.fork() # replace with your own process fork/spawn logic
117
+ child_writer.inheritable = False # important, prevent socket leaks!
118
+
119
+ if child_pid:
120
+ print(f'Message {parent_reader.recv()!r} received')
121
+ else:
122
+ child_writer.send({'data': b'Hello world!'})
123
+ ```
124
+ ```
125
+ Message {'data': b'Hello world!'} received
126
+ ```
127
+
88
128
  ### Simple asyncio IPC with pipe
89
129
 
90
130
  ```python
@@ -105,7 +145,6 @@ with socketwrapper.pipe(framing=True) as (parent_reader, child_writer):
105
145
 
106
146
  asyncio.run(parent(parent_reader) if child_pid else child(child_writer))
107
147
  ```
108
-
109
148
  ```
110
149
  Message b'Hello world!' received
111
150
  ```
@@ -129,7 +168,6 @@ with socketwrapper.socketpair(framing=True) as (parent_duplex, child_duplex):
129
168
  print(f'Message {child_duplex.recv()!r} received in child')
130
169
  child_duplex.send(b'Hello parent!')
131
170
  ```
132
-
133
171
  ```
134
172
  Message b'Hello child!' received in child
135
173
  Message b'Hello parent!' received in parent
@@ -153,25 +191,46 @@ def child(conn: multiprocessing.connection.Connection) -> None:
153
191
 
154
192
  asyncio.run(main())
155
193
 
156
- parent_conn, child_conn = multiprocessing.Pipe()
157
- with parent_conn, child_conn:
158
- child_process = multiprocessing.Process(target=child, args=(child_conn,))
159
- child_process.start()
194
+ if __name__ == '__main__':
195
+ parent_conn, child_conn = multiprocessing.Pipe()
196
+ with parent_conn, child_conn:
197
+ child_process = multiprocessing.Process(target=child, args=(child_conn,))
198
+ child_process.start()
160
199
 
161
- parent_conn.send_bytes(b'Hello child!')
162
- print(f'Message {parent_conn.recv_bytes()!r} received in parent')
163
- child_process.join(1)
200
+ parent_conn.send_bytes(b'Hello child!')
201
+ print(f'Message {parent_conn.recv_bytes()!r} received in parent')
202
+ child_process.join(1)
164
203
  ```
165
-
166
204
  ```
167
205
  Message b'Hello child!' received in child
168
206
  Message b'Hello parent!' received in parent
169
207
  ```
170
208
 
209
+ ### Socketwrapper for cross-interpreter communication
210
+
211
+ ```py
212
+ import concurrent.futures
213
+ import socketwrapper
214
+
215
+ def child(child_fileno: int) -> None:
216
+ child_writer = socketwrapper.MessageWriter(child_fileno)
217
+ child_writer.send(b'Hello World')
218
+
219
+ if __name__ == '__main__':
220
+ with (socketwrapper.pipe(framing=True) as (parent_reader, child_writer),
221
+ concurrent.futures.InterpreterPoolExecutor() as pool):
222
+ pool.submit(child, child_writer.fileno())
223
+ print(f'Message {parent_reader.recv()!r} received')
224
+ ```
225
+ ```
226
+ Message b'Hello World' received
227
+ ```
228
+
171
229
  ### Custom socketwrapper framing with progress
172
230
 
173
231
  ```py
174
232
  import collections.abc
233
+ import io
175
234
  import itertools
176
235
  import os
177
236
  import socketwrapper
@@ -195,7 +254,7 @@ def progress(arrow: str, size: int, min_chunk: int = 1024) -> collections.abc.Ge
195
254
  class ProgressFraming(socketwrapper.framing.VarIntBytes):
196
255
 
197
256
  @classmethod
198
- def frames(cls, buffer: bytearray) -> collections.abc.Generator[int, None, None]:
257
+ def frames(cls, buffer: io.BytesIO) -> collections.abc.Generator[int, None, None]:
199
258
  frames = super().frames(buffer)
200
259
  yield from itertools.islice(frames, 2)
201
260
  yield from progress('>', next(frames))
@@ -4,8 +4,8 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'socketwrapper'
7
- description = 'high level socket and pipe wrapper'
8
- version = '0.0.1'
7
+ description = 'high level socket and pipe wrappers'
8
+ version = '0.0.3'
9
9
  requires-python = '>=3.12'
10
10
  keywords = ['socket', 'pipe', 'ipc', 'asyncio']
11
11
  readme = { file = 'README.md', content-type = 'text/markdown' }
@@ -22,7 +22,7 @@ authors = [
22
22
  { name = 'Felipe A Hernandez' },
23
23
  { email = 'ergoithz@gmail.com' },
24
24
  ]
25
- dependencies = ['typing-extensions >= 4.15 ; python_version < "3.13"']
25
+ dependencies = ['typing-extensions >= 4.6 ; python_version < "3.13"']
26
26
 
27
27
  [tool.setuptools.package-data]
28
28
  socketwrapper = ["py.typed"]
@@ -37,8 +37,10 @@ exclude = [
37
37
  pythonVersion = '3.12'
38
38
 
39
39
  [project.optional-dependencies]
40
+ msgpack = ['msgpack']
40
41
  dev = [
41
42
  'coverage',
43
+ 'msgpack',
42
44
  'ruff',
43
45
  'wheel',
44
46
  'yapf',
@@ -46,6 +48,7 @@ dev = [
46
48
 
47
49
  [project.urls]
48
50
  homepage = 'https://gitlab.com/ergoithz/socketwrapper'
51
+ repository = 'https://gitlab.com/ergoithz/socketwrapper'
49
52
  issue-tracker = 'https://gitlab.com/ergoithz/socketwrapper/-/issues'
50
53
  release-notes = 'https://gitlab.com/ergoithz/socketwrapper/-/releases'
51
54
  issue-new = 'https://gitlab.com/ergoithz/socketwrapper/-/issues/new'