Uh oh!
There was an error while loading. Please reload this page.
feat: add Python pip-publishable SDK for CSM-TCP-Router - #31
Conversation
Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/4a1ee665-7464-4bd0-8898-0725daef43d5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com>
Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/4a1ee665-7464-4bd0-8898-0725daef43d5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com>
Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/93afe5c4-c917-4b9b-a347-189efb3bf4db Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a pip-publishable Python SDK (csm-tcp-router-client) for the CSM-TCP-Router protocol v0, expanding the existing sync client with a full asyncio client, packaging metadata, CI, docs, examples, and a comprehensive test suite.
Changes:
- Added
AsyncTcpRouterClient(asyncio-based API) alongside a syncTcpRouterClient, plus internal protocol/transport layers and public models/exceptions. - Added unit + integration tests (including a TCP
MockServerfixture) covering protocol, sync client, and async client behavior. - Added packaging/CI/docs/examples for PyPI/TestPyPI publishing and end-user onboarding.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| SDK/python-package/tests/test_protocol.py | Adds unit tests for protocol encode/decode/parse behavior. |
| SDK/python-package/tests/test_integration.py | Adds integration tests for the sync client against a real TCP mock server. |
| SDK/python-package/tests/test_client.py | Adds sync client unit tests using mocked transport + direct packet injection. |
| SDK/python-package/tests/test_async_client.py | Adds async client unit + integration tests. |
| SDK/python-package/tests/conftest.py | Provides MockServer fixture used by integration tests. |
| SDK/python-package/tests/init.py | Marks tests as a package. |
| SDK/python-package/src/csm_tcp_router/models.py | Defines public enums/models (PacketType, responses, notifications). |
| SDK/python-package/src/csm_tcp_router/exceptions.py | Defines the SDK exception hierarchy. |
| SDK/python-package/src/csm_tcp_router/client.py | Implements the sync TcpRouterClient API on top of the transport. |
| SDK/python-package/src/csm_tcp_router/async_client.py | Implements AsyncTcpRouterClient using asyncio streams/queues. |
| SDK/python-package/src/csm_tcp_router/_transport.py | Implements the internal threaded TCP transport and receive loop. |
| SDK/python-package/src/csm_tcp_router/_protocol.py | Implements protocol v0 framing/codec utilities. |
| SDK/python-package/src/csm_tcp_router/init.py | Exposes top-level public API and sets version to 0.2.0. |
| SDK/python-package/pyproject.toml | Adds build/test/lint configuration and package metadata for v0.2.0. |
| SDK/python-package/examples/subscribe_status.py | Adds sync example demonstrating status subscription callbacks. |
| SDK/python-package/examples/basic_usage.py | Adds sync quickstart example (connect/ping/list modules). |
| SDK/python-package/examples/async_usage.py | Adds asyncio quickstart example covering core features. |
| SDK/python-package/README.zh-cn.md | Adds full Chinese documentation for installation, API, and usage. |
| SDK/python-package/README.md | Adds English documentation for installation, API, and usage. |
| SDK/python-package/LICENSE | Adds MIT license file. |
| SDK/python-package/CHANGELOG.md | Adds changelog entries for 0.2.0 and initial release notes. |
| .github/workflows/Python_SDK.yml | Adds CI for lint/test/build and gated TestPyPI→PyPI publishing on tags. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def _parse_server_error(packet: Packet) -> ServerError: | ||
| """Extract code and message from CSM Error format ``[Error: <code>] <msg>``.""" | ||
| text = packet.data.decode("utf-8", errors="replace").strip() | ||
| code = "" | ||
| msg = text |
There was a problem hiding this comment.
_parse_server_error() is duplicated in both client.py and async_client.py. To avoid the two implementations drifting over time, consider moving this into a shared internal helper (e.g., _errors.py) and importing it from both clients.
| - Package version bumped to `0.2.0`. | ||
| - `asyncio_mode = "auto"` added to `pyproject.toml` pytest options; all async | ||
| tests run automatically without explicit `@pytest.mark.asyncio` decorators. | ||
There was a problem hiding this comment.
The 0.2.0 section contains a second "### Added" block that appears to describe the initial release (0.1.0), but it’s still nested under 0.2.0. This makes the changelog ambiguous. Consider adding a dedicated ## [0.1.0] – <date> section (or moving these bullets under [Unreleased] if appropriate) instead of repeating "### Added" under 0.2.0.
| ## [0.1.0] |
| ) | ||
| try: | ||
| sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| sock.settimeout(timeout) | ||
| sock.connect((host, port)) | ||
| sock.settimeout(None) # switch to blocking for the recv loop | ||
| except OSError as exc: |
There was a problem hiding this comment.
Transport.connect() creates the socket inside the try, but on OSError it raises without closing the partially-created socket. In retry loops like wait_for_server(), this can leak file descriptors. Close sock in the exception path (e.g., sock.close() in a finally/except block) before re-raising RouterConnectionError.
| ) | |
| try: | |
| sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| sock.settimeout(timeout) | |
| sock.connect((host, port)) | |
| sock.settimeout(None) # switch to blocking for the recv loop | |
| exceptOSErrorasexc: | |
| ) | |
| sock: Optional[socket.socket] =None | |
| try: | |
| sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| sock.settimeout(timeout) | |
| sock.connect((host, port)) | |
| sock.settimeout(None) # switch to blocking for the recv loop | |
| exceptOSErrorasexc: | |
| ifsockisnotNone: | |
| try: | |
| sock.close() | |
| exceptOSError: | |
| pass |
| This class mirrors the LabVIEW ClientAPI VIs and speaks the | ||
| CSM-TCP-Router protocol v0. It is thread-safe: multiple threads may | ||
| call its methods concurrently. |
There was a problem hiding this comment.
The class docstring claims the client is thread-safe and that multiple threads may call methods concurrently, but synchronous commands share a single _resp_queue/_cmd_resp_queue with no request correlation or serialization. Concurrent send_and_wait() calls can consume each other’s responses (and an ERROR/disconnect sentinel only unblocks one waiter), so the concurrency guarantee is not correct as written. Either (a) enforce a single in-flight waiter per queue via locks, or (b) revise the docstring to document the single-in-flight limitation.
| def disconnect(self) -> None: | ||
| """Disconnect from the server and release all resources. | ||
| Safe to call even if not currently connected. | ||
| """ |
There was a problem hiding this comment.
disconnect() only closes the transport; it does not notify/unblock any threads currently waiting in _wait_for_resp() / _wait_for_cmd_resp(). If a disconnect happens while another thread is blocked, it will wait until timeout even though the connection is already gone. Consider having disconnect() (or Transport.disconnect()) inject a connection-lost sentinel into the internal queues (and ensure it wakes all waiters).
| defdisconnect(self) ->None: | |
| """Disconnectfromtheserverandreleaseallresources. | |
| Safetocallevenifnotcurrentlyconnected. | |
| """ | |
| def_enqueue_disconnect_sentinel(self, q: object) ->None: | |
| """Wake queue-based waiters with a connection-lost error.""" | |
| ifnotisinstance(q, queue.Queue): | |
| return | |
| # Enqueue enough sentinels to wake any threads currently blocked on | |
| # queue.get() without relying on timeout expiry. | |
| waiter_count=max(1, threading.active_count()) | |
| for_inrange(waiter_count): | |
| try: | |
| q.put_nowait(RouterConnectionError("Disconnected from server")) | |
| exceptqueue.Full: | |
| break | |
| def_notify_disconnect_waiters(self) ->None: | |
| """Inject connection-lost sentinels into internal response queues.""" | |
| self._enqueue_disconnect_sentinel(getattr(self, "_resp_queue", None)) | |
| self._enqueue_disconnect_sentinel(getattr(self, "_cmd_resp_queue", None)) | |
| defdisconnect(self) ->None: | |
| """Disconnectfromtheserverandreleaseallresources. | |
| Safetocallevenifnotcurrentlyconnected. | |
| """ | |
| self._notify_disconnect_waiters() |
| try: | ||
| if asyncio.iscoroutinefunction(cb): | ||
| await cb(resp) # type: ignore[arg-type] | ||
| else: | ||
| cb(resp) # type: ignore[arg-type] |
There was a problem hiding this comment.
Async callbacks are detected via asyncio.iscoroutinefunction(cb), but that misses callables where __call__ returns an awaitable (callable objects, some wrappers), which can lead to un-awaited coroutine warnings and dropped work. A more robust pattern is to call the callback and then await the result if it is awaitable (e.g., via inspect.isawaitable). Apply the same approach for both async-resp and status callbacks.
| """Put sentinels in waiter queues when the connection is lost.""" | ||
| if self._resp_queue is None: | ||
| return | ||
| sentinel = RouterConnectionError("Connection lost unexpectedly.") | ||
| self._resp_queue.put_nowait(sentinel) |
There was a problem hiding this comment.
_notify_disconnect() only enqueues a single ConnectionError sentinel into each waiter queue. If multiple coroutines are concurrently blocked on _wait_for_resp() / _wait_for_cmd_resp(), only one will be released and the others can hang until timeout. Consider re-queueing the sentinel after a waiter consumes it, or switch to an event/flag checked by waiters so all pending operations fail fast on disconnect.
| wire = encode_packet(command.encode("utf-8"), PacketType.CMD) | ||
| await self._send_raw(wire) | ||
| return await self._wait_for_resp(timeout) |
There was a problem hiding this comment.
send_and_wait() awaits the next item from the shared _resp_queue, but there is no serialization/correlation between requests. If multiple tasks call send_and_wait() concurrently, responses can be delivered to the wrong caller. Consider adding an async lock to allow only one in-flight send_and_wait() at a time (and similarly for cmd-resp waiters), or document that these methods must not be used concurrently on the same client instance.
nevstop
commented
Apr 22, 2026
@copilot apply changes based on the comments in this thread |
…ks, disconnect sentinels, isawaitable, changelog) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/b0917f8e-c50c-4a63-ae30-a1c245a6d3d7 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com>
All 8 review-comment issues addressed in commit
114/114 tests pass; ruff and CodeQL clean. |
* feat: add Python pip-publishable SDK for CSM-TCP-Router (#31) * feat: add Python pip-publishable SDK for CSM-TCP-Router Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/4a1ee665-7464-4bd0-8898-0725daef43d5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * fix: add least-privilege permissions to CI workflow jobs Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/4a1ee665-7464-4bd0-8898-0725daef43d5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * feat: add asyncio client, Chinese README, and TestPyPI CI stage (v0.2.0) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/93afe5c4-c917-4b9b-a347-189efb3bf4db Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * fix: address all PR review comments (shared _errors, socket leak, locks, disconnect sentinels, isawaitable, changelog) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/b0917f8e-c50c-4a63-ae30-a1c245a6d3d7 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Add bilingual VI API reference docs for CSM-TCP-Router (Server + Client) (#35) * Initial plan * docs: add bilingual VI API documentation for CSM-TCP-Router Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/cacb955d-6c38-4fc7-b30d-9381fbbd06e1 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: move VI API docs under src and align reference format Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/117da425-df26-4ecc-a8c4-ab0e98412e50 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: restore compatibility notes in status API sections Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/117da425-df26-4ecc-a8c4-ab0e98412e50 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
* Refactor bilingual README for clarity and replace Mermaid diagrams with Excalidraw-based PNG images (#29) * docs: rewrite bilingual README with mermaid diagrams Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/457dc57e-fd6d-4087-a604-3a7a4dd68b7b Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: replace mermaid diagrams with static PNG images Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a92684df-d1ef-4e7f-801e-473ee3d2911d Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: replace mermaid with png diagrams and add excalidraw sources Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a92684df-d1ef-4e7f-801e-473ee3d2911d Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: align client diagram alt text with sequence content Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a92684df-d1ef-4e7f-801e-473ee3d2911d Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: normalize client diagram naming and alt text Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a92684df-d1ef-4e7f-801e-473ee3d2911d Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: unify client diagram alt text naming Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a92684df-d1ef-4e7f-801e-473ee3d2911d Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: improve diagram alt text accessibility in both READMEs Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a92684df-d1ef-4e7f-801e-473ee3d2911d Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Convert `.doc/CSM-TCP-Router.drawio` to Excalidraw source and synced PNG export (#30) * docs: add excalidraw and png converted from drawio Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/8747d072-0055-4877-a383-891476e8e333 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: fix application spelling in converted diagram Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/8747d072-0055-4877-a383-891476e8e333 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * 17 python sdk (#32) * feat: add Python pip-publishable SDK for CSM-TCP-Router (#31) * feat: add Python pip-publishable SDK for CSM-TCP-Router Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/4a1ee665-7464-4bd0-8898-0725daef43d5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * fix: add least-privilege permissions to CI workflow jobs Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/4a1ee665-7464-4bd0-8898-0725daef43d5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * feat: add asyncio client, Chinese README, and TestPyPI CI stage (v0.2.0) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/93afe5c4-c917-4b9b-a347-189efb3bf4db Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * fix: address all PR review comments (shared _errors, socket leak, locks, disconnect sentinels, isawaitable, changelog) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/b0917f8e-c50c-4a63-ae30-a1c245a6d3d7 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Add bilingual VI API reference docs for CSM-TCP-Router (Server + Client) (#35) * Initial plan * docs: add bilingual VI API documentation for CSM-TCP-Router Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/cacb955d-6c38-4fc7-b30d-9381fbbd06e1 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: move VI API docs under src and align reference format Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/117da425-df26-4ecc-a8c4-ab0e98412e50 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * docs: restore compatibility notes in status API sections Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/117da425-df26-4ecc-a8c4-ab0e98412e50 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> * update PythonClientAPI/* * Consolidate Python SDK into single-file `csm_tcp_router_client` module and release as v0.3.0 (#37) * Consolidate Python SDK into single-file csm_tcp_router_client module Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/ffc74aa4-b55d-45b4-b066-749d1db8c176 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Bump SDK to 0.3.0 and fix workflow paths so publish jobs trigger Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/f2eec384-ae45-4817-bcb3-1f990db4954b Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Add C# csm-tcp-router-client SDK (#38) * Initial plan * Add C# csm-tcp-router-client SDK (single-file), VS solution, xUnit tests, example, NuGet packaging, and GitHub Actions workflow Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/1c9d260f-6983-4c60-9d7a-f07538723b70 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Address review: deterministic closed-port helper, ManualResetEventSlim in unsubscribe test, observe WaitForServerAsync connect task, force disconnect on RESP/CMD_RESP timeout Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/a52165ab-7829-42b0-91f9-e4ba84e0b6b9 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Add C csm-tcp-router-client SDK (multi-platform, VS2026, CMake, tests) (#40) * Add C csm-tcp-router-client SDK with VS2026 + CMake + tests Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/ea6c42b2-b6f8-4ebe-8438-786601832ef5 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Address PR review comments on the C SDK Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/de04612d-484c-4905-9c04-06c451a01e15 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Drop redundant g_wsa_lock_inited; route cleanup through InitOnceExecuteOnce Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/de04612d-484c-4905-9c04-06c451a01e15 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Fix INADDR_LOOPBACK undeclared on macOS in mock_server.c (#41) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/eab9769d-1260-4715-8d72-1e3241719ef1 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * 将 SDK/ 下所有代码注释翻译为中文 (#42) * translate: convert all C SDK comments from English to Chinese Translated all code comments in 11 C SDK files from English to Chinese, preserving all code logic, variable names, function names, string literals, Doxygen tags (@PARAM, @return, etc.) and technical proper names (TCP, CSM, WSA, POSIX, BSD, Win32, Winsock2, pthreads, CMake, NUL, DLL, etc.). Files translated: - SDK/c/include/csm_tcp_router_client.h - SDK/c/src/csm_tcp_router_client.c - SDK/c/examples/basic_usage.c - SDK/c/examples/subscribe_status.c - SDK/c/tests/test_harness.h - SDK/c/tests/mock_server.h - SDK/c/tests/mock_server.c - SDK/c/tests/test_main.c - SDK/c/tests/test_client.c - SDK/c/tests/test_protocol.c - SDK/c/tests/test_integration.c Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * translate: convert all C# SDK comments from English to Chinese Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * translate: convert all Python SDK comments from English to Chinese Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * translate: convert all Python SDK comments from English to Chinese (partial) Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/097602f2-f319-49ea-84a2-3c8a30aa0915 Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Add interactive ClientConsole example to Python, C# and C SDKs (#43) * Add interactive ClientConsole example to Python, C# and C SDKs Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/ca3628f9-8283-448f-8789-d860c873c1dc Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * Validate port argument in Python and C# ClientConsole examples Agent-Logs-Url: https://github.com/NEVSTOP-LAB/CSM-TCP-Router-App/sessions/1a565ac6-daf6-4291-8c0c-b3444c37d8ba Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <8196752+nevstop@users.noreply.github.com> * update deps * 重命名example * backup code * mass compile to trigger build --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: nevstop <nevstop@NEVSTOP-LAB>
_errors.py– shared_parse_server_errorhelper (removes duplication betweenclient.pyandasync_client.py)_transport.py– close socket in exception path (fixes fd leak in retry loops)client.py– add_resp_lock/_cmd_resp_lockthreading locks to serialise concurrent waiters; fix docstring;disconnect()injects sentinels to unblock blocked threads; import from_errorsasync_client.py– add_resp_lock/_cmd_resp_lockasyncio locks;disconnect()injects sentinels; useinspect.isawaitablefor callback detection; import from_errorsCHANGELOG.md– fix duplicate### Addedblock; move 0.1.0 content into proper## [0.1.0]sectiontests/test_async_client.py– update_client_with_queues()andtest_send_when_not_connected_raisesto call_init_async_objects()so locks are also initialised