1
0
mirror of https://github.com/enpaul/kodak.git synced 2024-12-27 02:03:31 +00:00

Rename project to kodak

This commit is contained in:
Ethan Paul 2021-10-28 23:17:00 -04:00
parent 99d2ca4816
commit 67abbd5374
No known key found for this signature in database
GPG Key ID: D0E2CBF1245E92BF
31 changed files with 132 additions and 152 deletions

2
.gitignore vendored
View File

@ -14,7 +14,7 @@ dist/
.venv/
.mypy_cache/
fresnel_lens/openapi.yaml
kodak/openapi.yaml
.vscode/
.idea/

View File

@ -32,7 +32,7 @@ repos:
name: reorder-python-imports
entry: reorder-python-imports
args:
- "--unclassifiable-application-module=fresnel_lens"
- "--unclassifiable-application-module=kodak"
language: system
types: [python]

View File

@ -1,7 +1,7 @@
# fresnel-lens makefile
# kodak makefile
# You can set these variables from the command line
PROJECT = fresnel_lens
PROJECT = kodak
.PHONY: help
# Put it first so that "make" without argument is like "make help"

View File

@ -1,4 +1,4 @@
# fresnel-lens
# kodak
HTTP server for handling image uploads and thumbnail generation.

View File

@ -1,15 +0,0 @@
from typing import Tuple
from fresnel_lens.resources._shared import FresnelResource
from fresnel_lens.resources.alias import ImageAlias
from fresnel_lens.resources.heartbeat import Heartbeat
from fresnel_lens.resources.image import Image
from fresnel_lens.resources.openapi import OpenAPI
RESOURCES: Tuple[FresnelResource, ...] = (
Heartbeat,
Image,
ImageAlias,
OpenAPI,
)

View File

@ -1,10 +0,0 @@
from fresnel_lens.resources._shared import FresnelResource
from fresnel_lens.resources._shared import ResponseTuple
class Image(FresnelResource):
routes = ("/image/<string:image_name>",)
def get(self, image_name: str) -> ResponseTuple:
raise NotImplementedError

View File

@ -1,9 +1,9 @@
"""Programatically accessible project metadata"""
__title__ = "fresnel-lens"
__title__ = "kodak"
__version__ = "0.1.0"
__authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
__license__ = "MIT"
__summary__ = "HTTP server for uploading images and generating thumbnails"
__url__ = "https://github.com/enpaul/fresnel-lens/"
__url__ = "https://github.com/enpaul/kodak/"

View File

@ -1,12 +1,12 @@
"""Development server stub entrypoint
Flask comes with a built-in development server. This entrypoint allows ``fresnel_lens``
Flask comes with a built-in development server. This entrypoint allows ``kodak``
to be run directly to run the development server and expose some simple config options for ease of
access. Run the below command to start the server:
::
python -m fresnel_lens
python -m kodak
In addition to the helpful CLI flags, the Flask development server run by this module will also
load any ``.env`` files in the current working directory when running the application.
@ -17,7 +17,7 @@ load any ``.env`` files in the current working directory when running the applic
import argparse
import sys
from fresnel_lens.application import APPLICATION
from kodak.application import APPLICATION
# pylint: disable=invalid-name

View File

@ -1,8 +1,8 @@
import flask
from fresnel_lens import configuration
from fresnel_lens import database
from fresnel_lens import exceptions
from kodak import configuration
from kodak import database
from kodak import exceptions
def make_the_tea() -> None:
@ -21,7 +21,7 @@ def initialize_database() -> None:
database.initialize(flask.current_app.appconfig)
class FresnelFlask(flask.Flask):
class KodakFlask(flask.Flask):
"""Extend the default Flask object to add the custom application config
There's probably an easier/more kosher way to do this, but ¯\\_(ツ)_/¯
@ -29,4 +29,4 @@ class FresnelFlask(flask.Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.appconfig: configuration.FresnelConfig = configuration.load()
self.appconfig: configuration.KodakConfig = configuration.load()

View File

@ -1,12 +1,12 @@
import flask_restful
from fresnel_lens import resources
from fresnel_lens._server import FresnelFlask
from fresnel_lens._server import initialize_database
from fresnel_lens._server import make_the_tea
from kodak import resources
from kodak._server import initialize_database
from kodak._server import KodakFlask
from kodak._server import make_the_tea
APPLICATION = FresnelFlask(__name__)
APPLICATION = KodakFlask(__name__)
API = flask_restful.Api(APPLICATION, catch_all_404s=True)

View File

@ -10,7 +10,7 @@ from typing import Optional
from typing import Sequence
from typing import Union
from fresnel_lens import constants
from kodak import constants
class DimensionConfig(NamedTuple):
@ -19,35 +19,19 @@ class DimensionConfig(NamedTuple):
value: int
def _default_sqlite_pragmas() -> Dict[str, Any]:
"""Default SQLite pragmas
.. note:: This needs to be a separate callout function to avoid setting a mutable type in the
dataclass signature.
.. note:: These settings are taken directly from
`the Peewee docs <http://docs.peewee-orm.com/en/latest/peewee/database.html#recommended-settings>`_.
"""
return {
"journal_mode": "wal",
"cache_size": -1 * 64000,
"foreign_keys": 1,
"ignore_check_constraints": 0,
"synchronous": 0,
}
@dataclass
class DatabaseSqliteConfig:
path: Path = Path.cwd() / "fresnel.db"
pragmas: Dict[str, Any] = field(default_factory=_default_sqlite_pragmas)
pragmas: Dict[str, Any] = field(
default_factory=lambda: constants.DEFAULT_SQLITE_PRAGMAS
)
@classmethod
def from_env(cls):
return cls(
path=Path(os.environ.get("FRESNEL_DB_SQLITE_PATH", cls.path)),
pragmas=json.loads(os.environ["FRESNEL_DB_SQLITE_PRAGMAS"])
if "FRESNEL_DB_SQLITE_PRAGMAS" in os.environ
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
else constants.DEFAULT_SQLITE_PRAGMAS,
)
@ -64,11 +48,11 @@ class DatabaseMariaConfig:
@classmethod
def from_env(cls):
return cls(
hostname=os.getenv("FRESNEL_DB_MARIA_HOSTNAME", cls.hostname),
username=os.getenv("FRESNEL_DB_MARIA_USERNAME", cls.username),
password=os.environ.get("FRESNEL_DB_MARIA_PASSWORD", cls.password),
port=int(os.environ.get("FRESNEL_DB_MARIA_PORT", cls.port)),
schema=os.getenv("FRESNEL_DB_MARIA_SCHEMA", cls.schema),
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),
)
@ -82,8 +66,8 @@ class DatabaseConfig:
@classmethod
def from_env(cls):
return cls(
backend=constants.DatabaseBackend[os.environ["FRESNEL_DB_BACKEND"].upper()]
if "FRESNEL_DB_BACKEND" in os.environ
backend=constants.DatabaseBackend[os.environ["KODAK_DB_BACKEND"].upper()]
if "KODAK_DB_BACKEND" in os.environ
else cls.backend
)
@ -104,9 +88,9 @@ class ManipConfig:
def from_env(cls, key: str):
strategy = (
constants.DimensionStrategy[
os.environ[f"FRESNEL_MANIP_{key}_STRATEGY"].upper()
os.environ[f"KODAK_MANIP_{key}_STRATEGY"].upper()
]
if f"FRESNEL_MANIP_{key}_STRATEGY" in os.environ
if f"KODAK_MANIP_{key}_STRATEGY" in os.environ
else cls.strategy
)
@ -115,30 +99,28 @@ class ManipConfig:
)
return cls(
name=os.getenv(f"FRESNEL_MANIP_{key}_NAME", key.lower()),
name=os.getenv(f"KODAK_MANIP_{key}_NAME", key.lower()),
strategy=strategy,
anchor=constants.Anchor(os.environ[f"FRESNEL_MANIP_{key}_ANCHOR"].lower())
if f"FRESNEL_MANIP_{key}_ANCHOR" in os.environ
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()]
for item in os.environ[f"FRESNEL_MANIP_{key}_FORMATS"].split(",")
for item in os.environ[f"KODAK_MANIP_{key}_FORMATS"].split(",")
]
if f"FRESNEL_MANIP_{key}_FORMATS" in os.environ
if f"KODAK_MANIP_{key}_FORMATS" in os.environ
else cls.formats,
horizontal=dimension_conversion(
os.environ[f"FRESNEL_MANIP_{key}_HORIZONTAL"]
)
if f"FRESNEL_MANIP_{key}_HORIZONTAL" in os.environ
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"FRESNEL_MANIP_{key}_VERTICAL"])
if f"FRESNEL_MANIP_{key}_VERTICAL" in os.environ
vertical=dimension_conversion(os.environ[f"KODAK_MANIP_{key}_VERTICAL"])
if f"KODAK_MANIP_{key}_VERTICAL" in os.environ
else cls.vertical,
)
@dataclass
class FresnelConfig:
class KodakConfig:
database: DatabaseConfig = field(default_factory=DatabaseConfig.from_env)
sourcedir: Path = Path.cwd() / "images"
manipdir: Path = Path.cwd() / "images"
@ -150,29 +132,29 @@ class FresnelConfig:
def from_env(cls):
manip_names = set(
[
key.replace("FRESNEL_MANIP_", "").partition("_")[0]
key.replace("KODAK_MANIP_", "").partition("_")[0]
for key in os.environ.keys()
if key.startswith("FRESNEL_MANIP_")
if key.startswith("KODAK_MANIP_")
]
)
return cls(
sourcedir=Path(os.environ.get("FRESNEL_SOURCEDIR", cls.sourcedir))
sourcedir=Path(os.environ.get("KODAK_SOURCEDIR", cls.sourcedir))
.expanduser()
.resolve(),
manipdir=Path(os.environ.get("FRESNEL_MANIPDIR", cls.manipdir))
manipdir=Path(os.environ.get("KODAK_MANIPDIR", cls.manipdir))
.expanduser()
.resolve(),
expose_source=os.getenv(
"FRESNEL_EXPOSE_SOURCE", str(cls.expose_source)
"KODAK_EXPOSE_SOURCE", str(cls.expose_source)
).lower()
== "true",
private=os.getenv("FRESNEL_PRIVATE", str(cls.private)).lower() == "true",
private=os.getenv("KODAK_PRIVATE", str(cls.private)).lower() == "true",
manips={name.lower(): ManipConfig.from_env(name) for name in manip_names},
)
def load() -> FresnelConfig:
def load() -> KodakConfig:
try:
return FresnelConfig.from_env()
return KodakConfig.from_env()
except (ValueError, TypeError, IndexError, KeyError) as err:
raise RuntimeError(err)

View File

@ -3,18 +3,18 @@ from typing import Tuple
import peewee
from fresnel_lens import constants
from fresnel_lens.configuration import FresnelConfig
from fresnel_lens.database._shared import FresnelModel
from fresnel_lens.database._shared import INTERFACE as interface
from fresnel_lens.database.image import ImageRecord
from fresnel_lens.database.thumbnail import ThumbnailRecord
from kodak import constants
from kodak.configuration import KodakConfig
from kodak.database._shared import INTERFACE as interface
from kodak.database._shared import KodakModel
from kodak.database.image import ImageRecord
from kodak.database.thumbnail import ThumbnailRecord
MODELS: Tuple[FresnelModel, ...] = (ImageRecord, ThumbnailRecord)
MODELS: Tuple[KodakModel, ...] = (ImageRecord, ThumbnailRecord)
def initialize(config: FresnelConfig):
def initialize(config: KodakConfig):
"""Initialize the database interface
Defining the database as an

View File

@ -7,7 +7,7 @@ import peewee
INTERFACE = peewee.DatabaseProxy()
class FresnelModel(peewee.Model):
class KodakModel(peewee.Model):
class Meta: # pylint: disable=too-few-public-methods,missing-class-docstring
database = INTERFACE

View File

@ -4,10 +4,10 @@ from typing import List
import peewee
from fresnel_lens.database._shared import FresnelModel
from kodak.database._shared import KodakModel
class ImageRecord(FresnelModel):
class ImageRecord(KodakModel):
"""Database record for"""
width = peewee.IntegerField(null=False)

View File

@ -1,10 +1,10 @@
import peewee
from fresnel_lens.database._shared import FresnelModel
from fresnel_lens.database.image import ImageRecord
from kodak.database._shared import KodakModel
from kodak.database.image import ImageRecord
class ThumbnailRecord(FresnelModel):
class ThumbnailRecord(KodakModel):
parent = peewee.ForeignKeyField(ImageRecord)
width = peewee.IntegerField(null=False)

View File

@ -2,13 +2,13 @@
::
FresnelException
KodakException
+-- ClientError
+-- ServerError
"""
class FresnelException(Exception):
class KodakException(Exception):
"""Whomp whomp, something went wrong
But seriously, don't ever raise this exception
@ -17,7 +17,7 @@ class FresnelException(Exception):
status: int
class ClientError(FresnelException):
class ClientError(KodakException):
"""Error while processing client side input"""
status = 400
@ -29,7 +29,7 @@ class ImageResourceDeletedError(ClientError):
status = 410
class ServerError(FresnelException):
class ServerError(KodakException):
"""Error while processing server side data"""
status = 500

View File

@ -0,0 +1,15 @@
from typing import Tuple
from kodak.resources._shared import KodakResource
from kodak.resources.alias import ImageAlias
from kodak.resources.heartbeat import Heartbeat
from kodak.resources.image import Image
from kodak.resources.openapi import OpenAPI
RESOURCES: Tuple[KodakResource, ...] = (
Heartbeat,
Image,
ImageAlias,
OpenAPI,
)

View File

@ -11,7 +11,7 @@ from typing import Union
import flask
import flask_restful
from fresnel_lens import __about__
from kodak import __about__
ResponseBody = Optional[Union[Dict[str, Any], List[Dict[str, Any]], List[str]]]
@ -33,7 +33,7 @@ class ResponseTuple(NamedTuple):
headers: ResponseHeaders
class FresnelResource(flask_restful.Resource):
class KodakResource(flask_restful.Resource):
"""Extension of the default :class:`flask_restful.Resource` class
Add a couple of useful things to the default resource class:

View File

@ -1,8 +1,8 @@
from fresnel_lens.resources._shared import FresnelResource
from fresnel_lens.resources._shared import ResponseTuple
from kodak.resources._shared import KodakResource
from kodak.resources._shared import ResponseTuple
class ImageAlias(FresnelResource):
class ImageAlias(KodakResource):
routes = ("/image/<string:image_name>/<string:alias>",)

View File

@ -1,10 +1,10 @@
from fresnel_lens import configuration
from fresnel_lens import database
from fresnel_lens.resources._shared import FresnelResource
from fresnel_lens.resources._shared import ResponseTuple
from kodak import configuration
from kodak import database
from kodak.resources._shared import KodakResource
from kodak.resources._shared import ResponseTuple
class Heartbeat(FresnelResource):
class Heartbeat(KodakResource):
routes = ("/heartbeat",)

10
kodak/resources/image.py Normal file
View File

@ -0,0 +1,10 @@
from kodak.resources._shared import KodakResource
from kodak.resources._shared import ResponseTuple
class Image(KodakResource):
routes = ("/image/<string:image_name>",)
def get(self, image_name: str) -> ResponseTuple:
raise NotImplementedError

View File

@ -2,13 +2,13 @@ from pathlib import Path
from ruamel.yaml import YAML
from fresnel_lens.resources._shared import FresnelResource
from fresnel_lens.resources._shared import ResponseTuple
from kodak.resources._shared import KodakResource
from kodak.resources._shared import ResponseTuple
yaml = YAML(typ="safe")
class OpenAPI(FresnelResource):
class OpenAPI(KodakResource):
"""Handle requests for the OpenAPI specification resource"""
routes = ("/openapi.json",)

View File

@ -2,7 +2,7 @@
openapi: "3.0.2"
info:
version: 0.1.0
title: Fresnel Lens
title: Kodak
description: >-
A simple HTTP service for mucking about with images. This is a super basic HTTP
service for autogenerating website-ready banner and preview images from full-size
@ -201,7 +201,7 @@ components:
description: Application name and version
schema:
type: string
example: fresnel-lens-1.0.0
example: kodak-1.0.0
Allowed:
description: Comma delimited list of valid HTTP verbs
schema:

14
poetry.lock generated
View File

@ -130,11 +130,11 @@ black = ">=19.3b0"
[[package]]
name = "cachecontrol"
version = "0.12.6"
version = "0.12.7"
description = "httplib2 caching for requests"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
python-versions = ">=3.6.*"
[package.dependencies]
lockfile = {version = ">=0.9", optional = true, markers = "extra == \"filecache\""}
@ -1264,7 +1264,7 @@ testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "psutil (>=5.6.1)", "pytes
[[package]]
name = "tox-poetry-installer"
version = "0.8.1"
version = "0.8.2"
description = "A plugin for Tox that lets you install test environment dependencies from the Poetry lockfile"
category = "dev"
optional = false
@ -1439,8 +1439,8 @@ blacken-docs = [
{file = "blacken_docs-1.10.0.tar.gz", hash = "sha256:e2121c95bf2f8a3ebb3110776d276f850f63b8e5753773ba2b4d0f415d862f23"},
]
cachecontrol = [
{file = "CacheControl-0.12.6-py2.py3-none-any.whl", hash = "sha256:10d056fa27f8563a271b345207402a6dcce8efab7e5b377e270329c62471b10d"},
{file = "CacheControl-0.12.6.tar.gz", hash = "sha256:be9aa45477a134aee56c8fac518627e1154df063e85f67d4f83ce0ccc23688e8"},
{file = "CacheControl-0.12.7-py2.py3-none-any.whl", hash = "sha256:e8b73019cdd0b70ee3c58e94fd1bcbbc921608809b7490fd10c13c29ce9f4752"},
{file = "CacheControl-0.12.7.tar.gz", hash = "sha256:f818f4851af250da0d0be644a2f3eedf79cfc10f33391fa478d21b306af2a990"},
]
cached-property = [
{file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"},
@ -2121,8 +2121,8 @@ tox = [
{file = "tox-3.23.1.tar.gz", hash = "sha256:307a81ddb82bd463971a273f33e9533a24ed22185f27db8ce3386bff27d324e3"},
]
tox-poetry-installer = [
{file = "tox-poetry-installer-0.8.1.tar.gz", hash = "sha256:e3ee6578baa7f0ff9129182cc68af9eb0bbde520f9b0460a3f6e451579832c21"},
{file = "tox_poetry_installer-0.8.1-py3-none-any.whl", hash = "sha256:7acb70fa996d36168fd4de6f86d8e045e972844b8ad955d6768b77518af82e7f"},
{file = "tox-poetry-installer-0.8.2.tar.gz", hash = "sha256:1a94f0d7783bf513280b77ba5353232a11e74d232dff039502232a4738694af2"},
{file = "tox_poetry_installer-0.8.2-py3-none-any.whl", hash = "sha256:f7dffc4397ae9c193b40d9f40df3f67fc3a6869f4604458b01f4eabb5d0de08a"},
]
traitlets = [
{file = "traitlets-5.0.5-py3-none-any.whl", hash = "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"},

View File

@ -1,17 +1,17 @@
[tool.poetry]
name = "fresnel-lens"
name = "kodak"
version = "0.1.0"
license = "MIT"
authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
description = "HTTP server for uploading images and generating thumbnails"
repository = "https://github.com/enpaul/fresnel-lens/"
repository = "https://github.com/enpaul/kodak/"
packages = [
{include = "fresnel_lens"},
{include = "kodak"},
{include = "tests", format = "sdist"}
]
include = [
"fresnel_lens/py.typed",
"fresnel_lens/openapi.yaml"
"kodak/py.typed",
"kodak/openapi.yaml"
]
keywords = ["flask", "image", "thumbnail", "hosting"]
readme = "README.md"

View File

@ -3,7 +3,7 @@ from pathlib import Path
import toml
from fresnel_lens import __about__
from kodak import __about__
def test_about():

View File

@ -3,7 +3,7 @@ import importlib.resources
import openapi_spec_validator
import ruamel.yaml
from fresnel_lens import __about__
from kodak import __about__
yaml = ruamel.yaml.YAML(typ="safe") # pylint: disable=invalid-name
@ -11,10 +11,10 @@ yaml = ruamel.yaml.YAML(typ="safe") # pylint: disable=invalid-name
def test_openapi():
openapi_spec_validator.validate_spec(
yaml.load(importlib.resources.read_text("fresnel_lens", "openapi.yaml"))
yaml.load(importlib.resources.read_text("kodak", "openapi.yaml"))
)
def test_openapi_version():
spec = yaml.load(importlib.resources.read_text("fresnel_lens", "openapi.yaml"))
spec = yaml.load(importlib.resources.read_text("kodak", "openapi.yaml"))
assert spec["info"]["version"] == __about__.__version__

10
tox.ini
View File

@ -18,13 +18,12 @@ locked_deps =
ruamel.yaml
toml
commands =
pytest --cov={envsitepackagesdir}/fresnel_lens --cov-config {toxinidir}/.coveragerc --cov-report term-missing {toxinidir}/tests/
pytest --cov={envsitepackagesdir}/kodak --cov-config {toxinidir}/.coveragerc --cov-report term-missing {toxinidir}/tests/
[testenv:static]
description = Static formatting and quality enforcement
basepython = python3.8
ignore_errors = true
skip_install = true
locked_deps =
black
blacken-docs
@ -37,14 +36,13 @@ locked_deps =
pylint
commands =
pre-commit run --all-files
pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/fresnel_lens/
mypy --ignore-missing-imports --no-strict-optional {toxinidir}/fresnel_lens/
pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/kodak/
mypy --ignore-missing-imports --no-strict-optional {toxinidir}/kodak/
[testenv:static-tests]
description = Static formatting and quality enforcement for the tests
basepython = python3.8
ignore_errors = true
skip_install = true
locked_deps =
pylint
mypy
@ -62,7 +60,7 @@ locked_deps =
safety
poetry
commands =
bandit --recursive --quiet {toxinidir}/fresnel_lens/
bandit --recursive --quiet {toxinidir}/kodak/
bandit --recursive --quiet --skip B101 {toxinidir}/tests/
poetry export --format requirements.txt --output {envtmpdir}/requirements.txt --without-hashes --dev
safety check --bare --file {envtmpdir}/requirements.txt