Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update typing for traitlets 5.13 #1350

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions jupyter_server/extension/application.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""An extension application."""
from __future__ import annotations

import logging
import re
import sys
Expand Down Expand Up @@ -158,19 +160,21 @@ class method. This method can be set as a entry_point in

@default("open_browser")
def _default_open_browser(self):
assert self.serverapp is not None
return self.serverapp.config["ServerApp"].get("open_browser", True)

@property
def config_file_paths(self):
"""Look on the same path as our parent for config files"""
# rely on parent serverapp, which should control all config loading
assert self.serverapp is not None
return self.serverapp.config_file_paths

# The extension name used to name the jupyter config
# file, jupyter_{name}_config.
# This should also match the jupyter subcommand used to launch
# this extension from the CLI, e.g. `jupyter {name}`.
name: t.Union[str, Unicode] = "ExtensionApp" # type:ignore[assignment]
name: str | Unicode = "ExtensionApp" # type:ignore[assignment]

@classmethod
def get_extension_package(cls):
Expand Down Expand Up @@ -206,7 +210,7 @@ def _default_url(self):
]

# A ServerApp is not defined yet, but will be initialized below.
serverapp = Any()
serverapp: ServerApp | None = Any() # type:ignore[assignment]

@default("serverapp")
def _default_serverapp(self):
Expand Down Expand Up @@ -242,6 +246,7 @@ def _default_log_format(self):
@default("static_url_prefix")
def _default_static_url_prefix(self):
static_url = f"static/{self.name}/"
assert self.serverapp is not None
return url_path_join(self.serverapp.base_url, static_url)

static_paths = List(
Expand All @@ -264,7 +269,9 @@ def _default_static_url_prefix(self):

settings = Dict(help=_i18n("""Settings that will passed to the server.""")).tag(config=True)

handlers = List(help=_i18n("""Handlers appended to the server.""")).tag(config=True)
handlers: List[tuple[t.Any, ...]] = List(
help=_i18n("""Handlers appended to the server.""")
).tag(config=True) # type:ignore[assignment]

def _config_file_name_default(self):
"""The default config file name."""
Expand Down Expand Up @@ -295,6 +302,7 @@ def _prepare_config(self):
def _prepare_settings(self):
"""Prepare the settings."""
# Make webapp settings accessible to initialize_settings method
assert self.serverapp is not None
webapp = self.serverapp.web_app
self.settings.update(**webapp.settings)

Expand All @@ -314,6 +322,7 @@ def _prepare_settings(self):

def _prepare_handlers(self):
"""Prepare the handlers."""
assert self.serverapp is not None
webapp = self.serverapp.web_app

# Get handlers defined by extension subclass.
Expand Down Expand Up @@ -352,7 +361,7 @@ def _prepare_handlers(self):
)
new_handlers.append(handler)

webapp.add_handlers(".*$", new_handlers)
webapp.add_handlers(".*$", new_handlers) # type:ignore[arg-type]

def _prepare_templates(self):
"""Add templates to web app settings if extension has templates."""
Expand All @@ -372,7 +381,7 @@ def _jupyter_server_config(self):
base_config["ServerApp"].update(self.serverapp_config)
return base_config

def _link_jupyter_server_extension(self, serverapp):
def _link_jupyter_server_extension(self, serverapp: ServerApp) -> None:
"""Link the ExtensionApp to an initialized ServerApp.

The ServerApp is stored as an attribute and config
Expand Down Expand Up @@ -436,6 +445,7 @@ def start(self):
"""
super().start()
# Start the server.
assert self.serverapp is not None
self.serverapp.start()

def current_activity(self):
Expand All @@ -447,6 +457,7 @@ async def stop_extension(self):

def stop(self):
"""Stop the underlying Jupyter server."""
assert self.serverapp is not None
self.serverapp.stop()
self.serverapp.clear_instance()

Expand Down
2 changes: 2 additions & 0 deletions jupyter_server/extension/manager.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""The extension manager."""
from __future__ import annotations

import importlib

from tornado.gen import multi
Expand Down
2 changes: 1 addition & 1 deletion jupyter_server/extension/serverextension.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ def list_server_extensions(self) -> None:
self.log.info(f" {name} {version} {GREEN_OK}")
except Exception as err:
exc_info = False
if int(self.log_level) <= logging.DEBUG:
if int(self.log_level) <= logging.DEBUG: # type:ignore[call-overload]
exc_info = True
self.log.warning(f" {RED_X} {err}", exc_info=exc_info)
# Add a blank line between paths.
Expand Down
4 changes: 2 additions & 2 deletions jupyter_server/gateway/gateway_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ def _gateway_retry_max_default(self):
)
gateway_token_renewer_class_env = "JUPYTER_GATEWAY_TOKEN_RENEWER_CLASS"
gateway_token_renewer_class = Type(
klass=GatewayTokenRenewerBase, # type:ignore[type-abstract]
klass=GatewayTokenRenewerBase,
config=True,
help="""The class to use for Gateway token renewal. (JUPYTER_GATEWAY_TOKEN_RENEWER_CLASS env var)""",
)
Expand Down Expand Up @@ -546,7 +546,7 @@ def __init__(self, **kwargs):
"""Initialize a gateway client."""
super().__init__(**kwargs)
self._connection_args = {} # initialized on first use
self.gateway_token_renewer = self.gateway_token_renewer_class(parent=self, log=self.log) # type:ignore[operator]
self.gateway_token_renewer = self.gateway_token_renewer_class(parent=self, log=self.log) # type:ignore[abstract]

# store of cookies with store time
self._cookies: ty.Dict[str, ty.Tuple[Morsel, datetime]] = {}
Expand Down
2 changes: 1 addition & 1 deletion jupyter_server/gateway/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ async def refresh_model(self, model=None):
# this kernel manager. The current kernel manager instance may not have
# a parent instance if, say, a server extension is using another application
# (e.g., papermill) that uses a KernelManager instance directly.
self.parent._kernel_connections[self.kernel_id] = int(model["connections"])
self.parent._kernel_connections[self.kernel_id] = int(model["connections"]) # type:ignore[index]

self.kernel = model
return model
Expand Down
16 changes: 8 additions & 8 deletions jupyter_server/serverapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,7 @@ def _deprecated_token(self, change: t.Any) -> None:
self._warn_deprecated_config(change, "IdentityProvider")

@default("token")
def _deprecated_token_access(self) -> None:
def _deprecated_token_access(self) -> str:
warnings.warn(
"ServerApp.token config is deprecated in jupyter-server 2.0. Use IdentityProvider.token",
DeprecationWarning,
Expand Down Expand Up @@ -1884,7 +1884,7 @@ def init_configurables(self) -> None:
self.gateway_config = GatewayClient.instance(parent=self)

if not issubclass(
self.kernel_manager_class, # type:ignore[arg-type]
self.kernel_manager_class,
AsyncMappingKernelManager,
):
warnings.warn(
Expand All @@ -1894,7 +1894,7 @@ def init_configurables(self) -> None:
)

if not issubclass(
self.contents_manager_class, # type:ignore[arg-type]
self.contents_manager_class,
AsyncContentsManager,
):
warnings.warn(
Expand Down Expand Up @@ -1925,8 +1925,8 @@ def init_configurables(self) -> None:
"because jupyter-client's version does not allow them (should be >8.3.0)."
)

self.kernel_manager = self.kernel_manager_class(**kwargs) # type:ignore[operator]
self.contents_manager = self.contents_manager_class( # type:ignore[operator]
self.kernel_manager = self.kernel_manager_class(**kwargs)
self.contents_manager = self.contents_manager_class(
parent=self,
log=self.log,
)
Expand Down Expand Up @@ -1968,11 +1968,11 @@ def init_configurables(self) -> None:
f"Ignoring deprecated config ServerApp.login_handler_class={self.login_handler_class}."
" Superseded by ServerApp.identity_provider_class={self.identity_provider_class}."
)
self.identity_provider = self.identity_provider_class(**identity_provider_kwargs) # type:ignore[operator]
self.identity_provider = self.identity_provider_class(**identity_provider_kwargs)

if self.identity_provider_class is LegacyIdentityProvider:
# legacy config stored the password in tornado_settings
self.tornado_settings["password"] = self.identity_provider.hashed_password
self.tornado_settings["password"] = self.identity_provider.hashed_password # type:ignore[attr-defined]
self.tornado_settings["token"] = self.identity_provider.token

if self._token_set:
Expand All @@ -1989,7 +1989,7 @@ def init_configurables(self) -> None:
# that means it has some config that should take higher priority than deprecated ServerApp.token
self.log.warning("Ignoring deprecated ServerApp.token config")

self.authorizer = self.authorizer_class( # type:ignore[operator]
self.authorizer = self.authorizer_class(
parent=self, log=self.log, identity_provider=self.identity_provider
)

Expand Down
7 changes: 5 additions & 2 deletions jupyter_server/services/contents/manager.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
"""A base class for contents managers."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations

import itertools
import json
import os
import re
import typing as t
import warnings
from fnmatch import fnmatch

Expand Down Expand Up @@ -259,8 +262,8 @@ def run_post_save_hook(self, model, os_path):
msg = "fUnexpected error while running post hook save: {e}"
raise HTTPError(500, msg) from None

_pre_save_hooks = List()
_post_save_hooks = List()
_pre_save_hooks: List[t.Any] = List()
_post_save_hooks: List[t.Any] = List()

def register_pre_save_hook(self, hook):
"""Register a pre save hook."""
Expand Down
13 changes: 7 additions & 6 deletions jupyter_server/services/kernels/connection/channels.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"""An implementation of a kernel connection."""
from __future__ import annotations

import asyncio
import json
import time
import typing as t
import weakref
from concurrent.futures import Future
from textwrap import dedent
from typing import Dict as Dict_t
from typing import MutableSet, cast

from jupyter_client import protocol_version as client_protocol_version
from tornado import gen, web
Expand Down Expand Up @@ -95,8 +96,8 @@ def write_message(self):
# class-level registry of open sessions
# allows checking for conflict on session-id,
# which is used as a zmq identity and must be unique.
_open_sessions: Dict_t[str, KernelWebsocketHandler] = {}
_open_sockets: MutableSet["ZMQChannelsWebsocketConnection"] = weakref.WeakSet()
_open_sessions: dict[str, KernelWebsocketHandler] = {}
_open_sockets: t.MutableSet[ZMQChannelsWebsocketConnection] = weakref.WeakSet()

_kernel_info_future: Future
_close_future: Future
Expand Down Expand Up @@ -127,7 +128,7 @@ def _default_close_future(self):
# Queue of (time stamp, byte count)
# Allows you to specify that the byte count should be lowered
# by a delta amount at some point in the future.
_iopub_window_byte_queue = List([])
_iopub_window_byte_queue: List[t.Any] = List([])

@classmethod
async def close_all(cls):
Expand Down Expand Up @@ -285,7 +286,7 @@ async def _register_session(self):
if (
self.kernel_id in self.multi_kernel_manager
): # only update open sessions if kernel is actively managed
self._open_sessions[self.session_key] = cast(
self._open_sessions[self.session_key] = t.cast(
KernelWebsocketHandler, self.websocket_handler
)

Expand Down
12 changes: 6 additions & 6 deletions jupyter_server/services/kernels/kernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations

import asyncio
import os
import pathlib
Expand All @@ -13,8 +15,6 @@
from collections import defaultdict
from datetime import datetime, timedelta
from functools import partial, wraps
from typing import Dict as DictType
from typing import Optional

from jupyter_client.ioloop.manager import AsyncIOLoopKernelManager
from jupyter_client.multikernelmanager import AsyncMultiKernelManager, MultiKernelManager
Expand Down Expand Up @@ -64,7 +64,7 @@ def _default_kernel_manager_class(self):

_kernel_connections = Dict()

_kernel_ports: DictType[str, t.List[int]] = Dict() # type: ignore[assignment]
_kernel_ports: dict[str, list[int]] = Dict() # type: ignore[assignment]

_culler_callback = None

Expand Down Expand Up @@ -206,7 +206,7 @@ async def _remove_kernel_when_ready(self, kernel_id, kernel_awaitable):
# TODO DEC 2022: Revise the type-ignore once the signatures have been changed upstream
# https://github.com/jupyter/jupyter_client/pull/905
async def _async_start_kernel( # type:ignore[override]
self, *, kernel_id: Optional[str] = None, path: Optional[ApiPath] = None, **kwargs: str
self, *, kernel_id: str | None = None, path: ApiPath | None = None, **kwargs: str
) -> str:
"""Start a kernel for a session and return its kernel_id.

Expand Down Expand Up @@ -797,12 +797,12 @@ class ServerKernelManager(AsyncIOLoopKernelManager):
# schema to register with this kernel manager's eventlogger.
# This trait should not be overridden.
@property
def core_event_schema_paths(self) -> t.List[pathlib.Path]:
def core_event_schema_paths(self) -> list[pathlib.Path]:
return [DEFAULT_EVENTS_SCHEMA_PATH / "kernel_actions" / "v1.yaml"]

# This trait is intended for subclasses to override and define
# custom event schemas.
extra_event_schema_paths = List(
extra_event_schema_paths: List[str] = List( # type:ignore[assignment]
default_value=[],
help="""
A list of pathlib.Path objects pointing at to register with
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ nowarn = "test -W default {args}"

[tool.hatch.envs.typing]
features = ["test"]
dependencies = [ "mypy~=1.6", "traitlets>=5.11.2", "jupyter_core>=5.3.2", "jupyter_client>=8.5"]
dependencies = [ "mypy~=1.6", "traitlets>=5.13", "jupyter_core>=5.5", "jupyter_client>=8.5"]
[tool.hatch.envs.typing.scripts]
test = "mypy --install-types --non-interactive {args:.}"

Expand Down
6 changes: 4 additions & 2 deletions tests/extension/mockextensions/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import os

from jupyter_events import EventLogger
Expand Down Expand Up @@ -44,7 +46,7 @@ def get(self):

class MockExtensionApp(ExtensionAppJinjaMixin, ExtensionApp):
name = "mockextension"
template_paths = List().tag(config=True)
template_paths: List[str] = List().tag(config=True) # type:ignore[assignment]
static_paths = [STATIC_PATH] # type:ignore[assignment]
mock_trait = Unicode("mock trait", config=True)
loaded = False
Expand All @@ -59,7 +61,7 @@ def initialize_settings(self):
# Only add this event if it hasn't already been added.
# Log the error if it fails, but don't crash the app.
try:
elogger: EventLogger = self.serverapp.event_logger
elogger: EventLogger = self.serverapp.event_logger # type:ignore[union-attr, assignment]
elogger.register_event_schema(EVENT_SCHEMA)
except SchemaRegistryException as err:
self.log.error(err)
Expand Down
6 changes: 3 additions & 3 deletions tests/services/kernels/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
from jupyter_server.services.kernels.websocket import KernelWebsocketHandler


async def test_websocket_connection(jp_serverapp):
app: ServerApp = jp_serverapp
kernel_id = await app.kernel_manager.start_kernel()
async def test_websocket_connection(jp_serverapp: ServerApp) -> None:
app = jp_serverapp
kernel_id = await app.kernel_manager.start_kernel() # type:ignore[has-type]
kernel = app.kernel_manager.get_kernel(kernel_id)
request = HTTPRequest("foo", "GET")
request.connection = MagicMock()
Expand Down
Loading