apply ruff fixes for UP031

This commit is contained in:
Min RK
2024-05-07 11:33:59 +02:00
parent 6051dc9fa7
commit 5636472ebf
37 changed files with 130 additions and 136 deletions

View File

@@ -7,5 +7,5 @@ import httpx
def get_client(): def get_client():
base_url = os.environ["JUPYTERHUB_API_URL"] base_url = os.environ["JUPYTERHUB_API_URL"]
token = os.environ["JUPYTERHUB_API_TOKEN"] token = os.environ["JUPYTERHUB_API_TOKEN"]
headers = {"Authorization": "Bearer %s" % token} headers = {"Authorization": f"Bearer {token}"}
return httpx.AsyncClient(base_url=base_url, headers=headers) return httpx.AsyncClient(base_url=base_url, headers=headers)

View File

@@ -38,7 +38,7 @@ def authenticated(f):
else: else:
# redirect to login url on failed auth # redirect to login url on failed auth
state = auth.generate_state(next_url=request.path) state = auth.generate_state(next_url=request.path)
response = make_response(redirect(auth.login_url + '&state=%s' % state)) response = make_response(redirect(auth.login_url + f'&state={state}'))
response.set_cookie(auth.state_cookie_name, state) response.set_cookie(auth.state_cookie_name, state)
return response return response

View File

@@ -11,7 +11,7 @@ c = get_config() # noqa
class DemoFormSpawner(LocalProcessSpawner): class DemoFormSpawner(LocalProcessSpawner):
def _options_form_default(self): def _options_form_default(self):
default_env = "YOURNAME=%s\n" % self.user.name default_env = f"YOURNAME={self.user.name}\n"
return f""" return f"""
<div class="form-group"> <div class="form-group">
<label for="args">Extra notebook CLI arguments</label> <label for="args">Extra notebook CLI arguments</label>

View File

@@ -70,6 +70,4 @@ def _check_version(hub_version, singleuser_version, log):
singleuser_version, singleuser_version,
) )
else: else:
log.debug( log.debug(f"jupyterhub and jupyterhub-singleuser both on version {hub_version}")
"jupyterhub and jupyterhub-singleuser both on version %s" % hub_version
)

View File

@@ -46,7 +46,7 @@ class TokenAPIHandler(APIHandler):
elif orm_token.service: elif orm_token.service:
model = self.service_model(orm_token.service) model = self.service_model(orm_token.service)
else: else:
self.log.warning("%s has no user or service. Deleting..." % orm_token) self.log.warning(f"{orm_token} has no user or service. Deleting...")
self.db.delete(orm_token) self.db.delete(orm_token)
self.db.commit() self.db.commit()
raise web.HTTPError(404) raise web.HTTPError(404)

View File

@@ -461,9 +461,9 @@ class APIHandler(BaseHandler):
name (str): name of the model, used in error messages name (str): name of the model, used in error messages
""" """
if not isinstance(model, dict): if not isinstance(model, dict):
raise web.HTTPError(400, "Invalid JSON data: %r" % model) raise web.HTTPError(400, f"Invalid JSON data: {model!r}")
if not set(model).issubset(set(model_types)): if not set(model).issubset(set(model_types)):
raise web.HTTPError(400, "Invalid JSON keys: %r" % model) raise web.HTTPError(400, f"Invalid JSON keys: {model!r}")
for key, value in model.items(): for key, value in model.items():
if not isinstance(value, model_types[key]): if not isinstance(value, model_types[key]):
raise web.HTTPError( raise web.HTTPError(

View File

@@ -19,7 +19,7 @@ class _GroupAPIHandler(APIHandler):
username = self.authenticator.normalize_username(username) username = self.authenticator.normalize_username(username)
user = self.find_user(username) user = self.find_user(username)
if user is None: if user is None:
raise web.HTTPError(400, "No such user: %s" % username) raise web.HTTPError(400, f"No such user: {username}")
users.append(user.orm_user) users.append(user.orm_user)
return users return users
@@ -87,7 +87,7 @@ class GroupListAPIHandler(_GroupAPIHandler):
for name in groupnames: for name in groupnames:
existing = orm.Group.find(self.db, name=name) existing = orm.Group.find(self.db, name=name)
if existing is not None: if existing is not None:
raise web.HTTPError(409, "Group %s already exists" % name) raise web.HTTPError(409, f"Group {name} already exists")
usernames = model.get('users', []) usernames = model.get('users', [])
# check that users exist # check that users exist
@@ -124,7 +124,7 @@ class GroupAPIHandler(_GroupAPIHandler):
existing = orm.Group.find(self.db, name=group_name) existing = orm.Group.find(self.db, name=group_name)
if existing is not None: if existing is not None:
raise web.HTTPError(409, "Group %s already exists" % group_name) raise web.HTTPError(409, f"Group {group_name} already exists")
usernames = model.get('users', []) usernames = model.get('users', [])
# check that users exist # check that users exist

View File

@@ -32,14 +32,14 @@ class ShutdownAPIHandler(APIHandler):
proxy = data['proxy'] proxy = data['proxy']
if proxy not in {True, False}: if proxy not in {True, False}:
raise web.HTTPError( raise web.HTTPError(
400, "proxy must be true or false, got %r" % proxy 400, f"proxy must be true or false, got {proxy!r}"
) )
app.cleanup_proxy = proxy app.cleanup_proxy = proxy
if 'servers' in data: if 'servers' in data:
servers = data['servers'] servers = data['servers']
if servers not in {True, False}: if servers not in {True, False}:
raise web.HTTPError( raise web.HTTPError(
400, "servers must be true or false, got %r" % servers 400, f"servers must be true or false, got {servers!r}"
) )
app.cleanup_servers = servers app.cleanup_servers = servers

View File

@@ -161,7 +161,7 @@ class UserListAPIHandler(APIHandler):
.having(func.count(orm.Server.id) == 0) .having(func.count(orm.Server.id) == 0)
) )
elif state_filter: elif state_filter:
raise web.HTTPError(400, "Unrecognized state filter: %r" % state_filter) raise web.HTTPError(400, f"Unrecognized state filter: {state_filter!r}")
# apply eager load options # apply eager load options
query = query.options( query = query.options(
@@ -246,15 +246,15 @@ class UserListAPIHandler(APIHandler):
continue continue
user = self.find_user(name) user = self.find_user(name)
if user is not None: if user is not None:
self.log.warning("User %s already exists" % name) self.log.warning(f"User {name} already exists")
else: else:
to_create.append(name) to_create.append(name)
if invalid_names: if invalid_names:
if len(invalid_names) == 1: if len(invalid_names) == 1:
msg = "Invalid username: %s" % invalid_names[0] msg = f"Invalid username: {invalid_names[0]}"
else: else:
msg = "Invalid usernames: %s" % ', '.join(invalid_names) msg = "Invalid usernames: {}".format(', '.join(invalid_names))
raise web.HTTPError(400, msg) raise web.HTTPError(400, msg)
if not to_create: if not to_create:
@@ -270,7 +270,7 @@ class UserListAPIHandler(APIHandler):
try: try:
await maybe_future(self.authenticator.add_user(user)) await maybe_future(self.authenticator.add_user(user))
except Exception as e: except Exception as e:
self.log.error("Failed to create user: %s" % name, exc_info=True) self.log.error(f"Failed to create user: {name}", exc_info=True)
self.users.delete(user) self.users.delete(user)
raise web.HTTPError(400, f"Failed to create user {name}: {e}") raise web.HTTPError(400, f"Failed to create user {name}: {e}")
else: else:
@@ -307,7 +307,7 @@ class UserAPIHandler(APIHandler):
data = self.get_json_body() data = self.get_json_body()
user = self.find_user(user_name) user = self.find_user(user_name)
if user is not None: if user is not None:
raise web.HTTPError(409, "User %s already exists" % user_name) raise web.HTTPError(409, f"User {user_name} already exists")
user = self.user_from_username(user_name) user = self.user_from_username(user_name)
if data: if data:
@@ -320,10 +320,10 @@ class UserAPIHandler(APIHandler):
try: try:
await maybe_future(self.authenticator.add_user(user)) await maybe_future(self.authenticator.add_user(user))
except Exception: except Exception:
self.log.error("Failed to create user: %s" % user_name, exc_info=True) self.log.error(f"Failed to create user: {user_name}", exc_info=True)
# remove from registry # remove from registry
self.users.delete(user) self.users.delete(user)
raise web.HTTPError(400, "Failed to create user: %s" % user_name) raise web.HTTPError(400, f"Failed to create user: {user_name}")
self.write(json.dumps(self.user_model(user))) self.write(json.dumps(self.user_model(user)))
self.set_status(201) self.set_status(201)
@@ -338,15 +338,14 @@ class UserAPIHandler(APIHandler):
if user.spawner._stop_pending: if user.spawner._stop_pending:
raise web.HTTPError( raise web.HTTPError(
400, 400,
"%s's server is in the process of stopping, please wait." % user_name, f"{user_name}'s server is in the process of stopping, please wait.",
) )
if user.running: if user.running:
await self.stop_single_user(user) await self.stop_single_user(user)
if user.spawner._stop_pending: if user.spawner._stop_pending:
raise web.HTTPError( raise web.HTTPError(
400, 400,
"%s's server is in the process of stopping, please wait." f"{user_name}'s server is in the process of stopping, please wait.",
% user_name,
) )
await maybe_future(self.authenticator.delete_user(user)) await maybe_future(self.authenticator.delete_user(user))
@@ -370,7 +369,9 @@ class UserAPIHandler(APIHandler):
if self.find_user(data['name']): if self.find_user(data['name']):
raise web.HTTPError( raise web.HTTPError(
400, 400,
"User %s already exists, username must be unique" % data['name'], "User {} already exists, username must be unique".format(
data['name']
),
) )
for key, value in data.items(): for key, value in data.items():
if key == 'auth_state': if key == 'auth_state':
@@ -402,7 +403,7 @@ class UserTokenListAPIHandler(APIHandler):
"""Get tokens for a given user""" """Get tokens for a given user"""
user = self.find_user(user_name) user = self.find_user(user_name)
if not user: if not user:
raise web.HTTPError(404, "No such user: %s" % user_name) raise web.HTTPError(404, f"No such user: {user_name}")
now = utcnow(with_tz=False) now = utcnow(with_tz=False)
api_tokens = [] api_tokens = []
@@ -624,7 +625,7 @@ class UserServerAPIHandler(APIHandler):
finally: finally:
spawner._spawn_pending = False spawner._spawn_pending = False
if state is None: if state is None:
raise web.HTTPError(400, "%s is already running" % spawner._log_name) raise web.HTTPError(400, f"{spawner._log_name} is already running")
options = self.get_json_body() options = self.get_json_body()
await self.spawn_single_user(user, server_name, options=options) await self.spawn_single_user(user, server_name, options=options)

View File

@@ -213,7 +213,7 @@ class NewToken(Application):
ThreadPoolExecutor(1).submit(init_roles_and_users).result() ThreadPoolExecutor(1).submit(init_roles_and_users).result()
user = orm.User.find(hub.db, self.name) user = orm.User.find(hub.db, self.name)
if user is None: if user is None:
print("No such user: %s" % self.name, file=sys.stderr) print(f"No such user: {self.name}", file=sys.stderr)
self.exit(1) self.exit(1)
token = user.new_api_token(note="command-line generated") token = user.new_api_token(note="command-line generated")
print(token) print(token)
@@ -1475,7 +1475,7 @@ class JupyterHub(Application):
new = change['new'] new = change['new']
if '://' not in new: if '://' not in new:
# assume sqlite, if given as a plain filename # assume sqlite, if given as a plain filename
self.db_url = 'sqlite:///%s' % new self.db_url = f'sqlite:///{new}'
db_kwargs = Dict( db_kwargs = Dict(
help="""Include any kwargs to pass to the database connection. help="""Include any kwargs to pass to the database connection.
@@ -1778,10 +1778,10 @@ class JupyterHub(Application):
[ [
# add trailing / to ``/user|services/:name` # add trailing / to ``/user|services/:name`
( (
r"%s(user|services)/([^/]+)" % self.base_url, rf"{self.base_url}(user|services)/([^/]+)",
handlers.AddSlashHandler, handlers.AddSlashHandler,
), ),
(r"(?!%s).*" % self.hub_prefix, handlers.PrefixRedirectHandler), (rf"(?!{self.hub_prefix}).*", handlers.PrefixRedirectHandler),
(r'(.*)', handlers.Template404), (r'(.*)', handlers.Template404),
] ]
) )
@@ -1910,7 +1910,7 @@ class JupyterHub(Application):
default_alt_names = ["IP:127.0.0.1", "DNS:localhost"] default_alt_names = ["IP:127.0.0.1", "DNS:localhost"]
if self.subdomain_host: if self.subdomain_host:
default_alt_names.append( default_alt_names.append(
"DNS:%s" % urlparse(self.subdomain_host).hostname f"DNS:{urlparse(self.subdomain_host).hostname}"
) )
# The signed certs used by hub-internal components # The signed certs used by hub-internal components
try: try:
@@ -2095,7 +2095,7 @@ class JupyterHub(Application):
ck.check_available() ck.check_available()
except Exception as e: except Exception as e:
self.exit( self.exit(
"auth_state is enabled, but encryption is not available: %s" % e f"auth_state is enabled, but encryption is not available: {e}"
) )
# give the authenticator a chance to check its own config # give the authenticator a chance to check its own config
@@ -2114,7 +2114,7 @@ class JupyterHub(Application):
self.authenticator.admin_users = set(admin_users) # force normalization self.authenticator.admin_users = set(admin_users) # force normalization
for username in admin_users: for username in admin_users:
if not self.authenticator.validate_username(username): if not self.authenticator.validate_username(username):
raise ValueError("username %r is not valid" % username) raise ValueError(f"username {username!r} is not valid")
new_users = [] new_users = []
@@ -2138,7 +2138,7 @@ class JupyterHub(Application):
self.authenticator.allowed_users = set(allowed_users) # force normalization self.authenticator.allowed_users = set(allowed_users) # force normalization
for username in allowed_users: for username in allowed_users:
if not self.authenticator.validate_username(username): if not self.authenticator.validate_username(username):
raise ValueError("username %r is not valid" % username) raise ValueError(f"username {username!r} is not valid")
if self.authenticator.allowed_users and self.authenticator.admin_users: if self.authenticator.allowed_users and self.authenticator.admin_users:
# make sure admin users are in the allowed_users set, if defined, # make sure admin users are in the allowed_users set, if defined,
@@ -2206,7 +2206,7 @@ class JupyterHub(Application):
user = orm.User.find(self.db, name=username) user = orm.User.find(self.db, name=username)
if user is None: if user is None:
if not self.authenticator.validate_username(username): if not self.authenticator.validate_username(username):
raise ValueError("Username %r is not valid" % username) raise ValueError(f"Username {username!r} is not valid")
self.log.info(f"Creating user {username} found in {hint}") self.log.info(f"Creating user {username} found in {hint}")
user = orm.User(name=username) user = orm.User(name=username)
self.db.add(user) self.db.add(user)
@@ -2317,9 +2317,7 @@ class JupyterHub(Application):
old_role = orm.Role.find(self.db, name=role_name) old_role = orm.Role.find(self.db, name=role_name)
if old_role: if old_role:
if not set(role_spec.get('scopes', [])).issubset(old_role.scopes): if not set(role_spec.get('scopes', [])).issubset(old_role.scopes):
self.log.warning( self.log.warning(f"Role {role_name} has obtained extra permissions")
"Role %s has obtained extra permissions" % role_name
)
roles_with_new_permissions.append(role_name) roles_with_new_permissions.append(role_name)
# make sure we load any default roles not overridden # make sure we load any default roles not overridden
@@ -2583,14 +2581,14 @@ class JupyterHub(Application):
elif kind == 'service': elif kind == 'service':
Class = orm.Service Class = orm.Service
else: else:
raise ValueError("kind must be user or service, not %r" % kind) raise ValueError(f"kind must be user or service, not {kind!r}")
db = self.db db = self.db
for token, name in token_dict.items(): for token, name in token_dict.items():
if kind == 'user': if kind == 'user':
name = self.authenticator.normalize_username(name) name = self.authenticator.normalize_username(name)
if not self.authenticator.validate_username(name): if not self.authenticator.validate_username(name):
raise ValueError("Token user name %r is not valid" % name) raise ValueError(f"Token user name {name!r} is not valid")
if kind == 'service': if kind == 'service':
if not any(service_name == name for service_name in self._service_map): if not any(service_name == name for service_name in self._service_map):
self.log.warning( self.log.warning(
@@ -2790,7 +2788,7 @@ class JupyterHub(Application):
for key, value in spec.items(): for key, value in spec.items():
trait = traits.get(key) trait = traits.get(key)
if trait is None: if trait is None:
raise AttributeError("No such service field: %s" % key) raise AttributeError(f"No such service field: {key}")
setattr(service, key, value) setattr(service, key, value)
# also set the value on the orm object # also set the value on the orm object
# unless it's marked as not in the db # unless it's marked as not in the db
@@ -2863,7 +2861,7 @@ class JupyterHub(Application):
client_id=service.oauth_client_id, client_id=service.oauth_client_id,
client_secret=service.api_token, client_secret=service.api_token,
redirect_uri=service.oauth_redirect_uri, redirect_uri=service.oauth_redirect_uri,
description="JupyterHub service %s" % service.name, description=f"JupyterHub service {service.name}",
) )
service.orm.oauth_client = oauth_client service.orm.oauth_client = oauth_client
# add access-scopes, derived from OAuthClient itself # add access-scopes, derived from OAuthClient itself
@@ -3456,7 +3454,7 @@ class JupyterHub(Application):
answer = '' answer = ''
def ask(): def ask():
prompt = "Overwrite %s with default config? [y/N]" % self.config_file prompt = f"Overwrite {self.config_file} with default config? [y/N]"
try: try:
return input(prompt).lower() or 'n' return input(prompt).lower() or 'n'
except KeyboardInterrupt: except KeyboardInterrupt:
@@ -3473,7 +3471,7 @@ class JupyterHub(Application):
config_text = self.generate_config_file() config_text = self.generate_config_file()
if isinstance(config_text, bytes): if isinstance(config_text, bytes):
config_text = config_text.decode('utf8') config_text = config_text.decode('utf8')
print("Writing default config to: %s" % self.config_file) print(f"Writing default config to: {self.config_file}")
with open(self.config_file, mode='w') as f: with open(self.config_file, mode='w') as f:
f.write(config_text) f.write(config_text)

View File

@@ -332,7 +332,7 @@ class Authenticator(LoggingConfigurable):
if short_names: if short_names:
sorted_names = sorted(short_names) sorted_names = sorted(short_names)
single = ''.join(sorted_names) single = ''.join(sorted_names)
string_set_typo = "set('%s')" % single string_set_typo = f"set('{single}')"
self.log.warning( self.log.warning(
"Allowed set contains single-character names: %s; did you mean set([%r]) instead of %s?", "Allowed set contains single-character names: %s; did you mean set([%r]) instead of %s?",
sorted_names[:8], sorted_names[:8],
@@ -663,7 +663,7 @@ class Authenticator(LoggingConfigurable):
return return
if isinstance(authenticated, dict): if isinstance(authenticated, dict):
if 'name' not in authenticated: if 'name' not in authenticated:
raise ValueError("user missing a name: %r" % authenticated) raise ValueError(f"user missing a name: {authenticated!r}")
else: else:
authenticated = {'name': authenticated} authenticated = {'name': authenticated}
authenticated.setdefault('auth_state', None) authenticated.setdefault('auth_state', None)
@@ -850,7 +850,7 @@ class Authenticator(LoggingConfigurable):
user (User): The User wrapper object user (User): The User wrapper object
""" """
if not self.validate_username(user.name): if not self.validate_username(user.name):
raise ValueError("Invalid username: %s" % user.name) raise ValueError(f"Invalid username: {user.name}")
if self.allow_existing_users and not self.allow_all: if self.allow_existing_users and not self.allow_all:
self.allowed_users.add(user.name) self.allowed_users.add(user.name)
@@ -1122,7 +1122,7 @@ class LocalAuthenticator(Authenticator):
try: try:
group = self._getgrnam(grnam) group = self._getgrnam(grnam)
except KeyError: except KeyError:
self.log.error('No such group: [%s]' % grnam) self.log.error(f'No such group: [{grnam}]')
continue continue
if group.gr_gid in user_group_gids: if group.gr_gid in user_group_gids:
return True return True
@@ -1193,7 +1193,7 @@ class LocalAuthenticator(Authenticator):
uid = self.uids[name] uid = self.uids[name]
cmd += ['--uid', '%d' % uid] cmd += ['--uid', '%d' % uid]
except KeyError: except KeyError:
self.log.debug("No UID for user %s" % name) self.log.debug(f"No UID for user {name}")
cmd += [name] cmd += [name]
self.log.info("Creating user: %s", ' '.join(map(shlex.quote, cmd))) self.log.info("Creating user: %s", ' '.join(map(shlex.quote, cmd)))
p = Popen(cmd, stdout=PIPE, stderr=STDOUT) p = Popen(cmd, stdout=PIPE, stderr=STDOUT)

View File

@@ -33,7 +33,7 @@ class CryptographyUnavailable(EncryptionUnavailable):
class NoEncryptionKeys(EncryptionUnavailable): class NoEncryptionKeys(EncryptionUnavailable):
def __str__(self): def __str__(self):
return "Encryption keys must be specified in %s env" % KEY_ENV return f"Encryption keys must be specified in {KEY_ENV} env"
def _validate_key(key): def _validate_key(key):

View File

@@ -95,7 +95,7 @@ def backup_db_file(db_file, log=None):
backup_db_file = f'{db_file}.{timestamp}.{i}' backup_db_file = f'{db_file}.{timestamp}.{i}'
# #
if os.path.exists(backup_db_file): if os.path.exists(backup_db_file):
raise OSError("backup db file already exists: %s" % backup_db_file) raise OSError(f"backup db file already exists: {backup_db_file}")
if log: if log:
log.info("Backing up %s => %s", db_file, backup_db_file) log.info("Backing up %s => %s", db_file, backup_db_file)
shutil.copy(db_file, backup_db_file) shutil.copy(db_file, backup_db_file)
@@ -167,7 +167,7 @@ def main(args=None):
# to subcommands # to subcommands
choices = ['shell', 'alembic'] choices = ['shell', 'alembic']
if not args or args[0] not in choices: if not args or args[0] not in choices:
print("Select a command from: %s" % ', '.join(choices)) print("Select a command from: {}".format(', '.join(choices)))
return 1 return 1
cmd, args = args[0], args[1:] cmd, args = args[0], args[1:]

View File

@@ -1512,7 +1512,7 @@ class BaseHandler(RequestHandler):
# so we run it sync here, instead of making a sync version of render_template # so we run it sync here, instead of making a sync version of render_template
try: try:
html = self.render_template('%s.html' % status_code, sync=True, **ns) html = self.render_template(f'{status_code}.html', sync=True, **ns)
except TemplateNotFound: except TemplateNotFound:
self.log.debug("Using default error template for %d", status_code) self.log.debug("Using default error template for %d", status_code)
try: try:

View File

@@ -236,12 +236,12 @@ class SpawnHandler(BaseHandler):
if for_user != user.name: if for_user != user.name:
user = self.find_user(for_user) user = self.find_user(for_user)
if user is None: if user is None:
raise web.HTTPError(404, "No such user: %s" % for_user) raise web.HTTPError(404, f"No such user: {for_user}")
spawner = user.get_spawner(server_name, replace_failed=True) spawner = user.get_spawner(server_name, replace_failed=True)
if spawner.ready: if spawner.ready:
raise web.HTTPError(400, "%s is already running" % (spawner._log_name)) raise web.HTTPError(400, f"{spawner._log_name} is already running")
elif spawner.pending: elif spawner.pending:
raise web.HTTPError( raise web.HTTPError(
400, f"{spawner._log_name} is pending {spawner.pending}" 400, f"{spawner._log_name} is pending {spawner.pending}"
@@ -251,7 +251,7 @@ class SpawnHandler(BaseHandler):
for key, byte_list in self.request.body_arguments.items(): for key, byte_list in self.request.body_arguments.items():
form_options[key] = [bs.decode('utf8') for bs in byte_list] form_options[key] = [bs.decode('utf8') for bs in byte_list]
for key, byte_list in self.request.files.items(): for key, byte_list in self.request.files.items():
form_options["%s_file" % key] = byte_list form_options[f"{key}_file"] = byte_list
try: try:
self.log.debug( self.log.debug(
"Triggering spawn with supplied form options for %s", spawner._log_name "Triggering spawn with supplied form options for %s", spawner._log_name
@@ -345,7 +345,7 @@ class SpawnPendingHandler(BaseHandler):
if for_user != current_user.name: if for_user != current_user.name:
user = self.find_user(for_user) user = self.find_user(for_user)
if user is None: if user is None:
raise web.HTTPError(404, "No such user: %s" % for_user) raise web.HTTPError(404, f"No such user: {for_user}")
if server_name and server_name not in user.spawners: if server_name and server_name not in user.spawners:
raise web.HTTPError(404, f"{user.name} has no such server {server_name}") raise web.HTTPError(404, f"{user.name} has no such server {server_name}")
@@ -642,7 +642,7 @@ class ProxyErrorHandler(BaseHandler):
message_html = ' '.join( message_html = ' '.join(
[ [
"Your server appears to be down.", "Your server appears to be down.",
"Try restarting it <a href='%s'>from the hub</a>" % hub_home, f"Try restarting it <a href='{hub_home}'>from the hub</a>",
] ]
) )
ns = dict( ns = dict(
@@ -655,7 +655,7 @@ class ProxyErrorHandler(BaseHandler):
self.set_header('Content-Type', 'text/html') self.set_header('Content-Type', 'text/html')
# render the template # render the template
try: try:
html = await self.render_template('%s.html' % status_code, **ns) html = await self.render_template(f'{status_code}.html', **ns)
except TemplateNotFound: except TemplateNotFound:
self.log.debug("Using default error template for %d", status_code) self.log.debug("Using default error template for %d", status_code)
html = await self.render_template('error.html', **ns) html = await self.render_template('error.html', **ns)

View File

@@ -156,7 +156,7 @@ class JupyterHubRequestValidator(RequestValidator):
self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first() self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first()
) )
if orm_client is None: if orm_client is None:
raise ValueError("No such client: %s" % client_id) raise ValueError(f"No such client: {client_id}")
scopes = set(orm_client.allowed_scopes) scopes = set(orm_client.allowed_scopes)
if 'inherit' not in scopes: if 'inherit' not in scopes:
# add identify-user scope # add identify-user scope
@@ -255,7 +255,7 @@ class JupyterHubRequestValidator(RequestValidator):
self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first() self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first()
) )
if orm_client is None: if orm_client is None:
raise ValueError("No such client: %s" % client_id) raise ValueError(f"No such client: {client_id}")
orm_code = orm.OAuthCode( orm_code = orm.OAuthCode(
code=code['code'], code=code['code'],
@@ -345,7 +345,7 @@ class JupyterHubRequestValidator(RequestValidator):
app_log.debug("Saving bearer token %s", log_token) app_log.debug("Saving bearer token %s", log_token)
if request.user is None: if request.user is None:
raise ValueError("No user for access token: %s" % request.user) raise ValueError(f"No user for access token: {request.user}")
client = ( client = (
self.db.query(orm.OAuthClient) self.db.query(orm.OAuthClient)
.filter_by(identifier=request.client.client_id) .filter_by(identifier=request.client.client_id)

View File

@@ -1113,7 +1113,7 @@ class APIToken(Hashed, Base):
elif kind == 'service': elif kind == 'service':
prefix_match = prefix_match.filter(cls.service_id != None) prefix_match = prefix_match.filter(cls.service_id != None)
elif kind is not None: elif kind is not None:
raise ValueError("kind must be 'user', 'service', or None, not %r" % kind) raise ValueError(f"kind must be 'user', 'service', or None, not {kind!r}")
for orm_token in prefix_match: for orm_token in prefix_match:
if orm_token.match(token): if orm_token.match(token):
if not orm_token.client_id: if not orm_token.client_id:

View File

@@ -221,11 +221,11 @@ class Proxy(LoggingConfigurable):
host_route = not routespec.startswith('/') host_route = not routespec.startswith('/')
if host_route and not self.host_routing: if host_route and not self.host_routing:
raise ValueError( raise ValueError(
"Cannot add host-based route %r, not using host-routing" % routespec f"Cannot add host-based route {routespec!r}, not using host-routing"
) )
if self.host_routing and not host_route: if self.host_routing and not host_route:
raise ValueError( raise ValueError(
"Cannot add route without host %r, using host-routing" % routespec f"Cannot add route without host {routespec!r}, using host-routing"
) )
# add trailing slash # add trailing slash
if not routespec.endswith('/'): if not routespec.endswith('/'):
@@ -613,8 +613,8 @@ class ConfigurableHTTPProxy(Proxy):
# check for required token if proxy is external # check for required token if proxy is external
if not self.auth_token and not self.should_start: if not self.auth_token and not self.should_start:
raise ValueError( raise ValueError(
"%s.auth_token or CONFIGPROXY_AUTH_TOKEN env is required" f"{self.__class__.__name__}.auth_token or CONFIGPROXY_AUTH_TOKEN env is required"
" if Proxy.should_start is False" % self.__class__.__name__ " if Proxy.should_start is False"
) )
def _check_previous_process(self): def _check_previous_process(self):
@@ -758,11 +758,11 @@ class ConfigurableHTTPProxy(Proxy):
) )
except FileNotFoundError as e: except FileNotFoundError as e:
self.log.error( self.log.error(
"Failed to find proxy %r\n" f"Failed to find proxy {self.command!r}\n"
"The proxy can be installed with `npm install -g configurable-http-proxy`." "The proxy can be installed with `npm install -g configurable-http-proxy`."
"To install `npm`, install nodejs which includes `npm`." "To install `npm`, install nodejs which includes `npm`."
"If you see an `EACCES` error or permissions error, refer to the `npm` " "If you see an `EACCES` error or permissions error, refer to the `npm` "
"documentation on How To Prevent Permissions Errors." % self.command "documentation on How To Prevent Permissions Errors."
) )
raise raise

View File

@@ -1257,7 +1257,7 @@ def define_custom_scopes(scopes):
The keys are the scopes, The keys are the scopes,
while the values are dictionaries with at least a `description` field, while the values are dictionaries with at least a `description` field,
and optional `subscopes` field. and optional `subscopes` field.
%s CUSTOM_SCOPE_DESCRIPTION
Examples:: Examples::
define_custom_scopes( define_custom_scopes(
@@ -1274,7 +1274,7 @@ def define_custom_scopes(scopes):
}, },
} }
) )
""" % indent(_custom_scope_description, " " * 8) """.replace("CUSTOM_SCOPE_DESCRIPTION", indent(_custom_scope_description, " " * 8))
for scope, scope_definition in scopes.items(): for scope, scope_definition in scopes.items():
if scope in scope_definitions and scope_definitions[scope] != scope_definition: if scope in scope_definitions and scope_definitions[scope] != scope_definition:
raise ValueError( raise ValueError(

View File

@@ -613,11 +613,8 @@ class HubAuth(SingletonConfigurable):
r = await AsyncHTTPClient().fetch(req, raise_error=False) r = await AsyncHTTPClient().fetch(req, raise_error=False)
except Exception as e: except Exception as e:
app_log.error("Error connecting to %s: %s", self.api_url, e) app_log.error("Error connecting to %s: %s", self.api_url, e)
msg = "Failed to connect to Hub API at %r." % self.api_url msg = f"Failed to connect to Hub API at {self.api_url!r}."
msg += ( msg += f" Is the Hub accessible at this URL (from host: {socket.gethostname()})?"
" Is the Hub accessible at this URL (from host: %s)?"
% socket.gethostname()
)
if '127.0.0.1' in self.api_url: if '127.0.0.1' in self.api_url:
msg += ( msg += (
" Make sure to set c.JupyterHub.hub_ip to an IP accessible to" " Make sure to set c.JupyterHub.hub_ip to an IP accessible to"
@@ -1045,7 +1042,7 @@ class HubOAuth(HubAuth):
@validate('oauth_client_id', 'api_token') @validate('oauth_client_id', 'api_token')
def _ensure_not_empty(self, proposal): def _ensure_not_empty(self, proposal):
if not proposal.value: if not proposal.value:
raise ValueError("%s cannot be empty." % proposal.trait.name) raise ValueError(f"{proposal.trait.name} cannot be empty.")
return proposal.value return proposal.value
oauth_redirect_uri = Unicode( oauth_redirect_uri = Unicode(
@@ -1561,7 +1558,7 @@ class HubOAuthCallbackHandler(HubOAuthenticated, RequestHandler):
error = self.get_argument("error", False) error = self.get_argument("error", False)
if error: if error:
msg = self.get_argument("error_description", error) msg = self.get_argument("error_description", error)
raise HTTPError(400, "Error in oauth: %s" % msg) raise HTTPError(400, f"Error in oauth: {msg}")
code = self.get_argument("code", False) code = self.get_argument("code", False)
if not code: if not code:

View File

@@ -327,7 +327,7 @@ class Service(LoggingConfigurable):
@default('oauth_client_id') @default('oauth_client_id')
def _default_client_id(self): def _default_client_id(self):
return 'service-%s' % self.name return f'service-{self.name}'
@validate("oauth_client_id") @validate("oauth_client_id")
def _validate_client_id(self, proposal): def _validate_client_id(self, proposal):
@@ -419,7 +419,7 @@ class Service(LoggingConfigurable):
async def start(self): async def start(self):
"""Start a managed service""" """Start a managed service"""
if not self.managed: if not self.managed:
raise RuntimeError("Cannot start unmanaged service %s" % self) raise RuntimeError(f"Cannot start unmanaged service {self}")
self.log.info("Starting service %r: %r", self.name, self.command) self.log.info("Starting service %r: %r", self.name, self.command)
env = {} env = {}
env.update(self.environment) env.update(self.environment)
@@ -473,7 +473,7 @@ class Service(LoggingConfigurable):
"""Stop a managed service""" """Stop a managed service"""
self.log.debug("Stopping service %s", self.name) self.log.debug("Stopping service %s", self.name)
if not self.managed: if not self.managed:
raise RuntimeError("Cannot stop unmanaged service %s" % self) raise RuntimeError(f"Cannot stop unmanaged service {self}")
if self.spawner: if self.spawner:
if self.orm.server: if self.orm.server:
self.db.delete(self.orm.server) self.db.delete(self.orm.server)

View File

@@ -341,7 +341,7 @@ class SingleUserNotebookAppMixin(Configurable):
# If we receive a non-absolute path, make it absolute. # If we receive a non-absolute path, make it absolute.
value = os.path.abspath(value) value = os.path.abspath(value)
if not os.path.isdir(value): if not os.path.isdir(value):
raise TraitError("No such notebook dir: %r" % value) raise TraitError(f"No such notebook dir: {value!r}")
return value return value
@default('log_level') @default('log_level')

View File

@@ -994,7 +994,7 @@ class Spawner(LoggingConfigurable):
env = {} env = {}
if self.env: if self.env:
warnings.warn( warnings.warn(
"Spawner.env is deprecated, found %s" % self.env, DeprecationWarning f"Spawner.env is deprecated, found {self.env}", DeprecationWarning
) )
env.update(self.env) env.update(self.env)
@@ -1494,7 +1494,7 @@ def _try_setcwd(path):
path, _ = os.path.split(path) path, _ = os.path.split(path)
else: else:
return return
print("Couldn't set CWD at all (%s), using temp dir" % exc, file=sys.stderr) print(f"Couldn't set CWD at all ({exc}), using temp dir", file=sys.stderr)
td = mkdtemp() td = mkdtemp()
os.chdir(td) os.chdir(td)
@@ -1524,7 +1524,7 @@ def set_user_setuid(username, chdir=True):
try: try:
os.setgroups(gids) os.setgroups(gids)
except Exception as e: except Exception as e:
print('Failed to set groups %s' % e, file=sys.stderr) print(f'Failed to set groups {e}', file=sys.stderr)
os.setuid(uid) os.setuid(uid)
# start in the user's home dir # start in the user's home dir

View File

@@ -83,7 +83,7 @@ async def app(request, io_loop, ssl_tmpdir):
try: try:
mocked_app.stop() mocked_app.stop()
except Exception as e: except Exception as e:
print("Error stopping Hub: %s" % e, file=sys.stderr) print(f"Error stopping Hub: {e}", file=sys.stderr)
request.addfinalizer(fin) request.addfinalizer(fin)
await mocked_app.initialize([]) await mocked_app.initialize([])

View File

@@ -54,7 +54,7 @@ class APIHandler(web.RequestHandler):
api_token = os.environ['JUPYTERHUB_API_TOKEN'] api_token = os.environ['JUPYTERHUB_API_TOKEN']
api_url = os.environ['JUPYTERHUB_API_URL'] api_url = os.environ['JUPYTERHUB_API_URL']
r = requests.get( r = requests.get(
api_url + path, headers={'Authorization': 'token %s' % api_token} api_url + path, headers={'Authorization': f'token {api_token}'}
) )
r.raise_for_status() r.raise_for_status()
self.set_header('Content-Type', 'application/json') self.set_header('Content-Type', 'application/json')

View File

@@ -63,7 +63,7 @@ async def test_auth_api(app):
app, app,
'authorizations/token', 'authorizations/token',
api_token, api_token,
headers={'Authorization': 'token: %s' % user.cookie_id}, headers={'Authorization': f'token: {user.cookie_id}'},
) )
assert r.status_code == 403 assert r.status_code == 403
@@ -965,7 +965,7 @@ async def test_spawn(app):
status = await app_user.spawner.poll() status = await app_user.spawner.poll()
assert status is None assert status is None
assert spawner.server.base_url == ujoin(app.base_url, 'user/%s' % name) + '/' assert spawner.server.base_url == ujoin(app.base_url, f'user/{name}') + '/'
url = public_url(app, user) url = public_url(app, user)
kwargs = {} kwargs = {}
if app.internal_ssl: if app.internal_ssl:
@@ -1412,7 +1412,7 @@ async def test_progress_bad_slow(request, app, no_patience, slow_bad_spawn):
async def progress_forever(): async def progress_forever():
"""progress function that yields messages forever""" """progress function that yields messages forever"""
for i in range(1, 10): for i in range(1, 10):
yield {'progress': i, 'message': 'Stage %s' % i} yield {'progress': i, 'message': f'Stage {i}'}
# wait a long time before the next event # wait a long time before the next event
await asyncio.sleep(10) await asyncio.sleep(10)
@@ -1741,7 +1741,7 @@ async def test_token_for_user(app, as_user, for_user, status):
if for_user != 'missing': if for_user != 'missing':
for_user_obj = add_user(app.db, app, name=for_user) for_user_obj = add_user(app.db, app, name=for_user)
data = {'username': for_user} data = {'username': for_user}
headers = {'Authorization': 'token %s' % u.new_api_token()} headers = {'Authorization': f'token {u.new_api_token()}'}
r = await api_request( r = await api_request(
app, app,
'users', 'users',
@@ -1765,7 +1765,7 @@ async def test_token_for_user(app, as_user, for_user, status):
if for_user == as_user: if for_user == as_user:
note = 'Requested via api' note = 'Requested via api'
else: else:
note = 'Requested via api by user %s' % as_user note = f'Requested via api by user {as_user}'
assert reply['note'] == note assert reply['note'] == note
# delete the token # delete the token
@@ -1836,7 +1836,7 @@ async def test_token_list(app, as_user, for_user, status):
u = add_user(app.db, app, name=as_user) u = add_user(app.db, app, name=as_user)
if for_user != 'missing': if for_user != 'missing':
for_user_obj = add_user(app.db, app, name=for_user) for_user_obj = add_user(app.db, app, name=for_user)
headers = {'Authorization': 'token %s' % u.new_api_token()} headers = {'Authorization': f'token {u.new_api_token()}'}
r = await api_request(app, 'users', for_user, 'tokens', headers=headers) r = await api_request(app, 'users', for_user, 'tokens', headers=headers)
assert r.status_code == status assert r.status_code == status
if status != 200: if status != 200:
@@ -2214,7 +2214,7 @@ async def test_get_service(app, mockservice_url):
r = await api_request( r = await api_request(
app, app,
f"services/{mockservice.name}", f"services/{mockservice.name}",
headers={'Authorization': 'token %s' % mockservice.api_token}, headers={'Authorization': f'token {mockservice.api_token}'},
) )
r.raise_for_status() r.raise_for_status()

View File

@@ -57,7 +57,7 @@ async def test_upgrade(tmpdir, hub_version):
# use persistent temp env directory # use persistent temp env directory
# to reuse across multiple runs # to reuse across multiple runs
env_dir = os.path.join(tempfile.gettempdir(), 'test-hub-upgrade-%s' % hub_version) env_dir = os.path.join(tempfile.gettempdir(), f'test-hub-upgrade-{hub_version}')
generate_old_db(env_dir, hub_version, db_url) generate_old_db(env_dir, hub_version, db_url)

View File

@@ -120,7 +120,7 @@ async def test_admin_version(app):
@pytest.mark.parametrize('sort', ['running', 'last_activity', 'admin', 'name']) @pytest.mark.parametrize('sort', ['running', 'last_activity', 'admin', 'name'])
async def test_admin_sort(app, sort): async def test_admin_sort(app, sort):
cookies = await app.login_user('admin') cookies = await app.login_user('admin')
r = await get_page('admin?sort=%s' % sort, app, cookies=cookies) r = await get_page(f'admin?sort={sort}', app, cookies=cookies)
r.raise_for_status() r.raise_for_status()
assert r.status_code == 200 assert r.status_code == 200
@@ -170,7 +170,7 @@ async def test_spawn_redirect(app, last_failed):
r.raise_for_status() r.raise_for_status()
print(urlparse(r.url)) print(urlparse(r.url))
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, '/user/%s/' % name) assert path == ujoin(app.base_url, f'/user/{name}/')
# stop server to ensure /user/name is handled by the Hub # stop server to ensure /user/name is handled by the Hub
r = await api_request( r = await api_request(
@@ -181,7 +181,7 @@ async def test_spawn_redirect(app, last_failed):
# test handing of trailing slash on `/user/name` # test handing of trailing slash on `/user/name`
r = await get_page('user/' + name, app, hub=False, cookies=cookies) r = await get_page('user/' + name, app, hub=False, cookies=cookies)
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, 'hub/user/%s/' % name) assert path == ujoin(app.base_url, f'hub/user/{name}/')
assert r.status_code == 424 assert r.status_code == 424
@@ -586,7 +586,7 @@ async def test_user_redirect(app, username):
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
r = await async_requests.get(r.url, cookies=cookies) r = await async_requests.get(r.url, cookies=cookies)
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, '/user/%s/notebooks/test.ipynb' % name) assert path == ujoin(app.base_url, f'/user/{name}/notebooks/test.ipynb')
async def test_user_redirect_hook(app, username): async def test_user_redirect_hook(app, username):
@@ -1240,7 +1240,7 @@ async def test_token_page(app):
r.raise_for_status() r.raise_for_status()
body = extract_body(r) body = extract_body(r)
assert "API Tokens" in body, body assert "API Tokens" in body, body
assert "Server at %s" % user.base_url in body, body assert f"Server at {user.base_url}" in body, body
assert "Authorized Applications" in body, body assert "Authorized Applications" in body, body
@@ -1299,7 +1299,7 @@ async def test_pre_spawn_start_exc_options_form(app):
r.raise_for_status() r.raise_for_status()
assert FormSpawner.options_form in r.text assert FormSpawner.options_form in r.text
# spawning the user server should throw the pre_spawn_start error # spawning the user server should throw the pre_spawn_start error
with pytest.raises(Exception, match="%s" % exc): with pytest.raises(Exception, match=str(exc)):
await user.spawn() await user.spawn()

View File

@@ -171,7 +171,7 @@ async def test_external_proxy(request):
async def test_check_routes(app, username, disable_check_routes): async def test_check_routes(app, username, disable_check_routes):
proxy = app.proxy proxy = app.proxy
test_user = add_user(app.db, app, name=username) test_user = add_user(app.db, app, name=username)
r = await api_request(app, 'users/%s/server' % username, method='post') r = await api_request(app, f'users/{username}/server', method='post')
r.raise_for_status() r.raise_for_status()
# check a valid route exists for user # check a valid route exists for user

View File

@@ -956,7 +956,7 @@ async def test_user_group_roles(app, create_temp_role):
# jack's API token # jack's API token
token = user.new_api_token() token = user.new_api_token()
headers = {'Authorization': 'token %s' % token} headers = {'Authorization': f'token {token}'}
r = await api_request(app, f'users/{user.name}', method='get', headers=headers) r = await api_request(app, f'users/{user.name}', method='get', headers=headers)
assert r.status_code == 200 assert r.status_code == 200
r.raise_for_status() r.raise_for_status()
@@ -968,7 +968,7 @@ async def test_user_group_roles(app, create_temp_role):
assert len(reply['roles']) == 1 assert len(reply['roles']) == 1
assert group_role.name not in reply['roles'] assert group_role.name not in reply['roles']
headers = {'Authorization': 'token %s' % token} headers = {'Authorization': f'token {token}'}
r = await api_request(app, 'groups', method='get', headers=headers) r = await api_request(app, 'groups', method='get', headers=headers)
assert r.status_code == 200 assert r.status_code == 200
r.raise_for_status() r.raise_for_status()
@@ -978,7 +978,7 @@ async def test_user_group_roles(app, create_temp_role):
assert len(reply) == 1 assert len(reply) == 1
assert reply[0]['name'] == 'A' assert reply[0]['name'] == 'A'
headers = {'Authorization': 'token %s' % token} headers = {'Authorization': f'token {token}'}
r = await api_request(app, f'users/{user.name}', method='get', headers=headers) r = await api_request(app, f'users/{user.name}', method='get', headers=headers)
assert r.status_code == 200 assert r.status_code == 200
r.raise_for_status() r.raise_for_status()

View File

@@ -289,7 +289,7 @@ async def test_exceeding_user_permissions(
orm_api_token = orm.APIToken.find(app.db, token=api_token) orm_api_token = orm.APIToken.find(app.db, token=api_token)
# store scopes user does not have # store scopes user does not have
orm_api_token.scopes = list(orm_api_token.scopes) + ['list:users', 'read:users'] orm_api_token.scopes = list(orm_api_token.scopes) + ['list:users', 'read:users']
headers = {'Authorization': 'token %s' % api_token} headers = {'Authorization': f'token {api_token}'}
r = await api_request(app, 'users', headers=headers) r = await api_request(app, 'users', headers=headers)
assert r.status_code == 200 assert r.status_code == 200
keys = {key for user in r.json() for key in user.keys()} keys = {key for user in r.json() for key in user.keys()}
@@ -307,7 +307,7 @@ async def test_user_service_separation(app, mockservice_url, create_temp_role):
roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role']) roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role'])
user.roles.remove(orm.Role.find(app.db, name='user')) user.roles.remove(orm.Role.find(app.db, name='user'))
api_token = user.new_api_token() api_token = user.new_api_token()
headers = {'Authorization': 'token %s' % api_token} headers = {'Authorization': f'token {api_token}'}
r = await api_request(app, 'users', headers=headers) r = await api_request(app, 'users', headers=headers)
assert r.status_code == 200 assert r.status_code == 200
keys = {key for user in r.json() for key in user.keys()} keys = {key for user in r.json() for key in user.keys()}
@@ -551,7 +551,7 @@ async def test_server_state_access(
) )
service = create_service_with_scopes("read:users:name!user=bianca", *scopes) service = create_service_with_scopes("read:users:name!user=bianca", *scopes)
api_token = service.new_api_token() api_token = service.new_api_token()
headers = {'Authorization': 'token %s' % api_token} headers = {'Authorization': f'token {api_token}'}
# can I get the user model? # can I get the user model?
r = await api_request(app, 'users', user.name, headers=headers) r = await api_request(app, 'users', user.name, headers=headers)

View File

@@ -88,7 +88,7 @@ async def test_hubauth_token(app, mockservice_url, create_user_with_scopes):
# token in ?token parameter is not allowed by default # token in ?token parameter is not allowed by default
r = await async_requests.get( r = await async_requests.get(
public_url(app, mockservice_url) + '/whoami/?token=%s' % token, public_url(app, mockservice_url) + f'/whoami/?token={token}',
allow_redirects=False, allow_redirects=False,
) )
assert r.status_code == 403 assert r.status_code == 403
@@ -150,7 +150,7 @@ async def test_hubauth_service_token(request, app, mockservice_url, scopes, allo
# token in Authorization header # token in Authorization header
r = await async_requests.get( r = await async_requests.get(
public_url(app, mockservice_url) + 'whoami/', public_url(app, mockservice_url) + 'whoami/',
headers={'Authorization': 'token %s' % token}, headers={'Authorization': f'token {token}'},
allow_redirects=False, allow_redirects=False,
) )
service_model = { service_model = {
@@ -170,7 +170,7 @@ async def test_hubauth_service_token(request, app, mockservice_url, scopes, allo
# token in ?token parameter is not allowed by default # token in ?token parameter is not allowed by default
r = await async_requests.get( r = await async_requests.get(
public_url(app, mockservice_url) + 'whoami/?token=%s' % token, public_url(app, mockservice_url) + f'whoami/?token={token}',
allow_redirects=False, allow_redirects=False,
) )
assert r.status_code == 403 assert r.status_code == 403
@@ -303,7 +303,7 @@ async def test_oauth_service_roles(
# we should be looking at the oauth confirmation page # we should be looking at the oauth confirmation page
assert urlparse(r.url).path == app.base_url + 'hub/api/oauth2/authorize' assert urlparse(r.url).path == app.base_url + 'hub/api/oauth2/authorize'
# verify oauth state cookie was set at some point # verify oauth state cookie was set at some point
assert set(r.history[0].cookies.keys()) == {'service-%s-oauth-state' % service.name} assert set(r.history[0].cookies.keys()) == {f'service-{service.name}-oauth-state'}
page = BeautifulSoup(r.text, "html.parser") page = BeautifulSoup(r.text, "html.parser")
scope_inputs = page.find_all("input", {"name": "scopes"}) scope_inputs = page.find_all("input", {"name": "scopes"})
@@ -318,9 +318,9 @@ async def test_oauth_service_roles(
r.raise_for_status() r.raise_for_status()
assert r.url == url assert r.url == url
# verify oauth cookie is set # verify oauth cookie is set
assert 'service-%s' % service.name in set(s.cookies.keys()) assert f'service-{service.name}' in set(s.cookies.keys())
# verify oauth state cookie has been consumed # verify oauth state cookie has been consumed
assert 'service-%s-oauth-state' % service.name not in set(s.cookies.keys()) assert f'service-{service.name}-oauth-state' not in set(s.cookies.keys())
# second request should be authenticated, which means no redirects # second request should be authenticated, which means no redirects
r = await s.get(url, allow_redirects=False) r = await s.get(url, allow_redirects=False)
@@ -402,16 +402,16 @@ async def test_oauth_access_scopes(
# we should be looking at the oauth confirmation page # we should be looking at the oauth confirmation page
assert urlparse(r.url).path == app.base_url + 'hub/api/oauth2/authorize' assert urlparse(r.url).path == app.base_url + 'hub/api/oauth2/authorize'
# verify oauth state cookie was set at some point # verify oauth state cookie was set at some point
assert set(r.history[0].cookies.keys()) == {'service-%s-oauth-state' % service.name} assert set(r.history[0].cookies.keys()) == {f'service-{service.name}-oauth-state'}
# submit the oauth form to complete authorization # submit the oauth form to complete authorization
r = await s.post(r.url, data={"_xsrf": s.cookies["_xsrf"]}) r = await s.post(r.url, data={"_xsrf": s.cookies["_xsrf"]})
r.raise_for_status() r.raise_for_status()
assert r.url == url assert r.url == url
# verify oauth cookie is set # verify oauth cookie is set
assert 'service-%s' % service.name in set(s.cookies.keys()) assert f'service-{service.name}' in set(s.cookies.keys())
# verify oauth state cookie has been consumed # verify oauth state cookie has been consumed
assert 'service-%s-oauth-state' % service.name not in set(s.cookies.keys()) assert f'service-{service.name}-oauth-state' not in set(s.cookies.keys())
# second request should be authenticated, which means no redirects # second request should be authenticated, which means no redirects
r = await s.get(url, allow_redirects=False) r = await s.get(url, allow_redirects=False)
@@ -499,8 +499,8 @@ async def test_oauth_cookie_collision(
name = 'mypha' name = 'mypha'
create_user_with_scopes("access:services", name=name) create_user_with_scopes("access:services", name=name)
s.cookies = await app.login_user(name) s.cookies = await app.login_user(name)
state_cookie_name = 'service-%s-oauth-state' % service.name state_cookie_name = f'service-{service.name}-oauth-state'
service_cookie_name = 'service-%s' % service.name service_cookie_name = f'service-{service.name}'
url_1 = url + "?oauth_test=1" url_1 = url + "?oauth_test=1"
oauth_1 = await s.get(url_1) oauth_1 = await s.get(url_1)
assert state_cookie_name in s.cookies assert state_cookie_name in s.cookies
@@ -582,7 +582,7 @@ async def test_oauth_logout(app, mockservice_url, create_user_with_scopes):
4. cache hit 4. cache hit
""" """
service = mockservice_url service = mockservice_url
service_cookie_name = 'service-%s' % service.name service_cookie_name = f'service-{service.name}'
url = url_path_join(public_url(app, mockservice_url), 'owhoami/?foo=bar') url = url_path_join(public_url(app, mockservice_url), 'owhoami/?foo=bar')
# first request is only going to set login cookie # first request is only going to set login cookie
s = AsyncSession() s = AsyncSession()

View File

@@ -221,8 +221,8 @@ def test_string_formatting(db):
name = s.user.name name = s.user.name
assert s.notebook_dir == 'user/{username}/' assert s.notebook_dir == 'user/{username}/'
assert s.default_url == '/base/{username}' assert s.default_url == '/base/{username}'
assert s.format_string(s.notebook_dir) == 'user/%s/' % name assert s.format_string(s.notebook_dir) == f'user/{name}/'
assert s.format_string(s.default_url) == '/base/%s' % name assert s.format_string(s.default_url) == f'/base/{name}'
async def test_popen_kwargs(db): async def test_popen_kwargs(db):
@@ -496,7 +496,7 @@ async def test_hub_connect_url(db):
assert env["JUPYTERHUB_API_URL"] == "https://example.com/api" assert env["JUPYTERHUB_API_URL"] == "https://example.com/api"
assert ( assert (
env["JUPYTERHUB_ACTIVITY_URL"] env["JUPYTERHUB_ACTIVITY_URL"]
== "https://example.com/api/users/%s/activity" % name == f"https://example.com/api/users/{name}/activity"
) )

View File

@@ -149,7 +149,7 @@ def auth_header(db, name):
if user is None: if user is None:
raise KeyError(f"No such user: {name}") raise KeyError(f"No such user: {name}")
token = user.new_api_token() token = user.new_api_token()
return {'Authorization': 'token %s' % token} return {'Authorization': f'token {token}'}
@check_db_locks @check_db_locks
@@ -198,7 +198,7 @@ async def api_request(
def get_page(path, app, hub=True, **kw): def get_page(path, app, hub=True, **kw):
if "://" in path: if "://" in path:
raise ValueError( raise ValueError(
"Not a hub page path: %r. Did you mean async_requests.get?" % path f"Not a hub page path: {path!r}. Did you mean async_requests.get?"
) )
if hub: if hub:
prefix = app.hub.base_url prefix = app.hub.base_url

View File

@@ -125,7 +125,7 @@ class UserDict(dict):
elif isinstance(key, str): elif isinstance(key, str):
orm_user = self.db.query(orm.User).filter(orm.User.name == key).first() orm_user = self.db.query(orm.User).filter(orm.User.name == key).first()
if orm_user is None: if orm_user is None:
raise KeyError("No such user: %s" % key) raise KeyError(f"No such user: {key}")
else: else:
key = orm_user.id key = orm_user.id
if isinstance(key, orm.User): if isinstance(key, orm.User):
@@ -142,7 +142,7 @@ class UserDict(dict):
if id not in self: if id not in self:
orm_user = self.db.query(orm.User).filter(orm.User.id == id).first() orm_user = self.db.query(orm.User).filter(orm.User.id == id).first()
if orm_user is None: if orm_user is None:
raise KeyError("No such user: %s" % id) raise KeyError(f"No such user: {id}")
user = self.add(orm_user) user = self.add(orm_user)
else: else:
user = super().__getitem__(id) user = super().__getitem__(id)
@@ -505,7 +505,7 @@ class User:
# use fully quoted name for client_id because it will be used in cookie-name # use fully quoted name for client_id because it will be used in cookie-name
# self.escaped_name may contain @ which is legal in URLs but not cookie keys # self.escaped_name may contain @ which is legal in URLs but not cookie keys
client_id = 'jupyterhub-user-%s' % quote(self.name) client_id = f'jupyterhub-user-{quote(self.name)}'
if server_name: if server_name:
client_id = f'{client_id}-{quote(server_name)}' client_id = f'{client_id}-{quote(server_name)}'
@@ -790,7 +790,7 @@ class User:
orm_server = orm.Server(base_url=base_url) orm_server = orm.Server(base_url=base_url)
db.add(orm_server) db.add(orm_server)
note = "Server at %s" % base_url note = f"Server at {base_url}"
db.commit() db.commit()
spawner = self.get_spawner(server_name, replace_failed=True) spawner = self.get_spawner(server_name, replace_failed=True)
@@ -962,7 +962,7 @@ class User:
) )
self.db.delete(found) self.db.delete(found)
self.db.commit() self.db.commit()
raise ValueError("Invalid token for %s!" % self.name) raise ValueError(f"Invalid token for {self.name}!")
else: else:
# Spawner.api_token has changed, but isn't in the db. # Spawner.api_token has changed, but isn't in the db.
# What happened? Maybe something unclean in a resumed container. # What happened? Maybe something unclean in a resumed container.
@@ -975,7 +975,7 @@ class User:
self.new_api_token( self.new_api_token(
spawner.api_token, spawner.api_token,
generated=False, generated=False,
note="retrieved from spawner %s" % server_name, note=f"retrieved from spawner {server_name}",
scopes=resolved_scopes, scopes=resolved_scopes,
) )
# update OAuth client secret with updated API token # update OAuth client secret with updated API token

View File

@@ -504,7 +504,7 @@ def print_ps_info(file=sys.stderr):
if cpu >= 10: if cpu >= 10:
cpu_s = "%i" % cpu cpu_s = "%i" % cpu
else: else:
cpu_s = "%.1f" % cpu cpu_s = f"{cpu:.1f}"
# format memory (only resident set) # format memory (only resident set)
rss = p.memory_info().rss rss = p.memory_info().rss
@@ -562,7 +562,7 @@ def print_stacks(file=sys.stderr):
print("Active threads: %i" % threading.active_count(), file=file) print("Active threads: %i" % threading.active_count(), file=file)
for thread in threading.enumerate(): for thread in threading.enumerate():
print("Thread %s:" % thread.name, end='', file=file) print(f"Thread {thread.name}:", end='', file=file)
frame = sys._current_frames()[thread.ident] frame = sys._current_frames()[thread.ident]
stack = traceback.extract_stack(frame) stack = traceback.extract_stack(frame)
if thread is threading.current_thread(): if thread is threading.current_thread():

View File

@@ -157,7 +157,7 @@ class CSS(BaseCommand):
try: try:
check_call(args, cwd=here, shell=shell) check_call(args, cwd=here, shell=shell)
except OSError as e: except OSError as e:
print("Failed to build css: %s" % e, file=sys.stderr) print(f"Failed to build css: {e}", file=sys.stderr)
print("You can install js dependencies with `npm install`", file=sys.stderr) print("You can install js dependencies with `npm install`", file=sys.stderr)
raise raise
# update data-files in case this created new files # update data-files in case this created new files