Skip to content

Commit 63463c4

Browse files
authored
Add typings to commonly used APIs (#1333)
1 parent 1ece796 commit 63463c4

File tree

31 files changed

+407
-323
lines changed

31 files changed

+407
-323
lines changed

examples/simple/simple_ext1/handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class ParameterHandler(ExtensionHandlerMixin, JupyterHandler):
3636

3737
def get(self, matched_part=None, *args, **kwargs):
3838
"""Handle a get with parameters."""
39-
var1 = self.get_argument("var1", default=None)
39+
var1 = self.get_argument("var1", default="")
4040
components = [x for x in self.request.path.split("/") if x]
4141
self.write("<h1>Hello Simple App 1 from Handler.</h1>")
4242
self.write(f"<p>matched_part: {url_escape(matched_part)}</p>")

examples/simple/simple_ext2/handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class ParameterHandler(ExtensionHandlerMixin, JupyterHandler):
99

1010
def get(self, matched_part=None, *args, **kwargs):
1111
"""Get a parameterized response."""
12-
var1 = self.get_argument("var1", default=None)
12+
var1 = self.get_argument("var1", default="")
1313
components = [x for x in self.request.path.split("/") if x]
1414
self.write("<h1>Hello Simple App 2 from Handler.</h1>")
1515
self.write(f"<p>matched_part: {url_escape(matched_part)}</p>")

jupyter_server/_tz.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"""
66
# Copyright (c) Jupyter Development Team.
77
# Distributed under the terms of the Modified BSD License.
8+
from __future__ import annotations
9+
810
from datetime import datetime, timedelta, tzinfo
11+
from typing import Callable
912

1013
# constant for zero offset
1114
ZERO = timedelta(0)
@@ -14,19 +17,19 @@
1417
class tzUTC(tzinfo): # noqa
1518
"""tzinfo object for UTC (zero offset)"""
1619

17-
def utcoffset(self, d):
20+
def utcoffset(self, d: datetime | None) -> timedelta:
1821
"""Compute utcoffset."""
1922
return ZERO
2023

21-
def dst(self, d):
24+
def dst(self, d: datetime | None) -> timedelta:
2225
"""Compute dst."""
2326
return ZERO
2427

2528

2629
UTC = tzUTC() # type:ignore[abstract]
2730

2831

29-
def utc_aware(unaware):
32+
def utc_aware(unaware: Callable[..., datetime]) -> Callable[..., datetime]:
3033
"""decorator for adding UTC tzinfo to datetime's utcfoo methods"""
3134

3235
def utc_method(*args, **kwargs):
@@ -40,7 +43,7 @@ def utc_method(*args, **kwargs):
4043
utcnow = utc_aware(datetime.utcnow)
4144

4245

43-
def isoformat(dt):
46+
def isoformat(dt: datetime) -> str:
4447
"""Return iso-formatted timestamp
4548
4649
Like .isoformat(), but uses Z for UTC instead of +00:00

jupyter_server/auth/decorator.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@
33
# Copyright (c) Jupyter Development Team.
44
# Distributed under the terms of the Modified BSD License.
55
from functools import wraps
6-
from typing import Callable, Optional, Union
6+
from typing import Any, Callable, Optional, TypeVar, Union, cast
77

88
from tornado.log import app_log
99
from tornado.web import HTTPError
1010

1111
from .utils import HTTP_METHOD_TO_AUTH_ACTION
1212

13+
FuncT = TypeVar("FuncT", bound=Callable[..., Any])
14+
1315

1416
def authorized(
15-
action: Optional[Union[str, Callable]] = None,
17+
action: Optional[Union[str, FuncT]] = None,
1618
resource: Optional[str] = None,
1719
message: Optional[str] = None,
18-
) -> Callable:
20+
) -> FuncT:
1921
"""A decorator for tornado.web.RequestHandler methods
2022
that verifies whether the current user is authorized
2123
to make the following request.
@@ -73,4 +75,4 @@ def inner(self, *args, **kwargs):
7375
# no-arguments `@authorized` decorator called
7476
return wrapper(method)
7577

76-
return wrapper
78+
return cast(FuncT, wrapper)

jupyter_server/auth/identity.py

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

3030
# circular imports for type checking
3131
if TYPE_CHECKING:
32-
from jupyter_server.base.handlers import JupyterHandler
32+
from jupyter_server.base.handlers import AuthenticatedHandler, JupyterHandler
3333
from jupyter_server.serverapp import ServerApp
3434

3535
_non_alphanum = re.compile(r"[^A-Za-z0-9]")
@@ -321,7 +321,7 @@ def user_from_cookie(self, cookie_value: str) -> User | None:
321321
user["color"],
322322
)
323323

324-
def get_cookie_name(self, handler: JupyterHandler) -> str:
324+
def get_cookie_name(self, handler: AuthenticatedHandler) -> str:
325325
"""Return the login cookie name
326326
327327
Uses IdentityProvider.cookie_name, if defined.
@@ -333,7 +333,7 @@ def get_cookie_name(self, handler: JupyterHandler) -> str:
333333
else:
334334
return _non_alphanum.sub("-", f"username-{handler.request.host}")
335335

336-
def set_login_cookie(self, handler: JupyterHandler, user: User) -> None:
336+
def set_login_cookie(self, handler: AuthenticatedHandler, user: User) -> None:
337337
"""Call this on handlers to set the login cookie for success"""
338338
cookie_options = {}
339339
cookie_options.update(self.cookie_options)
@@ -350,7 +350,7 @@ def set_login_cookie(self, handler: JupyterHandler, user: User) -> None:
350350
handler.set_secure_cookie(cookie_name, self.user_to_cookie(user), **cookie_options)
351351

352352
def _force_clear_cookie(
353-
self, handler: JupyterHandler, name: str, path: str = "/", domain: str | None = None
353+
self, handler: AuthenticatedHandler, name: str, path: str = "/", domain: str | None = None
354354
) -> None:
355355
"""Deletes the cookie with the given name.
356356
@@ -376,7 +376,7 @@ def _force_clear_cookie(
376376
morsel["domain"] = domain
377377
handler.add_header("Set-Cookie", morsel.OutputString())
378378

379-
def clear_login_cookie(self, handler: JupyterHandler) -> None:
379+
def clear_login_cookie(self, handler: AuthenticatedHandler) -> None:
380380
"""Clear the login cookie, effectively logging out the session."""
381381
cookie_options = {}
382382
cookie_options.update(self.cookie_options)
@@ -478,7 +478,7 @@ def generate_anonymous_user(self, handler: JupyterHandler) -> User:
478478
handler.log.debug(f"Generating new user for token-authenticated request: {user_id}")
479479
return User(user_id, name, display_name, initials, None, color)
480480

481-
def should_check_origin(self, handler: JupyterHandler) -> bool:
481+
def should_check_origin(self, handler: AuthenticatedHandler) -> bool:
482482
"""Should the Handler check for CORS origin validation?
483483
484484
Origin check should be skipped for token-authenticated requests.
@@ -489,7 +489,7 @@ def should_check_origin(self, handler: JupyterHandler) -> bool:
489489
"""
490490
return not self.is_token_authenticated(handler)
491491

492-
def is_token_authenticated(self, handler: JupyterHandler) -> bool:
492+
def is_token_authenticated(self, handler: AuthenticatedHandler) -> bool:
493493
"""Returns True if handler has been token authenticated. Otherwise, False.
494494
495495
Login with a token is used to signal certain things, such as:
@@ -713,11 +713,11 @@ def login_available(self):
713713
self.settings
714714
)
715715

716-
def should_check_origin(self, handler: JupyterHandler) -> bool:
716+
def should_check_origin(self, handler: AuthenticatedHandler) -> bool:
717717
"""Whether we should check origin."""
718718
return self.login_handler_class.should_check_origin(handler) # type:ignore[attr-defined]
719719

720-
def is_token_authenticated(self, handler: JupyterHandler) -> bool:
720+
def is_token_authenticated(self, handler: AuthenticatedHandler) -> bool:
721721
"""Whether we are token authenticated."""
722722
return self.login_handler_class.is_token_authenticated(handler) # type:ignore[attr-defined]
723723

jupyter_server/auth/login.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,10 @@ def post(self):
123123
if new_password and getattr(self.identity_provider, "allow_password_change", False):
124124
config_dir = self.settings.get("config_dir", "")
125125
config_file = os.path.join(config_dir, "jupyter_server_config.json")
126-
self.identity_provider.hashed_password = self.settings[
127-
"password"
128-
] = set_password(new_password, config_file=config_file)
126+
if hasattr(self.identity_provider, "hashed_password"):
127+
self.identity_provider.hashed_password = self.settings[
128+
"password"
129+
] = set_password(new_password, config_file=config_file)
129130
self.log.info("Wrote hashed password to %s" % config_file)
130131
else:
131132
self.set_status(401)

0 commit comments

Comments
 (0)