From ef8816b7108de4ff35dbb2a31fd4ec0274acea9b Mon Sep 17 00:00:00 2001 From: Francesco Bartoli Date: Sat, 6 Apr 2024 20:45:51 +0200 Subject: [PATCH] Fix ordering python imports --- .pre-commit-config.yaml | 12 ++--- app/auth/auth_interface.py | 1 + app/auth/auth_jwks.py | 10 ++-- app/auth/models.py | 8 ++- app/auth/oauth2.py | 4 +- app/config/app.py | 1 + app/config/auth.py | 9 ++-- app/config/logging.py | 4 +- app/main.py | 26 +++++----- app/middleware/oauth2.py | 9 ++-- app/middleware/pygeoapi.py | 7 +-- app/pygeoapi/openapi.py | 7 +-- app/schemas/logging.py | 1 + app/utils/app_exceptions.py | 1 + ...get_list_of_app_exceptions_for_frontend.py | 2 +- app/utils/request_exceptions.py | 1 + app/utils/service_result.py | 2 +- cli.py | 12 ++--- noxfile.py | 1 + pygeoapi-openapi.yml | 49 +++++++++++++++++++ scripts/docker/build.py | 2 +- tests/conftest.py | 1 + tests/test_cli.py | 4 +- tests/test_openapi_contract.py | 2 +- 24 files changed, 121 insertions(+), 55 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cf4db90..0f1b920 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,12 +40,6 @@ repos: language: system types: [python] args: [--py37-plus] - - id: reorder-python-imports - name: Reorder python imports - entry: reorder-python-imports - language: system - types: [python] - args: [--application-directories=app] - id: trailing-whitespace name: Trim Trailing Whitespace entry: trailing-whitespace-fixer @@ -56,3 +50,9 @@ repos: rev: v2.4.1 hooks: - id: prettier + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + name: isort + args: ["--force-single-line", "--line-length=100", "--profile=black"] diff --git a/app/auth/auth_interface.py b/app/auth/auth_interface.py index 6c6785a..80e58a3 100644 --- a/app/auth/auth_interface.py +++ b/app/auth/auth_interface.py @@ -1,4 +1,5 @@ """Auth interface module.""" + from abc import ABC from abc import abstractmethod from typing import Dict diff --git a/app/auth/auth_jwks.py b/app/auth/auth_jwks.py index 00a0506..ed45867 100644 --- a/app/auth/auth_jwks.py +++ b/app/auth/auth_jwks.py @@ -1,20 +1,22 @@ """Auth JWKS module.""" + import typing from dataclasses import dataclass from dataclasses import field import httpx -from app.auth.auth_interface import AuthInterface -from app.auth.exceptions import Oauth2Error -from app.config.logging import create_logger -from authlib.jose import errors from authlib.jose import JsonWebKey from authlib.jose import JsonWebToken from authlib.jose import JWTClaims from authlib.jose import KeySet +from authlib.jose import errors from starlette.requests import Request from starlette.responses import RedirectResponse +from app.auth.auth_interface import AuthInterface +from app.auth.exceptions import Oauth2Error +from app.config.logging import create_logger + # from cachetools import cached # from cachetools import TTLCache diff --git a/app/auth/models.py b/app/auth/models.py index d200569..197fb80 100644 --- a/app/auth/models.py +++ b/app/auth/models.py @@ -1,9 +1,7 @@ -from openapi_pydantic.v3.v3_0_3 import Response +"""Authentication models module.""" +from openapi_pydantic.v3.v3_0_3 import Response unauthorized = { - "401": Response( - description="Unauthorized response", - message="Unauthenticated" - ) + "401": Response(description="Unauthorized response", message="Unauthenticated") } diff --git a/app/auth/oauth2.py b/app/auth/oauth2.py index 690122c..ea07e13 100644 --- a/app/auth/oauth2.py +++ b/app/auth/oauth2.py @@ -1,13 +1,15 @@ """OAuth2 provider module.""" + import re from abc import ABC from abc import abstractmethod from typing import List from typing import Optional -from app.auth.auth_interface import AuthInterface from starlette.requests import Request +from app.auth.auth_interface import AuthInterface + class Injectable(ABC): """Define interface for injectables.""" diff --git a/app/config/app.py b/app/config/app.py index 7c2173f..7061705 100644 --- a/app/config/app.py +++ b/app/config/app.py @@ -1,4 +1,5 @@ """App configuration module.""" + from functools import lru_cache from typing import Optional diff --git a/app/config/auth.py b/app/config/auth.py index 558b4db..9e87747 100644 --- a/app/config/auth.py +++ b/app/config/auth.py @@ -1,12 +1,13 @@ """Authn and Authz module.""" -from app.auth.auth_jwks import JWKSAuthentication -from app.auth.auth_jwks import JWKSConfig -from app.auth.oauth2 import Oauth2Provider -from app.config.app import configuration as cfg + from fastapi_opa import OPAConfig from fastapi_opa.auth import OIDCAuthentication from fastapi_opa.auth import OIDCConfig +from app.auth.auth_jwks import JWKSAuthentication +from app.auth.auth_jwks import JWKSConfig +from app.auth.oauth2 import Oauth2Provider +from app.config.app import configuration as cfg # The hostname of your Open Policy Agent instance opa_host = cfg.OPA_URL diff --git a/app/config/logging.py b/app/config/logging.py index 12475a1..34ca7e0 100644 --- a/app/config/logging.py +++ b/app/config/logging.py @@ -1,12 +1,14 @@ """Logging module.""" + import logging import sys from pathlib import Path +from loguru import logger + from app.config.app import configuration as cfg from app.schemas.logging import LoggerModel from app.schemas.logging import LoggingBase -from loguru import logger class InterceptHandler(logging.Handler): diff --git a/app/main.py b/app/main.py index a1c7200..b251a9c 100644 --- a/app/main.py +++ b/app/main.py @@ -1,4 +1,5 @@ """Main module.""" + import os import sys from pathlib import Path @@ -6,16 +7,6 @@ import loguru import uvicorn -from app.config.app import configuration as cfg -from app.config.logging import create_logger -from app.middleware.oauth2 import Oauth2Middleware -from app.middleware.pygeoapi import OpenapiSecurityMiddleware -from app.utils.app_exceptions import app_exception_handler -from app.utils.app_exceptions import AppExceptionError -from app.utils.pygeoapi_exceptions import PygeoapiEnvError -from app.utils.pygeoapi_exceptions import PygeoapiLanguageError -from app.utils.request_exceptions import http_exception_handler -from app.utils.request_exceptions import request_validation_exception_handler from fastapi import FastAPI from fastapi.exceptions import RequestValidationError from fastapi_opa import OPAMiddleware @@ -24,13 +15,22 @@ from openapi_pydantic.v3.v3_0_3 import OAuthFlow from openapi_pydantic.v3.v3_0_3 import OAuthFlows from openapi_pydantic.v3.v3_0_3 import SecurityScheme -from starlette.exceptions import HTTPException as StarletteHTTPException -from starlette.middleware.cors import CORSMiddleware - from pygeoapi.l10n import LocaleError from pygeoapi.openapi import generate_openapi_document from pygeoapi.provider.base import ProviderConnectionError +from starlette.exceptions import HTTPException as StarletteHTTPException +from starlette.middleware.cors import CORSMiddleware +from app.config.app import configuration as cfg +from app.config.logging import create_logger +from app.middleware.oauth2 import Oauth2Middleware +from app.middleware.pygeoapi import OpenapiSecurityMiddleware +from app.utils.app_exceptions import AppExceptionError +from app.utils.app_exceptions import app_exception_handler +from app.utils.pygeoapi_exceptions import PygeoapiEnvError +from app.utils.pygeoapi_exceptions import PygeoapiLanguageError +from app.utils.request_exceptions import http_exception_handler +from app.utils.request_exceptions import request_validation_exception_handler if cfg.LOG_LEVEL == "debug": logger.remove() diff --git a/app/middleware/oauth2.py b/app/middleware/oauth2.py index 5add409..d8a4da2 100644 --- a/app/middleware/oauth2.py +++ b/app/middleware/oauth2.py @@ -1,13 +1,10 @@ """OAuth2 middleware module.""" + import asyncio import re from typing import List from typing import Optional -from app.auth.exceptions import Oauth2Error -from app.auth.oauth2 import Oauth2Provider -from app.config.app import configuration as cfg -from app.config.logging import create_logger from fastapi.responses import JSONResponse from starlette.requests import Request from starlette.responses import RedirectResponse @@ -16,6 +13,10 @@ from starlette.types import Scope from starlette.types import Send +from app.auth.exceptions import Oauth2Error +from app.auth.oauth2 import Oauth2Provider +from app.config.app import configuration as cfg +from app.config.logging import create_logger logger = create_logger("app.middleware.oauth2") diff --git a/app/middleware/pygeoapi.py b/app/middleware/pygeoapi.py index 19e1e36..45ddacf 100644 --- a/app/middleware/pygeoapi.py +++ b/app/middleware/pygeoapi.py @@ -1,11 +1,9 @@ """Openapi middleware module.""" + from typing import Any from typing import Dict from typing import List -from app.config.app import configuration as cfg -from app.config.logging import create_logger -from app.pygeoapi.openapi import augment_security from openapi_pydantic.v3.v3_0_3 import SecurityScheme from starlette.datastructures import Headers from starlette.datastructures import MutableHeaders @@ -15,6 +13,9 @@ from starlette.types import Scope from starlette.types import Send +from app.config.app import configuration as cfg +from app.config.logging import create_logger +from app.pygeoapi.openapi import augment_security logger = create_logger("app.middleware.pygeoapi") diff --git a/app/pygeoapi/openapi.py b/app/pygeoapi/openapi.py index 326b22b..93fa005 100644 --- a/app/pygeoapi/openapi.py +++ b/app/pygeoapi/openapi.py @@ -1,13 +1,14 @@ """Override vanilla openapi module.""" + from typing import List -from app.auth.models import unauthorized -from app.config.app import configuration as cfg -from app.config.logging import create_logger from openapi_pydantic.v3.v3_0_3 import OpenAPI from openapi_pydantic.v3.v3_0_3 import SecurityScheme from pydantic_core import ValidationError +from app.auth.models import unauthorized +from app.config.app import configuration as cfg +from app.config.logging import create_logger logger = create_logger("app.pygeoapi.openapi") diff --git a/app/schemas/logging.py b/app/schemas/logging.py index e3dbe4e..e7da410 100644 --- a/app/schemas/logging.py +++ b/app/schemas/logging.py @@ -1,4 +1,5 @@ """Logging module.""" + from pathlib import Path from pydantic import BaseModel diff --git a/app/utils/app_exceptions.py b/app/utils/app_exceptions.py index 889458f..068fd68 100644 --- a/app/utils/app_exceptions.py +++ b/app/utils/app_exceptions.py @@ -1,4 +1,5 @@ """App exceptions module.""" + from fastapi import Request from starlette.responses import JSONResponse diff --git a/app/utils/get_list_of_app_exceptions_for_frontend.py b/app/utils/get_list_of_app_exceptions_for_frontend.py index ed59836..d29a0fb 100644 --- a/app/utils/get_list_of_app_exceptions_for_frontend.py +++ b/app/utils/get_list_of_app_exceptions_for_frontend.py @@ -1,8 +1,8 @@ """App exceptions for frontend module.""" + from app.config.logging import create_logger from app.utils.app_exceptions import AppException - logger = create_logger( name="app.utils.get_list_of_app_exceptions_for_frontend", ) diff --git a/app/utils/request_exceptions.py b/app/utils/request_exceptions.py index 7e48664..b581856 100644 --- a/app/utils/request_exceptions.py +++ b/app/utils/request_exceptions.py @@ -1,4 +1,5 @@ """Request exceptions module.""" + from fastapi.encoders import jsonable_encoder from fastapi.exceptions import RequestValidationError from starlette.exceptions import HTTPException diff --git a/app/utils/service_result.py b/app/utils/service_result.py index d284833..5b9d973 100644 --- a/app/utils/service_result.py +++ b/app/utils/service_result.py @@ -1,10 +1,10 @@ """Service result module.""" + import inspect from app.config.logging import create_logger from app.utils.app_exceptions import AppExceptionError - logger = create_logger("app.utils.service_result") diff --git a/cli.py b/cli.py index c416118..f68106c 100644 --- a/cli.py +++ b/cli.py @@ -1,21 +1,21 @@ """Command-line interface.""" + import os from pathlib import Path import typer -from app.config.app import configuration as cfg -from app.pygeoapi.openapi import augment_security -from app.utils.pygeoapi_exceptions import PygeoapiEnvError -from app.utils.pygeoapi_exceptions import PygeoapiLanguageError from openapi_pydantic.v3.v3_0_3 import OAuthFlow from openapi_pydantic.v3.v3_0_3 import OAuthFlows from openapi_pydantic.v3.v3_0_3 import SecurityScheme -from rich.console import Console - from pygeoapi.l10n import LocaleError from pygeoapi.openapi import generate_openapi_document from pygeoapi.provider.base import ProviderConnectionError +from rich.console import Console +from app.config.app import configuration as cfg +from app.pygeoapi.openapi import augment_security +from app.utils.pygeoapi_exceptions import PygeoapiEnvError +from app.utils.pygeoapi_exceptions import PygeoapiLanguageError log_console = Console() err_console = Console(stderr=True, style="bold red") diff --git a/noxfile.py b/noxfile.py index 260c66d..10dc38d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,4 +1,5 @@ """Nox sessions.""" + import os import shutil import sys diff --git a/pygeoapi-openapi.yml b/pygeoapi-openapi.yml index 5577241..37e9994 100644 --- a/pygeoapi-openapi.yml +++ b/pygeoapi-openapi.yml @@ -110,6 +110,13 @@ components: type: string type: array style: form + resourceId: + description: Configuration resource identifier + in: path + name: resourceId + required: true + schema: + type: string skipGeometry: description: This option can be used to skip response geometries for each feature. explode: false @@ -377,6 +384,7 @@ paths: tags: - lakes options: + description: lakes of the world, public domain operationId: optionsLakesFeatures responses: "200": @@ -406,6 +414,7 @@ paths: tags: - lakes options: + description: lakes of the world, public domain operationId: optionsLakesFeature parameters: - $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId @@ -434,6 +443,25 @@ paths: summary: Get Large Lakes queryables tags: - lakes + /collections/lakes/schema: + get: + description: lakes of the world, public domain + operationId: getLakesQueryables + parameters: + - *id001 + - *id002 + responses: + "200": + $ref: "#/components/responses/Queryables" + "400": + $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter + "404": + $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound + "500": + $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError + summary: Get Large Lakes schema + tags: + - lakes /collections/obs: get: description: My cool observations @@ -526,6 +554,7 @@ paths: tags: - obs options: + description: My cool observations operationId: optionsObsFeatures responses: "200": @@ -555,6 +584,7 @@ paths: tags: - obs options: + description: My cool observations operationId: optionsObsFeature parameters: - $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId @@ -583,6 +613,25 @@ paths: summary: Get Observations queryables tags: - obs + /collections/obs/schema: + get: + description: My cool observations + operationId: getObsQueryables + parameters: + - *id001 + - *id002 + responses: + "200": + $ref: "#/components/responses/Queryables" + "400": + $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter + "404": + $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound + "500": + $ref: https://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError + summary: Get Observations schema + tags: + - obs /conformance: get: description: API conformance definition diff --git a/scripts/docker/build.py b/scripts/docker/build.py index 83499d8..35bb23d 100644 --- a/scripts/docker/build.py +++ b/scripts/docker/build.py @@ -1,4 +1,5 @@ """Build the Dockerfile.""" + import logging import shlex import shutil @@ -8,7 +9,6 @@ import typer - logger = logging.getLogger(__name__) diff --git a/tests/conftest.py b/tests/conftest.py index dc038d5..6ed51ee 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ """Configuration for tests.""" + import os import sys from unittest import mock diff --git a/tests/test_cli.py b/tests/test_cli.py index 753a7af..ae4e8e7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,7 +1,9 @@ """Test cases for the cli module.""" -from cli import app + from typer.testing import CliRunner +from cli import app + def test_openapi_succeeds(runner: CliRunner) -> None: """It exits with a status code of zero.""" diff --git a/tests/test_openapi_contract.py b/tests/test_openapi_contract.py index 3ad972c..952bba9 100644 --- a/tests/test_openapi_contract.py +++ b/tests/test_openapi_contract.py @@ -1,6 +1,6 @@ """OpenAPI contract tests module.""" -import schemathesis +import schemathesis schema = schemathesis.from_pytest_fixture("protected_apikey_schema")