chores: updates-and-linters (#1868)

* switch to ruff

* add ruff

* run ruff --fix

* update ruff

* resolve ruff errors

* drop isort from CI

* fix decorator order
This commit is contained in:
Hayden 2022-11-30 20:20:28 -09:00 committed by GitHub
parent fd0e02a5c6
commit 82dc586bac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 362 additions and 536 deletions

10
.flake8
View File

@ -1,10 +0,0 @@
[flake8]
extend-ignore = [
E501 # Line Length - See Black Config in pyproject.toml
E402 # Import Not at Top of File
]
exclude = _all_models.py
per-file-ignores =
__init__.py:F403,F401

View File

@ -66,10 +66,9 @@ jobs:
poetry add "psycopg2-binary==2.8.6" poetry add "psycopg2-binary==2.8.6"
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' || steps.cache-validate.outputs.cache-hit-success != 'true' if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' || steps.cache-validate.outputs.cache-hit-success != 'true'
- name: Formatting (Black & isort) - name: Formatting (Black)
run: | run: |
poetry run black . --check poetry run black . --check
poetry run isort . --check-only
- name: Lint (Flake8) - name: Lint (Flake8)
run: | run: |

View File

@ -10,22 +10,11 @@ repos:
- id: end-of-file-fixer - id: end-of-file-fixer
- id: trailing-whitespace - id: trailing-whitespace
exclude: ^tests/data/ exclude: ^tests/data/
- repo: https://github.com/asottile/pyupgrade
rev: v3.1.0
hooks:
- id: pyupgrade
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
name: isort (python)
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.3.0 rev: 22.3.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/pycqa/flake8 - repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "4.0.1" rev: v0.0.149
hooks: hooks:
- id: flake8 - id: ruff
additional_dependencies:
- "flake8-print==4.0.0"

View File

@ -29,7 +29,7 @@
"i18n-ally.sourceLanguage": "en-US", "i18n-ally.sourceLanguage": "en-US",
"python.formatting.provider": "black", "python.formatting.provider": "black",
"python.linting.enabled": true, "python.linting.enabled": true,
"python.linting.flake8Enabled": true, "python.linting.flake8Enabled": false,
"python.linting.pylintEnabled": false, "python.linting.pylintEnabled": false,
"python.linting.pylintArgs": ["--rcfile=${workspaceFolder}/.pylintrc"], "python.linting.pylintArgs": ["--rcfile=${workspaceFolder}/.pylintrc"],
"python.testing.autoTestDiscoverOnSaveEnabled": false, "python.testing.autoTestDiscoverOnSaveEnabled": false,
@ -44,7 +44,7 @@
"explorer.fileNesting.enabled": true, "explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": { "explorer.fileNesting.patterns": {
"package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig", "package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig",
"pyproject.toml": "poetry.lock, alembic.ini, .pylintrc, .flake8", "pyproject.toml": "poetry.lock, alembic.ini, .pylintrc",
"netlify.toml": "runtime.txt", "netlify.toml": "runtime.txt",
"docker-compose.yml": "Dockerfile, .dockerignore, docker-compose.dev.yml, docker-compose.yml", "docker-compose.yml": "Dockerfile, .dockerignore, docker-compose.dev.yml, docker-compose.yml",
"README.md": "LICENSE, SECURITY.md" "README.md": "LICENSE, SECURITY.md"

View File

@ -84,12 +84,11 @@ backend-typecheck:
backend-test: ## 🧪 Run tests quickly with the default Python backend-test: ## 🧪 Run tests quickly with the default Python
poetry run pytest poetry run pytest
backend-format: ## 🧺 Format, Check and Flake8 backend-format: ## 🧺 Format the codebase
poetry run isort .
poetry run black . poetry run black .
backend-lint: backend-lint: ## 🧹 Lint the codebase (Ruff)
poetry run flake8 mealie tests poetry run ruff mealie
backend-all: backend-format backend-lint backend-typecheck backend-test ## 🧪 Runs all the backend checks and tests backend-all: backend-format backend-lint backend-typecheck backend-test ## 🧪 Runs all the backend checks and tests

View File

@ -15,15 +15,18 @@ settings = get_app_settings()
description = f""" description = f"""
Mealie is a web application for managing your recipes, meal plans, and shopping lists. This is the Restful Mealie is a web application for managing your recipes, meal plans, and shopping lists. This is the Restful
API interactive documentation that can be used to explore the API. If you're justing getting started with API interactive documentation that can be used to explore the API. If you're justing getting started with
the API and want to get started quickly, you can use the [API Usage | Mealie Docs](https://hay-kot.github.io/mealie/documentation/getting-started/api-usage/) the API and want to get started quickly, you can use the
[API Usage | Mealie Docs](https://hay-kot.github.io/mealie/documentation/getting-started/api-usage/)
as a reference for how to get started. as a reference for how to get started.
As of this release <b>{APP_VERSION}</b>, Mealie is still in rapid development and therefore some of these APIs may change from version to version. As of this release <b>{APP_VERSION}</b>, Mealie is still in rapid development and therefore some of these APIs may
change from version to version.
If you have any questions or comments about mealie, please use the discord server to talk to the developers or other community members. If you have any questions or comments about mealie, please use the discord server to talk to the developers or other
If you'd like to file an issue, please use the [GitHub Issue Tracker | Mealie](https://github.com/hay-kot/mealie/issues/new/choose) community members. If you'd like to file an issue, please use the
[GitHub Issue Tracker | Mealie](https://github.com/hay-kot/mealie/issues/new/choose)
## Helpful Links ## Helpful Links
@ -32,8 +35,6 @@ If you'd like to file an issue, please use the [GitHub Issue Tracker | Mealie](h
- [Discord](https://discord.gg/QuStdQGSGK) - [Discord](https://discord.gg/QuStdQGSGK)
- [Demo](https://demo.mealie.io) - [Demo](https://demo.mealie.io)
- [Beta](https://demo.mealie.io) - [Beta](https://demo.mealie.io)
""" """
app = FastAPI( app = FastAPI(

View File

@ -2,7 +2,6 @@ import shutil
import tempfile import tempfile
from collections.abc import AsyncGenerator, Callable, Generator from collections.abc import AsyncGenerator, Callable, Generator
from pathlib import Path from pathlib import Path
from typing import Optional
from uuid import uuid4 from uuid import uuid4
from fastapi import Depends, HTTPException, status from fastapi import Depends, HTTPException, status
@ -116,7 +115,7 @@ def validate_long_live_token(session: Session, client_token: str, user_id: str)
raise HTTPException(status.HTTP_401_UNAUTHORIZED) from e raise HTTPException(status.HTTP_401_UNAUTHORIZED) from e
def validate_file_token(token: Optional[str] = None) -> Path: def validate_file_token(token: str | None = None) -> Path:
""" """
Args: Args:
token (Optional[str], optional): _description_. Defaults to None. token (Optional[str], optional): _description_. Defaults to None.
@ -143,7 +142,7 @@ def validate_file_token(token: Optional[str] = None) -> Path:
return file_path return file_path
def validate_recipe_token(token: Optional[str] = None) -> str: def validate_recipe_token(token: str | None = None) -> str:
""" """
Args: Args:
token (Optional[str], optional): _description_. Defaults to None. token (Optional[str], optional): _description_. Defaults to None.

View File

@ -7,7 +7,7 @@ from mealie.core.config import determine_data_dir
DATA_DIR = determine_data_dir() DATA_DIR = determine_data_dir()
from .config import get_app_settings from .config import get_app_settings # noqa E402
LOGGER_FILE = DATA_DIR.joinpath("mealie.log") LOGGER_FILE = DATA_DIR.joinpath("mealie.log")
DATE_FORMAT = "%d-%b-%y %H:%M:%S" DATE_FORMAT = "%d-%b-%y %H:%M:%S"

View File

@ -1,17 +1,19 @@
from abc import ABC, abstractproperty from abc import ABC, abstractmethod
from pathlib import Path from pathlib import Path
from pydantic import BaseModel, BaseSettings, PostgresDsn from pydantic import BaseModel, BaseSettings, PostgresDsn
class AbstractDBProvider(ABC): class AbstractDBProvider(ABC):
@abstractproperty @property
@abstractmethod
def db_url(self) -> str: def db_url(self) -> str:
pass ...
@property @property
@abstractmethod
def db_url_public(self) -> str: def db_url_public(self) -> str:
pass ...
class SQLiteProvider(AbstractDBProvider, BaseModel): class SQLiteProvider(AbstractDBProvider, BaseModel):

View File

@ -1,6 +1,5 @@
import secrets import secrets
from pathlib import Path from pathlib import Path
from typing import Optional
from pydantic import BaseSettings, NoneStr from pydantic import BaseSettings, NoneStr
@ -54,7 +53,7 @@ class AppSettings(BaseSettings):
# Database Configuration # Database Configuration
DB_ENGINE: str = "sqlite" # Options: 'sqlite', 'postgres' DB_ENGINE: str = "sqlite" # Options: 'sqlite', 'postgres'
DB_PROVIDER: Optional[AbstractDBProvider] = None DB_PROVIDER: AbstractDBProvider | None = None
@property @property
def DB_URL(self) -> str | None: def DB_URL(self) -> str | None:
@ -71,13 +70,13 @@ class AppSettings(BaseSettings):
# =============================================== # ===============================================
# Email Configuration # Email Configuration
SMTP_HOST: Optional[str] SMTP_HOST: str | None
SMTP_PORT: Optional[str] = "587" SMTP_PORT: str | None = "587"
SMTP_FROM_NAME: Optional[str] = "Mealie" SMTP_FROM_NAME: str | None = "Mealie"
SMTP_FROM_EMAIL: Optional[str] SMTP_FROM_EMAIL: str | None
SMTP_USER: Optional[str] SMTP_USER: str | None
SMTP_PASSWORD: Optional[str] SMTP_PASSWORD: str | None
SMTP_AUTH_STRATEGY: Optional[str] = "TLS" # Options: 'TLS', 'SSL', 'NONE' SMTP_AUTH_STRATEGY: str | None = "TLS" # Options: 'TLS', 'SSL', 'NONE'
@property @property
def SMTP_ENABLE(self) -> bool: def SMTP_ENABLE(self) -> bool:

View File

@ -1,2 +1,8 @@
from .auto_init import auto_init from .auto_init import auto_init
from .guid import GUID from .guid import GUID
__all__ = [
"auto_init",
"GUID",
]

View File

@ -17,7 +17,7 @@ class Translator(Protocol):
pass pass
@lru_cache() @lru_cache
def _load_factory() -> i18n.ProviderFactory: def _load_factory() -> i18n.ProviderFactory:
return i18n.ProviderFactory( return i18n.ProviderFactory(
directory=TRANSLATIONS, directory=TRANSLATIONS,

View File

@ -1,7 +0,0 @@
"""
This package containers helpful development tools to be used for development and testing. It shouldn't be used for or imported
in production
"""
from .lifespan_tracker import *
from .timer import *

View File

@ -1,26 +0,0 @@
import time
# log_lifetime is a class decorator that logs the creation and destruction of a class
# It is used to track the lifespan of a class during development or testing.
# It SHOULD NOT be used in production code.
def log_lifetime(cls):
class LifeTimeClass(cls):
def __init__(self, *args, **kwargs):
print(f"Creating an instance of {cls.__name__}") # noqa: T001
self.__lifespan_timer_start = time.perf_counter()
super().__init__(*args, **kwargs)
def __del__(self):
toc = time.perf_counter()
print(f"Downloaded the tutorial in {toc - self.__lifespan_timer_start:0.4f} seconds") # noqa: T001
print(f"Deleting an instance of {cls.__name__}") # noqa: T001
try:
super().__del__()
except AttributeError:
pass
return LifeTimeClass

View File

@ -1,12 +0,0 @@
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start} seconds") # noqa: T001
return result
return wrapper

View File

@ -283,7 +283,7 @@ class RepositoryGeneric(Generic[Schema, Model]):
except ValueError as e: except ValueError as e:
self.logger.error(e) self.logger.error(e)
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e)) from e
count = query.count() count = query.count()

View File

@ -1,5 +1,3 @@
from typing import Union
from pydantic import UUID4 from pydantic import UUID4
from mealie.db.models.group import Group from mealie.db.models.group import Group
@ -15,7 +13,7 @@ from .repository_generic import RepositoryGeneric
class RepositoryGroup(RepositoryGeneric[GroupInDB, Group]): class RepositoryGroup(RepositoryGeneric[GroupInDB, Group]):
def get_by_name(self, name: str, limit=1) -> Union[GroupInDB, Group, None]: def get_by_name(self, name: str, limit=1) -> GroupInDB | Group | None:
dbgroup = self.session.query(self.model).filter_by(**{"name": name}).one_or_none() dbgroup = self.session.query(self.model).filter_by(**{"name": name}).one_or_none()
if dbgroup is None: if dbgroup is None:
return None return None

View File

@ -1,5 +1,5 @@
from random import randint from random import randint
from typing import Any, Optional from typing import Any
from uuid import UUID from uuid import UUID
from pydantic import UUID4 from pydantic import UUID4
@ -135,10 +135,10 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
pagination: PaginationQuery, pagination: PaginationQuery,
override=None, override=None,
load_food=False, load_food=False,
cookbook: Optional[ReadCookBook] = None, cookbook: ReadCookBook | None = None,
categories: Optional[list[UUID4 | str]] = None, categories: list[UUID4 | str] | None = None,
tags: Optional[list[UUID4 | str]] = None, tags: list[UUID4 | str] | None = None,
tools: Optional[list[UUID4 | str]] = None, tools: list[UUID4 | str] | None = None,
) -> RecipePagination: ) -> RecipePagination:
q = self.session.query(self.model) q = self.session.query(self.model)
@ -307,7 +307,7 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
.limit(limit) .limit(limit)
] ]
def get_by_slug(self, group_id: UUID4, slug: str, limit=1) -> Optional[Recipe]: def get_by_slug(self, group_id: UUID4, slug: str, limit=1) -> Recipe | None:
dbrecipe = ( dbrecipe = (
self.session.query(RecipeModel) self.session.query(RecipeModel)
.filter(RecipeModel.group_id == group_id, RecipeModel.slug == slug) .filter(RecipeModel.group_id == group_id, RecipeModel.slug == slug)

View File

@ -5,7 +5,7 @@ See their repository for details -> https://github.com/dmontagu/fastapi-utils
""" """
import inspect import inspect
from collections.abc import Callable from collections.abc import Callable
from typing import Any, TypeVar, Union, cast, get_type_hints from typing import Any, TypeVar, cast, get_type_hints
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from fastapi.routing import APIRoute from fastapi.routing import APIRoute
@ -92,8 +92,8 @@ def _init_cbv(cls: type[Any], instance: Any = None) -> None:
else: else:
old_init(self, *args, **kwargs) old_init(self, *args, **kwargs)
setattr(cls, "__signature__", new_signature) cls.__signature__ = new_signature
setattr(cls, "__init__", new_init) cls.__init__ = new_init
setattr(cls, CBV_CLASS_KEY, True) setattr(cls, CBV_CLASS_KEY, True)
for name in private_attributes: for name in private_attributes:
@ -122,7 +122,7 @@ def _register_endpoints(router: APIRouter, cls: type[Any], *urls: str) -> None:
} }
prefix_length = len(router.prefix) prefix_length = len(router.prefix)
routes_to_append: list[tuple[int, Union[Route, WebSocketRoute]]] = [] routes_to_append: list[tuple[int, Route | WebSocketRoute]] = []
for _, func in function_members: for _, func in function_members:
index_route = numbered_routes_by_endpoint.get(func) index_route = numbered_routes_by_endpoint.get(func)
@ -177,7 +177,7 @@ def _allocate_routes_by_method_name(router: APIRouter, url: str, function_member
api_resource(func) api_resource(func)
def _update_cbv_route_endpoint_signature(cls: type[Any], route: Union[Route, WebSocketRoute]) -> None: def _update_cbv_route_endpoint_signature(cls: type[Any], route: Route | WebSocketRoute) -> None:
""" """
Fixes the endpoint signature for a cbv route to ensure FastAPI performs dependency injection properly. Fixes the endpoint signature for a cbv route to ensure FastAPI performs dependency injection properly.
""" """
@ -191,4 +191,4 @@ def _update_cbv_route_endpoint_signature(cls: type[Any], route: Union[Route, Web
] ]
new_signature = old_signature.replace(parameters=new_parameters) new_signature = old_signature.replace(parameters=new_parameters)
setattr(route.endpoint, "__signature__", new_signature) route.endpoint.__signature__ = new_signature

View File

@ -3,7 +3,6 @@ import json
from collections.abc import Callable from collections.abc import Callable
from enum import Enum from enum import Enum
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
from typing import Optional, Union
from fastapi import APIRouter, Depends, Request, Response from fastapi import APIRouter, Depends, Request, Response
from fastapi.routing import APIRoute from fastapi.routing import APIRoute
@ -14,14 +13,14 @@ from mealie.core.dependencies import get_admin_user, get_current_user
class AdminAPIRouter(APIRouter): class AdminAPIRouter(APIRouter):
"""Router for functions to be protected behind admin authentication""" """Router for functions to be protected behind admin authentication"""
def __init__(self, tags: Optional[list[Union[str, Enum]]] = None, prefix: str = "", **kwargs): def __init__(self, tags: list[str | Enum] | None = None, prefix: str = "", **kwargs):
super().__init__(tags=tags, prefix=prefix, dependencies=[Depends(get_admin_user)], **kwargs) super().__init__(tags=tags, prefix=prefix, dependencies=[Depends(get_admin_user)], **kwargs)
class UserAPIRouter(APIRouter): class UserAPIRouter(APIRouter):
"""Router for functions to be protected behind user authentication""" """Router for functions to be protected behind user authentication"""
def __init__(self, tags: Optional[list[Union[str, Enum]]] = None, prefix: str = "", **kwargs): def __init__(self, tags: list[str | Enum] | None = None, prefix: str = "", **kwargs):
super().__init__(tags=tags, prefix=prefix, dependencies=[Depends(get_current_user)], **kwargs) super().__init__(tags=tags, prefix=prefix, dependencies=[Depends(get_current_user)], **kwargs)

View File

@ -1,5 +1,4 @@
from datetime import timedelta from datetime import timedelta
from typing import Optional
from fastapi import APIRouter, Depends, Form, status from fastapi import APIRouter, Depends, Form, status
from fastapi.exceptions import HTTPException from fastapi.exceptions import HTTPException
@ -27,8 +26,8 @@ class CustomOAuth2Form(OAuth2PasswordRequestForm):
password: str = Form(...), password: str = Form(...),
remember_me: bool = Form(False), remember_me: bool = Form(False),
scope: str = Form(""), scope: str = Form(""),
client_id: Optional[str] = Form(None), client_id: str | None = Form(None),
client_secret: Optional[str] = Form(None), client_secret: str | None = Form(None),
): ):
self.grant_type = grant_type self.grant_type = grant_type
self.username = username self.username = username

View File

@ -1,10 +1,8 @@
from functools import cached_property from functools import cached_property
from typing import Type
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
from pydantic import UUID4 from pydantic import UUID4
from mealie.core.exceptions import mealie_registered_exceptions
from mealie.routes._base.base_controllers import BaseUserController from mealie.routes._base.base_controllers import BaseUserController
from mealie.routes._base.controller import controller from mealie.routes._base.controller import controller
from mealie.routes._base.mixins import HttpRepo from mealie.routes._base.mixins import HttpRepo

View File

@ -1,6 +1,5 @@
from datetime import date from datetime import date
from functools import cached_property from functools import cached_property
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
@ -84,15 +83,17 @@ class GroupMealplanController(BaseUserController):
return self.mixins.create_one( return self.mixins.create_one(
SavePlanEntry(date=data.date, entry_type=data.entry_type, recipe_id=recipe.id, group_id=self.group_id) SavePlanEntry(date=data.date, entry_type=data.entry_type, recipe_id=recipe.id, group_id=self.group_id)
) )
except IndexError: except IndexError as e:
raise HTTPException(status_code=404, detail=ErrorResponse.respond(message="No recipes match your rules")) raise HTTPException(
status_code=404, detail=ErrorResponse.respond(message="No recipes match your rules")
) from e
@router.get("", response_model=PlanEntryPagination) @router.get("", response_model=PlanEntryPagination)
def get_all( def get_all(
self, self,
q: PaginationQuery = Depends(PaginationQuery), q: PaginationQuery = Depends(PaginationQuery),
start_date: Optional[date] = None, start_date: date | None = None,
end_date: Optional[date] = None, end_date: date | None = None,
): ):
# merge start and end dates into pagination query only if either is provided # merge start and end dates into pagination query only if either is provided
if start_date or end_date: if start_date or end_date:

View File

@ -45,7 +45,7 @@ class GroupMigrationController(BaseUserController):
migrator: BaseMigrator migrator: BaseMigrator
match migration_type: match migration_type: # noqa match not supported by ruff
case SupportedMigrations.chowdown: case SupportedMigrations.chowdown:
migrator = ChowdownMigrator(**args) migrator = ChowdownMigrator(**args)
case SupportedMigrations.mealie_alpha: case SupportedMigrations.mealie_alpha:

View File

@ -41,5 +41,5 @@ async def get_recipe_asset(recipe_id: UUID4, file_name: str):
try: try:
return FileResponse(file) return FileResponse(file)
except Exception: except Exception as e:
raise HTTPException(status.HTTP_404_NOT_FOUND) raise HTTPException(status.HTTP_404_NOT_FOUND) from e

View File

@ -140,7 +140,7 @@ router = UserAPIRouter(prefix="/recipes", tags=["Recipe: CRUD"], route_class=Mea
@controller(router) @controller(router)
class RecipeController(BaseRecipeController): class RecipeController(BaseRecipeController):
def handle_exceptions(self, ex: Exception) -> None: def handle_exceptions(self, ex: Exception) -> None:
match type(ex): match type(ex): # noqa match statement not supported
case exceptions.PermissionDenied: case exceptions.PermissionDenied:
self.logger.error("Permission Denied on recipe controller action") self.logger.error("Permission Denied on recipe controller action")
raise HTTPException(status_code=403, detail=ErrorResponse.respond(message="Permission Denied")) raise HTTPException(status_code=403, detail=ErrorResponse.respond(message="Permission Denied"))

View File

@ -1,3 +1 @@
from typing import Optional NoneFloat = float | None
NoneFloat = Optional[float]

View File

@ -1,5 +1,4 @@
from datetime import datetime from datetime import datetime
from typing import Optional
from pydantic import BaseModel from pydantic import BaseModel
@ -20,9 +19,9 @@ class ImportJob(BackupOptions):
class CreateBackup(BaseModel): class CreateBackup(BaseModel):
tag: Optional[str] tag: str | None
options: BackupOptions options: BackupOptions
templates: Optional[list[str]] templates: list[str] | None
class BackupFile(BaseModel): class BackupFile(BaseModel):

View File

@ -1,16 +1,14 @@
from typing import Optional
from pydantic.main import BaseModel from pydantic.main import BaseModel
class ImportBase(BaseModel): class ImportBase(BaseModel):
name: str name: str
status: bool status: bool
exception: Optional[str] exception: str | None
class RecipeImport(ImportBase): class RecipeImport(ImportBase):
slug: Optional[str] slug: str | None
class CommentImport(ImportBase): class CommentImport(ImportBase):

View File

@ -1,5 +1,3 @@
from typing import Optional
from pydantic import validator from pydantic import validator
from slugify import slugify from slugify import slugify
@ -10,7 +8,7 @@ from ..recipe.recipe_category import RecipeCategoryResponse
class CustomPageBase(MealieModel): class CustomPageBase(MealieModel):
name: str name: str
slug: Optional[str] slug: str | None
position: int position: int
categories: list[RecipeCategoryResponse] = [] categories: list[RecipeCategoryResponse] = []

View File

@ -1,5 +1,3 @@
from typing import Optional
from pydantic import UUID4 from pydantic import UUID4
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
@ -10,4 +8,4 @@ from .group_preferences import UpdateGroupPreferences
class GroupAdminUpdate(MealieModel): class GroupAdminUpdate(MealieModel):
id: UUID4 id: UUID4
name: str name: str
preferences: Optional[UpdateGroupPreferences] = None preferences: UpdateGroupPreferences | None = None

View File

@ -1,5 +1,4 @@
from datetime import date from datetime import date
from typing import Optional
from pydantic import validator from pydantic import validator
@ -7,16 +6,16 @@ from mealie.schema._mealie import MealieModel
class MealIn(MealieModel): class MealIn(MealieModel):
slug: Optional[str] slug: str | None
name: Optional[str] name: str | None
description: Optional[str] description: str | None
class Config: class Config:
orm_mode = True orm_mode = True
class MealDayIn(MealieModel): class MealDayIn(MealieModel):
date: Optional[date] date: date | None
meals: list[MealIn] meals: list[MealIn]
class Config: class Config:
@ -48,7 +47,7 @@ class MealPlanIn(MealieModel):
class MealPlanOut(MealPlanIn): class MealPlanOut(MealPlanIn):
id: int id: int
shopping_list: Optional[int] shopping_list: int | None
class Config: class Config:
orm_mode = True orm_mode = True

View File

@ -1,6 +1,5 @@
from datetime import date from datetime import date
from enum import Enum from enum import Enum
from typing import Optional
from uuid import UUID from uuid import UUID
from pydantic import validator from pydantic import validator
@ -27,7 +26,7 @@ class CreatePlanEntry(MealieModel):
entry_type: PlanEntryType = PlanEntryType.breakfast entry_type: PlanEntryType = PlanEntryType.breakfast
title: str = "" title: str = ""
text: str = "" text: str = ""
recipe_id: Optional[UUID] recipe_id: UUID | None
@validator("recipe_id", always=True) @validator("recipe_id", always=True)
@classmethod @classmethod
@ -51,7 +50,7 @@ class SavePlanEntry(CreatePlanEntry):
class ReadPlanEntry(UpdatePlanEntry): class ReadPlanEntry(UpdatePlanEntry):
recipe: Optional[RecipeSummary] recipe: RecipeSummary | None
class Config: class Config:
orm_mode = True orm_mode = True

View File

@ -1,5 +1,3 @@
from typing import Optional
from pydantic.utils import GetterDict from pydantic.utils import GetterDict
from mealie.db.models.group.shopping_list import ShoppingList from mealie.db.models.group.shopping_list import ShoppingList
@ -7,7 +5,7 @@ from mealie.schema._mealie import MealieModel
class ListItem(MealieModel): class ListItem(MealieModel):
title: Optional[str] title: str | None
text: str = "" text: str = ""
quantity: int = 1 quantity: int = 1
checked: bool = False checked: bool = False
@ -18,7 +16,7 @@ class ListItem(MealieModel):
class ShoppingListIn(MealieModel): class ShoppingListIn(MealieModel):
name: str name: str
group: Optional[str] group: str | None
items: list[ListItem] items: list[ListItem]

View File

@ -1,12 +1,10 @@
from typing import Optional
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
class RecipeAsset(MealieModel): class RecipeAsset(MealieModel):
name: str name: str
icon: str icon: str
file_name: Optional[str] file_name: str | None
class Config: class Config:
orm_mode = True orm_mode = True

View File

@ -65,7 +65,7 @@ class RecipeTagResponse(RecipeCategoryResponse):
pass pass
from mealie.schema.recipe.recipe import RecipeSummary from mealie.schema.recipe.recipe import RecipeSummary # noqa: E402
RecipeCategoryResponse.update_forward_refs() RecipeCategoryResponse.update_forward_refs()
RecipeTagResponse.update_forward_refs() RecipeTagResponse.update_forward_refs()

View File

@ -1,5 +1,4 @@
from datetime import datetime from datetime import datetime
from typing import Optional
from pydantic import UUID4 from pydantic import UUID4
@ -9,7 +8,7 @@ from mealie.schema.response.pagination import PaginationBase
class UserBase(MealieModel): class UserBase(MealieModel):
id: UUID4 id: UUID4
username: Optional[str] username: str | None
admin: bool admin: bool
class Config: class Config:

View File

@ -1,16 +1,14 @@
from typing import Optional
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
class Nutrition(MealieModel): class Nutrition(MealieModel):
calories: Optional[str] calories: str | None
fat_content: Optional[str] fat_content: str | None
protein_content: Optional[str] protein_content: str | None
carbohydrate_content: Optional[str] carbohydrate_content: str | None
fiber_content: Optional[str] fiber_content: str | None
sodium_content: Optional[str] sodium_content: str | None
sugar_content: Optional[str] sugar_content: str | None
class Config: class Config:
orm_mode = True orm_mode = True

View File

@ -1,4 +1,3 @@
from typing import Optional
from uuid import UUID, uuid4 from uuid import UUID, uuid4
from pydantic import UUID4, Field from pydantic import UUID4, Field
@ -11,15 +10,15 @@ class IngredientReferences(MealieModel):
A list of ingredient references. A list of ingredient references.
""" """
reference_id: Optional[UUID4] reference_id: UUID4 | None
class Config: class Config:
orm_mode = True orm_mode = True
class RecipeStep(MealieModel): class RecipeStep(MealieModel):
id: Optional[UUID] = Field(default_factory=uuid4) id: UUID | None = Field(default_factory=uuid4)
title: Optional[str] = "" title: str | None = ""
text: str text: str
ingredient_references: list[IngredientReferences] = [] ingredient_references: list[IngredientReferences] = []

View File

@ -1,5 +1,3 @@
import typing
from pydantic import UUID4 from pydantic import UUID4
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
@ -23,7 +21,7 @@ class RecipeToolOut(RecipeToolCreate):
class RecipeToolResponse(RecipeToolOut): class RecipeToolResponse(RecipeToolOut):
recipes: typing.List["Recipe"] = [] recipes: list["Recipe"] = []
class Config: class Config:
orm_mode = True orm_mode = True

View File

@ -62,7 +62,14 @@ class QueryFilter:
self.filter_components = QueryFilter._parse_base_components_into_filter_components(base_components) self.filter_components = QueryFilter._parse_base_components_into_filter_components(base_components)
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<<{" ".join([str(component.value if isinstance(component, LogicalOperator) else component) for component in self.filter_components])}>>' joined = " ".join(
[
str(component.value if isinstance(component, LogicalOperator) else component)
for component in self.filter_components
],
)
return f"<<{joined}>>"
def filter_query(self, query: Query, model: type[Model]) -> Query: def filter_query(self, query: Query, model: type[Model]) -> Query:
segments: list[str] = [] segments: list[str] = []
@ -76,8 +83,9 @@ class QueryFilter:
segments.append(component.value) segments.append(component.value)
continue continue
# for some reason typing doesn't like the lsep and rsep literals, so we explicitly mark this as a filter component instead # for some reason typing doesn't like the lsep and rsep literals, so
# cast doesn't actually do anything at runtime # we explicitly mark this as a filter component instead cast doesn't
# actually do anything at runtime
component = cast(QueryFilterComponent, component) component = cast(QueryFilterComponent, component)
if not hasattr(model, component.attribute_name): if not hasattr(model, component.attribute_name):

View File

@ -1,5 +1,3 @@
from typing import Optional
from pydantic import BaseModel from pydantic import BaseModel
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
@ -8,10 +6,10 @@ from mealie.schema._mealie import MealieModel
class ErrorResponse(BaseModel): class ErrorResponse(BaseModel):
message: str message: str
error: bool = True error: bool = True
exception: Optional[str] = None exception: str | None = None
@classmethod @classmethod
def respond(cls, message: str, exception: Optional[str] = None) -> dict: def respond(cls, message: str, exception: str | None = None) -> dict:
""" """
This method is an helper to create an object and convert to a dictionary This method is an helper to create an object and convert to a dictionary
in the same call, for use while providing details to a HTTPException in the same call, for use while providing details to a HTTPException

View File

@ -1,5 +1,3 @@
from typing import Optional
from pydantic import UUID4, BaseModel from pydantic import UUID4, BaseModel
from pydantic.types import constr from pydantic.types import constr
@ -12,8 +10,8 @@ class Token(BaseModel):
class TokenData(BaseModel): class TokenData(BaseModel):
user_id: Optional[UUID4] user_id: UUID4 | None
username: Optional[constr(to_lower=True, strip_whitespace=True)] = None # type: ignore username: constr(to_lower=True, strip_whitespace=True) | None = None # type: ignore
class UnlockResults(MealieModel): class UnlockResults(MealieModel):

View File

@ -1,6 +1,6 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Any
from uuid import UUID from uuid import UUID
from pydantic import UUID4, Field, validator from pydantic import UUID4, Field, validator
@ -62,13 +62,13 @@ class GroupBase(MealieModel):
class UserBase(MealieModel): class UserBase(MealieModel):
username: Optional[str] username: str | None
full_name: Optional[str] = None full_name: str | None = None
email: constr(to_lower=True, strip_whitespace=True) # type: ignore email: constr(to_lower=True, strip_whitespace=True) # type: ignore
admin: bool = False admin: bool = False
group: Optional[str] group: str | None
advanced: bool = False advanced: bool = False
favorite_recipes: Optional[list[str]] = [] favorite_recipes: list[str] | None = []
can_invite: bool = False can_invite: bool = False
can_manage: bool = False can_manage: bool = False
@ -103,9 +103,9 @@ class UserOut(UserBase):
id: UUID4 id: UUID4
group: str group: str
group_id: UUID4 group_id: UUID4
tokens: Optional[list[LongLiveTokenOut]] tokens: list[LongLiveTokenOut] | None
cache_key: str cache_key: str
favorite_recipes: Optional[list[str]] = [] favorite_recipes: list[str] | None = []
class Config: class Config:
orm_mode = True orm_mode = True
@ -171,14 +171,14 @@ class PrivateUser(UserOut):
class UpdateGroup(GroupBase): class UpdateGroup(GroupBase):
id: UUID4 id: UUID4
name: str name: str
categories: Optional[list[CategoryBase]] = [] categories: list[CategoryBase] | None = []
webhooks: list[Any] = [] webhooks: list[Any] = []
class GroupInDB(UpdateGroup): class GroupInDB(UpdateGroup):
users: Optional[list[UserOut]] users: list[UserOut] | None
preferences: Optional[ReadGroupPreferences] = None preferences: ReadGroupPreferences | None = None
class Config: class Config:
orm_mode = True orm_mode = True

View File

@ -1 +1,6 @@
from .email_service import EmailService, EmailTemplate from .email_service import EmailService, EmailTemplate
__all__ = [
"EmailService",
"EmailTemplate",
]

View File

@ -130,7 +130,7 @@ class WebhookEventListener(EventListenerBase):
return scheduled_webhooks return scheduled_webhooks
def publish_to_subscribers(self, event: Event, subscribers: list[ReadWebhook]) -> None: def publish_to_subscribers(self, event: Event, subscribers: list[ReadWebhook]) -> None:
match event.document_data.document_type: match event.document_data.document_type: # noqa - match statement not supported by ruff
case EventDocumentType.mealplan: case EventDocumentType.mealplan:
# TODO: limit mealplan data to a date range instead of returning all mealplans # TODO: limit mealplan data to a date range instead of returning all mealplans
meal_repo = self.repos.meals.by_group(self.group_id) meal_repo = self.repos.meals.by_group(self.group_id)

View File

@ -1,5 +1,3 @@
from typing import Optional
from fastapi import BackgroundTasks, Depends from fastapi import BackgroundTasks, Depends
from pydantic import UUID4 from pydantic import UUID4
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
@ -45,7 +43,7 @@ class EventBusService:
group_id: UUID4 | None group_id: UUID4 | None
def __init__( def __init__(
self, bg: Optional[BackgroundTasks] = None, session: Optional[Session] = None, group_id: UUID4 | None = None self, bg: BackgroundTasks | None = None, session: Session | None = None, group_id: UUID4 | None = None
) -> None: ) -> None:
self.bg = bg self.bg = bg
self.session = session self.session = session
@ -61,7 +59,7 @@ class EventBusService:
integration_id: str, integration_id: str,
group_id: UUID4, group_id: UUID4,
event_type: EventTypes, event_type: EventTypes,
document_data: Optional[EventDocumentDataBase], document_data: EventDocumentDataBase | None,
message: str = "", message: str = "",
) -> None: ) -> None:
self.group_id = group_id self.group_id = group_id

View File

@ -3,7 +3,7 @@ from abc import abstractmethod, abstractproperty
from collections.abc import Iterator from collections.abc import Iterator
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Callable, Optional from typing import Callable
from uuid import UUID from uuid import UUID
from pydantic import BaseModel from pydantic import BaseModel
@ -28,7 +28,7 @@ class ExportedItem:
class ABCExporter(BaseService): class ABCExporter(BaseService):
write_dir_to_zip: Callable[[Path, str, Optional[set[str]]], None] | None write_dir_to_zip: Callable[[Path, str, set[str] | None], None] | None
def __init__(self, db: AllRepositories, group_id: UUID) -> None: def __init__(self, db: AllRepositories, group_id: UUID) -> None:
self.logger = get_logger() self.logger = get_logger()

View File

@ -169,7 +169,9 @@ class ShoppingListService:
if not updated_shopping_list: if not updated_shopping_list:
raise UnexpectedNone("Shopping List not found") raise UnexpectedNone("Shopping List not found")
updated_shopping_list_items, deleted_shopping_list_items = self.consolidate_and_save(updated_shopping_list.list_items) # type: ignore updated_shopping_list_items, deleted_shopping_list_items = self.consolidate_and_save(
updated_shopping_list.list_items, # type: ignore
)
updated_shopping_list.list_items = updated_shopping_list_items updated_shopping_list.list_items = updated_shopping_list_items
not_found = True not_found = True
@ -268,5 +270,8 @@ class ShoppingListService:
self.list_refs.update(recipe_ref.id, ref) self.list_refs.update(recipe_ref.id, ref)
break break
# Save Changes return (
return self.shopping_lists.get_one(shopping_list.id), updated_shopping_list_items, deleted_shopping_list_items # type: ignore self.shopping_lists.get_one(shopping_list.id),
updated_shopping_list_items,
deleted_shopping_list_items,
) # type: ignore

View File

@ -2,7 +2,6 @@ import tempfile
import zipfile import zipfile
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Optional
from slugify import slugify from slugify import slugify
@ -15,7 +14,7 @@ from .utils.migration_helpers import MigrationReaders, glob_walker, import_image
class NextcloudDir: class NextcloudDir:
name: str name: str
recipe: dict recipe: dict
image: Optional[Path] image: Path | None
@property @property
def slug(self): def slug(self):

View File

@ -1,5 +1,4 @@
from collections.abc import Callable from collections.abc import Callable
from typing import Optional
from pydantic import BaseModel from pydantic import BaseModel
@ -12,4 +11,4 @@ class MigrationAlias(BaseModel):
key: str key: str
alias: str alias: str
func: Optional[Callable] = None func: Callable | None = None

View File

@ -1 +1,5 @@
from .process import parse from .process import parse
__all__ = [
"parse",
]

View File

@ -26,8 +26,8 @@ def parse_fraction(x):
raise ValueError raise ValueError
try: try:
return int(frac_split[0]) / int(frac_split[1]) return int(frac_split[0]) / int(frac_split[1])
except ZeroDivisionError: except ZeroDivisionError as e:
raise ValueError raise ValueError from e
def parse_amount(ing_str) -> tuple[float, str, str]: def parse_amount(ing_str) -> tuple[float, str, str]:

View File

@ -52,7 +52,8 @@ def wrap_or_clause(string: str):
Attempts to wrap or clauses in () Attempts to wrap or clauses in ()
Examples: Examples:
'1 tsp. Diamond Crystal or ½ tsp. Morton kosher salt, plus more' -> '1 teaspoon diamond crystal (or 1/2 teaspoon morton kosher salt), plus more' '1 tsp. Diamond Crystal or ½ tsp. Morton kosher salt, plus more'
-> '1 teaspoon diamond crystal (or 1/2 teaspoon morton kosher salt), plus more'
""" """
# TODO: Needs more adequite testing to be sure this doesn't have side effects. # TODO: Needs more adequite testing to be sure this doesn't have side effects.

View File

@ -17,14 +17,17 @@ async def largest_content_len(urls: list[str]) -> tuple[str, int]:
largest_url = "" largest_url = ""
largest_len = 0 largest_len = 0
def do(session: requests.Session, url: str):
def _do() -> requests.Response:
return session.head(url, headers={"User-Agent": _FIREFOX_UA})
return _do
with ThreadPoolExecutor(max_workers=10) as executor: with ThreadPoolExecutor(max_workers=10) as executor:
with requests.Session() as session: with requests.Session() as session:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
tasks = [ tasks = [loop.run_in_executor(executor, do(session, url)) for url in urls]
loop.run_in_executor(executor, lambda: session.head(url, headers={"User-Agent": _FIREFOX_UA}))
for url in urls
]
response: requests.Response # required for type hinting within the loop response: requests.Response # required for type hinting within the loop
for response in await asyncio.gather(*tasks): for response in await asyncio.gather(*tasks):

View File

@ -3,7 +3,6 @@ import shutil
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from shutil import copytree, rmtree from shutil import copytree, rmtree
from typing import Union
from zipfile import ZipFile from zipfile import ZipFile
from fastapi import UploadFile from fastapi import UploadFile
@ -27,12 +26,6 @@ step_text = """Recipe steps as well as other fields in the recipe page support m
[My Link](https://demo.mealie.io) [My Link](https://demo.mealie.io)
**Embed an image**
Use the `height="100"` or `width="100"` attributes to set the size of the image.
<img height="100" src="https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=960&q=80"></img>
""" """
ingredient_note = "1 Cup Flour" ingredient_note = "1 Cup Flour"
@ -110,7 +103,7 @@ class RecipeService(BaseService):
return Recipe(**additional_attrs) return Recipe(**additional_attrs)
def create_one(self, create_data: Union[Recipe, CreateRecipe]) -> Recipe: def create_one(self, create_data: Recipe | CreateRecipe) -> Recipe:
if create_data.name is None: if create_data.name is None:
create_data.name = "New Recipe" create_data.name = "New Recipe"

View File

@ -6,22 +6,22 @@ import logging
from asyncio import ensure_future from asyncio import ensure_future
from functools import wraps from functools import wraps
from traceback import format_exception from traceback import format_exception
from typing import Any, Callable, Coroutine, Optional, Union from typing import Any, Callable, Coroutine
from starlette.concurrency import run_in_threadpool from starlette.concurrency import run_in_threadpool
NoArgsNoReturnFuncT = Callable[[], None] NoArgsNoReturnFuncT = Callable[[], None]
NoArgsNoReturnAsyncFuncT = Callable[[], Coroutine[Any, Any, None]] NoArgsNoReturnAsyncFuncT = Callable[[], Coroutine[Any, Any, None]]
NoArgsNoReturnDecorator = Callable[[Union[NoArgsNoReturnFuncT, NoArgsNoReturnAsyncFuncT]], NoArgsNoReturnAsyncFuncT] NoArgsNoReturnDecorator = Callable[[NoArgsNoReturnFuncT | NoArgsNoReturnAsyncFuncT], NoArgsNoReturnAsyncFuncT]
def repeat_every( def repeat_every(
*, *,
minutes: float, minutes: float,
wait_first: bool = False, wait_first: bool = False,
logger: Optional[logging.Logger] = None, logger: logging.Logger | None = None,
raise_exceptions: bool = False, raise_exceptions: bool = False,
max_repetitions: Optional[int] = None, max_repetitions: int | None = None,
) -> NoArgsNoReturnDecorator: ) -> NoArgsNoReturnDecorator:
""" """
This function returns a decorator that modifies a function so it is periodically re-executed after its first call. This function returns a decorator that modifies a function so it is periodically re-executed after its first call.
@ -46,7 +46,7 @@ def repeat_every(
The maximum number of times to call the repeated function. If `None`, the function is repeated forever. The maximum number of times to call the repeated function. If `None`, the function is repeated forever.
""" """
def decorator(func: Union[NoArgsNoReturnAsyncFuncT, NoArgsNoReturnFuncT]) -> NoArgsNoReturnAsyncFuncT: def decorator(func: NoArgsNoReturnAsyncFuncT | NoArgsNoReturnFuncT) -> NoArgsNoReturnAsyncFuncT:
""" """
Converts the decorated function into a repeated, periodically-called version of itself. Converts the decorated function into a repeated, periodically-called version of itself.
""" """

View File

@ -1,5 +1,4 @@
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Optional
from pydantic import UUID4 from pydantic import UUID4
@ -18,7 +17,7 @@ from mealie.services.event_bus_service.event_types import (
last_ran = datetime.now(timezone.utc) last_ran = datetime.now(timezone.utc)
def post_group_webhooks(start_dt: Optional[datetime] = None, group_id: Optional[UUID4] = None) -> None: def post_group_webhooks(start_dt: datetime | None = None, group_id: UUID4 | None = None) -> None:
"""Post webhook events to specified group, or all groups""" """Post webhook events to specified group, or all groups"""
global last_ran global last_ran

View File

@ -95,7 +95,7 @@ def clean_image(image: str | list | dict | None = None, default="no image") -> s
if not image: if not image:
return default return default
match image: match image: # noqa - match statement not supported
case str(image): case str(image):
return image return image
case list(image): case list(image):
@ -189,7 +189,13 @@ def clean_instructions(steps_object: list | dict | str, default: list | None = N
# } # }
# #
steps_object = typing.cast(list[dict[str, str]], steps_object) steps_object = typing.cast(list[dict[str, str]], steps_object)
return clean_instructions(functools.reduce(operator.concat, [x["itemListElement"] for x in steps_object], [])) # type: ignore return clean_instructions(
functools.reduce(
operator.concat, # type: ignore
[x["itemListElement"] for x in steps_object],
[],
)
)
case _: case _:
raise TypeError(f"Unexpected type for instructions: {type(steps_object)}, {steps_object}") raise TypeError(f"Unexpected type for instructions: {type(steps_object)}, {steps_object}")

View File

@ -42,7 +42,7 @@ class PasswordResetService(BaseService):
email_servive.send_forgot_password(email, reset_url) email_servive.send_forgot_password(email, reset_url)
except Exception as e: except Exception as e:
self.logger.error(f"failed to send reset email: {e}") self.logger.error(f"failed to send reset email: {e}")
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR, "Failed to send reset email") raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR, "Failed to send reset email") from e
def reset_password(self, token: str, new_password: str): def reset_password(self, token: str, new_password: str):
# Validate Token # Validate Token

331
poetry.lock generated
View File

@ -56,19 +56,19 @@ python-versions = "*"
[[package]] [[package]]
name = "apprise" name = "apprise"
version = "0.9.9" version = "1.2.0"
description = "Push Notifications that work with just about every platform!" description = "Push Notifications that work with just about every platform!"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=2.7" python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
certifi = "*"
click = ">=5.0" click = ">=5.0"
markdown = "*" markdown = "*"
PyYAML = "*" PyYAML = "*"
requests = "*" requests = "*"
requests-oauthlib = "*" requests-oauthlib = "*"
six = "*"
[[package]] [[package]]
name = "astroid" name = "astroid"
@ -83,14 +83,6 @@ lazy-object-proxy = ">=1.4.0"
setuptools = ">=20.0" setuptools = ">=20.0"
wrapt = ">=1.11,<2" wrapt = ">=1.11,<2"
[[package]]
name = "atomicwrites"
version = "1.4.1"
description = "Atomic file writes."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
name = "attrs" name = "attrs"
version = "21.4.0" version = "21.4.0"
@ -107,15 +99,12 @@ tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy"
[[package]] [[package]]
name = "bcrypt" name = "bcrypt"
version = "3.2.2" version = "4.0.1"
description = "Modern password hashing for your software and your servers" description = "Modern password hashing for your software and your servers"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[package.dependencies]
cffi = ">=1.1"
[package.extras] [package.extras]
tests = ["pytest (>=3.2.1,!=3.3.0)"] tests = ["pytest (>=3.2.1,!=3.3.0)"]
typecheck = ["mypy"] typecheck = ["mypy"]
@ -169,22 +158,11 @@ category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[[package]]
name = "cffi"
version = "1.15.1"
description = "Foreign Function Interface for Python calling C code."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
pycparser = "*"
[[package]] [[package]]
name = "cfgv" name = "cfgv"
version = "3.3.1" version = "3.3.1"
description = "Validate configuration and produce human readable error messages." description = "Validate configuration and produce human readable error messages."
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=3.6.1" python-versions = ">=3.6.1"
@ -264,7 +242,7 @@ graph = ["objgraph (>=1.7.2)"]
name = "distlib" name = "distlib"
version = "0.3.4" version = "0.3.4"
description = "Distribution utilities" description = "Distribution utilities"
category = "dev" category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
@ -283,6 +261,17 @@ six = ">=1.9.0"
gmpy = ["gmpy"] gmpy = ["gmpy"]
gmpy2 = ["gmpy2"] gmpy2 = ["gmpy2"]
[[package]]
name = "exceptiongroup"
version = "1.0.4"
description = "Backport of PEP 654 (exception groups)"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
test = ["pytest (>=6)"]
[[package]] [[package]]
name = "extruct" name = "extruct"
version = "0.13.0" version = "0.13.0"
@ -327,7 +316,7 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (
name = "filelock" name = "filelock"
version = "3.7.1" version = "3.7.1"
description = "A platform independent file lock." description = "A platform independent file lock."
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
@ -335,32 +324,6 @@ python-versions = ">=3.7"
docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
[[package]]
name = "flake8"
version = "4.0.1"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.8.0,<2.9.0"
pyflakes = ">=2.4.0,<2.5.0"
[[package]]
name = "flake8-print"
version = "4.0.1"
description = "print statement checker plugin for flake8"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
flake8 = ">=3.0"
pycodestyle = "*"
six = "*"
[[package]] [[package]]
name = "ghp-import" name = "ghp-import"
version = "2.1.0" version = "2.1.0"
@ -455,7 +418,7 @@ test = ["Cython (==0.29.22)"]
name = "identify" name = "identify"
version = "2.5.1" version = "2.5.1"
description = "File identification library for Python" description = "File identification library for Python"
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
@ -720,7 +683,7 @@ python-versions = "*"
name = "nodeenv" name = "nodeenv"
version = "1.7.0" version = "1.7.0"
description = "Node.js virtual environment builder" description = "Node.js virtual environment builder"
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
@ -830,7 +793,7 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa
name = "platformdirs" name = "platformdirs"
version = "2.5.2" version = "2.5.2"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
@ -852,9 +815,9 @@ testing = ["pytest", "pytest-benchmark"]
[[package]] [[package]]
name = "pre-commit" name = "pre-commit"
version = "2.19.0" version = "2.20.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks." description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
@ -874,14 +837,6 @@ category = "main"
optional = true optional = true
python-versions = ">=3.6" python-versions = ">=3.6"
[[package]]
name = "py"
version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "pyasn1" name = "pyasn1"
version = "0.4.8" version = "0.4.8"
@ -901,22 +856,6 @@ python-versions = "*"
[package.dependencies] [package.dependencies]
pyasn1 = ">=0.4.6,<0.5.0" pyasn1 = ">=0.4.6,<0.5.0"
[[package]]
name = "pycodestyle"
version = "2.8.0"
description = "Python style guide checker"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pycparser"
version = "2.21"
description = "C parser in Python"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "1.10.2" version = "1.10.2"
@ -944,14 +883,6 @@ python-versions = "*"
click = "*" click = "*"
pydantic = "*" pydantic = "*"
[[package]]
name = "pyflakes"
version = "2.4.0"
description = "passive checker of Python programs"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
name = "pygments" name = "pygments"
version = "2.12.0" version = "2.12.0"
@ -1046,40 +977,23 @@ Pillow = ">=8.0.0"
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "6.2.5" version = "7.2.0"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0" attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""} colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*" iniconfig = "*"
packaging = "*" packaging = "*"
pluggy = ">=0.12,<2.0" pluggy = ">=0.12,<2.0"
py = ">=1.8.2" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
toml = "*"
[package.extras] [package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "pytest-cov"
version = "2.12.1"
description = "Pytest plugin for measuring coverage."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.dependencies]
coverage = ">=5.2.1"
pytest = ">=4.6"
toml = "*"
[package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
@ -1208,7 +1122,7 @@ rdflib = ">=5.0.0"
[[package]] [[package]]
name = "recipe-scrapers" name = "recipe-scrapers"
version = "14.23.0" version = "14.24.0"
description = "Python package, scraping recipes from all over the internet" description = "Python package, scraping recipes from all over the internet"
category = "main" category = "main"
optional = false optional = false
@ -1280,6 +1194,14 @@ python-versions = ">=3.6,<4"
[package.dependencies] [package.dependencies]
pyasn1 = ">=0.1.3" pyasn1 = ">=0.1.3"
[[package]]
name = "ruff"
version = "0.0.149"
description = "An extremely fast Python linter, written in Rust."
category = "dev"
optional = false
python-versions = ">=3.7"
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "65.4.0" version = "65.4.0"
@ -1375,7 +1297,7 @@ python-versions = "*"
name = "toml" name = "toml"
version = "0.10.2" version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language" description = "Python Library for Tom's Obvious, Minimal Language"
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
@ -1506,7 +1428,7 @@ test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOp
name = "virtualenv" name = "virtualenv"
version = "20.15.1" version = "20.15.1"
description = "Virtual Python Environment builder" description = "Virtual Python Environment builder"
category = "dev" category = "main"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
@ -1595,7 +1517,7 @@ pgsql = ["psycopg2-binary"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "9b8033d971c49138bf8eb949e57e104b82b795ad45551586c1624f494388b5ef" content-hash = "39816ee8fea6764e99683a670968b08acb6887c529d5fe7af864b0ad9fbafb4e"
[metadata.files] [metadata.files]
aiofiles = [ aiofiles = [
@ -1619,32 +1541,39 @@ appdirs = [
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
] ]
apprise = [ apprise = [
{file = "apprise-0.9.9-py2.py3-none-any.whl", hash = "sha256:afc4a637598b984b2bda3d997a362f52906ef9e3167f81001440153a4d57b871"}, {file = "apprise-1.2.0-py2.py3-none-any.whl", hash = "sha256:9f7dd12e8cebeef7268c87b64f04a22c4a99ca3af17113af91985501e1a7d478"},
{file = "apprise-0.9.9.tar.gz", hash = "sha256:6ba3d0e8307e2647c3240ec1a0d5571f3a453f9143d94834ecb02660b0e8d244"}, {file = "apprise-1.2.0.tar.gz", hash = "sha256:6e31afa18f47452eaccd56fb7ee83d92452c534d15f392407ed1a0e3c465244b"},
] ]
astroid = [ astroid = [
{file = "astroid-2.11.7-py3-none-any.whl", hash = "sha256:86b0a340a512c65abf4368b80252754cda17c02cdbbd3f587dddf98112233e7b"}, {file = "astroid-2.11.7-py3-none-any.whl", hash = "sha256:86b0a340a512c65abf4368b80252754cda17c02cdbbd3f587dddf98112233e7b"},
{file = "astroid-2.11.7.tar.gz", hash = "sha256:bb24615c77f4837c707669d16907331374ae8a964650a66999da3f5ca68dc946"}, {file = "astroid-2.11.7.tar.gz", hash = "sha256:bb24615c77f4837c707669d16907331374ae8a964650a66999da3f5ca68dc946"},
] ]
atomicwrites = [
{file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
]
attrs = [ attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
] ]
bcrypt = [ bcrypt = [
{file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"}, {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"},
{file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26"}, {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"},
{file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb"}, {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"},
{file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a"}, {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"},
{file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521"}, {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"},
{file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40"}, {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"},
{file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa"}, {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"},
{file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"}, {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"},
{file = "bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e"}, {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"},
{file = "bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129"}, {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"},
{file = "bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb"}, {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"},
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"},
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"},
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"},
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"},
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"},
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"},
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"},
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"},
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"},
{file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"},
] ]
beautifulsoup4 = [ beautifulsoup4 = [
{file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"},
@ -1658,72 +1587,6 @@ certifi = [
{file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
{file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
] ]
cffi = [
{file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
{file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
{file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
{file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
{file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
{file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
{file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
{file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
{file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
{file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
{file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
{file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
{file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
{file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
{file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
{file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
{file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
{file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
{file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
{file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
{file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
{file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
{file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
{file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
{file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
{file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
{file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
{file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
{file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
{file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
{file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
{file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
{file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
{file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
{file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
]
cfgv = [ cfgv = [
{file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
@ -1814,6 +1677,10 @@ ecdsa = [
{file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"},
{file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"},
] ]
exceptiongroup = [
{file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"},
{file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"},
]
extruct = [ extruct = [
{file = "extruct-0.13.0-py2.py3-none-any.whl", hash = "sha256:fe19b9aefdb4dfbf828c2b082b81a363a03a44c7591c2d6b62ca225cb8f8c0be"}, {file = "extruct-0.13.0-py2.py3-none-any.whl", hash = "sha256:fe19b9aefdb4dfbf828c2b082b81a363a03a44c7591c2d6b62ca225cb8f8c0be"},
{file = "extruct-0.13.0.tar.gz", hash = "sha256:50a5b5bac4c5e19ecf682bf63a28fde0b1bb57433df7057371f60b58c94a2c64"}, {file = "extruct-0.13.0.tar.gz", hash = "sha256:50a5b5bac4c5e19ecf682bf63a28fde0b1bb57433df7057371f60b58c94a2c64"},
@ -1826,14 +1693,6 @@ filelock = [
{file = "filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"}, {file = "filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
{file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"}, {file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
] ]
flake8 = [
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
]
flake8-print = [
{file = "flake8-print-4.0.1.tar.gz", hash = "sha256:12b3c3bf65329d8ca9acde949fb3b932ec113e9e5ffa6cb7cd55a7dbcd67dae1"},
{file = "flake8_print-4.0.1-py3-none-any.whl", hash = "sha256:e246bcd5b07d5259af460b7eff148052c49114640380d7f22340f30920fabf02"},
]
ghp-import = [ ghp-import = [
{file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
@ -2203,10 +2062,7 @@ orjson = [
{file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"}, {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"},
{file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"}, {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"},
{file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"}, {file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"},
{file = "orjson-3.8.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:200eae21c33f1f8b02a11f5d88d76950cd6fd986d88f1afe497a8ae2627c49aa"},
{file = "orjson-3.8.0-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9529990f3eab54b976d327360aa1ff244a4b12cb5e4c5b3712fcdd96e8fe56d4"},
{file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"}, {file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"},
{file = "orjson-3.8.0-cp311-none-win_amd64.whl", hash = "sha256:b21c7af0ff6228ca7105f54f0800636eb49201133e15ddb80ac20c1ce973ef07"},
{file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"}, {file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"},
{file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"}, {file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"},
{file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"}, {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"},
@ -2320,13 +2176,12 @@ pluggy = [
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
] ]
pre-commit = [ pre-commit = [
{file = "pre_commit-2.19.0-py2.py3-none-any.whl", hash = "sha256:10c62741aa5704faea2ad69cb550ca78082efe5697d6f04e5710c3c229afdd10"}, {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"},
{file = "pre_commit-2.19.0.tar.gz", hash = "sha256:4233a1e38621c87d9dda9808c6606d7e7ba0e087cd56d3fe03202a01d2919615"}, {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"},
] ]
psycopg2-binary = [ psycopg2-binary = [
{file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"}, {file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f2534ab7dc7e776a263b463a16e189eb30e85ec9bbe1bff9e78dae802608932"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76"},
@ -2360,7 +2215,6 @@ psycopg2-binary = [
{file = "psycopg2_binary-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e6aa71ae45f952a2205377773e76f4e3f27951df38e69a4c95440c779e013560"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24"},
@ -2372,7 +2226,6 @@ psycopg2-binary = [
{file = "psycopg2_binary-2.9.3-cp38-cp38-win32.whl", hash = "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-win32.whl", hash = "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b3a24a1982ae56461cc24f6680604fffa2c1b818e9dc55680da038792e004d18"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c"},
@ -2384,10 +2237,6 @@ psycopg2-binary = [
{file = "psycopg2_binary-2.9.3-cp39-cp39-win32.whl", hash = "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-win32.whl", hash = "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f"},
] ]
py = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
]
pyasn1 = [ pyasn1 = [
{file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"},
{file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"},
@ -2396,14 +2245,6 @@ pyasn1-modules = [
{file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"},
{file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"},
] ]
pycodestyle = [
{file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
{file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
]
pycparser = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
]
pydantic = [ pydantic = [
{file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"},
{file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"},
@ -2446,10 +2287,6 @@ pydantic-to-typescript = [
{file = "pydantic-to-typescript-1.0.8.tar.gz", hash = "sha256:609fd9ce891840311e2e98a315cd273375ab3dc9b21018823c0095303f06c581"}, {file = "pydantic-to-typescript-1.0.8.tar.gz", hash = "sha256:609fd9ce891840311e2e98a315cd273375ab3dc9b21018823c0095303f06c581"},
{file = "pydantic_to_typescript-1.0.8-py3-none-any.whl", hash = "sha256:39653c323b35fdd07ee0e1650a480e68cc091814701b05a04a6f77c60acb6262"}, {file = "pydantic_to_typescript-1.0.8-py3-none-any.whl", hash = "sha256:39653c323b35fdd07ee0e1650a480e68cc091814701b05a04a6f77c60acb6262"},
] ]
pyflakes = [
{file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
{file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
]
pygments = [ pygments = [
{file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
{file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
@ -2502,12 +2339,8 @@ pytesseract = [
{file = "pytesseract-0.3.9.tar.gz", hash = "sha256:7e2bafc7f48d1bb71443ce4633a56f5e21925a98f220a36c336297edcd1956d0"}, {file = "pytesseract-0.3.9.tar.gz", hash = "sha256:7e2bafc7f48d1bb71443ce4633a56f5e21925a98f220a36c336297edcd1956d0"},
] ]
pytest = [ pytest = [
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"},
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"},
]
pytest-cov = [
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
{file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
] ]
python-dateutil = [ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
@ -2575,8 +2408,8 @@ rdflib-jsonld = [
{file = "rdflib_jsonld-0.6.2-py2.py3-none-any.whl", hash = "sha256:011afe67672353ca9978ab9a4bee964dff91f14042f2d8a28c22a573779d2f8b"}, {file = "rdflib_jsonld-0.6.2-py2.py3-none-any.whl", hash = "sha256:011afe67672353ca9978ab9a4bee964dff91f14042f2d8a28c22a573779d2f8b"},
] ]
recipe-scrapers = [ recipe-scrapers = [
{file = "recipe_scrapers-14.23.0-py3-none-any.whl", hash = "sha256:a90e560c8efd41ff8528badf0ddab5d0410c40509e29554e9b93f05571ef2014"}, {file = "recipe_scrapers-14.24.0-py3-none-any.whl", hash = "sha256:1eed9d9010a771387a37aaec27b7c199cb3c4e74c6b9afaa00f1af6f43dc3e26"},
{file = "recipe_scrapers-14.23.0.tar.gz", hash = "sha256:507ad4611cd39b55c1a8a09d974f39c9e8b3d1e70eadfaecc1447f47be2e81c7"}, {file = "recipe_scrapers-14.24.0.tar.gz", hash = "sha256:37ad2b8c113b4d530450ccb7406330e105ccad0dbc5666eb6fafa5ef4e16c408"},
] ]
requests = [ requests = [
{file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
@ -2594,6 +2427,24 @@ rsa = [
{file = "rsa-4.8-py3-none-any.whl", hash = "sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"}, {file = "rsa-4.8-py3-none-any.whl", hash = "sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"},
{file = "rsa-4.8.tar.gz", hash = "sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17"}, {file = "rsa-4.8.tar.gz", hash = "sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17"},
] ]
ruff = [
{file = "ruff-0.0.149-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:e56d77e2a33067e480d6e9ecc328b066c9f8a96ec0f049f7c6107ff1d7106f7f"},
{file = "ruff-0.0.149-py3-none-macosx_10_9_x86_64.macosx_10_9_arm64.macosx_10_9_universal2.whl", hash = "sha256:ad6e65923abbc59cb677c6d3bbfd778f87a95942c5499eb595afd6803999bf80"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eab933a922721930fd6fd02b1001355ee8b81e8810796d7e5d16d2e72a14dc88"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:89c5bbc74e2a79f853c3477f1b87846a77b489029d49e4ff53cfcb3d41217b8c"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:afa90ff653ef1354ffeaca92c8fb57a8aac16019a702c1c1cf50625b580eb421"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9dc2710115b3006231ab6843d5dc1719618cd7972fa69fcd30e8b3496f380cd9"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d79584f96f133f5856d846a162a9f083ac116b890707ef32b4446f4a5b15ccec"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8efb6b2f96b127239ee17de9eb9f858b01c72483a9a2c100126ec54d4313f63d"},
{file = "ruff-0.0.149-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f198fc1cb6cf66e864156449079921a846abe8b6488674f646ea09bccd81457"},
{file = "ruff-0.0.149-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7e7bde713fd6a6305078dbf54c61e403d120b29093a3e365ec71607574ad1caa"},
{file = "ruff-0.0.149-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5437e96025dc4427e77e8cf2b49c5ac04b2f3c9e9c62799d60f5f0d5bfc20be8"},
{file = "ruff-0.0.149-py3-none-musllinux_1_2_i686.whl", hash = "sha256:481b5093db3dd59cf31c192bfe8c1594cebd46e28a36f86d9a1683802a73e9a7"},
{file = "ruff-0.0.149-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a02c571dbb09c3ee0a17be507ddeec5cdbca2ab098f26aeead2fe691843a837a"},
{file = "ruff-0.0.149-py3-none-win32.whl", hash = "sha256:58605add6c6f4b5d8306290c66965609da386c5b686a30c535a319dfba3c9af7"},
{file = "ruff-0.0.149-py3-none-win_amd64.whl", hash = "sha256:58f640e94d5473db4cde84211659576aeccb88ae459e273f204683596b5ec205"},
{file = "ruff-0.0.149.tar.gz", hash = "sha256:b6707c1ecc9730900138eb92dd0e7cd9123364ae9b33ba2cc9d623990129a29e"},
]
setuptools = [ setuptools = [
{file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"}, {file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"},
{file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"}, {file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"},

View File

@ -1,72 +1,71 @@
[tool.poetry] [tool.poetry]
authors = ["Hayden <hay-kot@pm.me>"]
description = "A Recipe Manager"
license = "AGPL"
name = "mealie" name = "mealie"
version = "1.0.0b" version = "1.0.0b"
description = "A Recipe Manager"
authors = ["Hayden <hay-kot@pm.me>"]
license = "AGPL"
[tool.poetry.scripts] [tool.poetry.scripts]
start = "mealie.app:main" start = "mealie.app:main"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" Jinja2 = "^3.1.2"
Pillow = "^9.2.0"
PyYAML = "^5.3.1"
SQLAlchemy = "^1.4.29"
aiofiles = "0.5.0" aiofiles = "0.5.0"
alembic = "^1.7.5"
aniso8601 = "7.0.0" aniso8601 = "7.0.0"
appdirs = "1.4.4" appdirs = "1.4.4"
fastapi = "^0.85.1" apprise = "^1.2.0"
uvicorn = {extras = ["standard"], version = "^0.13.0"} bcrypt = "^4.0.1"
SQLAlchemy = "^1.4.29"
alembic = "^1.7.5"
Jinja2 = "^3.1.2"
python-dotenv = "^0.15.0"
python-slugify = "^6.1.2"
requests = "^2.25.1"
PyYAML = "^5.3.1"
extruct = "^0.13.0" extruct = "^0.13.0"
python-multipart = "^0.0.5" fastapi = "^0.85.1"
bcrypt = "^3.2.0"
python-jose = "^3.3.0"
passlib = "^1.7.4"
lxml = "^4.7.1"
Pillow = "^9.2.0"
apprise = "^0.9.6"
recipe-scrapers = "^14.20.0"
psycopg2-binary = {version = "^2.9.1", optional = true}
gunicorn = "^20.1.0" gunicorn = "^20.1.0"
python-ldap = "^3.3.1" lxml = "^4.7.1"
orjson = "^3.8.0"
passlib = "^1.7.4"
psycopg2-binary = {version = "^2.9.1", optional = true}
pydantic = "^1.10.2" pydantic = "^1.10.2"
tzdata = "^2021.5"
pyhumps = "^3.5.3" pyhumps = "^3.5.3"
pytesseract = "^0.3.9" pytesseract = "^0.3.9"
orjson = "^3.8.0" python = "^3.10"
python-dateutil = "^2.8.2" python-dateutil = "^2.8.2"
python-dotenv = "^0.15.0"
python-jose = "^3.3.0"
python-ldap = "^3.3.1"
python-multipart = "^0.0.5"
python-slugify = "^6.1.2"
recipe-scrapers = "^14.24.0"
requests = "^2.25.1"
tzdata = "^2021.5"
uvicorn = {extras = ["standard"], version = "^0.13.0"}
pre-commit = "^2.20.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pylint = "^2.6.0"
pytest = "^6.2.1"
pytest-cov = "^2.11.0"
mkdocs-material = "^8.2.3"
flake8 = "^4.0.1"
coverage = "^5.5"
pydantic-to-typescript = "^1.0.7"
rich = "^10.7.0"
isort = "^5.9.3"
flake8-print = "^4.0.0"
black = "^21.12b0" black = "^21.12b0"
coverage = "^5.5"
coveragepy-lcov = "^0.1.1" coveragepy-lcov = "^0.1.1"
mkdocs-material = "^8.2.3"
mypy = "^0.960" mypy = "^0.960"
types-python-slugify = "^5.0.3" openapi-spec-validator = "^0.4.0"
pre-commit = "^2.20.0"
pydantic-to-typescript = "^1.0.7"
pylint = "^2.6.0"
pytest = "^7.2.0"
rich = "^10.7.0"
ruff = "^0.0.149"
types-PyYAML = "^6.0.4" types-PyYAML = "^6.0.4"
types-python-dateutil = "^2.8.18"
types-python-slugify = "^5.0.3"
types-requests = "^2.27.12" types-requests = "^2.27.12"
types-urllib3 = "^1.26.11" types-urllib3 = "^1.26.11"
pre-commit = "^2.17.0"
types-python-dateutil = "^2.8.18"
openapi-spec-validator = "^0.4.0"
[tool.poetry.group.dev.dependencies]
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
requires = ["poetry-core>=1.0.0"]
[tool.black] [tool.black]
line-length = 120 line-length = 120
@ -80,16 +79,11 @@ min_confidence = 60
paths = ["mealie"] paths = ["mealie"]
sort_by_size = true sort_by_size = true
[tool.isort]
profile = "black"
line_length = 120
multi_line_output = 3
[tool.pytest.ini_options] [tool.pytest.ini_options]
addopts = "-ra -q"
minversion = "6.0" minversion = "6.0"
addopts = "-ra -q --cov=mealie"
python_files = 'test_*'
python_classes = '*Tests' python_classes = '*Tests'
python_files = 'test_*'
python_functions = 'test_*' python_functions = 'test_*'
testpaths = [ testpaths = [
"tests", "tests",
@ -102,8 +96,60 @@ skip_empty = true
pgsql = ["psycopg2-binary"] pgsql = ["psycopg2-binary"]
[tool.mypy] [tool.mypy]
python_version = "3.10"
ignore_missing_imports = true
follow_imports = "skip" follow_imports = "skip"
strict_optional = true ignore_missing_imports = true
plugins = "pydantic.mypy" plugins = "pydantic.mypy"
python_version = "3.10"
strict_optional = true
[tool.ruff]
line-length = 120
format = "text"
# Enable Pyflakes `E` and `F` codes by default.
ignore = ["F403", "I252","B008"]
select = [
"E", # pycodestyles
"F", # pyflakes
"I", # isort
"T", # flake8-print
"U", # pyupgrade
"B", # flake8-bugbear
# "ANN", # flake8-annotations
# "C", # McCabe complexity
# "RUF", # Ruff specific
# "BLE", # blind-except
]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
# Assume Python 3.10.
target-version = "py310"
[tool.ruff.per-file-ignores]
"__init__.py" = ["E402","E501"]
[tool.ruff.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10