mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-15 14:03:02 +00:00
implement UserDict.get
behaves more like one would expect (same as try get-key, except: return default) without relying on cache presence or underlying key type (integer only)
This commit is contained in:
@@ -676,9 +676,10 @@ class BaseHandler(RequestHandler):
|
|||||||
raise ValueError("Username doesn't match! %s != %s" % (username, user.name))
|
raise ValueError("Username doesn't match! %s != %s" % (username, user.name))
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
new_user = username not in self.users
|
user = self.find_user(username)
|
||||||
user = self.user_from_username(username)
|
new_user = user is None
|
||||||
if new_user:
|
if new_user:
|
||||||
|
user = self.user_from_username(username)
|
||||||
await maybe_future(self.authenticator.add_user(user))
|
await maybe_future(self.authenticator.add_user(user))
|
||||||
# Only set `admin` if the authenticator returned an explicit value.
|
# Only set `admin` if the authenticator returned an explicit value.
|
||||||
if admin is not None and admin != user.admin:
|
if admin is not None and admin != user.admin:
|
||||||
|
22
jupyterhub/tests/test_user.py
Normal file
22
jupyterhub/tests/test_user.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from ..user import UserDict
|
||||||
|
from .utils import add_user
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("attr", ["self", "id", "name"])
|
||||||
|
async def test_userdict_get(db, attr):
|
||||||
|
u = add_user(db, name="rey", app=False)
|
||||||
|
userdict = UserDict(db_factory=lambda: db, settings={})
|
||||||
|
|
||||||
|
if attr == "self":
|
||||||
|
key = u
|
||||||
|
else:
|
||||||
|
key = getattr(u, attr)
|
||||||
|
|
||||||
|
# `in` checks cache only
|
||||||
|
assert key not in userdict
|
||||||
|
assert userdict.get(key)
|
||||||
|
assert userdict.get(key).id == u.id
|
||||||
|
# `in` should find it now
|
||||||
|
assert key in userdict
|
@@ -34,7 +34,23 @@ from .utils import url_path_join
|
|||||||
class UserDict(dict):
|
class UserDict(dict):
|
||||||
"""Like defaultdict, but for users
|
"""Like defaultdict, but for users
|
||||||
|
|
||||||
Getting by a user id OR an orm.User instance returns a User wrapper around the orm user.
|
Users can be retrieved by:
|
||||||
|
|
||||||
|
- integer database id
|
||||||
|
- orm.User object
|
||||||
|
- username str
|
||||||
|
|
||||||
|
A User wrapper object is always returned.
|
||||||
|
|
||||||
|
This dict contains at least all active users,
|
||||||
|
but not necessarily all users in the database.
|
||||||
|
|
||||||
|
Checking `key in userdict` returns whether
|
||||||
|
an item is already in the cache,
|
||||||
|
*not* whether it is in the database.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.2
|
||||||
|
``'username' in userdict`` pattern is now supported
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, db_factory, settings):
|
def __init__(self, db_factory, settings):
|
||||||
@@ -57,11 +73,28 @@ class UserDict(dict):
|
|||||||
return self[orm_user.id]
|
return self[orm_user.id]
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
|
"""key in userdict checks presence in the cache
|
||||||
|
|
||||||
|
it does not check if the user is in the database
|
||||||
|
"""
|
||||||
if isinstance(key, (User, orm.User)):
|
if isinstance(key, (User, orm.User)):
|
||||||
key = key.id
|
key = key.id
|
||||||
|
elif isinstance(key, str):
|
||||||
|
# username lookup, O(N)
|
||||||
|
for user in self.values():
|
||||||
|
if user.name == key:
|
||||||
|
key = user.id
|
||||||
|
break
|
||||||
return dict.__contains__(self, key)
|
return dict.__contains__(self, key)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
|
"""UserDict allows retrieval of user by any of:
|
||||||
|
|
||||||
|
- User object
|
||||||
|
- orm.User object
|
||||||
|
- username (str)
|
||||||
|
- orm.User.id int (actual key used in underlying dict)
|
||||||
|
"""
|
||||||
if isinstance(key, User):
|
if isinstance(key, User):
|
||||||
key = key.id
|
key = key.id
|
||||||
elif isinstance(key, str):
|
elif isinstance(key, str):
|
||||||
@@ -69,7 +102,7 @@ class UserDict(dict):
|
|||||||
if orm_user is None:
|
if orm_user is None:
|
||||||
raise KeyError("No such user: %s" % key)
|
raise KeyError("No such user: %s" % key)
|
||||||
else:
|
else:
|
||||||
key = orm_user
|
key = orm_user.id
|
||||||
if isinstance(key, orm.User):
|
if isinstance(key, orm.User):
|
||||||
# users[orm_user] returns User(orm_user)
|
# users[orm_user] returns User(orm_user)
|
||||||
orm_user = key
|
orm_user = key
|
||||||
@@ -92,6 +125,20 @@ class UserDict(dict):
|
|||||||
else:
|
else:
|
||||||
raise KeyError(repr(key))
|
raise KeyError(repr(key))
|
||||||
|
|
||||||
|
def get(self, key, default=None):
|
||||||
|
"""Retrieve a User object if it can be found, else default
|
||||||
|
|
||||||
|
Lookup can be by User object, id, or name
|
||||||
|
|
||||||
|
.. versionchanged:: 1.2
|
||||||
|
``get()`` accesses the database instead of just the cache by integer id,
|
||||||
|
so is equivalent to catching KeyErrors on attempted lookup.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self[key]
|
||||||
|
except KeyError:
|
||||||
|
return default
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
user = self[key]
|
user = self[key]
|
||||||
for orm_spawner in user.orm_user._orm_spawners:
|
for orm_spawner in user.orm_user._orm_spawners:
|
||||||
|
Reference in New Issue
Block a user