mirror of
https://github.com/enpaul/kodak.git
synced 2024-11-23 15:07:13 +00:00
Rename project to dehance
This commit is contained in:
parent
3b05fb2053
commit
6a7662ae0f
115
.gitignore
vendored
115
.gitignore
vendored
@ -1,112 +1,27 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
env/
|
|
||||||
build/
|
build/
|
||||||
develop-eggs/
|
|
||||||
dist/
|
dist/
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
.installed.cfg
|
*.pyc
|
||||||
*.egg
|
|
||||||
requirements.txt
|
|
||||||
|
|
||||||
# PyInstaller
|
*.swp
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.coverage
|
.coverage
|
||||||
.coverage.*
|
*_cache/
|
||||||
.cache
|
.tox/
|
||||||
nosetests.xml
|
.cache/
|
||||||
coverage.xml
|
.venv/
|
||||||
*.cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
docs/imagemonk*.rst
|
|
||||||
docs/modules.rst
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# celery beat schedule file
|
|
||||||
celerybeat-schedule
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# dotenv
|
|
||||||
.env
|
|
||||||
|
|
||||||
# virtualenv
|
|
||||||
.venv
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
|
|
||||||
# Pycharm
|
docs/_build/
|
||||||
.idea/
|
docs/modules.rst
|
||||||
.idea/vcs.xml
|
docs/dehance*.rst
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
|
||||||
# Project specific
|
|
||||||
*.db
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
@ -1,48 +1,59 @@
|
|||||||
---
|
---
|
||||||
# All of the pre-commit hooks here actually use the `pytyhon` pre-commit language
|
|
||||||
# setting. However, for the python language setting, pre-commit will create and manage
|
|
||||||
# a cached virtual environment for each hook ID and do a bare `pip install <repo>` into
|
|
||||||
# the venv to setup the hook. This can result in conflicting dependency versions between
|
|
||||||
# the version installed to the pre-commit venv and the version installed to the Poetry
|
|
||||||
# venv specified in the lockfile.
|
|
||||||
#
|
|
||||||
# The solution is to specify `language: system` for all hooks and then install the
|
|
||||||
# required dependencies to the Poetry venv. The `system` language skips the isolated
|
|
||||||
# venv creation and looks for the entrypoint specified by the hook in the global
|
|
||||||
# environment which, if running in the Poetry venv, will find the entrypoint provided
|
|
||||||
# by the Poetry-managed dependency.
|
|
||||||
#
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: local
|
||||||
rev: v3.3.0
|
|
||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
name: end-of-file-fixer
|
||||||
|
entry: end-of-file-fixer
|
||||||
language: system
|
language: system
|
||||||
|
types: [text]
|
||||||
|
|
||||||
- id: fix-encoding-pragma
|
- id: fix-encoding-pragma
|
||||||
|
name: fix-encoding-pragma
|
||||||
|
entry: fix-encoding-pragma
|
||||||
args:
|
args:
|
||||||
- "--remove"
|
- "--remove"
|
||||||
language: system
|
language: system
|
||||||
- id: trailing-whitespace
|
types: [python]
|
||||||
|
|
||||||
|
- id: trailing-whitespace-fixer
|
||||||
|
name: trailing-whitespace-fixer
|
||||||
|
entry: trailing-whitespace-fixer
|
||||||
language: system
|
language: system
|
||||||
|
types: [text]
|
||||||
|
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
|
name: check-merge-conflict
|
||||||
|
entry: check-merge-conflict
|
||||||
language: system
|
language: system
|
||||||
|
types: [text]
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
|
||||||
rev: master
|
|
||||||
hooks:
|
|
||||||
- id: black
|
|
||||||
language: system
|
|
||||||
|
|
||||||
- repo: https://github.com/asottile/blacken-docs
|
|
||||||
rev: v1.8.0
|
|
||||||
hooks:
|
|
||||||
- id: blacken-docs
|
|
||||||
language: system
|
|
||||||
|
|
||||||
- repo: https://github.com/asottile/reorder_python_imports
|
|
||||||
rev: v2.3.6
|
|
||||||
hooks:
|
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
|
name: reorder-python-imports
|
||||||
|
entry: reorder-python-imports
|
||||||
args:
|
args:
|
||||||
- "--unclassifiable-application-module=imagemonk"
|
- "--unclassifiable-application-module=dehance"
|
||||||
language: system
|
language: system
|
||||||
|
types: [python]
|
||||||
|
|
||||||
|
- id: black
|
||||||
|
name: black
|
||||||
|
entry: black
|
||||||
|
language: system
|
||||||
|
types: [python]
|
||||||
|
|
||||||
|
- id: blacken-docs
|
||||||
|
name: blacken-docs
|
||||||
|
entry: blacken-docs
|
||||||
|
language: system
|
||||||
|
types: [text]
|
||||||
|
|
||||||
|
- id: mdformat
|
||||||
|
name: mdformat
|
||||||
|
entry: mdformat
|
||||||
|
language: system
|
||||||
|
args:
|
||||||
|
- "--number"
|
||||||
|
- "--wrap=90"
|
||||||
|
types:
|
||||||
|
- markdown
|
||||||
|
23
LICENSE.md
23
LICENSE.md
@ -1,11 +1,12 @@
|
|||||||
## Copyright 2020 Ethan Paul
|
## Copyright 2020 Ethan Paul
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
software and associated documentation files (the "Software"), to deal in the Software
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
||||||
the Software.
|
The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
substantial portions of the Software.
|
||||||
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
|
|
||||||
|
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
|
||||||
|
11
Makefile
11
Makefile
@ -1,7 +1,7 @@
|
|||||||
# ImageMonk makefile
|
# Dehance makefile
|
||||||
|
|
||||||
# You can set these variables from the command line
|
# You can set these variables from the command line
|
||||||
PROJECT = imagemonk
|
PROJECT = dehance
|
||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
# Put it first so that "make" without argument is like "make help"
|
# Put it first so that "make" without argument is like "make help"
|
||||||
@ -28,7 +28,8 @@ clean-docs:
|
|||||||
rm --force docs/$(PROJECT)*.rst
|
rm --force docs/$(PROJECT)*.rst
|
||||||
rm --force docs/modules.rst
|
rm --force docs/modules.rst
|
||||||
|
|
||||||
clean: clean-tox clean-py clean-docs; ## Clean temp build/cache files and directories
|
clean: clean-tox clean-py clean-docs ## Clean temp build/cache files and directories
|
||||||
|
rm --force ./*db*
|
||||||
|
|
||||||
wheel: ## Build Python binary distribution wheel package
|
wheel: ## Build Python binary distribution wheel package
|
||||||
poetry build --format wheel
|
poetry build --format wheel
|
||||||
@ -37,10 +38,10 @@ source: ## Build Python source distribution package
|
|||||||
poetry build --format sdist
|
poetry build --format sdist
|
||||||
|
|
||||||
test: clean-tox ## Run the project testsuite(s)
|
test: clean-tox ## Run the project testsuite(s)
|
||||||
tox
|
poetry run tox --parallelize-locked-install=10
|
||||||
|
|
||||||
publish: clean test wheel source ## Build and upload to pypi (requires $PYPI_API_KEY be set)
|
publish: clean test wheel source ## Build and upload to pypi (requires $PYPI_API_KEY be set)
|
||||||
@poetry publish --username __token__ --password $(PYPI_API_KEY)
|
@poetry publish --username __token__ --password $(PYPI_API_KEY)
|
||||||
|
|
||||||
docs: clean-docs ## Build the documentation using Sphinx
|
docs: clean-docs ## Build the documentation using Sphinx
|
||||||
tox -e docs
|
poetry run tox -e docs
|
||||||
|
39
README.md
39
README.md
@ -1,5 +1,42 @@
|
|||||||
# imagemonk
|
# dehance
|
||||||
|
|
||||||
HTTP server for handling image uploads and thumbnail generation.
|
HTTP server for handling image uploads and thumbnail generation.
|
||||||
|
|
||||||
This project requires [Poetry 1.0+](https://python-poetry.org/)
|
This project requires [Poetry 1.0+](https://python-poetry.org/)
|
||||||
|
|
||||||
|
## Implementation goals
|
||||||
|
|
||||||
|
Support token based authentication:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /auth/token
|
||||||
|
|
||||||
|
GET /img/abcdefg.jpg?token=XYZ
|
||||||
|
```
|
||||||
|
|
||||||
|
Support dynamic resolution generation:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /img/abcdefg/100x50.jpg
|
||||||
|
```
|
||||||
|
|
||||||
|
Support server-side aliasing of resolutions to names:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /img/abcdefg/foobar.jpg # translates to something like 120x90
|
||||||
|
```
|
||||||
|
|
||||||
|
Support parameter-based selection of scaling method:
|
||||||
|
|
||||||
|
```
|
||||||
|
# "absolute scale horizontal", "relative scale vertical"
|
||||||
|
GET /img/abcdefg/200x100.jpg?h=abs&v=rel
|
||||||
|
```
|
||||||
|
|
||||||
|
Support both sqlite and maria storage backend
|
||||||
|
|
||||||
|
Support redis caching to relieve file system strain
|
||||||
|
|
||||||
|
Support autocleaning of cached file system files to reduce directory size
|
||||||
|
|
||||||
|
Support
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""Programatically accessible project metadata"""
|
"""Programatically accessible project metadata"""
|
||||||
|
|
||||||
|
|
||||||
__title__ = "imagemonk"
|
__title__ = "dehance"
|
||||||
__version__ = "0.1.0"
|
__version__ = "0.1.0"
|
||||||
__authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
|
__authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
__summary__ = "HTTP server for uploading images and generating thumbnails"
|
__summary__ = "HTTP server for uploading images and generating thumbnails"
|
||||||
__url__ = "https://github.com/mocproject/imagemonk/"
|
__url__ = "https://github.com/mocproject/dehance/"
|
@ -1,12 +1,12 @@
|
|||||||
"""Development server stub entrypoint
|
"""Development server stub entrypoint
|
||||||
|
|
||||||
Flask comes with a built-in development server. This entrypoint allows ``imagemonk``
|
Flask comes with a built-in development server. This entrypoint allows ``dehance``
|
||||||
to be run directly to run the development server and expose some simple config options for ease of
|
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:
|
access. Run the below command to start the server:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
python -m imagemonk
|
python -m dehance
|
||||||
|
|
||||||
In addition to the helpful CLI flags, the Flask development server run by this module will also
|
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.
|
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 argparse
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from imagemonk.application import APPLICATION
|
from dehance.application import APPLICATION
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
@ -1,11 +1,11 @@
|
|||||||
import flask
|
import flask
|
||||||
|
|
||||||
from imagemonk import __about__
|
from dehance import __about__
|
||||||
from imagemonk import configuration
|
from dehance import configuration
|
||||||
from imagemonk import constants
|
from dehance import constants
|
||||||
from imagemonk import database
|
from dehance import database
|
||||||
from imagemonk import exceptions
|
from dehance import exceptions
|
||||||
from imagemonk.resources import ResponseHeaders
|
from dehance.resources import ResponseHeaders
|
||||||
|
|
||||||
|
|
||||||
def make_the_tea() -> None:
|
def make_the_tea() -> None:
|
||||||
@ -23,7 +23,7 @@ def initialize_database() -> None:
|
|||||||
database.initialize(flask.current_app.appconfig)
|
database.initialize(flask.current_app.appconfig)
|
||||||
|
|
||||||
|
|
||||||
class ImageMonkRequest(flask.Request):
|
class DehanceRequest(flask.Request):
|
||||||
"""Extend the default Flask request object to add custom application state settings"""
|
"""Extend the default Flask request object to add custom application state settings"""
|
||||||
|
|
||||||
def make_response_headers(self) -> ResponseHeaders:
|
def make_response_headers(self) -> ResponseHeaders:
|
||||||
@ -40,14 +40,14 @@ class ImageMonkRequest(flask.Request):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ImageMonkFlask(flask.Flask):
|
class DehanceFlask(flask.Flask):
|
||||||
"""Extend the default Flask object to add the custom application config
|
"""Extend the default Flask object to add the custom application config
|
||||||
|
|
||||||
There's probably an easier/more kosher way to do this, but ¯\\_(ツ)_/¯
|
There's probably an easier/more kosher way to do this, but ¯\\_(ツ)_/¯
|
||||||
"""
|
"""
|
||||||
|
|
||||||
request_class = ImageMonkRequest
|
request_class = DehanceRequest
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.appconfig: configuration.ImageMonkConfig = configuration.load()
|
self.appconfig: configuration.DehanceConfig = configuration.load()
|
@ -1,12 +1,12 @@
|
|||||||
import flask_restful
|
import flask_restful
|
||||||
|
|
||||||
from imagemonk import resources
|
from dehance import resources
|
||||||
from imagemonk._server import ImageMonkFlask
|
from dehance._server import DehanceFlask
|
||||||
from imagemonk._server import initialize_database
|
from dehance._server import initialize_database
|
||||||
from imagemonk._server import make_the_tea
|
from dehance._server import make_the_tea
|
||||||
|
|
||||||
|
|
||||||
APPLICATION = ImageMonkFlask(__name__)
|
APPLICATION = DehanceFlask(__name__)
|
||||||
API = flask_restful.Api(APPLICATION, catch_all_404s=True)
|
API = flask_restful.Api(APPLICATION, catch_all_404s=True)
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ from typing import Dict
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from imagemonk import constants
|
from dehance import constants
|
||||||
|
|
||||||
|
|
||||||
def _default_sqlite_pragmas() -> Dict[str, Any]:
|
def _default_sqlite_pragmas() -> Dict[str, Any]:
|
||||||
@ -31,7 +31,7 @@ def _default_sqlite_pragmas() -> Dict[str, Any]:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class _DBSqliteConfig:
|
class _DBSqliteConfig:
|
||||||
path: Path = Path.cwd() / "imagemonk.db"
|
path: Path = Path.cwd() / "dehance.db"
|
||||||
pragmas: Dict[str, Any] = field(default_factory=_default_sqlite_pragmas)
|
pragmas: Dict[str, Any] = field(default_factory=_default_sqlite_pragmas)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -51,7 +51,7 @@ class _DBMariaConfig:
|
|||||||
username: str = "root"
|
username: str = "root"
|
||||||
password: Optional[str] = None
|
password: Optional[str] = None
|
||||||
port: int = 3306
|
port: int = 3306
|
||||||
schema: str = "imagemonk"
|
schema: str = "dehance"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def build(cls):
|
def build(cls):
|
||||||
@ -106,7 +106,7 @@ class _UploadConfig:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ImageMonkConfig:
|
class DehanceConfig:
|
||||||
database: _DBConfig = field(default_factory=_DBConfig.build)
|
database: _DBConfig = field(default_factory=_DBConfig.build)
|
||||||
upload: _UploadConfig = field(default_factory=_UploadConfig.build)
|
upload: _UploadConfig = field(default_factory=_UploadConfig.build)
|
||||||
storage_path: Path = Path.cwd()
|
storage_path: Path = Path.cwd()
|
||||||
@ -120,6 +120,6 @@ class ImageMonkConfig:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load() -> ImageMonkConfig:
|
def load() -> DehanceConfig:
|
||||||
|
|
||||||
return ImageMonkConfig.build()
|
return DehanceConfig.build()
|
@ -7,7 +7,7 @@ class SupportedDatabaseBackend(enum.Enum):
|
|||||||
SQLITE = enum.auto()
|
SQLITE = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
HTTP_HEADER_RESPONSE_VERSION = "x-imagemonk-version"
|
HTTP_HEADER_RESPONSE_VERSION = "x-dehance-version"
|
||||||
|
|
||||||
HTTP_HEADER_RESPONSE_DIGEST = "Digest"
|
HTTP_HEADER_RESPONSE_DIGEST = "Digest"
|
||||||
|
|
@ -3,18 +3,18 @@ from typing import Tuple
|
|||||||
|
|
||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
from imagemonk import constants
|
from dehance import constants
|
||||||
from imagemonk.configuration import ImageMonkConfig
|
from dehance.configuration import DehanceConfig
|
||||||
from imagemonk.database._shared import ImageMonkModel
|
from dehance.database._shared import DehanceModel
|
||||||
from imagemonk.database._shared import INTERFACE as interface
|
from dehance.database._shared import INTERFACE as interface
|
||||||
from imagemonk.database.image import ImageRecord
|
from dehance.database.image import ImageRecord
|
||||||
from imagemonk.database.thumbnail import ThumbnailRecord
|
from dehance.database.thumbnail import ThumbnailRecord
|
||||||
|
|
||||||
|
|
||||||
MODELS: Tuple[ImageMonkModel, ...] = (ImageRecord, ThumbnailRecord)
|
MODELS: Tuple[DehanceModel, ...] = (ImageRecord, ThumbnailRecord)
|
||||||
|
|
||||||
|
|
||||||
def initialize(config: ImageMonkConfig):
|
def initialize(config: DehanceConfig):
|
||||||
"""Initialize the database interface
|
"""Initialize the database interface
|
||||||
|
|
||||||
Defining the database as an
|
Defining the database as an
|
@ -7,7 +7,7 @@ import peewee
|
|||||||
INTERFACE = peewee.DatabaseProxy()
|
INTERFACE = peewee.DatabaseProxy()
|
||||||
|
|
||||||
|
|
||||||
class ImageMonkModel(peewee.Model):
|
class DehanceModel(peewee.Model):
|
||||||
class Meta: # pylint: disable=too-few-public-methods,missing-class-docstring
|
class Meta: # pylint: disable=too-few-public-methods,missing-class-docstring
|
||||||
database = INTERFACE
|
database = INTERFACE
|
||||||
|
|
@ -4,10 +4,10 @@ from typing import List
|
|||||||
|
|
||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
from imagemonk.database._shared import ImageMonkModel
|
from dehance.database._shared import DehanceModel
|
||||||
|
|
||||||
|
|
||||||
class ImageRecord(ImageMonkModel):
|
class ImageRecord(DehanceModel):
|
||||||
"""Database record for"""
|
"""Database record for"""
|
||||||
|
|
||||||
width = peewee.IntegerField(null=False)
|
width = peewee.IntegerField(null=False)
|
@ -1,10 +1,10 @@
|
|||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
from imagemonk.database._shared import ImageMonkModel
|
from dehance.database._shared import DehanceModel
|
||||||
from imagemonk.database.image import ImageRecord
|
from dehance.database.image import ImageRecord
|
||||||
|
|
||||||
|
|
||||||
class ThumbnailRecord(ImageMonkModel):
|
class ThumbnailRecord(DehanceModel):
|
||||||
|
|
||||||
parent = peewee.ForeignKeyField(ImageRecord)
|
parent = peewee.ForeignKeyField(ImageRecord)
|
||||||
width = peewee.IntegerField(null=False)
|
width = peewee.IntegerField(null=False)
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
ImageMonkException
|
DehanceException
|
||||||
+-- ClientError
|
+-- ClientError
|
||||||
+-- ServerError
|
+-- ServerError
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ImageMonkException(Exception):
|
class DehanceException(Exception):
|
||||||
"""Whomp whomp, something went wrong
|
"""Whomp whomp, something went wrong
|
||||||
|
|
||||||
But seriously, don't ever raise this exception
|
But seriously, don't ever raise this exception
|
||||||
@ -17,7 +17,7 @@ class ImageMonkException(Exception):
|
|||||||
status: int
|
status: int
|
||||||
|
|
||||||
|
|
||||||
class ClientError(ImageMonkException):
|
class ClientError(DehanceException):
|
||||||
"""Error while processing client side input"""
|
"""Error while processing client side input"""
|
||||||
|
|
||||||
status = 400
|
status = 400
|
||||||
@ -29,7 +29,7 @@ class ImageResourceDeletedError(ClientError):
|
|||||||
status = 410
|
status = 410
|
||||||
|
|
||||||
|
|
||||||
class ServerError(ImageMonkException):
|
class ServerError(DehanceException):
|
||||||
"""Error while processing server side data"""
|
"""Error while processing server side data"""
|
||||||
|
|
||||||
status = 500
|
status = 500
|
19
dehance/resources/__init__.py
Normal file
19
dehance/resources/__init__.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from dehance.resources._shared import DehanceResource
|
||||||
|
from dehance.resources._shared import ResponseBody
|
||||||
|
from dehance.resources._shared import ResponseHeaders
|
||||||
|
from dehance.resources.image import Image
|
||||||
|
from dehance.resources.image import ImageUpload
|
||||||
|
from dehance.resources.openapi import OpenAPI
|
||||||
|
from dehance.resources.thumbnail import ThumbnailResize
|
||||||
|
from dehance.resources.thumbnail import ThumbnailScale
|
||||||
|
|
||||||
|
|
||||||
|
RESOURCES: Tuple[DehanceResource, ...] = (
|
||||||
|
ImageUpload,
|
||||||
|
Image,
|
||||||
|
OpenAPI,
|
||||||
|
ThumbnailScale,
|
||||||
|
ThumbnailResize,
|
||||||
|
)
|
@ -31,7 +31,7 @@ class ResponseTuple(NamedTuple):
|
|||||||
headers: ResponseHeaders
|
headers: ResponseHeaders
|
||||||
|
|
||||||
|
|
||||||
class ImageMonkResource(flask_restful.Resource):
|
class DehanceResource(flask_restful.Resource):
|
||||||
"""Extension of the default :class:`flask_restful.Resource` class
|
"""Extension of the default :class:`flask_restful.Resource` class
|
||||||
|
|
||||||
Add a couple of useful things to the default resource class:
|
Add a couple of useful things to the default resource class:
|
@ -4,13 +4,13 @@ import uuid
|
|||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
|
||||||
from imagemonk import constants
|
from dehance import constants
|
||||||
from imagemonk import database
|
from dehance import database
|
||||||
from imagemonk import exceptions
|
from dehance import exceptions
|
||||||
from imagemonk.resources._shared import ImageMonkResource
|
from dehance.resources._shared import DehanceResource
|
||||||
|
|
||||||
|
|
||||||
class ImageUpload(ImageMonkResource):
|
class ImageUpload(DehanceResource):
|
||||||
|
|
||||||
routes = ("/image/",)
|
routes = ("/image/",)
|
||||||
|
|
||||||
@ -20,8 +20,6 @@ class ImageUpload(ImageMonkResource):
|
|||||||
|
|
||||||
uploaded = flask.request.files["image"]
|
uploaded = flask.request.files["image"]
|
||||||
|
|
||||||
breakpoint()
|
|
||||||
|
|
||||||
if not uploaded.filename:
|
if not uploaded.filename:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@ -47,16 +45,14 @@ class ImageUpload(ImageMonkResource):
|
|||||||
return None, 201
|
return None, 201
|
||||||
|
|
||||||
|
|
||||||
class Image(ImageMonkResource):
|
class Image(DehanceResource):
|
||||||
|
|
||||||
routes = ("/image/<string:image_id>.jpeg",)
|
routes = ("/image/<string:image_id>.jpeg",)
|
||||||
|
|
||||||
def get(self, image_id: str):
|
def get(self, image_id: str):
|
||||||
|
|
||||||
image = database.ImageRecord.get(
|
image = database.ImageRecord.get(
|
||||||
database.ImageRecord.uuid
|
database.ImageRecord.uuid == uuid.UUID(image_id)
|
||||||
== uuid.UUID(image_id) & database.ImageRecord.format
|
|
||||||
== format
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if image.deleted:
|
if image.deleted:
|
@ -2,12 +2,12 @@ from pathlib import Path
|
|||||||
|
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
from imagemonk.resources._shared import ImageMonkResource
|
from dehance.resources._shared import DehanceResource
|
||||||
|
|
||||||
yaml = YAML(typ="safe")
|
yaml = YAML(typ="safe")
|
||||||
|
|
||||||
|
|
||||||
class OpenAPI(ImageMonkResource):
|
class OpenAPI(DehanceResource):
|
||||||
|
|
||||||
routes = ("/openapi.json",)
|
routes = ("/openapi.json",)
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
from imagemonk.resources._shared import ImageMonkResource
|
from dehance.resources._shared import DehanceResource
|
||||||
|
|
||||||
|
|
||||||
class ThumbnailScale(ImageMonkResource):
|
class ThumbnailScale(DehanceResource):
|
||||||
|
|
||||||
routes = ("/thumb/<string:image_id>/scale/<int:scale_width>.jpg",)
|
routes = ("/thumb/<string:image_id>/scale/<int:scale_width>.jpg",)
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ class ThumbnailScale(ImageMonkResource):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class ThumbnailResize(ImageMonkResource):
|
class ThumbnailResize(DehanceResource):
|
||||||
|
|
||||||
routes = ("/thumb/<string:image_id>/size/<int:width>x<int:height>.jpg",)
|
routes = ("/thumb/<string:image_id>/size/<int:width>x<int:height>.jpg",)
|
||||||
|
|
@ -7,18 +7,19 @@
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).parent.resolve()
|
BASE_DIR = Path(__file__).parent.resolve()
|
||||||
ABOUT = {}
|
ABOUT = {}
|
||||||
with open(Path(BASE_DIR, "..", "imagemonk", "__about__.py")) as infile:
|
with open(Path(BASE_DIR, "..", "dehance", "__about__.py")) as infile:
|
||||||
exec(infile.read(), ABOUT)
|
exec(infile.read(), ABOUT)
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = ABOUT["__title__"]
|
project = ABOUT["__title__"]
|
||||||
copyright = "2020"
|
copyright = str(datetime.date.today().year)
|
||||||
author = ", ".join(ABOUT["__authors__"])
|
author = ", ".join(ABOUT["__authors__"])
|
||||||
|
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
ImageMonk
|
Dehance
|
||||||
=========
|
=========
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
:caption: Contents:
|
:caption: Contents:
|
||||||
|
|
||||||
API Reference <imagemonk>
|
API Reference <dehance>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from imagemonk.resources._shared import ImageMonkResource
|
|
||||||
from imagemonk.resources._shared import ResponseBody
|
|
||||||
from imagemonk.resources._shared import ResponseHeaders
|
|
||||||
from imagemonk.resources.image import Image
|
|
||||||
from imagemonk.resources.image import ImageUpload
|
|
||||||
from imagemonk.resources.openapi import OpenAPI
|
|
||||||
from imagemonk.resources.thumbnail import ThumbnailResize
|
|
||||||
from imagemonk.resources.thumbnail import ThumbnailScale
|
|
||||||
|
|
||||||
|
|
||||||
RESOURCES: Tuple[ImageMonkResource, ...] = (
|
|
||||||
ImageUpload,
|
|
||||||
Image,
|
|
||||||
OpenAPI,
|
|
||||||
ThumbnailScale,
|
|
||||||
ThumbnailResize,
|
|
||||||
)
|
|
@ -2,9 +2,9 @@
|
|||||||
openapi: "3.0.2"
|
openapi: "3.0.2"
|
||||||
info:
|
info:
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
title: ImageMonk
|
title: Dehance
|
||||||
description: >-
|
description: >-
|
||||||
ImageMonk is a simple HTTP server that allows users to upload
|
Dehance is a simple HTTP server that allows users to upload
|
||||||
images and retrieve them at a later time. In addition, it
|
images and retrieve them at a later time. In addition, it
|
||||||
supports generating (and caching) scaled versions of the
|
supports generating (and caching) scaled versions of the
|
||||||
uploaded images for use as thumbnails.
|
uploaded images for use as thumbnails.
|
||||||
@ -13,7 +13,7 @@ info:
|
|||||||
url: https://mit-license.org/
|
url: https://mit-license.org/
|
||||||
x-anchors:
|
x-anchors:
|
||||||
DefaultHeaders: &headers-default
|
DefaultHeaders: &headers-default
|
||||||
x-imagemonk-version:
|
x-dehance-version:
|
||||||
$ref: "#/components/headers/Version"
|
$ref: "#/components/headers/Version"
|
||||||
OptionsResponses: &responses-options
|
OptionsResponses: &responses-options
|
||||||
'204':
|
'204':
|
||||||
|
984
poetry.lock
generated
984
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,17 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "imagemonk"
|
name = "dehance"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
|
authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
|
||||||
description = "HTTP server for uploading images and generating thumbnails"
|
description = "HTTP server for uploading images and generating thumbnails"
|
||||||
repository = "https://github.com/mocproject/imagemonk/"
|
repository = "https://github.com/mocproject/dehance/"
|
||||||
packages = [
|
packages = [
|
||||||
{include = "imagemonk"},
|
{include = "dehance"},
|
||||||
{include = "tests", format = "sdist"}
|
{include = "tests", format = "sdist"}
|
||||||
]
|
]
|
||||||
include = [
|
include = [
|
||||||
"imagemonk/py.typed",
|
"dehance/py.typed",
|
||||||
"imagemonk/resources/openapi.yaml"
|
"dehance/resources/openapi.yaml"
|
||||||
]
|
]
|
||||||
keywords = ["flask", "image", "thumbnail", "hosting"]
|
keywords = ["flask", "image", "thumbnail", "hosting"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@ -45,10 +45,10 @@ peewee = "^3.13.3"
|
|||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
bandit = "^1.6.2"
|
bandit = "^1.6.2"
|
||||||
black = { git = "https://github.com/psf/black.git" }
|
black = "^21.4b2"
|
||||||
blacken-docs = "^1.9.1"
|
blacken-docs = "^1.9.1"
|
||||||
ipython = "^7.10.2"
|
ipython = "^7.10.2"
|
||||||
mypy = "^0.790"
|
mypy = "^0.800"
|
||||||
pre-commit = "^2.1.1"
|
pre-commit = "^2.1.1"
|
||||||
pre-commit-hooks = "^3.4.0"
|
pre-commit-hooks = "^3.4.0"
|
||||||
pylint = "^2.6.0"
|
pylint = "^2.6.0"
|
||||||
@ -60,7 +60,9 @@ sphinx = "^3.3.0"
|
|||||||
sphinx-autodoc-typehints = "^1.11.1"
|
sphinx-autodoc-typehints = "^1.11.1"
|
||||||
toml = "^0.10.1"
|
toml = "^0.10.1"
|
||||||
tox = "^3.20.0"
|
tox = "^3.20.0"
|
||||||
tox-poetry-installer = {extras = ["poetry"], version = "^0.6.1"}
|
tox-poetry-installer = {extras = ["poetry"], version = "^0.7.0"}
|
||||||
|
mdformat = "^0.6"
|
||||||
|
mdformat-gfm = "^0.2"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
@ -3,7 +3,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
from imagemonk import __about__
|
from dehance import __about__
|
||||||
|
|
||||||
|
|
||||||
def test_about():
|
def test_about():
|
||||||
|
12
tox.ini
12
tox.ini
@ -16,7 +16,7 @@ locked_deps =
|
|||||||
pytest-cov
|
pytest-cov
|
||||||
toml
|
toml
|
||||||
commands =
|
commands =
|
||||||
pytest --cov={envsitepackagesdir}/imagemonk --cov-config {toxinidir}/.coveragerc --cov-report term-missing {toxinidir}/tests/
|
pytest --cov={envsitepackagesdir}/dehance --cov-config {toxinidir}/.coveragerc --cov-report term-missing {toxinidir}/tests/
|
||||||
|
|
||||||
[testenv:static]
|
[testenv:static]
|
||||||
description = Static formatting and quality enforcement
|
description = Static formatting and quality enforcement
|
||||||
@ -26,6 +26,8 @@ skip_install = true
|
|||||||
locked_deps =
|
locked_deps =
|
||||||
black
|
black
|
||||||
blacken-docs
|
blacken-docs
|
||||||
|
mdformat
|
||||||
|
mdformat-gfm
|
||||||
mypy
|
mypy
|
||||||
reorder-python-imports
|
reorder-python-imports
|
||||||
pre-commit
|
pre-commit
|
||||||
@ -33,8 +35,8 @@ locked_deps =
|
|||||||
pylint
|
pylint
|
||||||
commands =
|
commands =
|
||||||
pre-commit run --all-files
|
pre-commit run --all-files
|
||||||
pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/imagemonk/
|
pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/dehance/
|
||||||
mypy --ignore-missing-imports --no-strict-optional {toxinidir}/imagemonk/
|
mypy --ignore-missing-imports --no-strict-optional {toxinidir}/dehance/
|
||||||
|
|
||||||
[testenv:static-tests]
|
[testenv:static-tests]
|
||||||
description = Static formatting and quality enforcement for the tests
|
description = Static formatting and quality enforcement for the tests
|
||||||
@ -58,7 +60,7 @@ locked_deps =
|
|||||||
safety
|
safety
|
||||||
poetry
|
poetry
|
||||||
commands =
|
commands =
|
||||||
bandit --recursive --quiet {toxinidir}/imagemonk/
|
bandit --recursive --quiet {toxinidir}/dehance/
|
||||||
bandit --recursive --quiet --skip B101 {toxinidir}/tests/
|
bandit --recursive --quiet --skip B101 {toxinidir}/tests/
|
||||||
poetry export --format requirements.txt --output {envtmpdir}/requirements.txt --without-hashes --dev
|
poetry export --format requirements.txt --output {envtmpdir}/requirements.txt --without-hashes --dev
|
||||||
safety check --bare --file {envtmpdir}/requirements.txt
|
safety check --bare --file {envtmpdir}/requirements.txt
|
||||||
@ -70,5 +72,5 @@ locked_deps =
|
|||||||
sphinx
|
sphinx
|
||||||
sphinx-autodoc-typehints
|
sphinx-autodoc-typehints
|
||||||
commands =
|
commands =
|
||||||
sphinx-apidoc --no-toc --output-dir {toxinidir}/docs/ {toxinidir}/imagemonk/
|
sphinx-apidoc --no-toc --output-dir {toxinidir}/docs/ {toxinidir}/dehance/
|
||||||
sphinx-build -W -b html {toxinidir}/docs/ {toxinidir}/docs/_build
|
sphinx-build -W -b html {toxinidir}/docs/ {toxinidir}/docs/_build
|
||||||
|
Loading…
Reference in New Issue
Block a user