feat: add avatars to users
This commit is contained in:
		
							parent
							
								
									a80f89d038
								
							
						
					
					
						commit
						0e54722eef
					
				
					 14 changed files with 424 additions and 11 deletions
				
			
		
							
								
								
									
										29
									
								
								alembic/versions/1711550209_add_avatars.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								alembic/versions/1711550209_add_avatars.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | """Add avatars | ||||||
|  | 
 | ||||||
|  | Revision ID: 7503d2a6094c | ||||||
|  | Revises: a000d800f45f | ||||||
|  | Create Date: 2024-03-27 15:36:49.749722 | ||||||
|  | 
 | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | from typing import Sequence, Union | ||||||
|  | 
 | ||||||
|  | import sqlalchemy as sa | ||||||
|  | 
 | ||||||
|  | from alembic import op | ||||||
|  | 
 | ||||||
|  | # revision identifiers, used by Alembic. | ||||||
|  | revision: str = "7503d2a6094c" | ||||||
|  | down_revision: Union[str, None] = "a000d800f45f" | ||||||
|  | branch_labels: Union[str, Sequence[str], None] = None | ||||||
|  | depends_on: Union[str, Sequence[str], None] = None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def upgrade() -> None: | ||||||
|  |     op.add_column("members", sa.Column("avatar", sa.Text(), nullable=True)) | ||||||
|  |     op.add_column("users", sa.Column("avatar", sa.Text(), nullable=True)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def downgrade() -> None: | ||||||
|  |     op.drop_column("users", "avatar") | ||||||
|  |     op.drop_column("members", "avatar") | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| from .v2.members import bp as members_blueprint | from .v2.members import bp as members_blueprint | ||||||
| from .v2.users import bp as users_blueprint |  | ||||||
| from .v2.meta import bp as meta_blueprint | from .v2.meta import bp as meta_blueprint | ||||||
|  | from .v2.users import bp as users_blueprint | ||||||
| 
 | 
 | ||||||
| __all__ = [users_blueprint, members_blueprint, meta_blueprint] | __all__ = [users_blueprint, members_blueprint, meta_blueprint] | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ from quart_schema import validate_response | ||||||
| from sqlalchemy import select | from sqlalchemy import select | ||||||
| from sqlalchemy.sql import func | from sqlalchemy.sql import func | ||||||
| 
 | 
 | ||||||
| from foxnouns.db import User, Member | from foxnouns.db import Member, User | ||||||
| from foxnouns.db.aio import async_session | from foxnouns.db.aio import async_session | ||||||
| from foxnouns.settings import BASE_DOMAIN | from foxnouns.settings import BASE_DOMAIN | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ from quart import Blueprint, g | ||||||
| from quart_schema import validate_request, validate_response | from quart_schema import validate_request, validate_response | ||||||
| from sqlalchemy import select | from sqlalchemy import select | ||||||
| 
 | 
 | ||||||
|  | from foxnouns import tasks | ||||||
| from foxnouns.auth import require_auth | from foxnouns.auth import require_auth | ||||||
| from foxnouns.db import User | from foxnouns.db import User | ||||||
| from foxnouns.db.aio import async_session | from foxnouns.db.aio import async_session | ||||||
|  | @ -38,6 +39,8 @@ class EditUserRequest(BasePatchModel): | ||||||
|     display_name: str | None = Field(max_length=100, default=None) |     display_name: str | None = Field(max_length=100, default=None) | ||||||
|     bio: str | None = Field(max_length=1024, default=None) |     bio: str | None = Field(max_length=1024, default=None) | ||||||
| 
 | 
 | ||||||
|  |     avatar: str | None = Field(max_length=1_000_000, default=None) | ||||||
|  | 
 | ||||||
|     @field_validator("username") |     @field_validator("username") | ||||||
|     @classmethod |     @classmethod | ||||||
|     def check_username(cls, value): |     def check_username(cls, value): | ||||||
|  | @ -53,6 +56,7 @@ async def edit_user(data: EditUserRequest): | ||||||
| 
 | 
 | ||||||
|     async with async_session() as session: |     async with async_session() as session: | ||||||
|         user = await session.scalar(select(User).where(User.id == g.user.id)) |         user = await session.scalar(select(User).where(User.id == g.user.id)) | ||||||
|  |         await user.awaitable_attrs.members | ||||||
| 
 | 
 | ||||||
|         if data.username: |         if data.username: | ||||||
|             user.username = data.username |             user.username = data.username | ||||||
|  | @ -63,6 +67,12 @@ async def edit_user(data: EditUserRequest): | ||||||
| 
 | 
 | ||||||
|         await session.commit() |         await session.commit() | ||||||
| 
 | 
 | ||||||
|  |         if data.is_set("avatar"): | ||||||
|  |             if data.avatar: | ||||||
|  |                 tasks.process_user_avatar.delay(user.id, data.avatar) | ||||||
|  |             else: | ||||||
|  |                 tasks.delete_user_avatar.delay(user.id) | ||||||
|  | 
 | ||||||
|         return SelfUserModel.model_validate(user) |         return SelfUserModel.model_validate(user) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,3 +13,5 @@ ASYNC_DATABASE_URL = URL.create( | ||||||
| 
 | 
 | ||||||
| engine = create_async_engine(ASYNC_DATABASE_URL, echo=ECHO_SQL) | engine = create_async_engine(ASYNC_DATABASE_URL, echo=ECHO_SQL) | ||||||
| async_session = async_sessionmaker(engine, expire_on_commit=False) | async_session = async_sessionmaker(engine, expire_on_commit=False) | ||||||
|  | 
 | ||||||
|  | __all__ = [engine, async_session] | ||||||
|  |  | ||||||
|  | @ -16,9 +16,9 @@ class Member(Base): | ||||||
|         BigInteger(), primary_key=True, default=Snowflake.generate_int |         BigInteger(), primary_key=True, default=Snowflake.generate_int | ||||||
|     ) |     ) | ||||||
|     name: Mapped[str] = mapped_column(Text(), nullable=False) |     name: Mapped[str] = mapped_column(Text(), nullable=False) | ||||||
| 
 |  | ||||||
|     display_name: Mapped[str | None] = mapped_column(Text(), nullable=True) |     display_name: Mapped[str | None] = mapped_column(Text(), nullable=True) | ||||||
|     bio: Mapped[str | None] = mapped_column(Text(), nullable=True) |     bio: Mapped[str | None] = mapped_column(Text(), nullable=True) | ||||||
|  |     avatar: Mapped[str | None] = mapped_column(Text(), nullable=True) | ||||||
| 
 | 
 | ||||||
|     names: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) |     names: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) | ||||||
|     pronouns: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) |     pronouns: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| from sqlalchemy import URL, create_engine | from sqlalchemy import URL, create_engine | ||||||
|  | from sqlalchemy.orm import sessionmaker | ||||||
| 
 | 
 | ||||||
| from foxnouns.settings import DATABASE, ECHO_SQL | from foxnouns.settings import DATABASE, ECHO_SQL | ||||||
| 
 | 
 | ||||||
|  | @ -11,3 +12,6 @@ SYNC_DATABASE_URL = URL.create( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| engine = create_engine(SYNC_DATABASE_URL, echo=ECHO_SQL) | engine = create_engine(SYNC_DATABASE_URL, echo=ECHO_SQL) | ||||||
|  | session = sessionmaker(engine) | ||||||
|  | 
 | ||||||
|  | __all__ = [engine, session] | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ class User(Base): | ||||||
|     username: Mapped[str] = mapped_column(Text(), unique=True, nullable=False) |     username: Mapped[str] = mapped_column(Text(), unique=True, nullable=False) | ||||||
|     display_name: Mapped[str | None] = mapped_column(Text(), nullable=True) |     display_name: Mapped[str | None] = mapped_column(Text(), nullable=True) | ||||||
|     bio: Mapped[str | None] = mapped_column(Text(), nullable=True) |     bio: Mapped[str | None] = mapped_column(Text(), nullable=True) | ||||||
|  |     avatar: Mapped[str | None] = mapped_column(Text(), nullable=True) | ||||||
| 
 | 
 | ||||||
|     names: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) |     names: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) | ||||||
|     pronouns: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) |     pronouns: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[]) | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ class BaseUserModel(BaseSnowflakeModel): | ||||||
|     name: str = Field(alias="username") |     name: str = Field(alias="username") | ||||||
|     display_name: str | None |     display_name: str | None | ||||||
|     bio: str | None |     bio: str | None | ||||||
|  |     avatar: str | None | ||||||
| 
 | 
 | ||||||
|     names: list[FieldEntry] = Field(default=[]) |     names: list[FieldEntry] = Field(default=[]) | ||||||
|     pronouns: list[PronounEntry] = Field(default=[]) |     pronouns: list[PronounEntry] = Field(default=[]) | ||||||
|  | @ -22,6 +23,7 @@ class BaseMemberModel(BaseSnowflakeModel): | ||||||
|     name: str |     name: str | ||||||
|     display_name: str | None |     display_name: str | None | ||||||
|     bio: str | None |     bio: str | None | ||||||
|  |     avatar: str | None | ||||||
| 
 | 
 | ||||||
|     names: list[FieldEntry] = Field(default=[]) |     names: list[FieldEntry] = Field(default=[]) | ||||||
|     pronouns: list[PronounEntry] = Field(default=[]) |     pronouns: list[PronounEntry] = Field(default=[]) | ||||||
|  |  | ||||||
|  | @ -6,12 +6,25 @@ env.read_env() | ||||||
| 
 | 
 | ||||||
| # Format: postgresql+{driver}//{user}:{password}@{host}/{name} | # Format: postgresql+{driver}//{user}:{password}@{host}/{name} | ||||||
| # Note that the driver is set by the application. | # Note that the driver is set by the application. | ||||||
| DATABASE = { | with env.prefixed("DATABASE_"): | ||||||
|     "USER": env("DATABASE_USER"), |     DATABASE = { | ||||||
|     "PASSWORD": env("DATABASE_PASSWORD"), |         "USER": env("USER"), | ||||||
|     "HOST": env("DATABASE_HOST"), |         "PASSWORD": env("PASSWORD"), | ||||||
|     "NAME": env("DATABASE_NAME"), |         "HOST": env("HOST"), | ||||||
| } |         "NAME": env("NAME"), | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | # The Redis database used for Celery and ephemeral storage. | ||||||
|  | REDIS_URL: str = env("REDIS_URL", "redis://localhost") | ||||||
|  | 
 | ||||||
|  | with env.prefixed("MINIO_"): | ||||||
|  |     MINIO = { | ||||||
|  |         "ENDPOINT": env("ENDPOINT"), | ||||||
|  |         "ACCESS_KEY": env("ACCESS_KEY"), | ||||||
|  |         "SECRET_KEY": env("SECRET_KEY"), | ||||||
|  |         "BUCKET": env("BUCKET"), | ||||||
|  |         "SECURE": env.bool("SECURE", True), | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| # The base domain the API is served on. This must be set. | # The base domain the API is served on. This must be set. | ||||||
| BASE_DOMAIN = env("BASE_DOMAIN") | BASE_DOMAIN = env("BASE_DOMAIN") | ||||||
|  |  | ||||||
							
								
								
									
										88
									
								
								foxnouns/tasks.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								foxnouns/tasks.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | import base64 | ||||||
|  | import hashlib | ||||||
|  | from io import BytesIO | ||||||
|  | 
 | ||||||
|  | import pyvips | ||||||
|  | from celery import Celery | ||||||
|  | from celery.utils.log import get_task_logger | ||||||
|  | from minio import Minio | ||||||
|  | from sqlalchemy import select, update | ||||||
|  | 
 | ||||||
|  | from foxnouns.db import User | ||||||
|  | from foxnouns.db.sync import session | ||||||
|  | from foxnouns.settings import MINIO, REDIS_URL | ||||||
|  | 
 | ||||||
|  | app = Celery("tasks", broker=REDIS_URL) | ||||||
|  | 
 | ||||||
|  | logger = get_task_logger(__name__) | ||||||
|  | 
 | ||||||
|  | minio = Minio( | ||||||
|  |     MINIO["ENDPOINT"], | ||||||
|  |     access_key=MINIO["ACCESS_KEY"], | ||||||
|  |     secret_key=MINIO["SECRET_KEY"], | ||||||
|  |     secure=MINIO["SECURE"], | ||||||
|  | ) | ||||||
|  | bucket = MINIO["BUCKET"] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def convert_avatar(uri: str) -> bytes: | ||||||
|  |     if not uri.startswith("data:image/"): | ||||||
|  |         raise ValueError("Not a data URI") | ||||||
|  | 
 | ||||||
|  |     content_type, encoded = uri.removeprefix("data:").split("base64,", 1) | ||||||
|  |     logger.info(f"{content_type=}") | ||||||
|  | 
 | ||||||
|  |     img = pyvips.Image.thumbnail_buffer( | ||||||
|  |         base64.b64decode(encoded), | ||||||
|  |         512, | ||||||
|  |         height=512, | ||||||
|  |         size=pyvips.Size.BOTH, | ||||||
|  |         crop=pyvips.Interesting.CENTRE, | ||||||
|  |     ) | ||||||
|  |     return img.write_to_buffer(".webp", Q=95) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.task | ||||||
|  | def process_user_avatar(user_id: int, avatar: str): | ||||||
|  |     with session() as conn: | ||||||
|  |         user = conn.scalar(select(User).where(User.id == user_id)) | ||||||
|  |     if not user: | ||||||
|  |         raise ValueError("process_user_avatar was passed the ID of a nonexistent user") | ||||||
|  | 
 | ||||||
|  |     img = convert_avatar(avatar) | ||||||
|  |     hash = hashlib.new("sha256", data=img).hexdigest() | ||||||
|  |     old_hash = user.avatar | ||||||
|  | 
 | ||||||
|  |     minio.put_object( | ||||||
|  |         bucket, | ||||||
|  |         f"users/{user_id}/avatars/{hash}.webp", | ||||||
|  |         BytesIO(img), | ||||||
|  |         len(img), | ||||||
|  |         "image/webp", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     with session() as conn: | ||||||
|  |         conn.execute(update(User).values(avatar=hash).where(User.id == user_id)) | ||||||
|  |         conn.commit() | ||||||
|  | 
 | ||||||
|  |     if old_hash: | ||||||
|  |         minio.remove_object(bucket, f"users/{user_id}/avatars/{old_hash}.webp") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.task | ||||||
|  | def delete_user_avatar(user_id: int): | ||||||
|  |     with session() as conn: | ||||||
|  |         user = conn.scalar(select(User).where(User.id == user_id)) | ||||||
|  |     if not user: | ||||||
|  |         raise ValueError("delete_user_avatar was passed the ID of a nonexistent user") | ||||||
|  |     if not user.avatar: | ||||||
|  |         logger.info( | ||||||
|  |             "delete_user_avatar was called for a user with a null avatar (%d)", user_id | ||||||
|  |         ) | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  |     minio.remove_object(bucket, f"users/{user_id}/avatars/{user.avatar}.webp") | ||||||
|  | 
 | ||||||
|  |     with session() as conn: | ||||||
|  |         conn.execute(update(User).values(avatar=None).where(User.id == user_id)) | ||||||
|  |         conn.commit() | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| 	import "bootstrap-icons/font/bootstrap-icons.scss"; | 	import "bootstrap-icons/font/bootstrap-icons.scss"; | ||||||
| 	import type { LayoutData } from "./$types"; | 	import type { LayoutData } from "./$types"; | ||||||
| 
 | 
 | ||||||
| 	export let data: LayoutData | 	export let data: LayoutData; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| {JSON.stringify(data.meta)} | {JSON.stringify(data.meta)} | ||||||
|  |  | ||||||
							
								
								
									
										260
									
								
								poetry.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										260
									
								
								poetry.lock
									
										
									
										generated
									
									
									
								
							|  | @ -59,6 +59,65 @@ files = [ | ||||||
|     {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, |     {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "argon2-cffi" | ||||||
|  | version = "23.1.0" | ||||||
|  | description = "Argon2 for Python" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.7" | ||||||
|  | files = [ | ||||||
|  |     {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, | ||||||
|  |     {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | argon2-cffi-bindings = "*" | ||||||
|  | 
 | ||||||
|  | [package.extras] | ||||||
|  | dev = ["argon2-cffi[tests,typing]", "tox (>4)"] | ||||||
|  | docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] | ||||||
|  | tests = ["hypothesis", "pytest"] | ||||||
|  | typing = ["mypy"] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "argon2-cffi-bindings" | ||||||
|  | version = "21.2.0" | ||||||
|  | description = "Low-level CFFI bindings for Argon2" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.6" | ||||||
|  | files = [ | ||||||
|  |     {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, | ||||||
|  |     {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | cffi = ">=1.0.1" | ||||||
|  | 
 | ||||||
|  | [package.extras] | ||||||
|  | dev = ["cogapp", "pre-commit", "pytest", "wheel"] | ||||||
|  | tests = ["pytest"] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "async-timeout" | name = "async-timeout" | ||||||
| version = "4.0.3" | version = "4.0.3" | ||||||
|  | @ -210,6 +269,83 @@ yaml = ["PyYAML (>=3.10)"] | ||||||
| zookeeper = ["kazoo (>=1.3.1)"] | zookeeper = ["kazoo (>=1.3.1)"] | ||||||
| zstd = ["zstandard (==0.22.0)"] | zstd = ["zstandard (==0.22.0)"] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "certifi" | ||||||
|  | version = "2024.2.2" | ||||||
|  | description = "Python package for providing Mozilla's CA Bundle." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.6" | ||||||
|  | files = [ | ||||||
|  |     {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, | ||||||
|  |     {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "cffi" | ||||||
|  | version = "1.16.0" | ||||||
|  | description = "Foreign Function Interface for Python calling C code." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.8" | ||||||
|  | files = [ | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, | ||||||
|  |     {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, | ||||||
|  |     {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, | ||||||
|  |     {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, | ||||||
|  |     {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, | ||||||
|  |     {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, | ||||||
|  |     {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | pycparser = "*" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "click" | name = "click" | ||||||
| version = "8.1.7" | version = "8.1.7" | ||||||
|  | @ -666,6 +802,25 @@ dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] | ||||||
| docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==4.0.0)", "sphinx-version-warning (==1.1.2)"] | docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==4.0.0)", "sphinx-version-warning (==1.1.2)"] | ||||||
| tests = ["pytest", "pytz", "simplejson"] | tests = ["pytest", "pytz", "simplejson"] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "minio" | ||||||
|  | version = "7.2.5" | ||||||
|  | description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "*" | ||||||
|  | files = [ | ||||||
|  |     {file = "minio-7.2.5-py3-none-any.whl", hash = "sha256:ed9176c96d4271cb1022b9ecb8a538b1e55b32ae06add6de16425cab99ef2304"}, | ||||||
|  |     {file = "minio-7.2.5.tar.gz", hash = "sha256:59d8906e2da248a9caac34d4958a859cc3a44abbe6447910c82b5abfa9d6a2e1"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | argon2-cffi = "*" | ||||||
|  | certifi = "*" | ||||||
|  | pycryptodome = "*" | ||||||
|  | typing-extensions = "*" | ||||||
|  | urllib3 = "*" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "packaging" | name = "packaging" | ||||||
| version = "24.0" | version = "24.0" | ||||||
|  | @ -678,6 +833,18 @@ files = [ | ||||||
|     {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, |     {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "pkgconfig" | ||||||
|  | version = "1.5.5" | ||||||
|  | description = "Interface Python with pkg-config" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.3,<4.0" | ||||||
|  | files = [ | ||||||
|  |     {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, | ||||||
|  |     {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "pluggy" | name = "pluggy" | ||||||
| version = "1.4.0" | version = "1.4.0" | ||||||
|  | @ -745,6 +912,60 @@ docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)" | ||||||
| pool = ["psycopg-pool"] | pool = ["psycopg-pool"] | ||||||
| test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] | test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] | ||||||
| 
 | 
 | ||||||
|  | [[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.*" | ||||||
|  | files = [ | ||||||
|  |     {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, | ||||||
|  |     {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "pycryptodome" | ||||||
|  | version = "3.20.0" | ||||||
|  | description = "Cryptographic library for Python" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
|  | files = [ | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, | ||||||
|  |     {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, | ||||||
|  |     {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "pydantic" | name = "pydantic" | ||||||
| version = "2.6.4" | version = "2.6.4" | ||||||
|  | @ -939,6 +1160,25 @@ files = [ | ||||||
| [package.extras] | [package.extras] | ||||||
| cli = ["click (>=5.0)"] | cli = ["click (>=5.0)"] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "pyvips" | ||||||
|  | version = "2.2.2" | ||||||
|  | description = "binding for the libvips image processing library, API mode" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "*" | ||||||
|  | files = [ | ||||||
|  |     {file = "pyvips-2.2.2.tar.gz", hash = "sha256:2aa169f2130e8f9d9b0d442fad10a70ff1c3d1bb6add099ce058987faa1f6829"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | cffi = ">=1.0.0" | ||||||
|  | pkgconfig = "*" | ||||||
|  | 
 | ||||||
|  | [package.extras] | ||||||
|  | doc = ["sphinx", "sphinx_rtd_theme"] | ||||||
|  | test = ["cffi (>=1.0.0)", "pyperf", "pytest"] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "quart" | name = "quart" | ||||||
| version = "0.19.4" | version = "0.19.4" | ||||||
|  | @ -1176,6 +1416,24 @@ files = [ | ||||||
|     {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, |     {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "urllib3" | ||||||
|  | version = "2.2.1" | ||||||
|  | description = "HTTP library with thread-safe connection pooling, file post, and more." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.8" | ||||||
|  | files = [ | ||||||
|  |     {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, | ||||||
|  |     {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.extras] | ||||||
|  | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] | ||||||
|  | h2 = ["h2 (>=4,<5)"] | ||||||
|  | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] | ||||||
|  | zstd = ["zstandard (>=0.18.0)"] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "uvicorn" | name = "uvicorn" | ||||||
| version = "0.28.1" | version = "0.28.1" | ||||||
|  | @ -1255,4 +1513,4 @@ h11 = ">=0.9.0,<1" | ||||||
| [metadata] | [metadata] | ||||||
| lock-version = "2.0" | lock-version = "2.0" | ||||||
| python-versions = "^3.11" | python-versions = "^3.11" | ||||||
| content-hash = "820a4c895eee0304a7cb8572d441c377a3ecb82cb300aa5f21823c96413c0d6d" | content-hash = "0f97996ff854041ec5bc98541863488c29ae65f44652721af67f3e06875c6bbb" | ||||||
|  |  | ||||||
|  | @ -23,6 +23,8 @@ asyncpg = "^0.29.0" | ||||||
| environs = "^11.0.0" | environs = "^11.0.0" | ||||||
| alembic = "^1.13.1" | alembic = "^1.13.1" | ||||||
| quart-cors = "^0.7.0" | quart-cors = "^0.7.0" | ||||||
|  | minio = "^7.2.5" | ||||||
|  | pyvips = "^2.2.2" | ||||||
| 
 | 
 | ||||||
| [tool.poetry.group.dev] | [tool.poetry.group.dev] | ||||||
| optional = true | optional = true | ||||||
|  | @ -41,6 +43,10 @@ pytest-asyncio = "^0.23.5.post1" | ||||||
| help = "Run a development server with auto-reload" | help = "Run a development server with auto-reload" | ||||||
| cmd = "env QUART_APP=foxnouns.app:app quart --debug run --reload" | cmd = "env QUART_APP=foxnouns.app:app quart --debug run --reload" | ||||||
| 
 | 
 | ||||||
|  | [tool.poe.tasks.celery] | ||||||
|  | help = "Run a Celery task worker" | ||||||
|  | cmd = "celery -A foxnouns.tasks worker" | ||||||
|  | 
 | ||||||
| [tool.poe.tasks.server] | [tool.poe.tasks.server] | ||||||
| help = "Run a production server" | help = "Run a production server" | ||||||
| cmd = "uvicorn 'foxnouns.app:app'" | cmd = "uvicorn 'foxnouns.app:app'" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue