Skip to content

Commit a7af554

Browse files
Force analysis of pycrdt_websocket imports, fix types (#476)
* Force analysis of `pycrdt_websocket` imports * Add `pycrdt-websocket` to mypy deps? * Upgrade mypy to latest (1.14.0 required for `follow_untyped_imports`) * Try without overides * Fix a number of typing issues * More fixes * More fixes * Fix partial issue * Fix type of `ystore_class` Co-authored-by: David Brochart <[email protected]> --------- Co-authored-by: David Brochart <[email protected]>
1 parent 5a75e2c commit a7af554

File tree

6 files changed

+31
-22
lines changed

6 files changed

+31
-22
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ repos:
3939
stages: [manual]
4040

4141
- repo: https://github.com/pre-commit/mirrors-mypy
42-
rev: v0.991
42+
rev: v1.15.0
4343
hooks:
4444
- id: mypy
4545
exclude: "(^binder/jupyter_config\\.py$)|(^scripts/bump_version\\.py$)|(/setup\\.py$)"
4646
args: ["--config-file", "pyproject.toml"]
47-
additional_dependencies: [tornado, pytest]
47+
additional_dependencies: [tornado, pytest, pycrdt-websocket]
4848
stages: [manual]
4949

5050
- repo: https://github.com/sirosen/check-jsonschema

projects/jupyter-server-ydoc/jupyter_server_ydoc/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def initialize_handlers(self):
105105
page_config.setdefault("serverSideExecution", self.server_side_execution)
106106

107107
# Set configurable parameters to YStore class
108-
ystore_class = partial(self.ystore_class, config=self.config)
108+
ystore_class: type[BaseYStore] = partial(self.ystore_class, config=self.config) # type:ignore[assignment]
109109

110110
self.ywebsocket_server = JupyterWebsocketServer(
111111
rooms_ready=False,
@@ -205,7 +205,7 @@ async def get_document(
205205
if copy:
206206
update = room.ydoc.get_update()
207207

208-
fork_ydoc = Doc()
208+
fork_ydoc: Doc = Doc()
209209
fork_ydoc.apply_update(update)
210210

211211
return YDOCS.get(room.file_type, YDOCS["file"])(fork_ydoc)

projects/jupyter-server-ydoc/jupyter_server_ydoc/handlers.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
import json
88
import uuid
99
from logging import Logger
10-
from typing import Any, Literal
10+
from typing import Any
1111
from uuid import uuid4
1212

1313
from jupyter_server.auth import authorized
1414
from jupyter_server.base.handlers import APIHandler, JupyterHandler
1515
from jupyter_server.utils import ensure_async
1616
from jupyter_ydoc import ydocs as YDOCS
1717
from pycrdt import Doc, UndoManager
18-
from pycrdt_websocket.websocket_server import YRoom
18+
from pycrdt_websocket.yroom import YRoom
1919
from pycrdt_websocket.ystore import BaseYStore
2020
from tornado import web
2121
from tornado.websocket import WebSocketHandler
@@ -115,7 +115,10 @@ def exception_logger(exception: Exception, log: Logger) -> bool:
115115

116116
file = self._file_loaders[file_id]
117117
updates_file_path = f".{file_type}:{file_id}.y"
118-
ystore = self._ystore_class(path=updates_file_path, log=self.log)
118+
ystore = self._ystore_class(
119+
path=updates_file_path,
120+
log=self.log, # type:ignore[call-arg]
121+
)
119122
self.room = DocumentRoom(
120123
self._room_id,
121124
file_format,
@@ -180,7 +183,7 @@ def initialize(
180183
self._websocket_server = ywebsocket_server
181184
self._message_queue = asyncio.Queue()
182185
self._room_id = ""
183-
self.room = None
186+
self.room = None # type:ignore
184187

185188
@property
186189
def path(self):
@@ -217,7 +220,7 @@ async def get(self, *args, **kwargs):
217220
raise web.HTTPError(403)
218221
return await super().get(*args, **kwargs)
219222

220-
async def open(self, room_id):
223+
async def open(self, room_id: str) -> None: # type:ignore[override]
221224
"""
222225
On connection open.
223226
"""
@@ -362,9 +365,7 @@ async def _clean_room(self) -> None:
362365
self._emit(LogLevel.INFO, "clean", "Loader deleted.")
363366
del self._room_locks[self._room_id]
364367

365-
def _on_global_awareness_event(
366-
self, topic: Literal["change", "update"], changes: tuple[dict[str, Any], Any]
367-
) -> None:
368+
def _on_global_awareness_event(self, topic: str, changes: tuple[dict[str, Any], Any]) -> None:
368369
"""
369370
Update the users when the global awareness changes.
370371
@@ -465,7 +466,7 @@ async def get(self, path: str) -> None:
465466
try:
466467
room_id = room_id_from_encoded_path(encoded_path)
467468
room: YRoom = await self.ywebsocket_server.get_room(room_id)
468-
fork_ydoc = Doc()
469+
fork_ydoc: Doc = Doc()
469470

470471
ydoc_factory = YDOCS.get(content_type)
471472
if ydoc_factory is None:
@@ -481,7 +482,9 @@ async def get(self, path: str) -> None:
481482
FORK_DOCUMENTS[idx] = ydoc_factory(fork_ydoc)
482483
undo_manager: UndoManager = FORK_DOCUMENTS[idx].undo_manager
483484

484-
updates_and_timestamps = [(item[0], item[-1]) async for item in room.ystore.read()]
485+
ystore = room.ystore
486+
assert ystore
487+
updates_and_timestamps = [(item[0], item[-1]) async for item in ystore.read()]
485488

486489
result_timestamps = []
487490

@@ -625,7 +628,7 @@ async def put(self, root_roomid):
625628
return self.finish({"code": 404, "error": "Root room not found"})
626629

627630
update = root_room.ydoc.get_update()
628-
fork_ydoc = Doc()
631+
fork_ydoc: Doc = Doc()
629632
fork_ydoc.apply_update(update)
630633
model = self.get_json_body()
631634
synchronize = model.get("synchronize", False)

projects/jupyter-server-ydoc/jupyter_server_ydoc/pytest_plugin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,12 @@ def _on_document_change(target: str, e: Any) -> None:
240240

241241
def rtc_create_SQLite_store_factory(jp_serverapp):
242242
async def _inner(type: str, path: str, content: str) -> DocumentRoom:
243-
db = SQLiteYStore(path=f"{type}:{path}", config=jp_serverapp.config)
243+
db = SQLiteYStore(
244+
path=f"{type}:{path}",
245+
# `SQLiteYStore` here is a subclass of booth `LoggingConfigurable`
246+
# and `pycrdt_websocket.ystore.SQLiteYStore`, but mypy gets lost:
247+
config=jp_serverapp.config, # type:ignore[call-arg]
248+
)
244249
_ = create_task(db.start())
245250
await db.started.wait()
246251

projects/jupyter-server-ydoc/jupyter_server_ydoc/rooms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from jupyter_events import EventLogger
1111
from jupyter_ydoc import ydocs as YDOCS
12-
from pycrdt_websocket.websocket_server import YRoom
12+
from pycrdt_websocket.yroom import YRoom
1313
from pycrdt_websocket.ystore import BaseYStore, YDocNotFound
1414

1515
from .loaders import FileLoader
@@ -103,7 +103,7 @@ async def initialize(self) -> None:
103103
It is important to set the ready property in the parent class (`self.ready = True`),
104104
this setter will subscribe for updates on the shared document.
105105
"""
106-
if self.ready: # type: ignore[has-type]
106+
if self.ready:
107107
return
108108

109109
self.log.info("Initializing room %s", self._room_id)

projects/jupyter-server-ydoc/jupyter_server_ydoc/websocketserver.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
from logging import Logger
88
from typing import Any, Callable
99

10-
from pycrdt_websocket.websocket_server import WebsocketServer, YRoom
10+
from pycrdt_websocket.websocket import Websocket
11+
from pycrdt_websocket.websocket_server import WebsocketServer
12+
from pycrdt_websocket.yroom import YRoom
1113
from pycrdt_websocket.ystore import BaseYStore
12-
from tornado.websocket import WebSocketHandler
1314

1415

1516
class RoomNotFound(LookupError):
@@ -38,7 +39,7 @@ class JupyterWebsocketServer(WebsocketServer):
3839

3940
def __init__(
4041
self,
41-
ystore_class: BaseYStore,
42+
ystore_class: type[BaseYStore],
4243
rooms_ready: bool = True,
4344
auto_clean_rooms: bool = True,
4445
exception_handler: Callable[[Exception, Logger], bool] | None = None,
@@ -132,7 +133,7 @@ async def get_room(self, path: str) -> YRoom:
132133
await self.start_room(room)
133134
return room
134135

135-
async def serve(self, websocket: WebSocketHandler) -> None:
136+
async def serve(self, websocket: Websocket) -> None:
136137
# start monitoring here as the event loop is not yet available when initializing the object
137138
if self.monitor_task is None:
138139
self.monitor_task = asyncio.create_task(self._monitor())

0 commit comments

Comments
 (0)