From 764f85fb40e15ce56eb78f01485a59f669783040 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 3 Apr 2021 11:25:57 -0800 Subject: [PATCH] Feature/additional endpoints (#257) * new recipe summary route * add categories to cards * add pillow * show tags instead of categories * additional debug info * add todays meal image url * about page * fix reactive tag * changelog + docs * bump version Co-authored-by: hay-kot --- docs/docs/changelog/v0.4.1.md | 6 + docs/docs/overrides/api.html | 2 +- docs/mkdocs.yml | 1 + frontend/src/api/meta.js | 7 + frontend/src/api/recipe.js | 6 + .../src/components/Admin/AdminSidebar.vue | 3 +- frontend/src/components/Recipe/RecipeCard.vue | 19 ++- .../Recipe/RecipeViewer/RecipeChips.vue | 19 ++- frontend/src/components/UI/CardSection.vue | 7 +- frontend/src/pages/Admin/About/index.vue | 91 +++++++++++ frontend/src/pages/Recipes/TagPage.vue | 2 +- frontend/src/routes/admin.js | 5 + frontend/src/store/index.js | 18 +-- mealie/core/config.py | 2 +- mealie/db/db_base.py | 13 +- mealie/routes/debug_routes.py | 24 ++- mealie/routes/mealplans/crud.py | 23 ++- mealie/routes/recipe/all_recipe_routes.py | 13 +- mealie/routes/recipe/recipe_crud_routes.py | 1 - mealie/schema/debug.py | 9 ++ mealie/schema/recipe.py | 27 +++- poetry.lock | 148 +++++++++--------- pyproject.toml | 3 +- 23 files changed, 330 insertions(+), 119 deletions(-) create mode 100644 frontend/src/pages/Admin/About/index.vue diff --git a/docs/docs/changelog/v0.4.1.md b/docs/docs/changelog/v0.4.1.md index 2b2a6d7b..5450bc4b 100644 --- a/docs/docs/changelog/v0.4.1.md +++ b/docs/docs/changelog/v0.4.1.md @@ -13,4 +13,10 @@ - Random meal-planner will no longer duplicate recipes unless no other options - New Quick Week button to generate next 5 day week of recipe slots. - Minor UI tweaks +- Recipe Cards now display 2 recipe tags +- Recipe images are now minified. This comes with a serious performance improvement. On initial startup you may experience some delays. Images are migrated to the new structure on startup, depending on the size of your database this can take some time. + - Note that original images are still kept for large displays like on the individual recipe pages. + - A smaller image is used for recipe cards + - A 'tiny' image is used for search images. + diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index 2219e40a..7e2e2ebc 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 080c3ca3..7d675172 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -74,6 +74,7 @@ nav: - Guidelines: "contributors/developers-guide/general-guidelines.md" - Development Road Map: "roadmap.md" - Change Log: + - v0.4.1 Frontend/UI: "changelog/v0.4.1.md" - v0.4.0 Authentication: "changelog/v0.4.0.md" - v0.3.0 Improvements: "changelog/v0.3.0.md" - v0.2.0 Now With Tests!: "changelog/v0.2.0.md" diff --git a/frontend/src/api/meta.js b/frontend/src/api/meta.js index e1aed1fe..59183c0c 100644 --- a/frontend/src/api/meta.js +++ b/frontend/src/api/meta.js @@ -5,6 +5,7 @@ const prefix = baseURL + "debug"; const debugURLs = { version: `${prefix}/version`, + debug: `${prefix}`, lastRecipe: `${prefix}/last-recipe-json`, demo: `${prefix}/is-demo`, }; @@ -14,6 +15,12 @@ export const metaAPI = { let response = await apiReq.get(debugURLs.version); return response.data; }, + + async getDebugInfo() { + const response = await apiReq.get(debugURLs.debug); + return response.data; + }, + async getLastJson() { let response = await apiReq.get(debugURLs.lastRecipe); return response.data; diff --git a/frontend/src/api/recipe.js b/frontend/src/api/recipe.js index 5eef791a..50e45e59 100644 --- a/frontend/src/api/recipe.js +++ b/frontend/src/api/recipe.js @@ -8,6 +8,7 @@ const prefix = baseURL + "recipes/"; const recipeURLs = { allRecipes: baseURL + "recipes", + summary: baseURL + "recipes" + "/summary", allRecipesByCategory: prefix + "category", create: prefix + "create", createByURL: prefix + "create-url", @@ -86,6 +87,11 @@ export const recipeAPI = { return response.data; }, + async allSummary() { + const response = await apiReq.get(recipeURLs.summary); + return response.data; + }, + recipeImage(recipeSlug) { return `/api/recipes/${recipeSlug}/image?image_type=original`; }, diff --git a/frontend/src/components/Admin/AdminSidebar.vue b/frontend/src/components/Admin/AdminSidebar.vue index 35876ef4..f0907049 100644 --- a/frontend/src/components/Admin/AdminSidebar.vue +++ b/frontend/src/components/Admin/AdminSidebar.vue @@ -74,7 +74,7 @@ - + mdi-information @@ -87,6 +87,7 @@ @@ -25,9 +26,9 @@ - + + + + \ No newline at end of file diff --git a/frontend/src/pages/Recipes/TagPage.vue b/frontend/src/pages/Recipes/TagPage.vue index e49fdb33..a6a0a991 100644 --- a/frontend/src/pages/Recipes/TagPage.vue +++ b/frontend/src/pages/Recipes/TagPage.vue @@ -33,7 +33,7 @@ export default { }, }, watch: { - async currentCategory() { + async currentTag() { this.getRecipes(); }, }, diff --git a/frontend/src/routes/admin.js b/frontend/src/routes/admin.js index e7637007..e52927db 100644 --- a/frontend/src/routes/admin.js +++ b/frontend/src/routes/admin.js @@ -6,6 +6,7 @@ import Migration from "@/pages/Admin/Migration"; import Profile from "@/pages/Admin/Profile"; import ManageUsers from "@/pages/Admin/ManageUsers"; import Settings from "@/pages/Admin/Settings"; +import About from "@/pages/Admin/About"; import { store } from "../store"; export default { @@ -50,5 +51,9 @@ export default { path: "settings", component: Settings, }, + { + path: "about", + component: About, + }, ], }; diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 8b0b4cc5..f8f17282 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -54,15 +54,15 @@ const store = new Vuex.Store({ actions: { async requestRecentRecipes() { - const keys = [ - "name", - "slug", - "image", - "description", - "dateAdded", - "rating", - ]; - const payload = await api.recipes.allByKeys(keys); + // const keys = [ + // "name", + // "slug", + // "image", + // "description", + // "dateAdded", + // "rating", + // ]; + const payload = await api.recipes.allSummary(); this.commit("setRecentRecipes", payload); }, diff --git a/mealie/core/config.py b/mealie/core/config.py index 5bcfe198..363b3298 100644 --- a/mealie/core/config.py +++ b/mealie/core/config.py @@ -5,7 +5,7 @@ from typing import Optional, Union from pydantic import BaseSettings, Field, validator -APP_VERSION = "v0.4.0" +APP_VERSION = "v0.4.1" DB_VERSION = "v0.4.0" CWD = Path(__file__).parent diff --git a/mealie/db/db_base.py b/mealie/db/db_base.py index 6aef2b24..f9e9a03a 100644 --- a/mealie/db/db_base.py +++ b/mealie/db/db_base.py @@ -15,17 +15,10 @@ class BaseDocument: self.schema: BaseModel # TODO: Improve Get All Query Functionality - def get_all(self, session: Session, limit: int = None, order_by: str = None) -> List[dict]: + def get_all(self, session: Session, limit: int = None, order_by: str = None, override_schema=None) -> List[dict]: + eff_schema = override_schema or self.schema - if self.orm_mode: - return [self.schema.from_orm(x) for x in session.query(self.sql_model).limit(limit).all()] - - # list = [x.dict() for x in session.query(self.sql_model).limit(limit).all()] - - # if limit == 1: - # return list[0] - - # return list + return [eff_schema.from_orm(x) for x in session.query(self.sql_model).limit(limit).all()] def get_all_limit_columns(self, session: Session, fields: List[str], limit: int = None) -> List[SqlAlchemyBase]: """Queries the database for the selected model. Restricts return responses to the diff --git a/mealie/routes/debug_routes.py b/mealie/routes/debug_routes.py index 5b0392cc..933e781c 100644 --- a/mealie/routes/debug_routes.py +++ b/mealie/routes/debug_routes.py @@ -3,15 +3,35 @@ import json from fastapi import APIRouter, Depends from mealie.core.config import APP_VERSION, LOGGER_FILE, app_dirs, settings from mealie.routes.deps import get_current_user -from mealie.schema.debug import AppInfo +from mealie.schema.debug import AppInfo, DebugInfo router = APIRouter(prefix="/api/debug", tags=["Debug"]) +@router.get("") +async def get_debug_info(current_user=Depends(get_current_user)): + """ Returns general information about the application for debugging """ + + return DebugInfo( + production=settings.PRODUCTION, + version=APP_VERSION, + demo_status=settings.IS_DEMO, + api_port=settings.API_PORT, + api_docs=settings.API_DOCS, + db_type=settings.DATABASE_TYPE, + sqlite_file=settings.SQLITE_FILE, + default_group=settings.DEFAULT_GROUP, + ) + + @router.get("/version") async def get_mealie_version(): """ Returns the current version of mealie""" - return AppInfo(version=APP_VERSION, demo_status=settings.IS_DEMO) + return AppInfo( + version=APP_VERSION, + demo_status=settings.IS_DEMO, + production=settings.PRODUCTION, + ) @router.get("/last-recipe-json") diff --git a/mealie/routes/mealplans/crud.py b/mealie/routes/mealplans/crud.py index c0498e6a..f1dcc02b 100644 --- a/mealie/routes/mealplans/crud.py +++ b/mealie/routes/mealplans/crud.py @@ -1,12 +1,14 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, HTTPException from mealie.db.database import db from mealie.db.db_setup import generate_session from mealie.routes.deps import get_current_user from mealie.schema.meal import MealPlanIn, MealPlanInDB from mealie.schema.snackbar import SnackResponse from mealie.schema.user import GroupInDB, UserInDB +from mealie.services.image import image from mealie.services.meal_services import get_todays_meal, process_meals from sqlalchemy.orm.session import Session +from starlette.responses import FileResponse router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"]) @@ -74,3 +76,22 @@ def get_today(session: Session = Depends(generate_session), current_user: UserIn recipe = get_todays_meal(session, group_in_db) return recipe.slug + + +@router.get("/today/image", tags=["Meal Plan"]) +def get_today(session: Session = Depends(generate_session), group_name: str = "Home"): + """ + Returns the image for todays meal-plan. + """ + + group_in_db: GroupInDB = db.groups.get(session, group_name, "name") + recipe = get_todays_meal(session, group_in_db) + + if recipe: + recipe_image = image.read_image(recipe.slug, image_type=image.IMG_OPTIONS.ORIGINAL_IMAGE) + else: + raise HTTPException(404, "no meal for today") + if recipe_image: + return FileResponse(recipe_image) + else: + raise HTTPException(404, "file not found") diff --git a/mealie/routes/recipe/all_recipe_routes.py b/mealie/routes/recipe/all_recipe_routes.py index 65990548..42dd6940 100644 --- a/mealie/routes/recipe/all_recipe_routes.py +++ b/mealie/routes/recipe/all_recipe_routes.py @@ -3,13 +3,24 @@ from typing import List, Optional from fastapi import APIRouter, Depends, Query from mealie.db.database import db from mealie.db.db_setup import generate_session -from mealie.schema.recipe import AllRecipeRequest +from mealie.schema.recipe import AllRecipeRequest, RecipeSummary from slugify import slugify from sqlalchemy.orm.session import Session router = APIRouter(tags=["Query All Recipes"]) +@router.get("/api/recipes/summary") +async def get_recipe_summary( + skip=0, + end=9999, + session: Session = Depends(generate_session), +): + """ Returns the summary data for recipes in the database """ + + return db.recipes.get_all(session, limit=end, override_schema=RecipeSummary) + + @router.get("/api/recipes") def get_all_recipes( keys: Optional[List[str]] = Query(...), diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index b044a80a..e696f87d 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -98,7 +98,6 @@ async def get_recipe_img(recipe_slug: str, image_type: ImageType = ImageType.ori which_image = IMG_OPTIONS.TINY_IMAGE recipe_image = read_image(recipe_slug, image_type=which_image) - print(recipe_image) if recipe_image: return FileResponse(recipe_image) else: diff --git a/mealie/schema/debug.py b/mealie/schema/debug.py index e0b8fccb..4cb94396 100644 --- a/mealie/schema/debug.py +++ b/mealie/schema/debug.py @@ -1,6 +1,15 @@ +from pathlib import Path from fastapi_camelcase import CamelModel class AppInfo(CamelModel): + production: bool version: str demo_status: bool + +class DebugInfo(AppInfo): + api_port: int + api_docs: bool + db_type: str + sqlite_file: Path + default_group: str \ No newline at end of file diff --git a/mealie/schema/recipe.py b/mealie/schema/recipe.py index be1df086..3ea0b9ae 100644 --- a/mealie/schema/recipe.py +++ b/mealie/schema/recipe.py @@ -34,12 +34,30 @@ class Nutrition(BaseModel): orm_mode = True -class Recipe(BaseModel): +class RecipeSummary(BaseModel): name: str - description: Optional[str] + slug: Optional[str] = "" image: Optional[Any] - recipeYield: Optional[str] + + description: Optional[str] recipeCategory: Optional[List[str]] = [] + tags: Optional[List[str]] = [] + rating: Optional[int] + + class Config: + orm_mode = True + + @classmethod + def getter_dict(_cls, name_orm: RecipeModel): + return { + **GetterDict(name_orm), + "recipeCategory": [x.name for x in name_orm.recipeCategory], + "tags": [x.name for x in name_orm.tags], + } + + +class Recipe(RecipeSummary): + recipeYield: Optional[str] recipeIngredient: Optional[list[str]] recipeInstructions: Optional[list[RecipeStep]] nutrition: Optional[Nutrition] @@ -50,11 +68,8 @@ class Recipe(BaseModel): performTime: Optional[str] = None # Mealie Specific - slug: Optional[str] = "" - tags: Optional[List[str]] = [] dateAdded: Optional[datetime.date] notes: Optional[List[RecipeNote]] = [] - rating: Optional[int] orgURL: Optional[str] extras: Optional[dict] = {} diff --git a/poetry.lock b/poetry.lock index 6b716505..20b2ae91 100644 --- a/poetry.lock +++ b/poetry.lock @@ -50,7 +50,7 @@ zookeeper = ["kazoo"] [[package]] name = "astroid" -version = "2.5.1" +version = "2.5.2" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -191,11 +191,11 @@ toml = ["toml"] [[package]] name = "decorator" -version = "4.4.2" +version = "5.0.4" description = "Decorators for Humans" category = "main" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" +python-versions = ">=3.5" [[package]] name = "ecdsa" @@ -412,11 +412,11 @@ python-versions = "*" [[package]] name = "lazy-object-proxy" -version = "1.5.2" +version = "1.6.0" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "livereload" @@ -610,7 +610,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" name = "pillow" version = "8.2.0" description = "Python Imaging Library (Fork)" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -698,14 +698,14 @@ python-versions = "*" [[package]] name = "pylint" -version = "2.7.2" +version = "2.7.4" description = "python code static checker" category = "dev" optional = false python-versions = "~=3.6" [package.dependencies] -astroid = ">=2.5.1,<2.6" +astroid = ">=2.5.2,<2.7" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" @@ -951,7 +951,7 @@ python-versions = ">=3.6" [[package]] name = "sqlalchemy" -version = "1.4.2" +version = "1.4.5" description = "Database Abstraction Library" category = "main" optional = false @@ -962,6 +962,7 @@ greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\""} [package.extras] aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] +aiosqlite = ["greenlet (!=0.4.17)", "aiosqlite"] asyncio = ["greenlet (!=0.4.17)"] mariadb_connector = ["mariadb (>=1.0.1)"] mssql = ["pyodbc"] @@ -977,6 +978,7 @@ postgresql_pg8000 = ["pg8000 (>=1.16.6)"] postgresql_psycopg2binary = ["psycopg2-binary"] postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql (<1)", "pymysql"] +sqlcipher = ["sqlcipher3-binary"] [[package]] name = "starlette" @@ -1162,7 +1164,7 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "32bff6a472fd8564106e2cfa20161a47d271d89ed44a5f2f2483f419fe259c92" +content-hash = "a81463b941cfdbc0e32e215644b172ec1111d5ada27864292d299d7d64fae4cf" [metadata.files] aiofiles = [ @@ -1182,8 +1184,8 @@ apscheduler = [ {file = "APScheduler-3.7.0.tar.gz", hash = "sha256:1cab7f2521e107d07127b042155b632b7a1cd5e02c34be5a28ff62f77c900c6a"}, ] astroid = [ - {file = "astroid-2.5.1-py3-none-any.whl", hash = "sha256:21d735aab248253531bb0f1e1e6d068f0ee23533e18ae8a6171ff892b98297cf"}, - {file = "astroid-2.5.1.tar.gz", hash = "sha256:cfc35498ee64017be059ceffab0a25bedf7548ab76f2bea691c5565896e7128d"}, + {file = "astroid-2.5.2-py3-none-any.whl", hash = "sha256:cd80bf957c49765dce6d92c43163ff9d2abc43132ce64d4b1b47717c6d2522df"}, + {file = "astroid-2.5.2.tar.gz", hash = "sha256:6b0ed1af831570e500e2437625979eaa3b36011f66ddfc4ce930128610258ca9"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, @@ -1320,8 +1322,8 @@ coverage = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] decorator = [ - {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, - {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, + {file = "decorator-5.0.4-py3-none-any.whl", hash = "sha256:7280eff5351d7004144b1f302347328c3d06e84271dbe690a5dc4b17eb586994"}, + {file = "decorator-5.0.4.tar.gz", hash = "sha256:cdd9d86d8aca11e4496f3cd26d48020db5a2fac247af0e918b3e0bbdb6e4a174"}, ] ecdsa = [ {file = "ecdsa-0.14.1-py2.py3-none-any.whl", hash = "sha256:e108a5fe92c67639abae3260e43561af914e7fd0d27bae6d2ec1312ae7934dfe"}, @@ -1444,30 +1446,28 @@ jstyleson = [ {file = "jstyleson-0.0.2.tar.gz", hash = "sha256:680003f3b15a2959e4e6a351f3b858e3c07dd3e073a0d54954e34d8ea5e1308e"}, ] lazy-object-proxy = [ - {file = "lazy-object-proxy-1.5.2.tar.gz", hash = "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4"}, - {file = "lazy_object_proxy-1.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315"}, - {file = "lazy_object_proxy-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871"}, - {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9"}, - {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128"}, - {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win32.whl", hash = "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847"}, - {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108"}, - {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068"}, - {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7"}, - {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win32.whl", hash = "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb"}, - {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a"}, - {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39"}, - {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0"}, - {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win32.whl", hash = "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef"}, - {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302"}, - {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163"}, - {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f"}, - {file = "lazy_object_proxy-1.5.2-cp38-cp38-win32.whl", hash = "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694"}, - {file = "lazy_object_proxy-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa"}, - {file = "lazy_object_proxy-1.5.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c"}, - {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"}, - {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458"}, - {file = "lazy_object_proxy-1.5.2-cp39-cp39-win32.whl", hash = "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166"}, - {file = "lazy_object_proxy-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84"}, + {file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"}, ] livereload = [ {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, @@ -1714,8 +1714,8 @@ pyhumps = [ {file = "pyhumps-1.6.1.tar.gz", hash = "sha256:01612603c5ad73a407299d806d30708a3935052276fdd93776953bccc0724e0a"}, ] pylint = [ - {file = "pylint-2.7.2-py3-none-any.whl", hash = "sha256:d09b0b07ba06bcdff463958f53f23df25e740ecd81895f7d2699ec04bbd8dc3b"}, - {file = "pylint-2.7.2.tar.gz", hash = "sha256:0e21d3b80b96740909d77206d741aa3ce0b06b41be375d92e1f3244a274c1f8a"}, + {file = "pylint-2.7.4-py3-none-any.whl", hash = "sha256:209d712ec870a0182df034ae19f347e725c1e615b2269519ab58a35b3fcbbe7a"}, + {file = "pylint-2.7.4.tar.gz", hash = "sha256:bd38914c7731cdc518634a8d3c5585951302b6e2b6de60fbb3f7a0220e21eeee"}, ] pymdown-extensions = [ {file = "pymdown-extensions-8.1.1.tar.gz", hash = "sha256:632371fa3bf1b21a0e3f4063010da59b41db049f261f4c0b0872069a9b6d1735"}, @@ -1849,40 +1849,40 @@ soupsieve = [ {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.4.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:aed22be55a608787bb6875dbcf3561349a0e88fe33fd88c318c1e5b4eeb2306a"}, - {file = "SQLAlchemy-1.4.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7e1b0ed6d720750f02333d2f52502dfc2a23185aacc2cc6ce6ec29d28c21397c"}, - {file = "SQLAlchemy-1.4.2-cp27-cp27m-win32.whl", hash = "sha256:9406b96a979ab8d6de5d89f58b1f103c9aeef6fb5367448537a8228619f11258"}, - {file = "SQLAlchemy-1.4.2-cp27-cp27m-win_amd64.whl", hash = "sha256:59ec279f1bd55e1d703e3d4b651600cc463cc3eafa8d8e5a70ab844f736348d4"}, - {file = "SQLAlchemy-1.4.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8cfcfcf2582b19c874fa20d0b75100abe17be80a4c637c0683b4eb919946dfee"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a6b4b7688fe7d251bbae3f9da4a487568bd584d13201bc7591c8639ad01fecdc"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0abab6d1044198993256f073340b14c459736777c550a7e914cd00444dcf9c30"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:5fb8f6a391992dd6aafe4fdf1dffbf7934fba1f5938593f20b152aa7f9619f82"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:97e333260a99d989f2a131aa8aa74140636dfbd030987150cb3748da607ea7db"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3fa75c854dba3f9b9c28bc5d88d246f6bc6f20b7480367c65339bcb2864d4707"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:1b9f3c7b281aa1c3d0c74ef12c4633e5f8358bb94f01be7b964887183fd53e5e"}, - {file = "SQLAlchemy-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:da72e3499bde4548e8b7d7f2ab23ceed09a5bac307bf51057e066c406a0ba2e1"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:8383292298bb85d7ad79a13c6571aff213b96c49737f3c3af129de63bbfb42c9"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4d1447183356c9679853926e81c7ebce3fbca9b1c607ea439975298c72137a36"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ff76d7dbf33f62e30e5a1d1b095d46afcdc49e42cbe33ce12014110147466700"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1ba6922331b3f38e116c9266206b044baf64576e5cebd87917b5ad872d7a025f"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:d3b2819f4d7ae56191efc6fc456eb1805ada2bd5ba93d918893bc24fa7a1e30c"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:3b290ff34de625143a05d2d172a88a064bb04a7938265b09d4e4bf45f21948f6"}, - {file = "SQLAlchemy-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5289cafee71037f15feeeaf736f01910b9e3572525b73b201bdd21816db010ed"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:0bb04fd7414718fb1f4dfa17efcb0be787363451cf99a5e992728925d298d9ae"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:4e88549a5e58ba8c80c5ea071ac3b4e590236672a882bb80f56da4afcee45d96"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:edec945ed57d11a1123657e4066f0bf747aaa93c8a65ec1c2c98172d1f2a9b7d"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:06125670280111e39014af87f14d74599fd4b39a512c74f1a10e21e5626eb158"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:e1692bdf1b95c97caab1201773a4576f59627997f598d30bdadc50dd9f897fec"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-win32.whl", hash = "sha256:65c4df9517da9cce2c1255282d3e39f2afbc3a02deba60d99b0a3283ae80ec0b"}, - {file = "SQLAlchemy-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c6197c88ad53c31f58de5a8180936b8ef027356e788cd5f6514b3439d3d897ac"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:6d6115edf1297bfa58994986ffe0dff21af18f0cba51dfa6d1769aa8a277be32"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:facacaea95e0822f7bbeaa6909b30b2836b14cff8790209d52a0c866e240b673"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6e517126d3bc13d455826befdc35a89f82f01d163848f68db02caa80d25433fc"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:09b08eb1bea621e47c2b0fcb0334fcbb00e1da2a3c2d45a98e56cd072b840719"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:7eba42098a13a3bcd509080b5e44d73783d9129ba0383793979bf518d01e8bb3"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-win32.whl", hash = "sha256:920db115eb06fc507fe2c774fb5c82a898b05dffbdadc7fafad51ce2cfd8c549"}, - {file = "SQLAlchemy-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:dcde5067a7dab1ff2eaea2f3622b2055c5225ce2aaf589c5a4c703d43519c4ba"}, - {file = "SQLAlchemy-1.4.2.tar.gz", hash = "sha256:6a8e4c2e65028933a6dc8643c8f5a4f295a367131195b3c708634925cb3e8ec1"}, + {file = "SQLAlchemy-1.4.5-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c3810ebcf1d42c532c8f5c3f442c705d94442a27a32f2df5344f0857306ab321"}, + {file = "SQLAlchemy-1.4.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7481f9c2c832a3bf37c80bee44d91ac9938b815cc06f7e795b976e300914aab9"}, + {file = "SQLAlchemy-1.4.5-cp27-cp27m-win32.whl", hash = "sha256:94040a92b6676f9ffdab6c6b479b3554b927a635c90698c761960b266b04fc88"}, + {file = "SQLAlchemy-1.4.5-cp27-cp27m-win_amd64.whl", hash = "sha256:02b039e0e7e6de2f15ea2d2de3995e31a170e700ec0b37b4eded662171711d19"}, + {file = "SQLAlchemy-1.4.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f16801795f1ffe9472360589a04301018c79e4582a85e68067275bb4f765e4e2"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:82f11b679df91275788be6734dd4a9dfa29bac67b85326992609f62b05bdab37"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a08027ae84efc563f0f2f341dda572eadebeca38c0ae028a009988f27e9e6230"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:70a1387396ea5b3022539b560c287daf79403d8b4b365f89b56d660e625a4457"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4f7ce3bfdab6520554af4a5b1df4513d45388624d015ba4d921daf48ce1d6503"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:08943201a1e3c6238e48f4d5d56c27ea1e1b39d3d9f36a9d81fc3cfb0e1b83bd"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-win32.whl", hash = "sha256:fbb0fda1c574975807aceb0e2332e0ecfe9e5656c191ed482c1a5eafe7a33823"}, + {file = "SQLAlchemy-1.4.5-cp36-cp36m-win_amd64.whl", hash = "sha256:8d6a9feb5efd2fdab25c6d5a0a5589fed9d789f5ec57ec12263fd0e60ce1dea6"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:c22bfac8d3b955cdb13f0fcd6343156bf56d925196cf7d9ab9ce9f61d3f1e11c"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:7c0c7bb49167ac738ca6ee6e7f94a9988a7e4e261d8da335341e8c8c8f3b2e9b"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:344b58b4b4193b72e8b768a51ef6eb5a4c948ce313a0f23e2ea081e71ce8ac0e"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:48540072f43b3c080159ec1f24a4b014c0ee83d3b73795399974aa358a8cf71b"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:81badd7d3e0e6aba70a5d1b50fabe8112e9835a6fdb0684054c3fe5378ce0d01"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:a103294583383660d9e06dbd82037dc8e94c184bdcb27b2be44ae4457dafc6b4"}, + {file = "SQLAlchemy-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5361e25181b9872d6906c8c9be7dc05cb0a0951d71ee59ee5a71c1deb301b8a8"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:7f5087104c3c5af11ea59e49ae66c33ca98b14a47d3796ae97498fca53f84aef"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:11e7a86209f69273e75d2dd64b06c0c2660e39cd942fce2170515c404ed7358a"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:8301ecf3e819eb5dbc171e84654ff60872807775301a55fe35b0ab2ba3742031"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:44e11a06168782b6d485daef197783366ce7ab0d5eea0066c899ae06cef47bbc"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:6f8fdad2f335d2f3ca2f3ee3b01404f7abcf519b03de2c510f1f42d16e39ffb4"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-win32.whl", hash = "sha256:f62c57ceadedeb8e7b98b48ac4d684bf2b0f73b9d882fed3ca260d9aedf6403f"}, + {file = "SQLAlchemy-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:301d0cd6ef1dc73b607748183da857e712d6f743de8d92b1e1f8facfb0ba2aa2"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:915d4fa08776c0252dc5a34fa15c6490f66f411ea1ac9492022f98875d6baf20"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7de84feb31af3d8fdf819cac2042928d0b60d3cb16f49c4b2f48d88db46e79f6"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:45b091ccbf94374ed14abde17e9a04522b0493a17282eaaf4383efdd413f5243"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:4df07161897191ed8d4a0cfc92425c81296160e5c5f76c9256716d3085172883"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ee4ddc904fb6414b5118af5b8d45e428aac2ccda01326b2ba2fe4354b0d8d1ae"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-win32.whl", hash = "sha256:2f11b5783933bff55291ca06496124347627d211ff2e509e846af1c35de0a3fb"}, + {file = "SQLAlchemy-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:0ee0054d4a598d2920cae14bcbd33e200e02c5e3b47b902627f8cf5d4c9a2a4b"}, + {file = "SQLAlchemy-1.4.5.tar.gz", hash = "sha256:1294f05916c044631fd626a4866326bbfbd17f62bd37510d000afaef4b35bd74"}, ] starlette = [ {file = "starlette-0.13.6-py3-none-any.whl", hash = "sha256:bd2ffe5e37fb75d014728511f8e68ebf2c80b0fa3d04ca1479f4dc752ae31ac9"}, diff --git a/pyproject.toml b/pyproject.toml index 68dd7b38..5af7567e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,8 @@ bcrypt = "^3.2.0" python-jose = "^3.2.0" passlib = "^1.7.4" lxml = "4.6.2" +Pillow = "^8.2.0" + [tool.poetry.dev-dependencies] pylint = "^2.6.0" @@ -39,7 +41,6 @@ pytest-cov = "^2.11.0" mkdocs-material = "^7.0.2" flake8 = "^3.9.0" coverage = "^5.5" -Pillow = "^8.2.0" [build-system] requires = ["poetry-core>=1.0.0"]