mirror of
https://github.com/enpaul/kodak.git
synced 2024-11-23 15:07:13 +00:00
Reimplement manip configuration settings
Add support for future color changes Once and for all settle how crop/scaling will work Add proper exceptions
This commit is contained in:
parent
67abbd5374
commit
dff79571ba
@ -1,3 +1,4 @@
|
||||
import enum
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
@ -5,18 +6,40 @@ from dataclasses import field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import NamedTuple
|
||||
from typing import Optional
|
||||
from typing import Sequence
|
||||
from typing import Set
|
||||
from typing import Union
|
||||
|
||||
from kodak import constants
|
||||
from kodak import exceptions
|
||||
|
||||
|
||||
class DimensionConfig(NamedTuple):
|
||||
strategy: constants.DimensionStrategy
|
||||
anchor: constants.Anchor
|
||||
value: int
|
||||
def _get_int(var: str, default: Optional[int]) -> Optional[int]:
|
||||
return int(os.environ[var]) if var in os.environ else default
|
||||
|
||||
|
||||
def _get_float(var: str, default: Optional[float]) -> Optional[float]:
|
||||
return float(os.environ[var]) if var in os.environ else default
|
||||
|
||||
|
||||
def _get_enum_by_name(
|
||||
var: str, enumeration: enum.Enum, default: enum.Enum
|
||||
) -> enum.Enum:
|
||||
return enumeration[os.environ[var].upper()] if var in os.environ else default
|
||||
|
||||
|
||||
def _get_enum_by_value(
|
||||
var: str, enumeration: enum.Enum, default: enum.Enum
|
||||
) -> enum.Enum:
|
||||
return enumeration(os.environ[var].lower()) if var in os.environ else default
|
||||
|
||||
|
||||
def _get_path(var: str, default: Union[str, Path]) -> Path:
|
||||
return Path(os.environ.get(var, default)).expanduser().resolve()
|
||||
|
||||
|
||||
def _get_bool(var: str, default: bool) -> bool:
|
||||
return os.getenv(var, str(default)).lower() == "true"
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -29,9 +52,9 @@ class DatabaseSqliteConfig:
|
||||
@classmethod
|
||||
def from_env(cls):
|
||||
return cls(
|
||||
path=Path(os.environ.get("KODAK_DB_SQLITE_PATH", cls.path)),
|
||||
pragmas=json.loads(os.environ["KODAK_DB_SQLITE_PRAGMAS"])
|
||||
if "KODAK_DB_SQLITE_PRAGMAS" in os.environ
|
||||
path=_get_path("KODAK_DATABASE_SQLITE_PATH", cls.path),
|
||||
pragmas=json.loads(os.environ["KODAK_DATABASE_SQLITE_PRAGMAS"])
|
||||
if "KODAK_DATABASE_SQLITE_PRAGMAS" in os.environ
|
||||
else constants.DEFAULT_SQLITE_PRAGMAS,
|
||||
)
|
||||
|
||||
@ -43,16 +66,16 @@ class DatabaseMariaConfig:
|
||||
username: str = "root"
|
||||
password: Optional[str] = None
|
||||
port: int = 3306
|
||||
schema: str = "fresnel"
|
||||
schema: str = "kodak"
|
||||
|
||||
@classmethod
|
||||
def from_env(cls):
|
||||
return cls(
|
||||
hostname=os.getenv("KODAK_DB_MARIA_HOSTNAME", cls.hostname),
|
||||
username=os.getenv("KODAK_DB_MARIA_USERNAME", cls.username),
|
||||
password=os.environ.get("KODAK_DB_MARIA_PASSWORD", cls.password),
|
||||
port=int(os.environ.get("KODAK_DB_MARIA_PORT", cls.port)),
|
||||
schema=os.getenv("KODAK_DB_MARIA_SCHEMA", cls.schema),
|
||||
hostname=os.getenv("KODAK_DATABASE_MARIADB_HOSTNAME", cls.hostname),
|
||||
username=os.getenv("KODAK_DATABASE_MARIADB_USERNAME", cls.username),
|
||||
password=os.environ.get("KODAK_DATABASE_MARIADB_PASSWORD", cls.password),
|
||||
port=_get_int("KODAK_DATABASE_MARIADB_PORT", cls.port),
|
||||
schema=os.getenv("KODAK_DATABASE_MARIADB_SCHEMA", cls.schema),
|
||||
)
|
||||
|
||||
|
||||
@ -66,56 +89,86 @@ class DatabaseConfig:
|
||||
@classmethod
|
||||
def from_env(cls):
|
||||
return cls(
|
||||
backend=constants.DatabaseBackend[os.environ["KODAK_DB_BACKEND"].upper()]
|
||||
if "KODAK_DB_BACKEND" in os.environ
|
||||
else cls.backend
|
||||
backend=_get_enum_by_name(
|
||||
"KODAK_DATABASE_BACKEND", constants.DatabaseBackend, cls.backend
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ManipCropConfig:
|
||||
horizontal: Optional[int] = None
|
||||
vertical: Optional[int] = None
|
||||
anchor: constants.CropAnchor = constants.CropAnchor.C
|
||||
|
||||
@classmethod
|
||||
def from_env(cls, key: str):
|
||||
return cls(
|
||||
anchor=_get_enum_by_value(
|
||||
f"KODAK_MANIP_{key}_CROP_ANCHOR", constants.CropAnchor, cls.anchor
|
||||
),
|
||||
horizontal=_get_int(f"KODAK_MANIP_{key}_CROP_HORIZONTAL", cls.horizontal),
|
||||
vertical=_get_int(f"KODAK_MANIP_{key}_CROP_VERTICAL", cls.vertical),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ManipScaleConfig:
|
||||
horizontal: Optional[Union[int, float]] = None
|
||||
vertical: Optional[Union[int, float]] = None
|
||||
strategy: constants.ScaleStrategy = constants.ScaleStrategy.ABSOLUTE
|
||||
|
||||
@classmethod
|
||||
def from_env(cls, key: str):
|
||||
strategy = _get_enum_by_name(
|
||||
f"KODAK_MANIP_{key}_SCALE_STRATEGY", constants.ScaleStrategy, cls.strategy
|
||||
)
|
||||
|
||||
if strategy == constants.ScaleStrategy.ABSOLUTE:
|
||||
parser = _get_int
|
||||
elif strategy == constants.ScaleStrategy.RELATIVE:
|
||||
parser = _get_float
|
||||
else:
|
||||
raise RuntimeError("This path should not be possible")
|
||||
|
||||
return cls(
|
||||
strategy=strategy,
|
||||
vertical=parser(f"KODAK_MANIP_{key}_SCALE_VERTICAL", cls.vertical),
|
||||
horizontal=parser(f"KODAK_MANIP_{key}_SCALE_HORIZONTAL", cls.horizontal),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ManipConfig:
|
||||
name: str
|
||||
strategy: constants.DimensionStrategy = constants.DimensionStrategy.SCALE
|
||||
anchor: constants.Anchor = constants.Anchor.C
|
||||
formats: Sequence[constants.ImageFormat] = (
|
||||
constants.ImageFormat.JPEG,
|
||||
constants.ImageFormat.PNG,
|
||||
crop: ManipCropConfig = field(default_factory=ManipCropConfig.from_env)
|
||||
scale: ManipScaleConfig = field(default_factory=ManipScaleConfig.from_env)
|
||||
formats: Set[constants.ImageFormat] = field(
|
||||
default_factory=lambda: constants.DEFAULT_SUPPORTED_FORMATS
|
||||
)
|
||||
horizontal: Optional[Union[int, float]] = None
|
||||
vertical: Optional[Union[int, float]] = None
|
||||
black_and_white: bool = False
|
||||
# TODO: Implement support for these settings
|
||||
# brightness: int = 0
|
||||
# contrast: int = 0
|
||||
# sepia: bool = False
|
||||
|
||||
@classmethod
|
||||
def from_env(cls, key: str):
|
||||
strategy = (
|
||||
constants.DimensionStrategy[
|
||||
os.environ[f"KODAK_MANIP_{key}_STRATEGY"].upper()
|
||||
]
|
||||
if f"KODAK_MANIP_{key}_STRATEGY" in os.environ
|
||||
else cls.strategy
|
||||
)
|
||||
|
||||
dimension_conversion = (
|
||||
float if strategy == constants.DimensionStrategy.RELATIVE else int
|
||||
)
|
||||
|
||||
return cls(
|
||||
name=os.getenv(f"KODAK_MANIP_{key}_NAME", key.lower()),
|
||||
strategy=strategy,
|
||||
anchor=constants.Anchor(os.environ[f"KODAK_MANIP_{key}_ANCHOR"].lower())
|
||||
if f"KODAK_MANIP_{key}_ANCHOR" in os.environ
|
||||
else cls.anchor,
|
||||
formats=[
|
||||
constants.ImageFormat[item.upper()]
|
||||
crop=ManipCropConfig.from_env(key),
|
||||
scale=ManipScaleConfig.from_env(key),
|
||||
formats=set(
|
||||
[
|
||||
constants.ImageFormat[item.strip().upper()]
|
||||
for item in os.environ[f"KODAK_MANIP_{key}_FORMATS"].split(",")
|
||||
]
|
||||
)
|
||||
if f"KODAK_MANIP_{key}_FORMATS" in os.environ
|
||||
else cls.formats,
|
||||
horizontal=dimension_conversion(os.environ[f"KODAK_MANIP_{key}_HORIZONTAL"])
|
||||
if f"KODAK_MANIP_{key}_HORIZONTAL" in os.environ
|
||||
else cls.horizontal,
|
||||
vertical=dimension_conversion(os.environ[f"KODAK_MANIP_{key}_VERTICAL"])
|
||||
if f"KODAK_MANIP_{key}_VERTICAL" in os.environ
|
||||
else cls.vertical,
|
||||
else constants.DEFAULT_SUPPORTED_FORMATS,
|
||||
black_and_white=_get_bool(
|
||||
f"KODAK_MANIP_{key}_BLACK_AND_WHITE", cls.black_and_white
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -138,17 +191,10 @@ class KodakConfig:
|
||||
]
|
||||
)
|
||||
return cls(
|
||||
sourcedir=Path(os.environ.get("KODAK_SOURCEDIR", cls.sourcedir))
|
||||
.expanduser()
|
||||
.resolve(),
|
||||
manipdir=Path(os.environ.get("KODAK_MANIPDIR", cls.manipdir))
|
||||
.expanduser()
|
||||
.resolve(),
|
||||
expose_source=os.getenv(
|
||||
"KODAK_EXPOSE_SOURCE", str(cls.expose_source)
|
||||
).lower()
|
||||
== "true",
|
||||
private=os.getenv("KODAK_PRIVATE", str(cls.private)).lower() == "true",
|
||||
sourcedir=_get_path("KODAK_SOURCEDIR", cls.sourcedir),
|
||||
manipdir=_get_path("KODAK_MANIPDIR", cls.manipdir),
|
||||
expose_source=_get_bool("KODAK_EXPOSE_SOURCE", cls.expose_source),
|
||||
private=_get_bool("KODAK_PRIVATE", cls.private),
|
||||
manips={name.lower(): ManipConfig.from_env(name) for name in manip_names},
|
||||
)
|
||||
|
||||
@ -157,4 +203,4 @@ def load() -> KodakConfig:
|
||||
try:
|
||||
return KodakConfig.from_env()
|
||||
except (ValueError, TypeError, IndexError, KeyError) as err:
|
||||
raise RuntimeError(err)
|
||||
raise exceptions.ConfigurationError(f"Failed to load configuration: {err}")
|
||||
|
@ -8,19 +8,17 @@ class DatabaseBackend(enum.Enum):
|
||||
SQLITE = peewee.SqliteDatabase
|
||||
|
||||
|
||||
class DimensionStrategy(enum.Enum):
|
||||
CROP = enum.auto()
|
||||
SCALE = enum.auto()
|
||||
class ScaleStrategy(enum.Enum):
|
||||
RELATIVE = enum.auto()
|
||||
ABSOLUTE = enum.auto()
|
||||
|
||||
|
||||
class ImageFormat(enum.Enum):
|
||||
JPEG = enum.auto()
|
||||
PNG = enum.auto()
|
||||
GIF = enum.auto()
|
||||
|
||||
|
||||
class Anchor(enum.Enum):
|
||||
class CropAnchor(enum.Enum):
|
||||
TL = "top-left"
|
||||
TC = "top-center"
|
||||
TR = "top-center"
|
||||
@ -39,3 +37,5 @@ DEFAULT_SQLITE_PRAGMAS = {
|
||||
"ignore_check_constraints": 0,
|
||||
"synchronous": 0,
|
||||
}
|
||||
|
||||
DEFAULT_SUPPORTED_FORMATS = {ImageFormat.JPEG, ImageFormat.PNG}
|
||||
|
@ -37,3 +37,7 @@ class ServerError(KodakException):
|
||||
|
||||
class ImageFileRemovedError(ServerError):
|
||||
"""Image file removed from server"""
|
||||
|
||||
|
||||
class ConfigurationError(ServerError):
|
||||
"""Failed to load the application configuration"""
|
||||
|
Loading…
Reference in New Issue
Block a user