zndraw-socketio 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

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,13 +1,35 @@
1
1
  from .wrapper import (
2
2
  AsyncClientWrapper as AsyncClientWrapper,
3
+ )
4
+ from .wrapper import (
3
5
  AsyncServerWrapper as AsyncServerWrapper,
6
+ )
7
+ from .wrapper import (
4
8
  AsyncSimpleClientWrapper as AsyncSimpleClientWrapper,
5
- Depends as Depends,
9
+ )
10
+ from .wrapper import (
6
11
  EventContext as EventContext,
12
+ )
13
+ from .wrapper import (
7
14
  SimpleClientWrapper as SimpleClientWrapper,
15
+ )
16
+ from .wrapper import (
8
17
  SioRequest as SioRequest,
18
+ )
19
+ from .wrapper import (
9
20
  SyncClientWrapper as SyncClientWrapper,
21
+ )
22
+ from .wrapper import (
10
23
  SyncServerWrapper as SyncServerWrapper,
24
+ )
25
+ from .wrapper import (
11
26
  get_event_name as get_event_name,
27
+ )
28
+ from .wrapper import (
12
29
  wrap as wrap,
13
30
  )
31
+
32
+ try:
33
+ from fastapi import Depends as Depends
34
+ except ImportError:
35
+ from zndraw_socketio.params import Depends as Depends
@@ -50,11 +50,6 @@ try:
50
50
  except ImportError:
51
51
  from zndraw_socketio.params import _DependsBase as _DependsClass
52
52
 
53
- try:
54
- from fastapi import Depends
55
- except ImportError:
56
- from zndraw_socketio.params import Depends
57
-
58
53
  try:
59
54
  from fastapi import Request
60
55
  except ImportError:
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: zndraw-socketio
3
+ Version: 0.1.1
4
+ Summary: Typed wrapper for python-socketio with Pydantic validation and dependency injection.
5
+ Project-URL: homepage, https://github.com/pythonFZ/zndraw-socketio
6
+ Project-URL: issues, https://github.com/pythonFZ/zndraw-socketio/issues
7
+ Author-email: Atomie CHEN <atomic_cwh@163.com>, Fabian Zills <fabian.zills@web.de>
8
+ License-File: LICENSE
9
+ Keywords: pydantic,socketio,typed,wrapper,zndraw
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: pydantic>=2.10.6
15
+ Requires-Dist: python-socketio>=5.12.1
16
+ Requires-Dist: typing-extensions>=4.13.0
17
+ Provides-Extra: asyncio-client
18
+ Requires-Dist: python-socketio[asyncio-client]>=5.12.1; extra == 'asyncio-client'
19
+ Provides-Extra: client
20
+ Requires-Dist: python-socketio[client]>=5.12.1; extra == 'client'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # ZnDraw SocketIO
24
+ This package provides an opinionated typed interface to the python-socketio library using pydantic models.
25
+
26
+ ```python
27
+ from zndraw_socketio import Wrapper
28
+ from pydantic import BaseModel
29
+ import socketio
30
+
31
+ sio = Wrapper(socketio.AsyncClient()) # can be server as well
32
+ ```
33
+
34
+ ## Emit Pattern
35
+ ```python
36
+ class Ping(BaseModel):
37
+ message: str
38
+
39
+ # kwargs are passed to socketio's emit method
40
+ # emits {"message": "Hello, World!"} to "ping"
41
+ await sio.emit(Ping(message="Hello, World!"), **kwargs)
42
+ # emits {"message": "Hello, World!"} to "my-ping"
43
+ await sio.emit("my-ping", Ping(message="Hello, World!"), **kwargs)
44
+ # standard sio behaviour
45
+ await sio.emit("event", {"payload": ...})
46
+ ```
47
+
48
+ ## Call / RPC Pattern
49
+ ```python
50
+ class Pong(BaseModel):
51
+ reply: str
52
+
53
+ # emits {"message": "Hello, World!"} to "ping" and receives Pong(reply=...) in return
54
+ response = await sio.call(Ping(message="Hello, World!"), response_model=Pong)
55
+ assert isinstance(response, Pong)
56
+ # emits {"message": "Hello, World!"} to "my-ping" and receives Pong(reply=...) in return
57
+ response = await sio.call("my-ping", Ping(message="Hello, World!"), response_model=Pong)
58
+ assert isinstance(response, Pong)
59
+ # standard sio behaviour
60
+ response = await sio.call("event", {"payload": ...})
61
+ # standard response obj, typically dict
62
+ ```
63
+
64
+ ## Event Names
65
+ By default, the event name is the class name in snake_case. You can customize it by setting the `event_name` attribute.
66
+
67
+ ```python
68
+ class CustomEvent(Event):
69
+ ...
70
+
71
+ assert CustomEvent.event_name == "custom_event"
72
+ ```
73
+
74
+ you can override it like this:
75
+
76
+ ```python
77
+ from typing import ClassVar
78
+
79
+ class CustomEvent(Event):
80
+ event_name: ClassVar[str] = "my_custom_event"
81
+ ```
82
+
83
+ ## Union Return Types
84
+ You might want to return `Response|ErrorResponse` from an event handler.
85
+
86
+ > [!NOTE]
87
+ > If your responses share fields, it is recommended to add a discriminator field to avoid ambiguity.
88
+
89
+
90
+ ```python
91
+ class ProblemDetail(BaseModel):
92
+ """RFC 9457 Problem Details.
93
+
94
+ https://www.rfc-editor.org/rfc/rfc9457.html
95
+ """
96
+ kind: Literal["error"] = "error" # The discriminator (nod needed in this example)
97
+ type: str = "about:blank"
98
+ title: str
99
+ status: int
100
+ detail: str | None = None
101
+ instance: str | None = None
102
+
103
+ class Response(BaseModel):
104
+ kind: Literal["response"] = "response" # The discriminator (not needed in this example)
105
+ data: str
106
+
107
+ class ServerRequest(BaseModel):
108
+ query: str
109
+
110
+
111
+ response_model = ... # do we need typing Annotated here?
112
+
113
+ response = await sio.call(ServerRequest(query="..."), response_model=response_model)
114
+ ```
@@ -0,0 +1,8 @@
1
+ zndraw_socketio/__init__.py,sha256=KER2gbnWyWq_OfjcZ7EEWJwFxLKgCmPp4e2IPL2EDtM,783
2
+ zndraw_socketio/params.py,sha256=kQvr0rLz5-ug0bGKlvhxPHfLiDIoMvUVWEGJotpPCjM,1338
3
+ zndraw_socketio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ zndraw_socketio/wrapper.py,sha256=sfhbFv2tzu47xV8T5rSVHLQFSqtAaa39-uk9q6MgQ9E,50662
5
+ zndraw_socketio-0.1.1.dist-info/METADATA,sha256=42ZNuCbjRUpDR6wW2IoIgdhrZycM7gsReiEWC5IkY0o,3533
6
+ zndraw_socketio-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
7
+ zndraw_socketio-0.1.1.dist-info/licenses/LICENSE,sha256=Ry21YmIoh82aAQa8oBStENUpHqywNGoW6f5Q8ahU5HE,1085
8
+ zndraw_socketio-0.1.1.dist-info/RECORD,,
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Atomie CHEN
3
+ Copyright (c) 2026 zndraw-socketio contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,212 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: zndraw-socketio
3
- Version: 0.1.0
4
- Summary: Typed wrapper for python-socketio with Pydantic validation and dependency injection.
5
- Project-URL: homepage, https://github.com/pythonFZ/zndraw-socketio
6
- Project-URL: issues, https://github.com/pythonFZ/zndraw-socketio/issues
7
- Author-email: Atomie CHEN <atomic_cwh@163.com>, Fabian Zills <fabian.zills@web.de>
8
- License-File: LICENSE
9
- Keywords: pydantic,socketio,typed,wrapper,zndraw
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
- Classifier: Programming Language :: Python :: 3
13
- Requires-Python: >=3.10
14
- Requires-Dist: pydantic>=2.10.6
15
- Requires-Dist: python-socketio>=5.12.1
16
- Requires-Dist: typing-extensions>=4.13.0
17
- Provides-Extra: asyncio-client
18
- Requires-Dist: python-socketio[asyncio-client]>=5.12.1; extra == 'asyncio-client'
19
- Provides-Extra: client
20
- Requires-Dist: python-socketio[client]>=5.12.1; extra == 'client'
21
- Description-Content-Type: text/markdown
22
-
23
- # zndraw-socketio
24
-
25
- Typed wrapper for [python-socketio](https://github.com/miguelgrinberg/python-socketio) with Pydantic validation and dependency injection.
26
-
27
-
28
- ## Installation
29
-
30
- ```sh
31
- pip install zndraw-socketio
32
- ```
33
-
34
- Optional extras for client transports:
35
-
36
- ```sh
37
- pip install zndraw-socketio[client]
38
- pip install zndraw-socketio[asyncio-client]
39
- ```
40
-
41
-
42
- ## Usage
43
-
44
- ### Wrap any socketio instance
45
-
46
- ```python
47
- import socketio
48
- from pydantic import BaseModel
49
- from zndraw_socketio import wrap
50
-
51
- class Ping(BaseModel):
52
- message: str
53
-
54
- class Pong(BaseModel):
55
- reply: str
56
-
57
- # Wrap any existing socketio instance
58
- tsio = wrap(socketio.AsyncClient())
59
-
60
- # Emit with automatic event name derivation (Ping -> "ping")
61
- await tsio.emit(Ping(message="Hello, World!"))
62
-
63
- # Emit with explicit event name
64
- await tsio.emit("my-ping", Ping(message="Hello, World!"))
65
-
66
- # Call with typed response
67
- response = await tsio.call(Ping(message="Hello"), response_model=Pong)
68
- # response is typed as Pong
69
- ```
70
-
71
- ### Handler registration with validation
72
-
73
- ```python
74
- # Event name derived from model class (Ping -> "ping")
75
- @tsio.on(Ping)
76
- async def handle_ping(data: Ping) -> Pong:
77
- return Pong(reply=data.message)
78
-
79
- # Or use function name as event name
80
- @tsio.event
81
- async def ping(data: Ping) -> Pong:
82
- return Pong(reply=data.message)
83
- ```
84
-
85
- ### Union response types
86
-
87
- ```python
88
- from typing import Annotated, Literal
89
- from pydantic import BaseModel, Discriminator
90
-
91
- class Success(BaseModel):
92
- kind: Literal["success"] = "success"
93
- data: str
94
-
95
- class Error(BaseModel):
96
- kind: Literal["error"] = "error"
97
- message: str
98
-
99
- # Simple union
100
- response = await tsio.call(request, response_model=Success | Error)
101
-
102
- # Discriminated union
103
- ResponseType = Annotated[Success | Error, Discriminator("kind")]
104
- response = await tsio.call(request, response_model=ResponseType)
105
- ```
106
-
107
- ### Custom event names
108
-
109
- ```python
110
- from typing import ClassVar
111
-
112
- class CustomEvent(BaseModel):
113
- event_name: ClassVar[str] = "my_custom_event"
114
- data: str
115
-
116
- # Uses "my_custom_event" instead of "custom_event"
117
- await tsio.emit(CustomEvent(data="hello"))
118
- ```
119
-
120
- ### Exception handlers
121
-
122
- ```python
123
- from zndraw_socketio import wrap, EventContext
124
-
125
- tsio = wrap(socketio.AsyncServer(async_mode="asgi"))
126
-
127
- @tsio.exception_handler(ValueError)
128
- async def handle_value_error(ctx: EventContext, exc: ValueError):
129
- return {"error": "value_error", "message": str(exc)}
130
-
131
- # Namespace-specific
132
- @tsio.exception_handler(ValueError, namespace="/chat")
133
- async def handle_chat_error(ctx: EventContext, exc: ValueError):
134
- return {"error": "chat_error", "message": str(exc)}
135
- ```
136
-
137
- ### Dependency injection
138
-
139
- ```python
140
- from typing import Annotated
141
- from fastapi import Depends
142
- from zndraw_socketio import wrap
143
-
144
- async def get_redis():
145
- return my_redis_pool
146
-
147
- RedisDep = Annotated[AsyncRedis, Depends(get_redis)]
148
-
149
- tsio = wrap(socketio.AsyncServer(async_mode="asgi"))
150
-
151
- @tsio.on(RoomLeave)
152
- async def room_leave(sid: str, data: RoomLeave, redis: RedisDep) -> RoomLeaveResponse:
153
- await redis.delete(f"presence:{data.room_id}:{sid}")
154
- return RoomLeaveResponse(status="ok")
155
- ```
156
-
157
- When FastAPI is not installed, import `Depends` from `zndraw_socketio`:
158
-
159
- ```python
160
- from zndraw_socketio import Depends
161
- ```
162
-
163
- ### FastAPI integration
164
-
165
- ```python
166
- import socketio
167
- from typing import Annotated
168
- from fastapi import FastAPI, Depends
169
- from zndraw_socketio import wrap, AsyncServerWrapper
170
-
171
- app = FastAPI()
172
- tsio = wrap(socketio.AsyncServer(async_mode="asgi"))
173
-
174
- SioServer = Annotated[AsyncServerWrapper, Depends(tsio)]
175
-
176
- @app.post("/notify")
177
- async def notify(server: SioServer):
178
- await server.emit("notification", {"msg": "hello"})
179
- return {"status": "sent"}
180
-
181
- combined_app = socketio.ASGIApp(tsio, app)
182
- ```
183
-
184
- ### SimpleClient support
185
-
186
- ```python
187
- tsio = wrap(socketio.SimpleClient())
188
- tsio.connect("http://localhost:5000")
189
-
190
- tsio.emit(Ping(message="Hello"))
191
- response = tsio.call(Ping(message="Hello"), response_model=Pong)
192
- event_name, data = tsio.receive(response_model=Pong)
193
- tsio.disconnect()
194
- ```
195
-
196
- ## Supported socketio types
197
-
198
- `wrap()` auto-detects the socketio instance type:
199
-
200
- | socketio type | Wrapper class |
201
- |---|---|
202
- | `AsyncClient` | `AsyncClientWrapper` |
203
- | `AsyncServer` | `AsyncServerWrapper` |
204
- | `Client` | `SyncClientWrapper` |
205
- | `Server` | `SyncServerWrapper` |
206
- | `SimpleClient` | `SimpleClientWrapper` |
207
- | `AsyncSimpleClient` | `AsyncSimpleClientWrapper` |
208
-
209
-
210
- ## License
211
-
212
- MIT License
@@ -1,8 +0,0 @@
1
- zndraw_socketio/__init__.py,sha256=eRrJNRHjGEBsBFUc1gOBE4p9j9-g-K5o4Ao5whz6OLU,455
2
- zndraw_socketio/params.py,sha256=kQvr0rLz5-ug0bGKlvhxPHfLiDIoMvUVWEGJotpPCjM,1338
3
- zndraw_socketio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- zndraw_socketio/wrapper.py,sha256=Lsjopx8X2ikCfg4NIXAmBvRmhcgcBqSVNmao8lI4QXM,50767
5
- zndraw_socketio-0.1.0.dist-info/METADATA,sha256=r0uoZMxmNAylGJOHDm4u8w_8qr-9gEJgVbMKifpX5_Y,5338
6
- zndraw_socketio-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
7
- zndraw_socketio-0.1.0.dist-info/licenses/LICENSE,sha256=SpSDGxJCTumVhMVOPkFg_x6q01lPcU6KsYh_7DhwJg0,1068
8
- zndraw_socketio-0.1.0.dist-info/RECORD,,