From c41b732fbdd9a3b650f4a55d61fc1c705cd76b5c Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 31 Mar 2022 12:21:57 +0200 Subject: [PATCH 1/2] switch to isort for import formatting isort produces nicer imports without wasting a huge amount of space --- .pre-commit-config.yaml | 6 +++--- pyproject.toml | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a1ca71df..b5a9bd0e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,10 +18,10 @@ repos: - --py36-plus # Autoformat: Python code - - repo: https://github.com/asottile/reorder_python_imports - rev: v3.0.1 + - repo: https://github.com/pycqa/isort + rev: 5.10.1 hooks: - - id: reorder-python-imports + - id: isort # Autoformat: Python code - repo: https://github.com/psf/black diff --git a/pyproject.toml b/pyproject.toml index e81f0658..41e217a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[tool.isort] +profile = "black" + [tool.black] skip-string-normalization = true target_version = [ From 7a9778249fd2f71ae3d9e70971ab6ff5803cef5a Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 31 Mar 2022 12:33:26 +0200 Subject: [PATCH 2/2] run pre-commit with isort --- docs/source/conf.py | 10 +- .../jupyterhub_config.py | 3 +- examples/custom-scopes/grades.py | 7 +- examples/external-oauth/whoami-oauth-basic.py | 9 +- examples/server-api/start-stop-server.py | 1 - examples/service-announcement/announcement.py | 4 +- examples/service-fastapi/app/models.py | 5 +- examples/service-fastapi/app/security.py | 4 +- examples/service-fastapi/app/service.py | 9 +- examples/service-whoami-flask/whoami-flask.py | 8 +- examples/service-whoami/whoami-oauth.py | 7 +- examples/service-whoami/whoami.py | 4 +- jupyterhub/__init__.py | 3 +- jupyterhub/_data.py | 2 +- jupyterhub/alembic/env.py | 4 +- .../19c0846f6344_base_revision_for_0_5.py | 2 +- .../versions/1cebaf56856c_session_id.py | 2 +- .../3ec6993fe20c_encrypted_auth_state.py | 3 +- .../versions/4dc2d5a8c53c_user_options.py | 3 +- .../versions/56cc5a70207e_token_tracking.py | 6 +- .../versions/651f5419b74d_api_token_scopes.py | 9 +- .../alembic/versions/833da8570507_rbac.py | 3 +- .../versions/896818069c98_token_expires.py | 2 +- .../versions/99a28a4418e1_user_created.py | 6 +- .../alembic/versions/af4cbdb2d13c_services.py | 2 +- .../d68c98b66cd4_client_description.py | 2 +- .../versions/eeb276e51423_auth_state.py | 3 +- jupyterhub/apihandlers/__init__.py | 7 +- jupyterhub/apihandlers/auth.py | 16 +--- jupyterhub/apihandlers/base.py | 9 +- jupyterhub/apihandlers/groups.py | 3 +- jupyterhub/apihandlers/services.py | 3 +- jupyterhub/apihandlers/users.py | 15 +-- jupyterhub/app.py | 96 +++++++++---------- jupyterhub/auth.py | 9 +- jupyterhub/crypto.py | 12 +-- jupyterhub/handlers/__init__.py | 5 +- jupyterhub/handlers/base.py | 59 +++++------- jupyterhub/handlers/metrics.py | 4 +- jupyterhub/handlers/pages.py | 6 +- jupyterhub/log.py | 9 +- jupyterhub/metrics.py | 3 +- jupyterhub/oauth/provider.py | 13 +-- jupyterhub/objects.py | 25 ++--- jupyterhub/orm.py | 59 ++++++------ jupyterhub/proxy.py | 25 ++--- jupyterhub/roles.py | 3 +- jupyterhub/scopes.py | 3 +- jupyterhub/services/auth.py | 15 +-- jupyterhub/services/service.py | 23 ++--- jupyterhub/singleuser/__init__.py | 6 +- jupyterhub/singleuser/mixins.py | 42 ++++---- jupyterhub/spawner.py | 42 ++++---- jupyterhub/tests/conftest.py | 15 +-- jupyterhub/tests/mocking.py | 16 +--- jupyterhub/tests/mockservice.py | 15 ++- jupyterhub/tests/mocksu.py | 5 +- jupyterhub/tests/test_api.py | 21 ++-- jupyterhub/tests/test_app.py | 10 +- jupyterhub/tests/test_auth.py | 14 +-- jupyterhub/tests/test_auth_expiry.py | 6 +- jupyterhub/tests/test_crypto.py | 6 +- jupyterhub/tests/test_db.py | 3 +- jupyterhub/tests/test_eventlog.py | 1 - .../tests/test_internal_ssl_connections.py | 3 +- jupyterhub/tests/test_metrics.py | 8 +- jupyterhub/tests/test_named_servers.py | 15 +-- jupyterhub/tests/test_orm.py | 8 +- jupyterhub/tests/test_pages.py | 25 +++-- jupyterhub/tests/test_proxy.py | 6 +- jupyterhub/tests/test_roles.py | 9 +- jupyterhub/tests/test_scopes.py | 28 +++--- jupyterhub/tests/test_services.py | 15 +-- jupyterhub/tests/test_services_auth.py | 11 +-- jupyterhub/tests/test_singleuser.py | 10 +- jupyterhub/tests/test_spawner.py | 10 +- jupyterhub/tests/test_traitlets.py | 7 +- jupyterhub/tests/test_version.py | 3 +- jupyterhub/tests/utils.py | 6 +- jupyterhub/traitlets.py | 8 +- jupyterhub/user.py | 27 ++---- jupyterhub/utils.py | 11 +-- setup.py | 4 +- 83 files changed, 360 insertions(+), 601 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2c6dc76e..d69b3cee 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -56,13 +56,15 @@ todo_include_todos = False # Set the default role so we can use `foo` instead of ``foo`` default_role = 'literal' -# -- Config ------------------------------------------------------------- -from jupyterhub.app import JupyterHub -from docutils import nodes -from sphinx.directives.other import SphinxDirective from contextlib import redirect_stdout from io import StringIO +from docutils import nodes +from sphinx.directives.other import SphinxDirective + +# -- Config ------------------------------------------------------------- +from jupyterhub.app import JupyterHub + # create a temp instance of JupyterHub just to get the output of the generate-config # and help --all commands. jupyterhub_app = JupyterHub() diff --git a/examples/azuread-with-group-management/jupyterhub_config.py b/examples/azuread-with-group-management/jupyterhub_config.py index f8da8746..32355013 100644 --- a/examples/azuread-with-group-management/jupyterhub_config.py +++ b/examples/azuread-with-group-management/jupyterhub_config.py @@ -7,9 +7,10 @@ to enable testing without administrative privileges. c = get_config() # noqa c.Application.log_level = 'DEBUG' -from oauthenticator.azuread import AzureAdOAuthenticator import os +from oauthenticator.azuread import AzureAdOAuthenticator + c.JupyterHub.authenticator_class = AzureAdOAuthenticator c.AzureAdOAuthenticator.client_id = os.getenv("AAD_CLIENT_ID") diff --git a/examples/custom-scopes/grades.py b/examples/custom-scopes/grades.py index 4b805264..f1f8be54 100644 --- a/examples/custom-scopes/grades.py +++ b/examples/custom-scopes/grades.py @@ -5,12 +5,9 @@ from urllib.parse import urlparse from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop -from tornado.web import Application -from tornado.web import authenticated -from tornado.web import RequestHandler +from tornado.web import Application, RequestHandler, authenticated -from jupyterhub.services.auth import HubOAuthCallbackHandler -from jupyterhub.services.auth import HubOAuthenticated +from jupyterhub.services.auth import HubOAuthCallbackHandler, HubOAuthenticated from jupyterhub.utils import url_path_join SCOPE_PREFIX = "custom:grades" diff --git a/examples/external-oauth/whoami-oauth-basic.py b/examples/external-oauth/whoami-oauth-basic.py index 2aca9f55..a89f8db7 100644 --- a/examples/external-oauth/whoami-oauth-basic.py +++ b/examples/external-oauth/whoami-oauth-basic.py @@ -5,13 +5,10 @@ so all URLs and requests necessary for OAuth with JupyterHub should be in one pl """ import json import os -from urllib.parse import urlencode -from urllib.parse import urlparse +from urllib.parse import urlencode, urlparse -from tornado import log -from tornado import web -from tornado.httpclient import AsyncHTTPClient -from tornado.httpclient import HTTPRequest +from tornado import log, web +from tornado.httpclient import AsyncHTTPClient, HTTPRequest from tornado.httputil import url_concat from tornado.ioloop import IOLoop diff --git a/examples/server-api/start-stop-server.py b/examples/server-api/start-stop-server.py index ae680535..d20e1530 100644 --- a/examples/server-api/start-stop-server.py +++ b/examples/server-api/start-stop-server.py @@ -16,7 +16,6 @@ import time import requests - log = logging.getLogger(__name__) diff --git a/examples/service-announcement/announcement.py b/examples/service-announcement/announcement.py index 6a50c33d..5354c70c 100644 --- a/examples/service-announcement/announcement.py +++ b/examples/service-announcement/announcement.py @@ -3,9 +3,7 @@ import datetime import json import os -from tornado import escape -from tornado import ioloop -from tornado import web +from tornado import escape, ioloop, web from jupyterhub.services.auth import HubAuthenticated diff --git a/examples/service-fastapi/app/models.py b/examples/service-fastapi/app/models.py index 33fdab68..fad8e1e8 100644 --- a/examples/service-fastapi/app/models.py +++ b/examples/service-fastapi/app/models.py @@ -1,8 +1,5 @@ from datetime import datetime -from typing import Any -from typing import Dict -from typing import List -from typing import Optional +from typing import Any, Dict, List, Optional from pydantic import BaseModel diff --git a/examples/service-fastapi/app/security.py b/examples/service-fastapi/app/security.py index 62b2ea5e..63fd2a5e 100644 --- a/examples/service-fastapi/app/security.py +++ b/examples/service-fastapi/app/security.py @@ -1,9 +1,7 @@ import json import os -from fastapi import HTTPException -from fastapi import Security -from fastapi import status +from fastapi import HTTPException, Security, status from fastapi.security import OAuth2AuthorizationCodeBearer from fastapi.security.api_key import APIKeyQuery diff --git a/examples/service-fastapi/app/service.py b/examples/service-fastapi/app/service.py index da3f8545..81d7b87d 100644 --- a/examples/service-fastapi/app/service.py +++ b/examples/service-fastapi/app/service.py @@ -1,14 +1,9 @@ import os -from fastapi import APIRouter -from fastapi import Depends -from fastapi import Form -from fastapi import Request +from fastapi import APIRouter, Depends, Form, Request from .client import get_client -from .models import AuthorizationError -from .models import HubApiError -from .models import User +from .models import AuthorizationError, HubApiError, User from .security import get_current_user # APIRouter prefix cannot end in / diff --git a/examples/service-whoami-flask/whoami-flask.py b/examples/service-whoami-flask/whoami-flask.py index 139925c9..2e08391b 100644 --- a/examples/service-whoami-flask/whoami-flask.py +++ b/examples/service-whoami-flask/whoami-flask.py @@ -7,16 +7,10 @@ import os import secrets from functools import wraps -from flask import Flask -from flask import make_response -from flask import redirect -from flask import request -from flask import Response -from flask import session +from flask import Flask, Response, make_response, redirect, request, session from jupyterhub.services.auth import HubOAuth - prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/') auth = HubOAuth(api_token=os.environ['JUPYTERHUB_API_TOKEN'], cache_max_age=60) diff --git a/examples/service-whoami/whoami-oauth.py b/examples/service-whoami/whoami-oauth.py index b2158e51..41466231 100644 --- a/examples/service-whoami/whoami-oauth.py +++ b/examples/service-whoami/whoami-oauth.py @@ -10,12 +10,9 @@ from urllib.parse import urlparse from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop -from tornado.web import Application -from tornado.web import authenticated -from tornado.web import RequestHandler +from tornado.web import Application, RequestHandler, authenticated -from jupyterhub.services.auth import HubOAuthCallbackHandler -from jupyterhub.services.auth import HubOAuthenticated +from jupyterhub.services.auth import HubOAuthCallbackHandler, HubOAuthenticated from jupyterhub.utils import url_path_join diff --git a/examples/service-whoami/whoami.py b/examples/service-whoami/whoami.py index 435ff329..da79d9ad 100644 --- a/examples/service-whoami/whoami.py +++ b/examples/service-whoami/whoami.py @@ -10,9 +10,7 @@ from urllib.parse import urlparse from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop -from tornado.web import Application -from tornado.web import authenticated -from tornado.web import RequestHandler +from tornado.web import Application, RequestHandler, authenticated from jupyterhub.services.auth import HubAuthenticated diff --git a/jupyterhub/__init__.py b/jupyterhub/__init__.py index 5e882401..948f47a6 100644 --- a/jupyterhub/__init__.py +++ b/jupyterhub/__init__.py @@ -1,2 +1 @@ -from ._version import __version__ -from ._version import version_info +from ._version import __version__, version_info diff --git a/jupyterhub/_data.py b/jupyterhub/_data.py index 04452d18..d665f193 100644 --- a/jupyterhub/_data.py +++ b/jupyterhub/_data.py @@ -4,7 +4,7 @@ def get_data_files(): """Walk up until we find share/jupyterhub""" import sys - from os.path import join, abspath, dirname, exists, split + from os.path import abspath, dirname, exists, join, split path = abspath(dirname(__file__)) starting_points = [path] diff --git a/jupyterhub/alembic/env.py b/jupyterhub/alembic/env.py index 30dfbd92..8b4cba1b 100644 --- a/jupyterhub/alembic/env.py +++ b/jupyterhub/alembic/env.py @@ -3,8 +3,7 @@ import sys from logging.config import fileConfig from alembic import context -from sqlalchemy import engine_from_config -from sqlalchemy import pool +from sqlalchemy import engine_from_config, pool # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -13,6 +12,7 @@ config = context.config # This line sets up loggers basically. if 'jupyterhub' in sys.modules: from traitlets.config import MultipleInstanceError + from jupyterhub.app import JupyterHub app = None diff --git a/jupyterhub/alembic/versions/19c0846f6344_base_revision_for_0_5.py b/jupyterhub/alembic/versions/19c0846f6344_base_revision_for_0_5.py index 5aa2b46d..9ee5a24a 100644 --- a/jupyterhub/alembic/versions/19c0846f6344_base_revision_for_0_5.py +++ b/jupyterhub/alembic/versions/19c0846f6344_base_revision_for_0_5.py @@ -11,8 +11,8 @@ down_revision = None branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op def upgrade(): diff --git a/jupyterhub/alembic/versions/1cebaf56856c_session_id.py b/jupyterhub/alembic/versions/1cebaf56856c_session_id.py index 14c4d68b..38f37b0b 100644 --- a/jupyterhub/alembic/versions/1cebaf56856c_session_id.py +++ b/jupyterhub/alembic/versions/1cebaf56856c_session_id.py @@ -15,8 +15,8 @@ import logging logger = logging.getLogger('alembic') -from alembic import op import sqlalchemy as sa +from alembic import op tables = ('oauth_access_tokens', 'oauth_codes') diff --git a/jupyterhub/alembic/versions/3ec6993fe20c_encrypted_auth_state.py b/jupyterhub/alembic/versions/3ec6993fe20c_encrypted_auth_state.py index 8e234318..73d8bc44 100644 --- a/jupyterhub/alembic/versions/3ec6993fe20c_encrypted_auth_state.py +++ b/jupyterhub/alembic/versions/3ec6993fe20c_encrypted_auth_state.py @@ -22,8 +22,9 @@ import logging logger = logging.getLogger('alembic') -from alembic import op import sqlalchemy as sa +from alembic import op + from jupyterhub.orm import JSONDict diff --git a/jupyterhub/alembic/versions/4dc2d5a8c53c_user_options.py b/jupyterhub/alembic/versions/4dc2d5a8c53c_user_options.py index 87417570..617a2d6d 100644 --- a/jupyterhub/alembic/versions/4dc2d5a8c53c_user_options.py +++ b/jupyterhub/alembic/versions/4dc2d5a8c53c_user_options.py @@ -11,8 +11,9 @@ down_revision = '896818069c98' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op + from jupyterhub.orm import JSONDict diff --git a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py index 6f2a2efa..0c74c09d 100644 --- a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py +++ b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py @@ -11,11 +11,11 @@ down_revision = '1cebaf56856c' branch_labels = None depends_on = None -from alembic import op -import sqlalchemy as sa - import logging +import sqlalchemy as sa +from alembic import op + logger = logging.getLogger('alembic') diff --git a/jupyterhub/alembic/versions/651f5419b74d_api_token_scopes.py b/jupyterhub/alembic/versions/651f5419b74d_api_token_scopes.py index bda81a2b..05677d4e 100644 --- a/jupyterhub/alembic/versions/651f5419b74d_api_token_scopes.py +++ b/jupyterhub/alembic/versions/651f5419b74d_api_token_scopes.py @@ -13,17 +13,12 @@ depends_on = None import sqlalchemy as sa from alembic import op -from sqlalchemy import Column -from sqlalchemy import ForeignKey -from sqlalchemy import Integer -from sqlalchemy import Table -from sqlalchemy import Unicode +from sqlalchemy import Column, ForeignKey, Integer, Table, Unicode from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from sqlalchemy.orm.session import Session -from jupyterhub import orm -from jupyterhub import roles +from jupyterhub import orm, roles def upgrade(): diff --git a/jupyterhub/alembic/versions/833da8570507_rbac.py b/jupyterhub/alembic/versions/833da8570507_rbac.py index 2abecea9..ec3325ec 100644 --- a/jupyterhub/alembic/versions/833da8570507_rbac.py +++ b/jupyterhub/alembic/versions/833da8570507_rbac.py @@ -12,12 +12,11 @@ down_revision = '4dc2d5a8c53c' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op from jupyterhub import orm - naming_convention = orm.meta.naming_convention diff --git a/jupyterhub/alembic/versions/896818069c98_token_expires.py b/jupyterhub/alembic/versions/896818069c98_token_expires.py index b3f62411..e8d1a84d 100644 --- a/jupyterhub/alembic/versions/896818069c98_token_expires.py +++ b/jupyterhub/alembic/versions/896818069c98_token_expires.py @@ -11,8 +11,8 @@ down_revision = 'd68c98b66cd4' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op def upgrade(): diff --git a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py index 738ecbe3..42ca4b0b 100644 --- a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py +++ b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py @@ -12,11 +12,11 @@ branch_labels = None depends_on = None -from alembic import op -import sqlalchemy as sa - from datetime import datetime +import sqlalchemy as sa +from alembic import op + def upgrade(): op.add_column('users', sa.Column('created', sa.DateTime, nullable=True)) diff --git a/jupyterhub/alembic/versions/af4cbdb2d13c_services.py b/jupyterhub/alembic/versions/af4cbdb2d13c_services.py index a0f5e8e9..b33da18e 100644 --- a/jupyterhub/alembic/versions/af4cbdb2d13c_services.py +++ b/jupyterhub/alembic/versions/af4cbdb2d13c_services.py @@ -11,8 +11,8 @@ down_revision = 'eeb276e51423' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op def upgrade(): diff --git a/jupyterhub/alembic/versions/d68c98b66cd4_client_description.py b/jupyterhub/alembic/versions/d68c98b66cd4_client_description.py index 68a9b0ff..4eb0a81e 100644 --- a/jupyterhub/alembic/versions/d68c98b66cd4_client_description.py +++ b/jupyterhub/alembic/versions/d68c98b66cd4_client_description.py @@ -11,8 +11,8 @@ down_revision = '99a28a4418e1' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op def upgrade(): diff --git a/jupyterhub/alembic/versions/eeb276e51423_auth_state.py b/jupyterhub/alembic/versions/eeb276e51423_auth_state.py index 8ae54901..5b4df64b 100644 --- a/jupyterhub/alembic/versions/eeb276e51423_auth_state.py +++ b/jupyterhub/alembic/versions/eeb276e51423_auth_state.py @@ -12,8 +12,9 @@ down_revision = '19c0846f6344' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op + from jupyterhub.orm import JSONDict diff --git a/jupyterhub/apihandlers/__init__.py b/jupyterhub/apihandlers/__init__.py index 7900d8af..39733829 100644 --- a/jupyterhub/apihandlers/__init__.py +++ b/jupyterhub/apihandlers/__init__.py @@ -1,9 +1,4 @@ -from . import auth -from . import groups -from . import hub -from . import proxy -from . import services -from . import users +from . import auth, groups, hub, proxy, services, users from .base import * default_handlers = [] diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index aec972df..643e3a3a 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -4,22 +4,14 @@ import itertools import json from datetime import datetime -from urllib.parse import parse_qsl -from urllib.parse import quote -from urllib.parse import urlencode -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import parse_qsl, quote, urlencode, urlparse, urlunparse from oauthlib import oauth2 from tornado import web -from .. import orm -from .. import roles -from .. import scopes -from ..utils import get_browser_protocol -from ..utils import token_authenticated -from .base import APIHandler -from .base import BaseHandler +from .. import orm, roles, scopes +from ..utils import get_browser_protocol, token_authenticated +from .base import APIHandler, BaseHandler class TokenAPIHandler(APIHandler): diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index d46eedff..1658999c 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -4,10 +4,7 @@ import json from functools import lru_cache from http.client import responses -from urllib.parse import parse_qs -from urllib.parse import urlencode -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import parse_qs, urlencode, urlparse, urlunparse from sqlalchemy.exc import SQLAlchemyError from tornado import web @@ -15,9 +12,7 @@ from tornado import web from .. import orm from ..handlers import BaseHandler from ..scopes import get_scopes_for -from ..utils import get_browser_protocol -from ..utils import isoformat -from ..utils import url_path_join +from ..utils import get_browser_protocol, isoformat, url_path_join PAGINATION_MEDIA_TYPE = "application/jupyterhub-pagination+json" diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index dbe9fec2..89a59c3b 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -6,8 +6,7 @@ import json from tornado import web from .. import orm -from ..scopes import needs_scope -from ..scopes import Scope +from ..scopes import Scope, needs_scope from .base import APIHandler diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 280729aa..43e69aa7 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -6,8 +6,7 @@ Currently GET-only, no actions can be taken to modify services. # Distributed under the terms of the Modified BSD License. import json -from ..scopes import needs_scope -from ..scopes import Scope +from ..scopes import Scope, needs_scope from .base import APIHandler diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 9b0bd34a..6341c3b1 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -3,26 +3,19 @@ # Distributed under the terms of the Modified BSD License. import asyncio import json -from datetime import datetime -from datetime import timedelta -from datetime import timezone +from datetime import datetime, timedelta, timezone from async_generator import aclosing from dateutil.parser import parse as parse_date -from sqlalchemy import func -from sqlalchemy import or_ +from sqlalchemy import func, or_ from tornado import web from tornado.iostream import StreamClosedError -from .. import orm -from .. import scopes +from .. import orm, scopes from ..roles import assign_default_roles from ..scopes import needs_scope from ..user import User -from ..utils import isoformat -from ..utils import iterate_until -from ..utils import maybe_future -from ..utils import url_path_join +from ..utils import isoformat, iterate_until, maybe_future, url_path_join from .base import APIHandler diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 8c7b4055..b262c3fe 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -14,15 +14,11 @@ import socket import sys import time from concurrent.futures import ThreadPoolExecutor -from datetime import datetime -from datetime import timedelta -from datetime import timezone +from datetime import datetime, timedelta, timezone from getpass import getuser from operator import itemgetter from textwrap import dedent -from urllib.parse import unquote -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import unquote, urlparse, urlunparse if sys.version_info[:2] < (3, 3): raise ValueError("Python < 3.3 not supported: %s" % sys.version) @@ -36,78 +32,72 @@ except AttributeError as e: asyncio_all_tasks = asyncio.Task.all_tasks asyncio_current_task = asyncio.Task.current_task -from dateutil.parser import parse as parse_date -from jinja2 import Environment, FileSystemLoader, PrefixLoader, ChoiceLoader -from sqlalchemy.exc import OperationalError, SQLAlchemyError - -from tornado.httpclient import AsyncHTTPClient import tornado.httpserver -from tornado.ioloop import IOLoop, PeriodicCallback -from tornado.log import app_log, access_log, gen_log import tornado.options +from dateutil.parser import parse as parse_date +from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader +from jupyter_telemetry.eventlog import EventLog +from sqlalchemy.exc import OperationalError, SQLAlchemyError from tornado import gen, web - +from tornado.httpclient import AsyncHTTPClient +from tornado.ioloop import IOLoop, PeriodicCallback +from tornado.log import access_log, app_log, gen_log from traitlets import ( - Unicode, - Integer, - Dict, - List, - Bool, Any, - Tuple, - Set, - Instance, + Bool, Bytes, + Dict, Float, + Instance, + Integer, + List, + Set, + Tuple, + Unicode, Union, - observe, default, + observe, validate, ) from traitlets.config import Application, Configurable, catch_config_error -from jupyter_telemetry.eventlog import EventLog - here = os.path.dirname(__file__) import jupyterhub -from . import handlers, apihandlers -from .handlers.static import CacheControlStaticFilesHandler, LogoHandler -from .services.service import Service -from . import crypto -from . import dbutil -from . import orm -from . import roles -from . import scopes -from .user import UserDict -from .oauth.provider import make_provider +from . import apihandlers, crypto, dbutil, handlers, orm, roles, scopes from ._data import DATA_FILES_PATH -from .log import CoroutineLogFormatter, log_request -from .proxy import Proxy, ConfigurableHTTPProxy -from .traitlets import URLPrefix, Command, EntryPointType, Callable -from .utils import ( - AnyTimeoutError, - catch_db_error, - maybe_future, - url_path_join, - print_stacks, - print_ps_info, - make_ssl_context, -) -from .metrics import HUB_STARTUP_DURATION_SECONDS -from .metrics import INIT_SPAWNERS_DURATION_SECONDS -from .metrics import RUNNING_SERVERS -from .metrics import TOTAL_USERS # classes for config from .auth import Authenticator, PAMAuthenticator from .crypto import CryptKeeper -from .spawner import Spawner, LocalProcessSpawner -from .objects import Hub, Server # For faking stats from .emptyclass import EmptyClass +from .handlers.static import CacheControlStaticFilesHandler, LogoHandler +from .log import CoroutineLogFormatter, log_request +from .metrics import ( + HUB_STARTUP_DURATION_SECONDS, + INIT_SPAWNERS_DURATION_SECONDS, + RUNNING_SERVERS, + TOTAL_USERS, +) +from .oauth.provider import make_provider +from .objects import Hub, Server +from .proxy import ConfigurableHTTPProxy, Proxy +from .services.service import Service +from .spawner import LocalProcessSpawner, Spawner +from .traitlets import Callable, Command, EntryPointType, URLPrefix +from .user import UserDict +from .utils import ( + AnyTimeoutError, + catch_db_error, + make_ssl_context, + maybe_future, + print_ps_info, + print_stacks, + url_path_join, +) common_aliases = { 'log-level': 'Application.log_level', diff --git a/jupyterhub/auth.py b/jupyterhub/auth.py index 585d5242..36411b9a 100644 --- a/jupyterhub/auth.py +++ b/jupyterhub/auth.py @@ -9,9 +9,7 @@ import warnings from concurrent.futures import ThreadPoolExecutor from functools import partial from shutil import which -from subprocess import PIPE -from subprocess import Popen -from subprocess import STDOUT +from subprocess import PIPE, STDOUT, Popen try: import pamela @@ -20,13 +18,12 @@ except Exception as e: _pamela_error = e from tornado.concurrent import run_on_executor - +from traitlets import Any, Bool, Dict, Integer, Set, Unicode, default, observe from traitlets.config import LoggingConfigurable -from traitlets import Bool, Integer, Set, Unicode, Dict, Any, default, observe from .handlers.login import LoginHandler -from .utils import maybe_future, url_path_join from .traitlets import Command +from .utils import maybe_future, url_path_join class Authenticator(LoggingConfigurable): diff --git a/jupyterhub/crypto.py b/jupyterhub/crypto.py index 039201b1..854017f8 100644 --- a/jupyterhub/crypto.py +++ b/jupyterhub/crypto.py @@ -4,18 +4,12 @@ import os from binascii import a2b_hex from concurrent.futures import ThreadPoolExecutor -from traitlets import Any -from traitlets import default -from traitlets import Integer -from traitlets import List -from traitlets import observe -from traitlets import validate -from traitlets.config import Config -from traitlets.config import SingletonConfigurable +from traitlets import Any, Integer, List, default, observe, validate +from traitlets.config import Config, SingletonConfigurable try: import cryptography - from cryptography.fernet import Fernet, MultiFernet, InvalidToken + from cryptography.fernet import Fernet, InvalidToken, MultiFernet except ImportError: cryptography = None diff --git a/jupyterhub/handlers/__init__.py b/jupyterhub/handlers/__init__.py index 6af7659f..e39e5730 100644 --- a/jupyterhub/handlers/__init__.py +++ b/jupyterhub/handlers/__init__.py @@ -1,7 +1,4 @@ -from . import base -from . import login -from . import metrics -from . import pages +from . import base, login, metrics, pages from .base import * from .login import * diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 098601ff..45880f91 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -9,50 +9,43 @@ import random import re import time import uuid -from datetime import datetime -from datetime import timedelta +from datetime import datetime, timedelta from http.client import responses -from urllib.parse import parse_qs -from urllib.parse import parse_qsl -from urllib.parse import urlencode -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import parse_qs, parse_qsl, urlencode, urlparse, urlunparse from jinja2 import TemplateNotFound from sqlalchemy.exc import SQLAlchemyError -from tornado import gen -from tornado import web -from tornado.httputil import HTTPHeaders -from tornado.httputil import url_concat +from tornado import gen, web +from tornado.httputil import HTTPHeaders, url_concat from tornado.ioloop import IOLoop from tornado.log import app_log -from tornado.web import addslash -from tornado.web import RequestHandler +from tornado.web import RequestHandler, addslash -from .. import __version__ -from .. import orm -from .. import roles -from .. import scopes -from ..metrics import PROXY_ADD_DURATION_SECONDS -from ..metrics import PROXY_DELETE_DURATION_SECONDS -from ..metrics import ProxyDeleteStatus -from ..metrics import RUNNING_SERVERS -from ..metrics import SERVER_POLL_DURATION_SECONDS -from ..metrics import SERVER_SPAWN_DURATION_SECONDS -from ..metrics import SERVER_STOP_DURATION_SECONDS -from ..metrics import ServerPollStatus -from ..metrics import ServerSpawnStatus -from ..metrics import ServerStopStatus -from ..metrics import TOTAL_USERS +from .. import __version__, orm, roles, scopes +from ..metrics import ( + PROXY_ADD_DURATION_SECONDS, + PROXY_DELETE_DURATION_SECONDS, + RUNNING_SERVERS, + SERVER_POLL_DURATION_SECONDS, + SERVER_SPAWN_DURATION_SECONDS, + SERVER_STOP_DURATION_SECONDS, + TOTAL_USERS, + ProxyDeleteStatus, + ServerPollStatus, + ServerSpawnStatus, + ServerStopStatus, +) from ..objects import Server from ..scopes import needs_scope from ..spawner import LocalProcessSpawner from ..user import User -from ..utils import AnyTimeoutError -from ..utils import get_accepted_mimetype -from ..utils import get_browser_protocol -from ..utils import maybe_future -from ..utils import url_path_join +from ..utils import ( + AnyTimeoutError, + get_accepted_mimetype, + get_browser_protocol, + maybe_future, + url_path_join, +) # pattern for the authentication token header auth_header_pat = re.compile(r'^(?:token|bearer)\s+([^\s]+)$', flags=re.IGNORECASE) diff --git a/jupyterhub/handlers/metrics.py b/jupyterhub/handlers/metrics.py index 844a203f..674aeddd 100644 --- a/jupyterhub/handlers/metrics.py +++ b/jupyterhub/handlers/metrics.py @@ -1,7 +1,5 @@ """Handlers for serving prometheus metrics""" -from prometheus_client import CONTENT_TYPE_LATEST -from prometheus_client import generate_latest -from prometheus_client import REGISTRY +from prometheus_client import CONTENT_TYPE_LATEST, REGISTRY, generate_latest from ..utils import metrics_authentication from .base import BaseHandler diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index cd311375..b13f4e9c 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -12,11 +12,9 @@ from tornado import web from tornado.httputil import url_concat from .. import __version__ -from ..metrics import SERVER_POLL_DURATION_SECONDS -from ..metrics import ServerPollStatus +from ..metrics import SERVER_POLL_DURATION_SECONDS, ServerPollStatus from ..scopes import needs_scope -from ..utils import maybe_future -from ..utils import url_path_join +from ..utils import maybe_future, url_path_join from .base import BaseHandler diff --git a/jupyterhub/log.py b/jupyterhub/log.py index 47534ab7..4a9638f0 100644 --- a/jupyterhub/log.py +++ b/jupyterhub/log.py @@ -6,13 +6,10 @@ import logging import traceback from functools import partial from http.cookies import SimpleCookie -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import urlparse, urlunparse -from tornado.log import access_log -from tornado.log import LogFormatter -from tornado.web import HTTPError -from tornado.web import StaticFileHandler +from tornado.log import LogFormatter, access_log +from tornado.web import HTTPError, StaticFileHandler from .handlers.pages import HealthCheckHandler from .metrics import prometheus_log_method diff --git a/jupyterhub/metrics.py b/jupyterhub/metrics.py index ff58748f..051aeaaa 100644 --- a/jupyterhub/metrics.py +++ b/jupyterhub/metrics.py @@ -21,8 +21,7 @@ them manually here. """ from enum import Enum -from prometheus_client import Gauge -from prometheus_client import Histogram +from prometheus_client import Gauge, Histogram REQUEST_DURATION_SECONDS = Histogram( 'jupyterhub_request_duration_seconds', diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 267f3965..3e1c6e0e 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -3,19 +3,14 @@ implements https://oauthlib.readthedocs.io/en/latest/oauth2/server.html """ from oauthlib import uri_validate -from oauthlib.oauth2 import RequestValidator -from oauthlib.oauth2 import WebApplicationServer -from oauthlib.oauth2.rfc6749.grant_types import authorization_code -from oauthlib.oauth2.rfc6749.grant_types import base +from oauthlib.oauth2 import RequestValidator, WebApplicationServer +from oauthlib.oauth2.rfc6749.grant_types import authorization_code, base from tornado.log import app_log from .. import orm from ..roles import roles_to_scopes -from ..scopes import _check_scopes_exist -from ..scopes import access_scopes -from ..scopes import identify_scopes -from ..utils import compare_token -from ..utils import hash_token +from ..scopes import _check_scopes_exist, access_scopes, identify_scopes +from ..utils import compare_token, hash_token # patch absolute-uri check # because we want to allow relative uri oauth diff --git a/jupyterhub/objects.py b/jupyterhub/objects.py index f5893a3e..4fd215e8 100644 --- a/jupyterhub/objects.py +++ b/jupyterhub/objects.py @@ -3,25 +3,20 @@ # Distributed under the terms of the Modified BSD License. import socket import warnings -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import urlparse, urlunparse -from traitlets import default -from traitlets import HasTraits -from traitlets import Instance -from traitlets import Integer -from traitlets import observe -from traitlets import Unicode -from traitlets import validate +from traitlets import HasTraits, Instance, Integer, Unicode, default, observe, validate from . import orm from .traitlets import URLPrefix -from .utils import can_connect -from .utils import make_ssl_context -from .utils import random_port -from .utils import url_path_join -from .utils import wait_for_http_server -from .utils import wait_for_server +from .utils import ( + can_connect, + make_ssl_context, + random_port, + url_path_join, + wait_for_http_server, + wait_for_server, +) class Server(HasTraits): diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 39e7984b..2536eb70 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -3,47 +3,44 @@ # Distributed under the terms of the Modified BSD License. import enum import json -from base64 import decodebytes -from base64 import encodebytes -from datetime import datetime -from datetime import timedelta +from base64 import decodebytes, encodebytes +from datetime import datetime, timedelta import alembic.command import alembic.config from alembic.script import ScriptDirectory -from sqlalchemy import Boolean -from sqlalchemy import Column -from sqlalchemy import create_engine -from sqlalchemy import DateTime -from sqlalchemy import event -from sqlalchemy import exc -from sqlalchemy import ForeignKey -from sqlalchemy import inspect -from sqlalchemy import Integer -from sqlalchemy import MetaData -from sqlalchemy import or_ -from sqlalchemy import select -from sqlalchemy import Table -from sqlalchemy import Unicode +from sqlalchemy import ( + Boolean, + Column, + DateTime, + ForeignKey, + Integer, + MetaData, + Table, + Unicode, + create_engine, + event, + exc, + inspect, + or_, + select, +) from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import backref -from sqlalchemy.orm import interfaces -from sqlalchemy.orm import object_session -from sqlalchemy.orm import relationship -from sqlalchemy.orm import Session -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import ( + Session, + backref, + interfaces, + object_session, + relationship, + sessionmaker, +) from sqlalchemy.pool import StaticPool from sqlalchemy.sql.expression import bindparam -from sqlalchemy.types import LargeBinary -from sqlalchemy.types import Text -from sqlalchemy.types import TypeDecorator +from sqlalchemy.types import LargeBinary, Text, TypeDecorator from tornado.log import app_log from .roles import roles_to_scopes -from .utils import compare_token -from .utils import hash_token -from .utils import new_token -from .utils import random_port +from .utils import compare_token, hash_token, new_token, random_port # top-level variable for easier mocking in tests utcnow = datetime.utcnow diff --git a/jupyterhub/proxy.py b/jupyterhub/proxy.py index 477a6ccc..f09bda83 100644 --- a/jupyterhub/proxy.py +++ b/jupyterhub/proxy.py @@ -26,29 +26,18 @@ from subprocess import Popen from urllib.parse import quote from weakref import WeakKeyDictionary -from tornado.httpclient import AsyncHTTPClient -from tornado.httpclient import HTTPError -from tornado.httpclient import HTTPRequest +from tornado.httpclient import AsyncHTTPClient, HTTPError, HTTPRequest from tornado.ioloop import PeriodicCallback -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import Instance -from traitlets import Integer -from traitlets import observe -from traitlets import Unicode +from traitlets import Any, Bool, Dict, Instance, Integer, Unicode, default, observe from traitlets.config import LoggingConfigurable -from . import utils -from .metrics import CHECK_ROUTES_DURATION_SECONDS -from .metrics import PROXY_POLL_DURATION_SECONDS -from .objects import Server -from .utils import AnyTimeoutError -from .utils import exponential_backoff -from .utils import url_path_join from jupyterhub.traitlets import Command +from . import utils +from .metrics import CHECK_ROUTES_DURATION_SECONDS, PROXY_POLL_DURATION_SECONDS +from .objects import Server +from .utils import AnyTimeoutError, exponential_backoff, url_path_join + def _one_at_a_time(method): """decorator to limit an async method to be called only once diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index c892e5f2..afa77a25 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -7,8 +7,7 @@ from functools import wraps from sqlalchemy import func from tornado.log import app_log -from . import orm -from . import scopes +from . import orm, scopes def get_default_roles(): diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 8af2263b..25db5c7e 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -23,8 +23,7 @@ import sqlalchemy as sa from tornado import web from tornado.log import app_log -from . import orm -from . import roles +from . import orm, roles """when modifying the scope definitions, make sure that `docs/source/rbac/generate-scope-table.py` is run so that changes are reflected in the documentation and REST API description.""" diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index 716dfaac..a2d59b87 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -40,21 +40,12 @@ from urllib.parse import urlencode import requests from tornado.httputil import url_concat from tornado.log import app_log -from tornado.web import HTTPError -from tornado.web import RequestHandler -from traitlets import default -from traitlets import Dict -from traitlets import Instance -from traitlets import Integer -from traitlets import observe -from traitlets import Set -from traitlets import Unicode -from traitlets import validate +from tornado.web import HTTPError, RequestHandler +from traitlets import Dict, Instance, Integer, Set, Unicode, default, observe, validate from traitlets.config import SingletonConfigurable from ..scopes import _intersect_expanded_scopes -from ..utils import get_browser_protocol -from ..utils import url_path_join +from ..utils import get_browser_protocol, url_path_join def check_scopes(required_scopes, scopes): diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index db761c7e..57876222 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -45,21 +45,22 @@ import pipes import shutil from subprocess import Popen -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import HasTraits -from traitlets import Instance -from traitlets import List -from traitlets import Unicode -from traitlets import validate +from traitlets import ( + Any, + Bool, + Dict, + HasTraits, + Instance, + List, + Unicode, + default, + validate, +) from traitlets.config import LoggingConfigurable from .. import orm from ..objects import Server -from ..spawner import LocalProcessSpawner -from ..spawner import set_user_setuid +from ..spawner import LocalProcessSpawner, set_user_setuid from ..traitlets import Command from ..utils import url_path_join diff --git a/jupyterhub/singleuser/__init__.py b/jupyterhub/singleuser/__init__.py index 0b06e2f6..60159406 100644 --- a/jupyterhub/singleuser/__init__.py +++ b/jupyterhub/singleuser/__init__.py @@ -2,10 +2,8 @@ Contains default notebook-app subclass and mixins """ -from .app import main -from .app import SingleUserNotebookApp -from .mixins import HubAuthenticatedHandler -from .mixins import make_singleuser_app +from .app import SingleUserNotebookApp, main +from .mixins import HubAuthenticatedHandler, make_singleuser_app # backward-compatibility JupyterHubLoginHandler = SingleUserNotebookApp.login_handler_class diff --git a/jupyterhub/singleuser/mixins.py b/jupyterhub/singleuser/mixins.py index d2a5ec6a..43aae9e3 100755 --- a/jupyterhub/singleuser/mixins.py +++ b/jupyterhub/singleuser/mixins.py @@ -21,35 +21,29 @@ from importlib import import_module from textwrap import dedent from urllib.parse import urlparse -from jinja2 import ChoiceLoader -from jinja2 import FunctionLoader +from jinja2 import ChoiceLoader, FunctionLoader from tornado import ioloop -from tornado.httpclient import AsyncHTTPClient -from tornado.httpclient import HTTPRequest +from tornado.httpclient import AsyncHTTPClient, HTTPRequest from tornado.web import RequestHandler -from traitlets import Any -from traitlets import Bool -from traitlets import Bytes -from traitlets import CUnicode -from traitlets import default -from traitlets import import_item -from traitlets import Integer -from traitlets import observe -from traitlets import TraitError -from traitlets import Unicode -from traitlets import validate +from traitlets import ( + Any, + Bool, + Bytes, + CUnicode, + Integer, + TraitError, + Unicode, + default, + import_item, + observe, + validate, +) from traitlets.config import Configurable -from .._version import __version__ -from .._version import _check_version +from .._version import __version__, _check_version from ..log import log_request -from ..services.auth import HubOAuth -from ..services.auth import HubOAuthCallbackHandler -from ..services.auth import HubOAuthenticated -from ..utils import exponential_backoff -from ..utils import isoformat -from ..utils import make_ssl_context -from ..utils import url_path_join +from ..services.auth import HubOAuth, HubOAuthCallbackHandler, HubOAuthenticated +from ..utils import exponential_backoff, isoformat, make_ssl_context, url_path_join def _bool_env(key): diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index 9b755cfb..b28326f0 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -19,29 +19,31 @@ from urllib.parse import urlparse from async_generator import aclosing from sqlalchemy import inspect from tornado.ioloop import PeriodicCallback -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import Float -from traitlets import Instance -from traitlets import Integer -from traitlets import List -from traitlets import observe -from traitlets import Unicode -from traitlets import Union -from traitlets import validate +from traitlets import ( + Any, + Bool, + Dict, + Float, + Instance, + Integer, + List, + Unicode, + Union, + default, + observe, + validate, +) from traitlets.config import LoggingConfigurable from .objects import Server -from .traitlets import ByteSpecification -from .traitlets import Callable -from .traitlets import Command -from .utils import AnyTimeoutError -from .utils import exponential_backoff -from .utils import maybe_future -from .utils import random_port -from .utils import url_path_join +from .traitlets import ByteSpecification, Callable, Command +from .utils import ( + AnyTimeoutError, + exponential_backoff, + maybe_future, + random_port, + url_path_join, +) if os.name == 'nt': import psutil diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 7bb8b48c..60109bb1 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -35,22 +35,17 @@ from getpass import getuser from subprocess import TimeoutExpired from unittest import mock -from pytest import fixture -from pytest import raises +from pytest import fixture, raises from tornado import ioloop from tornado.httpclient import HTTPError from tornado.platform.asyncio import AsyncIOMainLoop import jupyterhub.services.service -from . import mocking -from .. import crypto -from .. import orm -from .. import scopes -from ..roles import create_role -from ..roles import get_default_roles -from ..roles import mock_roles -from ..roles import update_roles + +from .. import crypto, orm, scopes +from ..roles import create_role, get_default_roles, mock_roles, update_roles from ..utils import random_port +from . import mocking from .mocking import MockHub from .test_services import mockservice_cmd from .utils import add_user diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index bdb976df..2821d0b0 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -37,23 +37,15 @@ from urllib.parse import urlparse from pamela import PAMError from tornado.ioloop import IOLoop -from traitlets import Bool -from traitlets import default -from traitlets import Dict +from traitlets import Bool, Dict, default -from .. import metrics -from .. import orm -from .. import roles +from .. import metrics, orm, roles from ..app import JupyterHub from ..auth import PAMAuthenticator from ..singleuser import SingleUserNotebookApp from ..spawner import SimpleLocalProcessSpawner -from ..utils import random_port -from ..utils import utcnow -from .utils import async_requests -from .utils import public_host -from .utils import public_url -from .utils import ssl_setup +from ..utils import random_port, utcnow +from .utils import async_requests, public_host, public_url, ssl_setup def mock_authenticate(username, password, service, encoding): diff --git a/jupyterhub/tests/mockservice.py b/jupyterhub/tests/mockservice.py index b50a6c9b..0afa50eb 100644 --- a/jupyterhub/tests/mockservice.py +++ b/jupyterhub/tests/mockservice.py @@ -19,15 +19,14 @@ import sys from urllib.parse import urlparse import requests -from tornado import httpserver -from tornado import ioloop -from tornado import log -from tornado import web +from tornado import httpserver, ioloop, log, web from tornado.httputil import url_concat -from jupyterhub.services.auth import HubAuthenticated -from jupyterhub.services.auth import HubOAuthCallbackHandler -from jupyterhub.services.auth import HubOAuthenticated +from jupyterhub.services.auth import ( + HubAuthenticated, + HubOAuthCallbackHandler, + HubOAuthenticated, +) from jupyterhub.utils import make_ssl_context @@ -123,7 +122,7 @@ def main(): if __name__ == '__main__': - from tornado.options import parse_command_line, options + from tornado.options import options, parse_command_line parse_command_line() options.logging = 'debug' diff --git a/jupyterhub/tests/mocksu.py b/jupyterhub/tests/mocksu.py index c9f4b85e..8b0723b9 100644 --- a/jupyterhub/tests/mocksu.py +++ b/jupyterhub/tests/mocksu.py @@ -16,10 +16,7 @@ import os import sys from urllib.parse import urlparse -from tornado import httpserver -from tornado import ioloop -from tornado import log -from tornado import web +from tornado import httpserver, ioloop, log, web from tornado.options import options from ..utils import make_ssl_context diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index a34f2d35..ec95edfe 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -4,32 +4,23 @@ import json import re import sys import uuid -from datetime import datetime -from datetime import timedelta +from datetime import datetime, timedelta from unittest import mock -from urllib.parse import quote -from urllib.parse import urlparse -from urllib.parse import urlunparse +from urllib.parse import quote, urlparse, urlunparse -from pytest import fixture -from pytest import mark +from pytest import fixture, mark from tornado.httputil import url_concat import jupyterhub + from .. import orm from ..apihandlers.base import PAGINATION_MEDIA_TYPE from ..objects import Server from ..utils import url_path_join as ujoin from ..utils import utcnow from .conftest import new_username -from .mocking import public_host -from .mocking import public_url -from .utils import add_user -from .utils import api_request -from .utils import async_requests -from .utils import auth_header -from .utils import find_user - +from .mocking import public_host, public_url +from .utils import add_user, api_request, async_requests, auth_header, find_user # -------------------- # Authentication tests diff --git a/jupyterhub/tests/test_app.py b/jupyterhub/tests/test_app.py index 6f9ea75a..593bc33f 100644 --- a/jupyterhub/tests/test_app.py +++ b/jupyterhub/tests/test_app.py @@ -6,11 +6,8 @@ import os import re import sys import time -from subprocess import check_output -from subprocess import PIPE -from subprocess import Popen -from tempfile import NamedTemporaryFile -from tempfile import TemporaryDirectory +from subprocess import PIPE, Popen, check_output +from tempfile import NamedTemporaryFile, TemporaryDirectory from unittest.mock import patch import pytest @@ -18,8 +15,7 @@ import traitlets from traitlets.config import Config from .. import orm -from ..app import COOKIE_SECRET_BYTES -from ..app import JupyterHub +from ..app import COOKIE_SECRET_BYTES, JupyterHub from .mocking import MockHub from .test_api import add_user diff --git a/jupyterhub/tests/test_auth.py b/jupyterhub/tests/test_auth.py index 667a046d..db4fd8bc 100644 --- a/jupyterhub/tests/test_auth.py +++ b/jupyterhub/tests/test_auth.py @@ -10,16 +10,10 @@ from requests import HTTPError from traitlets import Any from traitlets.config import Config -from .mocking import MockPAMAuthenticator -from .mocking import MockStructGroup -from .mocking import MockStructPasswd -from .utils import add_user -from .utils import async_requests -from .utils import get_page -from .utils import public_url -from jupyterhub import auth -from jupyterhub import crypto -from jupyterhub import orm +from jupyterhub import auth, crypto, orm + +from .mocking import MockPAMAuthenticator, MockStructGroup, MockStructPasswd +from .utils import add_user, async_requests, get_page, public_url async def test_pam_auth(): diff --git a/jupyterhub/tests/test_auth_expiry.py b/jupyterhub/tests/test_auth_expiry.py index ea8049f9..5b750e79 100644 --- a/jupyterhub/tests/test_auth_expiry.py +++ b/jupyterhub/tests/test_auth_expiry.py @@ -9,13 +9,11 @@ authentication can expire in a number of ways: """ from contextlib import contextmanager from unittest import mock -from urllib.parse import parse_qs -from urllib.parse import urlparse +from urllib.parse import parse_qs, urlparse import pytest -from .utils import api_request -from .utils import get_page +from .utils import api_request, get_page async def refresh_expired(authenticator, user): diff --git a/jupyterhub/tests/test_crypto.py b/jupyterhub/tests/test_crypto.py index 31e888ad..20d5f62b 100644 --- a/jupyterhub/tests/test_crypto.py +++ b/jupyterhub/tests/test_crypto.py @@ -1,13 +1,11 @@ import os -from binascii import b2a_base64 -from binascii import b2a_hex +from binascii import b2a_base64, b2a_hex from unittest.mock import patch import pytest from .. import crypto -from ..crypto import decrypt -from ..crypto import encrypt +from ..crypto import decrypt, encrypt keys = [('%i' % i).encode('ascii') * 32 for i in range(3)] hex_keys = [b2a_hex(key).decode('ascii') for key in keys] diff --git a/jupyterhub/tests/test_db.py b/jupyterhub/tests/test_db.py index a4a39f12..9284df0d 100644 --- a/jupyterhub/tests/test_db.py +++ b/jupyterhub/tests/test_db.py @@ -9,8 +9,7 @@ from pytest import raises from traitlets.config import Config from .. import orm -from ..app import NewToken -from ..app import UpgradeDB +from ..app import NewToken, UpgradeDB from ..scopes import _check_scopes_exist here = os.path.abspath(os.path.dirname(__file__)) diff --git a/jupyterhub/tests/test_eventlog.py b/jupyterhub/tests/test_eventlog.py index 3cfbaec1..d8dcd285 100644 --- a/jupyterhub/tests/test_eventlog.py +++ b/jupyterhub/tests/test_eventlog.py @@ -16,7 +16,6 @@ from traitlets.config import Config from .mocking import MockHub - # To test new schemas, add them to the `valid_events` # and `invalid_events` dictionary below. diff --git a/jupyterhub/tests/test_internal_ssl_connections.py b/jupyterhub/tests/test_internal_ssl_connections.py index 0a8a306c..b2563578 100644 --- a/jupyterhub/tests/test_internal_ssl_connections.py +++ b/jupyterhub/tests/test_internal_ssl_connections.py @@ -4,8 +4,7 @@ import time from unittest import mock import pytest -from requests.exceptions import ConnectionError -from requests.exceptions import SSLError +from requests.exceptions import ConnectionError, SSLError from ..utils import AnyTimeoutError from .test_api import add_user diff --git a/jupyterhub/tests/test_metrics.py b/jupyterhub/tests/test_metrics.py index 795ca89d..072dba7b 100644 --- a/jupyterhub/tests/test_metrics.py +++ b/jupyterhub/tests/test_metrics.py @@ -3,11 +3,9 @@ from unittest import mock import pytest -from .utils import api_request -from .utils import get_page -from jupyterhub import metrics -from jupyterhub import orm -from jupyterhub import roles +from jupyterhub import metrics, orm, roles + +from .utils import api_request, get_page async def test_total_users(app): diff --git a/jupyterhub/tests/test_named_servers.py b/jupyterhub/tests/test_named_servers.py index ee1b3961..70564fc1 100644 --- a/jupyterhub/tests/test_named_servers.py +++ b/jupyterhub/tests/test_named_servers.py @@ -2,22 +2,15 @@ import asyncio import json from unittest import mock -from urllib.parse import urlencode -from urllib.parse import urlparse +from urllib.parse import urlencode, urlparse import pytest from tornado.httputil import url_concat from ..utils import url_path_join -from .mocking import FormSpawner -from .mocking import public_url -from .test_api import add_user -from .test_api import api_request -from .test_api import fill_user -from .test_api import normalize_user -from .test_api import TIMESTAMP -from .utils import async_requests -from .utils import get_page +from .mocking import FormSpawner, public_url +from .test_api import TIMESTAMP, add_user, api_request, fill_user, normalize_user +from .utils import async_requests, get_page @pytest.fixture diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index c9ed8c51..7a7f0310 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -3,17 +3,13 @@ # Distributed under the terms of the Modified BSD License. import os import socket -from datetime import datetime -from datetime import timedelta +from datetime import datetime, timedelta from unittest import mock import pytest from tornado import gen -from .. import crypto -from .. import objects -from .. import orm -from .. import roles +from .. import crypto, objects, orm, roles from ..emptyclass import EmptyClass from ..user import User from .mocking import MockSpawner diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index a4f3e805..5d3911bb 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -2,31 +2,28 @@ import asyncio import sys from unittest import mock -from urllib.parse import parse_qs -from urllib.parse import urlencode -from urllib.parse import urlparse +from urllib.parse import parse_qs, urlencode, urlparse import pytest from bs4 import BeautifulSoup from tornado.escape import url_escape from tornado.httputil import url_concat -from .. import orm -from .. import roles -from .. import scopes +from .. import orm, roles, scopes from ..auth import Authenticator from ..handlers import BaseHandler from ..utils import url_path_join from ..utils import url_path_join as ujoin -from .mocking import FalsyCallableFormSpawner -from .mocking import FormSpawner +from .mocking import FalsyCallableFormSpawner, FormSpawner from .test_api import next_event -from .utils import api_request -from .utils import async_requests -from .utils import AsyncSession -from .utils import get_page -from .utils import public_host -from .utils import public_url +from .utils import ( + AsyncSession, + api_request, + async_requests, + get_page, + public_host, + public_url, +) async def test_root_no_auth(app): diff --git a/jupyterhub/tests/test_proxy.py b/jupyterhub/tests/test_proxy.py index dafa29cd..a9caa3ea 100644 --- a/jupyterhub/tests/test_proxy.py +++ b/jupyterhub/tests/test_proxy.py @@ -3,8 +3,7 @@ import json import os from contextlib import contextmanager from subprocess import Popen -from urllib.parse import quote -from urllib.parse import urlparse +from urllib.parse import quote, urlparse import pytest from traitlets.config import Config @@ -12,8 +11,7 @@ from traitlets.config import Config from ..utils import url_path_join as ujoin from ..utils import wait_for_http_server from .mocking import MockHub -from .test_api import add_user -from .test_api import api_request +from .test_api import add_user, api_request from .utils import skip_if_ssl diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 2ef1e69b..b62d9a22 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -8,14 +8,11 @@ import pytest from pytest import mark from tornado.log import app_log -from .. import orm -from .. import roles -from ..scopes import get_scopes_for -from ..scopes import scope_definitions +from .. import orm, roles +from ..scopes import get_scopes_for, scope_definitions from ..utils import utcnow from .mocking import MockHub -from .utils import add_user -from .utils import api_request +from .utils import add_user, api_request @mark.role diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 3548b54c..f8a08b4b 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -7,22 +7,20 @@ from pytest import mark from tornado import web from tornado.httputil import HTTPServerRequest -from .. import orm -from .. import roles -from .. import scopes +from .. import orm, roles, scopes from ..handlers import BaseHandler -from ..scopes import _check_scope_access -from ..scopes import _expand_self_scope -from ..scopes import _intersect_expanded_scopes -from ..scopes import expand_scopes -from ..scopes import get_scopes_for -from ..scopes import identify_scopes -from ..scopes import needs_scope -from ..scopes import parse_scopes -from ..scopes import Scope -from .utils import add_user -from .utils import api_request -from .utils import auth_header +from ..scopes import ( + Scope, + _check_scope_access, + _expand_self_scope, + _intersect_expanded_scopes, + expand_scopes, + get_scopes_for, + identify_scopes, + needs_scope, + parse_scopes, +) +from .utils import add_user, api_request, auth_header def get_handler_with_scopes(scopes): diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 55f2b6bb..a858553b 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -8,14 +8,15 @@ from async_generator import asynccontextmanager from .. import orm from ..roles import update_roles -from ..utils import exponential_backoff -from ..utils import maybe_future -from ..utils import random_port -from ..utils import url_path_join -from ..utils import wait_for_http_server +from ..utils import ( + exponential_backoff, + maybe_future, + random_port, + url_path_join, + wait_for_http_server, +) from .mocking import public_url -from .utils import async_requests -from .utils import skip_if_ssl +from .utils import async_requests, skip_if_ssl mockservice_path = os.path.dirname(os.path.abspath(__file__)) mockservice_py = os.path.join(mockservice_path, 'mockservice.py') diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 0eb8c783..0d25ddf2 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -4,9 +4,7 @@ import os import sys from binascii import hexlify from unittest import mock -from urllib.parse import parse_qs -from urllib.parse import quote -from urllib.parse import urlparse +from urllib.parse import parse_qs, quote, urlparse import pytest from bs4 import BeautifulSoup @@ -14,14 +12,11 @@ from pytest import raises from tornado.httputil import url_concat from tornado.log import app_log -from .. import orm -from .. import roles -from .. import scopes +from .. import orm, roles, scopes from ..services.auth import _ExpiringDict from ..utils import url_path_join from .mocking import public_url -from .utils import async_requests -from .utils import AsyncSession +from .utils import AsyncSession, async_requests # mock for sending monotonic counter way into the future monotonic_future = mock.patch('time.monotonic', lambda: sys.maxsize) diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index 89dbb8f9..828138e1 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -2,20 +2,18 @@ import os import sys from contextlib import contextmanager -from subprocess import CalledProcessError -from subprocess import check_output +from subprocess import CalledProcessError, check_output from unittest import mock from urllib.parse import urlparse import pytest import jupyterhub + from .. import orm from ..utils import url_path_join -from .mocking import public_url -from .mocking import StubSingleUserSpawner -from .utils import async_requests -from .utils import AsyncSession +from .mocking import StubSingleUserSpawner, public_url +from .utils import AsyncSession, async_requests @contextmanager diff --git a/jupyterhub/tests/test_spawner.py b/jupyterhub/tests/test_spawner.py index 4c01944e..1cc0332a 100644 --- a/jupyterhub/tests/test_spawner.py +++ b/jupyterhub/tests/test_spawner.py @@ -16,14 +16,10 @@ import pytest from .. import orm from .. import spawner as spawnermod -from ..objects import Hub -from ..objects import Server -from ..spawner import LocalProcessSpawner -from ..spawner import Spawner +from ..objects import Hub, Server +from ..spawner import LocalProcessSpawner, Spawner from ..user import User -from ..utils import AnyTimeoutError -from ..utils import new_token -from ..utils import url_path_join +from ..utils import AnyTimeoutError, new_token, url_path_join from .mocking import public_url from .test_api import add_user from .utils import async_requests diff --git a/jupyterhub/tests/test_traitlets.py b/jupyterhub/tests/test_traitlets.py index 416b532d..8ee21208 100644 --- a/jupyterhub/tests/test_traitlets.py +++ b/jupyterhub/tests/test_traitlets.py @@ -1,10 +1,7 @@ import pytest -from traitlets import HasTraits -from traitlets import TraitError +from traitlets import HasTraits, TraitError -from jupyterhub.traitlets import ByteSpecification -from jupyterhub.traitlets import Command -from jupyterhub.traitlets import URLPrefix +from jupyterhub.traitlets import ByteSpecification, Command, URLPrefix def test_url_prefix(): diff --git a/jupyterhub/tests/test_version.py b/jupyterhub/tests/test_version.py index db9fdd82..789f420b 100644 --- a/jupyterhub/tests/test_version.py +++ b/jupyterhub/tests/test_version.py @@ -3,8 +3,7 @@ import logging import pytest -from .._version import _check_version -from .._version import reset_globals +from .._version import _check_version, reset_globals def setup_function(function): diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index d300c84a..2e535d4b 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -7,11 +7,9 @@ import pytest import requests from certipy import Certipy -from jupyterhub import metrics -from jupyterhub import orm +from jupyterhub import metrics, orm from jupyterhub.objects import Server -from jupyterhub.roles import assign_default_roles -from jupyterhub.roles import update_roles +from jupyterhub.roles import assign_default_roles, update_roles from jupyterhub.utils import url_path_join as ujoin diff --git a/jupyterhub/traitlets.py b/jupyterhub/traitlets.py index 0cc616a9..543dfcff 100644 --- a/jupyterhub/traitlets.py +++ b/jupyterhub/traitlets.py @@ -4,13 +4,7 @@ Traitlets that are used in JupyterHub # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import entrypoints -from traitlets import Integer -from traitlets import List -from traitlets import TraitError -from traitlets import TraitType -from traitlets import Type -from traitlets import Undefined -from traitlets import Unicode +from traitlets import Integer, List, TraitError, TraitType, Type, Undefined, Unicode class URLPrefix(Unicode): diff --git a/jupyterhub/user.py b/jupyterhub/user.py index 71ee6ce5..05a555db 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -3,34 +3,21 @@ import json import warnings from collections import defaultdict -from datetime import datetime -from datetime import timedelta -from urllib.parse import quote -from urllib.parse import urlparse +from datetime import datetime, timedelta +from urllib.parse import quote, urlparse from sqlalchemy import inspect -from tornado import gen -from tornado import web +from tornado import gen, web from tornado.httputil import urlencode from tornado.log import app_log from . import orm -from ._version import __version__ -from ._version import _check_version -from .crypto import CryptKeeper -from .crypto import decrypt -from .crypto import encrypt -from .crypto import EncryptionUnavailable -from .crypto import InvalidToken -from .metrics import RUNNING_SERVERS -from .metrics import TOTAL_USERS +from ._version import __version__, _check_version +from .crypto import CryptKeeper, EncryptionUnavailable, InvalidToken, decrypt, encrypt +from .metrics import RUNNING_SERVERS, TOTAL_USERS from .objects import Server from .spawner import LocalProcessSpawner -from .utils import AnyTimeoutError -from .utils import make_ssl_context -from .utils import maybe_future -from .utils import url_path_join - +from .utils import AnyTimeoutError, make_ssl_context, maybe_future, url_path_join # detailed messages about the most common failure-to-start errors, # which manifest timeouts during start diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index aa3fa7f7..44bdaef9 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -16,18 +16,14 @@ import threading import uuid import warnings from binascii import b2a_hex -from datetime import datetime -from datetime import timezone +from datetime import datetime, timezone from hmac import compare_digest from operator import itemgetter from async_generator import aclosing from sqlalchemy.exc import SQLAlchemyError -from tornado import gen -from tornado import ioloop -from tornado import web -from tornado.httpclient import AsyncHTTPClient -from tornado.httpclient import HTTPError +from tornado import gen, ioloop, web +from tornado.httpclient import AsyncHTTPClient, HTTPError from tornado.log import app_log # For compatibility with python versions 3.6 or earlier. @@ -477,6 +473,7 @@ def print_stacks(file=sys.stderr): # no need to add them to startup import asyncio import traceback + from .log import coroutine_frames print("Active threads: %i" % threading.active_count(), file=file) diff --git a/setup.py b/setup.py index aaae3498..3fcbdffe 100755 --- a/setup.py +++ b/setup.py @@ -9,13 +9,11 @@ import shutil import sys from subprocess import check_call -from setuptools import Command -from setuptools import setup +from setuptools import Command, setup from setuptools.command.bdist_egg import bdist_egg from setuptools.command.build_py import build_py from setuptools.command.sdist import sdist - v = sys.version_info if v[:2] < (3, 6): error = "ERROR: JupyterHub requires Python version 3.6 or above."