fix(websocket): make @websocket usable from the package name - #116
Merged
andrevanzuydam merged 4 commits intoAug 20, 2026
Merged
Conversation
`tina4_python.websocket` is two things at once: the RFC 6455 subpackage, and — to every reader of the docs — the route decorator that sits beside @get/@post in core.router. Python binds a submodule onto its parent package the moment the submodule is imported, so the name resolved to the module and the documented usage died at import time: from tina4_python import websocket @websocket("/ws") # TypeError: 'module' object is not callable async def chat(connection, event, data): ... taking the whole route file down with it. Reproduced on 3.13.105: type(tina4_python.websocket).__name__ == "module", callable() False. Note what does NOT work: re-exporting the decorator from tina4_python/__init__.py, alongside get/post/put/cached/template and the rest of the core surface, which is where a reader would expect the fix. Importing the subpackage rebinds the attribute over that re-export afterwards, so the failure would come and go with import order — worse than a consistent one. Making the module itself callable is the only change that keeps both public surfaces: `from tina4_python.websocket import WebSocketServer` still resolves, and `@websocket("/ws")` now reaches core.router.websocket. The router import is deferred to call time so the subpackage keeps no import-time dependency on core.router. tests/test_websocket_decorator_name.py covers both halves; its four decorator tests fail against the unfixed source, and the three module-surface tests guard the exports the change could have cost. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A re-export after first load is stable; it still turns `import tina4_python.websocket as ws` into a function. Guard sys.modules, forward *args/**kwargs, pin backplane. Co-Authored-By: Tina4 <82961293+tina4stack@users.noreply.github.com>
Co-Authored-By: Tina4 <82961293+tina4stack@users.noreply.github.com>
Co-Authored-By: Tina4 <82961293+tina4stack@users.noreply.github.com>
andrevanzuydam
added a commit
that referenced
this pull request
Aug 20, 2026
Bumps version + moves the @websocket changelog entry into its own 3.13.106 section (it had been filed under the already-released 3.13.105). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue:
from tina4_python import websocketimported the RFC 6455 module, not the route decorator.@websocket("/ws")then raisedTypeError: 'module' object is not callable. Auto-discovery logged one error and dropped every route from that line onward. The landing page and the WebSocket spec both teach this import.Fix: make
tina4_python.websocketa callable module that forwards tocore.router.websocket.from tina4_python.websocket import WebSocketServerstill works. A re-export was not used: it would makeimport tina4_python.websocket as wsreturn the function and breakws.WebSocketServer.mypy/pyright still flag
Module not callableon the package spelling; import fromcore.routerif that matters.