Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update python dependencies #151

Merged
merged 28 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d54dd65
Fix openapi security scheme
francbartoli Aug 20, 2023
082f97f
Set running port from configuration
francbartoli Aug 20, 2023
48e3a1e
Add docker image build script
francbartoli Aug 20, 2023
f69ba2a
Add dynamic configuration for base path
francbartoli Aug 21, 2023
c984029
Update fastapi
francbartoli Aug 21, 2023
d8c4988
Make .env more sanitized
francbartoli Aug 21, 2023
2c4214a
Remove python 3.8
francbartoli Aug 21, 2023
0ecd5b8
Fix precommit
francbartoli Aug 22, 2023
acf4500
Fix safety
francbartoli Aug 22, 2023
04079b2
Merge remote-tracking branch 'origin/develop' into develop
francbartoli Aug 22, 2023
69edb1f
build(pyproject.toml): Add commitizen
francbartoli Aug 25, 2023
2d0fea3
fix(pyproject.toml): Fix backend dependency for pygeofilter
francbartoli Aug 25, 2023
864f40e
build(pyproject.toml): Update dependencies
francbartoli Aug 27, 2023
498ebf1
Fix base url in pygeoapi configuration
francbartoli Oct 3, 2023
61c9615
Update to pydantic v2
francbartoli Oct 3, 2023
6d52f59
fix(noxfile.py): Clean safety issue with rasterio and update mypy
francbartoli Oct 3, 2023
74e478c
fix(mypy.ini): Fix mypy errors
francbartoli Oct 3, 2023
c90cc51
feat(Config): Add config cache
francbartoli Oct 3, 2023
6a37a1f
test(noxfile.py): Add vulnerabilities testing and update dependencies
francbartoli Oct 21, 2023
56fe1ed
Execute bandit nox session
francbartoli Oct 21, 2023
c4a6db9
Fix pydantic v2 migration
francbartoli Oct 21, 2023
a403f52
feat(cli.py): Add command for enriched openapi document generation
francbartoli Oct 21, 2023
3eb4346
fix(test_cli.py): Fix openapi test
francbartoli Oct 22, 2023
e18d5d8
Clean dependencies
francbartoli Oct 22, 2023
712b39d
Update dependencies
francbartoli Dec 25, 2023
837a10b
Update dependencies for github action workflow
francbartoli Dec 25, 2023
ba367f8
Update pip version
francbartoli Dec 26, 2023
8319143
Ignore mypy errors for pydantic env argument
francbartoli Dec 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[flake8]
select = B,B9,C,D,DAR,E,F,N,RST,S,W
ignore = E203,E501,RST201,RST203,RST301,W503
ignore = E203,E501,RST201,RST203,RST301,W503,C901
max-line-length = 80
max-complexity = 10
docstring-convention = google
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/constraints.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pip==23.2
pip==23.3.2
nox==2023.4.22
nox-poetry==1.0.2
poetry==1.4.0
virtualenv==20.20.0
nox-poetry==1.0.3
poetry==1.6.1
virtualenv==20.24.7
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
include:
- { python: "3.10", os: "ubuntu-20.04", session: "pre-commit" }
- { python: "3.10", os: "ubuntu-20.04", session: "safety" }
- { python: "3.10", os: "ubuntu-20.04", session: "bandit" }
- { python: "3.10", os: "ubuntu-20.04", session: "mypy" }
- { python: "3.9", os: "ubuntu-20.04", session: "mypy" }
- { python: "3.10", os: "ubuntu-20.04", session: "tests" }
Expand Down
186 changes: 130 additions & 56 deletions app/config/app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""App configuration module."""
from functools import lru_cache
from typing import Optional

from pydantic import BaseSettings
from pydantic import Field
import pydantic
from pydantic_settings import BaseSettings
from pydantic_settings import SettingsConfigDict


class GlobalConfig(BaseSettings):
Expand All @@ -11,70 +13,141 @@ class GlobalConfig(BaseSettings):
# This variable will be loaded from the .env file. However, if there is a
# shell environment variable having the same name, that will take precedence.

ENV_STATE: Optional[str] = Field(None, env="ENV_STATE")
HOST: Optional[str] = Field(None, env="HOST")
PORT: Optional[str] = Field(None, env="PORT")
ENV_STATE: Optional[str] = pydantic.Field(None, env="ENV_STATE") # type: ignore
HOST: Optional[str] = pydantic.Field(None, env="HOST") # type: ignore
PORT: Optional[str] = pydantic.Field(None, env="PORT") # type: ignore

class Config:
"""Loads the dotenv file."""

env_file: str = ".env"
model_config = SettingsConfigDict(
env_file=".env",
extra="ignore",
case_sensitive=True,
env_prefix="",
env_nested_delimiter="_",
)


class DevConfig(GlobalConfig):
"""Development configurations."""

ROOT_PATH: Optional[str] = Field(None, env="DEV_ROOT_PATH")
AWS_LAMBDA_DEPLOY: Optional[bool] = Field(None, env="DEV_AWS_LAMBDA_DEPLOY")
LOG_PATH: Optional[str] = Field(None, env="DEV_LOG_PATH")
LOG_FILENAME: Optional[str] = Field(None, env="DEV_LOG_FILENAME")
LOG_LEVEL: Optional[str] = Field(None, env="DEV_LOG_LEVEL")
LOG_ENQUEUE: Optional[bool] = Field(None, env="DEV_LOG_ENQUEUE")
LOG_ROTATION: Optional[str] = Field(None, env="DEV_LOG_ROTATION")
LOG_RETENTION: Optional[str] = Field(None, env="DEV_LOG_RETENTION")
LOG_FORMAT: Optional[str] = Field(None, env="DEV_LOG_FORMAT")
OPA_ENABLED: Optional[bool] = Field(None, env="DEV_OPA_ENABLED")
OPA_URL: Optional[str] = Field(None, env="DEV_OPA_URL")
APP_URI: Optional[str] = Field(None, env="DEV_APP_URI")
OIDC_WELL_KNOWN_ENDPOINT: Optional[str] = Field(
ROOT_PATH: Optional[str] = pydantic.Field(None, env="DEV_ROOT_PATH") # type: ignore
AWS_LAMBDA_DEPLOY: Optional[bool] = pydantic.Field(
None, env="DEV_AWS_LAMBDA_DEPLOY"
) # type: ignore
LOG_PATH: Optional[str] = pydantic.Field(None, env="DEV_LOG_PATH") # type: ignore
LOG_FILENAME: Optional[str] = pydantic.Field(
None, env="DEV_LOG_FILENAME"
) # type: ignore
LOG_LEVEL: Optional[str] = pydantic.Field(None, env="DEV_LOG_LEVEL") # type: ignore
LOG_ENQUEUE: Optional[bool] = pydantic.Field(
None, env="DEV_LOG_ENQUEUE"
) # type: ignore
LOG_ROTATION: Optional[str] = pydantic.Field(
None, env="DEV_LOG_ROTATION"
) # type: ignore
LOG_RETENTION: Optional[str] = pydantic.Field(
None, env="DEV_LOG_RETENTION"
) # type: ignore
LOG_FORMAT: Optional[str] = pydantic.Field(
None, env="DEV_LOG_FORMAT"
) # type: ignore
OPA_ENABLED: Optional[bool] = pydantic.Field(
None, env="DEV_OPA_ENABLED"
) # type: ignore
OPA_URL: Optional[str] = pydantic.Field(None, env="DEV_OPA_URL") # type: ignore
APP_URI: Optional[str] = pydantic.Field(None, env="DEV_APP_URI") # type: ignore
OIDC_WELL_KNOWN_ENDPOINT: Optional[str] = pydantic.Field(
None, env="DEV_OIDC_WELL_KNOWN_ENDPOINT"
)
OIDC_CLIENT_ID: Optional[str] = Field(None, env="DEV_OIDC_CLIENT_ID")
OIDC_CLIENT_SECRET: Optional[str] = Field(None, env="DEV_OIDC_CLIENT_SECRET")
API_KEY_ENABLED: Optional[bool] = Field(None, env="DEV_API_KEY_ENABLED")
PYGEOAPI_KEY_GLOBAL: Optional[str] = Field(None, env="DEV_PYGEOAPI_KEY_GLOBAL")
PYGEOAPI_BASEURL: Optional[str] = Field(None, env="DEV_PYGEOAPI_BASEURL")
PYGEOAPI_CONFIG: Optional[str] = Field(None, env="DEV_PYGEOAPI_CONFIG")
PYGEOAPI_OPENAPI: Optional[str] = Field(None, env="DEV_PYGEOAPI_OPENAPI")
FASTGEOAPI_CONTEXT: Optional[str] = Field(None, env="DEV_FASTGEOAPI_CONTEXT")
) # type: ignore
OIDC_CLIENT_ID: Optional[str] = pydantic.Field(
None, env="DEV_OIDC_CLIENT_ID"
) # type: ignore
OIDC_CLIENT_SECRET: Optional[str] = pydantic.Field(
None, env="DEV_OIDC_CLIENT_SECRET"
) # type: ignore
API_KEY_ENABLED: Optional[bool] = pydantic.Field(
None, env="DEV_API_KEY_ENABLED"
) # type: ignore
PYGEOAPI_KEY_GLOBAL: Optional[str] = pydantic.Field(
None, env="DEV_PYGEOAPI_KEY_GLOBAL"
) # type: ignore
PYGEOAPI_BASEURL: Optional[str] = pydantic.Field(
None, env="DEV_PYGEOAPI_BASEURL"
) # type: ignore
PYGEOAPI_CONFIG: Optional[str] = pydantic.Field(
None, env="DEV_PYGEOAPI_CONFIG"
) # type: ignore
PYGEOAPI_OPENAPI: Optional[str] = pydantic.Field(
None, env="DEV_PYGEOAPI_OPENAPI"
) # type: ignore
FASTGEOAPI_CONTEXT: Optional[str] = pydantic.Field(
None, env="DEV_FASTGEOAPI_CONTEXT"
) # type: ignore

model_config = SettingsConfigDict(env_prefix="DEV_")


class ProdConfig(GlobalConfig):
"""Production configurations."""

ROOT_PATH: Optional[str] = Field(None, env="PROD_ROOT_PATH")
AWS_LAMBDA_DEPLOY: Optional[bool] = Field(None, env="PROD_AWS_LAMBDA_DEPLOY")
LOG_PATH: Optional[str] = Field(None, env="PROD_LOG_PATH")
LOG_FILENAME: Optional[str] = Field(None, env="PROD_LOG_FILENAME")
LOG_LEVEL: Optional[str] = Field(None, env="PROD_LOG_LEVEL")
LOG_ENQUEUE: Optional[bool] = Field(None, env="PROD_LOG_ENQUEUE")
LOG_ROTATION: Optional[str] = Field(None, env="PROD_LOG_ROTATION")
LOG_RETENTION: Optional[str] = Field(None, env="PROD_LOG_RETENTION")
LOG_FORMAT: Optional[str] = Field(None, env="PROD_LOG_FORMAT")
OPA_ENABLED: Optional[bool] = Field(None, env="PROD_OPA_ENABLED")
OPA_URL: Optional[str] = Field(None, env="PROD_OPA_URL")
APP_URI: Optional[str] = Field(None, env="PROD_APP_URI")
OIDC_WELL_KNOWN_ENDPOINT: Optional[str] = Field(
ROOT_PATH: Optional[str] = pydantic.Field(
None, env="PROD_ROOT_PATH"
) # type: ignore
AWS_LAMBDA_DEPLOY: Optional[bool] = pydantic.Field(
None, env="PROD_AWS_LAMBDA_DEPLOY"
) # type: ignore
LOG_PATH: Optional[str] = pydantic.Field(None, env="PROD_LOG_PATH") # type: ignore
LOG_FILENAME: Optional[str] = pydantic.Field(
None, env="PROD_LOG_FILENAME"
) # type: ignore
LOG_LEVEL: Optional[str] = pydantic.Field(
None, env="PROD_LOG_LEVEL"
) # type: ignore
LOG_ENQUEUE: Optional[bool] = pydantic.Field(
None, env="PROD_LOG_ENQUEUE"
) # type: ignore
LOG_ROTATION: Optional[str] = pydantic.Field(
None, env="PROD_LOG_ROTATION"
) # type: ignore
LOG_RETENTION: Optional[str] = pydantic.Field(
None, env="PROD_LOG_RETENTION"
) # type: ignore
LOG_FORMAT: Optional[str] = pydantic.Field(
None, env="PROD_LOG_FORMAT"
) # type: ignore
OPA_ENABLED: Optional[bool] = pydantic.Field(
None, env="PROD_OPA_ENABLED"
) # type: ignore
OPA_URL: Optional[str] = pydantic.Field(None, env="PROD_OPA_URL") # type: ignore
APP_URI: Optional[str] = pydantic.Field(None, env="PROD_APP_URI") # type: ignore
OIDC_WELL_KNOWN_ENDPOINT: Optional[str] = pydantic.Field(
None, env="PROD_OIDC_WELL_KNOWN_ENDPOINT"
)
OIDC_CLIENT_ID: Optional[str] = Field(None, env="PROD_OIDC_CLIENT_ID")
OIDC_CLIENT_SECRET: Optional[str] = Field(None, env="PROD_OIDC_CLIENT_SECRET")
API_KEY_ENABLED: Optional[bool] = Field(None, env="PROD_API_KEY_ENABLED")
PYGEOAPI_KEY_GLOBAL: Optional[str] = Field(None, env="PROD_PYGEOAPI_KEY_GLOBAL")
PYGEOAPI_BASEURL: Optional[str] = Field(None, env="PROD_PYGEOAPI_BASEURL")
PYGEOAPI_CONFIG: Optional[str] = Field(None, env="PROD_PYGEOAPI_CONFIG")
PYGEOAPI_OPENAPI: Optional[str] = Field(None, env="PROD_PYGEOAPI_OPENAPI")
FASTGEOAPI_CONTEXT: Optional[str] = Field(None, env="PROD_FASTGEOAPI_CONTEXT")
) # type: ignore
OIDC_CLIENT_ID: Optional[str] = pydantic.Field(
None, env="PROD_OIDC_CLIENT_ID"
) # type: ignore
OIDC_CLIENT_SECRET: Optional[str] = pydantic.Field(
None, env="PROD_OIDC_CLIENT_SECRET"
) # type: ignore
API_KEY_ENABLED: Optional[bool] = pydantic.Field(
None, env="PROD_API_KEY_ENABLED"
) # type: ignore
PYGEOAPI_KEY_GLOBAL: Optional[str] = pydantic.Field(
None, env="PROD_PYGEOAPI_KEY_GLOBAL"
) # type: ignore
PYGEOAPI_BASEURL: Optional[str] = pydantic.Field(
None, env="PROD_PYGEOAPI_BASEURL"
) # type: ignore
PYGEOAPI_CONFIG: Optional[str] = pydantic.Field(
None, env="PROD_PYGEOAPI_CONFIG"
) # type: ignore
PYGEOAPI_OPENAPI: Optional[str] = pydantic.Field(
None, env="PROD_PYGEOAPI_OPENAPI"
) # type: ignore
FASTGEOAPI_CONTEXT: Optional[str] = pydantic.Field(
None, env="PROD_FASTGEOAPI_CONTEXT"
) # type: ignore

model_config = SettingsConfigDict(env_prefix="PROD_")


class FactoryConfig:
Expand All @@ -84,13 +157,14 @@ def __init__(self, env_state: Optional[str]):
"""Initialize factory configuration."""
self.env_state = env_state

@lru_cache()
def __call__(self):
"""Handle runtime configuration."""
if self.env_state == "dev":
return DevConfig()
return DevConfig(**GlobalConfig().model_dump())

elif self.env_state == "prod":
return ProdConfig()
return ProdConfig(**GlobalConfig().model_dump())


configuration = FactoryConfig(GlobalConfig().ENV_STATE)()
configuration = FactoryConfig(env_state=GlobalConfig().ENV_STATE)()
14 changes: 7 additions & 7 deletions app/middleware/pygeoapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from typing import Any
from typing import Dict

from openapi_pydantic import OpenAPI
from openapi_pydantic import SecurityScheme
from openapi_pydantic.v3.v3_0_3 import OpenAPI
from openapi_pydantic.v3.v3_0_3 import SecurityScheme
from starlette.datastructures import Headers
from starlette.datastructures import MutableHeaders
from starlette.types import ASGIApp
Expand Down Expand Up @@ -76,16 +76,16 @@ async def send_with_security(self, message: Message) -> None: # noqa: C901
self.headers.update(headers_dict)
if message_type == "http.response.body":
initial_body = message.get("body", b"").decode()
openapi = OpenAPI.parse_raw(initial_body)
openapi = OpenAPI.model_validate_json(initial_body)
if self.security_scheme.type == "apiKey":
security_schemes = {
"securitySchemes": {
"PygeoApiKey": self.security_scheme.dict(
"PygeoApiKey": self.security_scheme.model_dump(
by_alias=True, exclude_none=True
)
}
}
body = openapi.dict(by_alias=True, exclude_none=True)
body = openapi.model_dump(by_alias=True, exclude_none=True)
components = body.get("components")
if components:
components.update(security_schemes)
Expand All @@ -102,8 +102,8 @@ async def send_with_security(self, message: Message) -> None: # noqa: C901
if secured_paths:
body["paths"] = secured_paths
binary_body = (
OpenAPI.parse_obj(body)
.json(by_alias=True, exclude_none=True, indent=2)
OpenAPI(**body)
.model_dump_json(by_alias=True, exclude_none=True, indent=2)
.encode()
)
headers = MutableHeaders(raw=self.initial_message["headers"])
Expand Down
Loading
Loading