From 713c8071fb04361782dd49c8c1c2ab6eb5ed0226 Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Wed, 4 Jun 2025 11:48:02 +0000 Subject: [PATCH 01/38] api: Make create_book a module --- src/api/src/create_book.py | 782 ------------------ src/api/src/create_book/__init__.py | 10 + src/api/src/create_book/config.py | 45 + src/api/src/create_book/create_book.py | 165 ++++ src/api/src/create_book/exceptions.py | 11 + .../src/create_book/generators/__init__.py | 2 + src/api/src/create_book/generators/epub.py | 115 +++ src/api/src/create_book/generators/pdf.py | 286 +++++++ src/api/src/create_book/logs.py | 18 + src/api/src/create_book/models.py | 42 + src/api/src/create_book/utils.py | 108 +++ 11 files changed, 802 insertions(+), 782 deletions(-) delete mode 100644 src/api/src/create_book.py create mode 100644 src/api/src/create_book/__init__.py create mode 100644 src/api/src/create_book/config.py create mode 100644 src/api/src/create_book/create_book.py create mode 100644 src/api/src/create_book/exceptions.py create mode 100644 src/api/src/create_book/generators/__init__.py create mode 100644 src/api/src/create_book/generators/epub.py create mode 100644 src/api/src/create_book/generators/pdf.py create mode 100644 src/api/src/create_book/logs.py create mode 100644 src/api/src/create_book/models.py create mode 100644 src/api/src/create_book/utils.py diff --git a/src/api/src/create_book.py b/src/api/src/create_book.py deleted file mode 100644 index 8a90a0b..0000000 --- a/src/api/src/create_book.py +++ /dev/null @@ -1,782 +0,0 @@ -from __future__ import annotations -from typing import List, Optional, Tuple, cast -from typing_extensions import TypedDict -import re -import logging -import tempfile -import unicodedata -from os import environ -from io import BytesIO -from enum import Enum -from base64 import b64encode -import bs4 -import backoff -from weasyprint import HTML, CSS, default_url_fetcher -from weasyprint.text.fonts import FontConfiguration -from ebooklib import epub -from exiftool import ExifTool -from eliot import to_file, start_action -from eliot.stdlib import EliotHandler -from bs4 import BeautifulSoup -from dotenv import load_dotenv -from pydantic import TypeAdapter, model_validator, field_validator -from pydantic_settings import BaseSettings -from aiohttp import ClientResponseError -from aiohttp_client_cache.session import CachedSession -from aiohttp_client_cache import FileBackend, RedisBackend - -load_dotenv(override=True) - -handler = EliotHandler() - -logging.getLogger("fastapi").setLevel(logging.INFO) -logging.getLogger("fastapi").addHandler(handler) - -exiftool_logger = logging.getLogger("exiftool") -exiftool_logger.addHandler(handler) - -logger = logging.Logger("wpd") -logger.addHandler(handler) - -if environ.get("DEBUG"): - to_file(open("eliot.log", "wb")) - - -# --- # - - -class CacheTypes(Enum): - file = "file" - redis = "redis" - - -class Config(BaseSettings): - USE_CACHE: bool = True - CACHE_TYPE: CacheTypes = CacheTypes.file - REDIS_CONNECTION_URL: str = "" - - @field_validator("USE_CACHE", mode="before") - def validate_use_cache(cls, value): - # Return default if value is an empty string - if value == "": - return True # Default value for USE_CACHE - return value - - @field_validator("CACHE_TYPE", mode="before") - def validate_cache_type(cls, value): - # Thanks https://stackoverflow.com/a/78157474 - if value == "": - return "file" - return value - - @model_validator(mode="after") - def prevent_mismatched_redis_url(self): - match self.CACHE_TYPE: - case CacheTypes.file: - if self.REDIS_CONNECTION_URL: - raise ValueError( - "REDIS_CONNECTION_URL provided when File cache selected. To use Redis as a cache, set CACHE_TYPE=redis." - ) - case CacheTypes.redis: - if not self.REDIS_CONNECTION_URL: - raise ValueError( - "REDIS_CONNECTION_URL not provided when Redis cache selected. To use File cache, set CACHE_TYPE=file." - ) - return self - - -config = Config() - -# --- # - -headers = { - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" -} - -if config.USE_CACHE: - match config.CACHE_TYPE: - case CacheTypes.file: - cache = FileBackend(use_temp=True, expire_after=43200) # 12 hours - case CacheTypes.redis: - cache = RedisBackend( - cache_name="wpd-aiohttp-cache", - address=config.REDIS_CONNECTION_URL, - expire_after=43200, # 12 hours - ) -else: - cache = None - -logger.info(f"Using {cache=}") - -# --- Utilities --- # - - -def smart_trim(text: str, max_length: int = 400) -> str: - """Truncate a string intelligently at newlines. Coherence and max-length adherence.""" - chunks = [t for t in text.split("\n") if t] - - to_return = "" - for chunk in chunks: - if len(to_return) + len(chunk) < max_length: - to_return = chunk + "
" - else: - to_return = to_return.rstrip("
") - break - - return to_return - - -def generate_clean_part_html(part: Part, content: str) -> bs4.Tag: - """Rebuild HTML Structure for a Part.""" - chapter_title = part["title"] - chapter_id = part["id"] - - clean = BeautifulSoup( - f""" -
-

{chapter_title}

-
- """, - "html.parser", - ) # html.parser doesn't create / tags automatically - - html = BeautifulSoup(content, "lxml") - for br in html.find_all("br"): - # Check if no content after br - if not br.next_sibling or br.next_sibling.name in ["br", None]: - br.decompose() - - section = cast(bs4.Tag, clean.find("section")) - if not section: - raise Exception() - - for child in html.find_all("p"): - current_paragraph = clean.new_tag("p") - - # Attempt to carry over paragraph styling - current_paragraph["style"] = child.get("style", "text-align: left;") - - for p_child in list(child.children): - if not p_child: - continue - if isinstance(p_child, bs4.element.Tag): - if p_child.name == "br": - p_child.decompose() - elif p_child.name == "img": - src = p_child["src"] - img_tag = clean.new_tag("img") - img_tag["src"] = src - section.append(img_tag) - section.append(clean.new_tag("br")) - elif p_child.name in ["b", "i"]: - styled_tag = clean.new_tag(p_child.name) - styled_content = clean.new_string(p_child.text) - styled_tag.append(styled_content) - current_paragraph.append(styled_tag) - else: - # Append any other tags as-is - current_paragraph.append(p_child) - elif isinstance(p_child, bs4.element.NavigableString): - content = clean.new_string(p_child) - current_paragraph.append(content) - - if current_paragraph.contents: - section.append(current_paragraph) - - if not list(child.children): - # Some p tags only contain brs, once brs are removed, they are empty and can be removed as well. - child.decompose() - - return section - - -def slugify(value, allow_unicode=False) -> str: - """ - Taken from https://github.com/django/django/blob/master/django/utils/text.py - Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated - dashes to single dashes. Remove characters that aren't alphanumerics, - underscores, or hyphens. Convert to lowercase. Also strip leading and - trailing whitespace, dashes, and underscores. - - Thanks https://stackoverflow.com/a/295466. - """ - value = str(value) - if allow_unicode: - value = unicodedata.normalize("NFKC", value) - else: - value = ( - unicodedata.normalize("NFKD", value) - .encode("ascii", "ignore") - .decode("ascii") - ) - value = re.sub(r"[^\w\s-]", "", value.lower()) - return re.sub(r"[-\s]+", "-", value).strip("-_") - - -async def fetch_cookies(username: str, password: str) -> dict: - # source: https://github.com/TheOnlyWayUp/WP-DM-Export/blob/dd4c7c51cb43f2108e0f63fc10a66cd24a740e4e/src/API/src/main.py#L25-L58 - """Retrieves authorization cookies from Wattpad by logging in with user creds. - - Args: - username (str): Username. - password (str): Password. - - Raises: - ValueError: Bad status code. - ValueError: No cookies returned. - - Returns: - dict: Authorization cookies. - """ - with start_action(action_type="api_fetch_cookies"): - async with CachedSession(headers=headers, cache=None) as session: - async with session.post( - "https://www.wattpad.com/auth/login?nextUrl=%2F&_data=routes%2Fauth.login", - data={ - "username": username.lower(), - "password": password, - }, # the username.lower() is for caching - ) as response: - if response.status != 204: - raise ValueError("Not a 204.") - - cookies = { - k: v.value - for k, v in response.cookies.items() # Thanks https://stackoverflow.com/a/32281245 - } - - if not cookies: - raise ValueError("No cookies.") - - return cookies - - -# --- Models --- # - - -class CopyrightData(TypedDict): - name: str - statement: str - freedoms: str - printing: str - image_url: Optional[str] - - -class Language(TypedDict): - name: str - - -class User(TypedDict): - username: str - avatar: str - description: str - - -class Part(TypedDict): - id: int - title: str - - -class Story(TypedDict): - id: str - title: str - createDate: str - modifyDate: str - language: Language - user: User - description: str - cover: str - completed: bool - tags: List[str] - mature: bool - url: str - parts: List[Part] - isPaywalled: bool - copyright: int - - -story_ta = TypeAdapter(Story) - - -# --- Exceptions --- # - - -class WattpadError(Exception): - """Base Exception class for Wattpad related errors.""" - - -class StoryNotFoundError(WattpadError): - """Display the "This story was not found" error to the user.""" - - ... - - -class PartNotFoundError(StoryNotFoundError): ... - - -# --- API Calls --- # - - -@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) -async def fetch_story_from_partId( - part_id: int, cookies: Optional[dict] = None -) -> Tuple[int, Story]: - """Fetch Story metadata from a Part ID.""" - with start_action(action_type="api_fetch_storyFromPartId"): - async with CachedSession( - headers=headers, cache=None if cookies else cache - ) as session: # Don't cache requests with Cookies. - async with session.get( - f"https://www.wattpad.com/api/v3/story_parts/{part_id}?fields=groupId,group(tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username,avatar,description),parts(id,title),cover,copyright)" - ) as response: - body = await response.json() - - if response.status == 400: - match body.get("error_code"): - case 1020: # "Story part not found" - logger.info(f"{part_id=} not found on Wattpad, returning.") - raise PartNotFoundError() - - response.raise_for_status() - - return int(body["groupId"]), story_ta.validate_python(body["group"]) - - -@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) -async def fetch_story(story_id: int, cookies: Optional[dict] = None) -> Story: - """Fetch Story metadata from a Story ID.""" - with start_action(action_type="api_fetch_story", story_id=story_id): - async with CachedSession( - headers=headers, cookies=cookies, cache=None if cookies else cache - ) as session: - async with session.get( - f"https://www.wattpad.com/api/v3/stories/{story_id}?fields=tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username,avatar,description),parts(id,title),cover,copyright" - ) as response: - body = await response.json() - - if response.status == 400: - match body.get("error_code"): - case 1017: # "Story not found" - logger.info(f"{story_id=} not found on Wattpad, returning.") - raise StoryNotFoundError() - - response.raise_for_status() - - return story_ta.validate_python(body) - - -@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) -async def fetch_story_content_zip( - story_id: int, cookies: Optional[dict] = None -) -> BytesIO: - """BytesIO Stream of an Archive of Part Contents for a Story.""" - with start_action(action_type="api_fetch_storyZip", story_id=story_id): - async with CachedSession( - headers=headers, - cookies=cookies, - cache=None if cookies else cache, - ) as session: - async with session.get( - f"https://www.wattpad.com/apiv2/?m=storytext&group_id={story_id}&output=zip" - ) as response: - response.raise_for_status() - - bytes_stream = BytesIO(await response.read()) - - return bytes_stream - - -@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) -async def fetch_image(url: str, should_cache: bool = False) -> bytes: - """Fetch image bytes.""" - with start_action(action_type="api_fetch_image", url=url): - async with CachedSession( - headers=headers, cache=cache if should_cache else None - ) as session: # Don't cache images. - async with session.get(url) as response: - response.raise_for_status() - - body = await response.read() - - return body - - -# --- Generation --- # - - -class EPUBGenerator: - """EPUB Generation utilities""" - - def __init__(self, data: Story, cover: bytes): - """Initialize EPUBGenerator. Create epub.EpubBook() and set metadata and cover.""" - self.epub = epub.EpubBook() - self.data = data - self.cover = cover - - # set metadata, defined in https://www.dublincore.org/specifications/dublin-core/dcmi-terms/#section-2 - self.epub.add_author(data["user"]["username"]) - - self.epub.add_metadata("DC", "title", data["title"]) - self.epub.add_metadata("DC", "description", data["description"]) - self.epub.add_metadata("DC", "date", data["createDate"]) - self.epub.add_metadata("DC", "modified", data["modifyDate"]) - self.epub.add_metadata("DC", "language", data["language"]["name"]) - - self.epub.add_metadata( - None, "meta", "", {"name": "tags", "content": ", ".join(data["tags"])} - ) - self.epub.add_metadata( - None, "meta", "", {"name": "mature", "content": str(int(data["mature"]))} - ) - self.epub.add_metadata( - None, - "meta", - "", - {"name": "completed", "content": str(int(data["completed"]))}, - ) - - # Set cover - self.epub.set_cover("cover.jpg", cover) - cover_chapter = epub.EpubHtml( - file_name="titlepage.xhtml", # Standard for cover page - ) - cover_chapter.set_content('') - self.epub.add_item(cover_chapter) - - async def add_chapters( - self, contents: List[bs4.Tag], download_images: bool = False - ): - """Add chapters to the Epub, downloading images if necessary. Sets the table of contents and spine.""" - chapters: List[epub.EpubHtml] = [] - - for cidx, (part, content) in enumerate(zip(self.data["parts"], contents)): - title = part["title"] - - # Thanks https://eu17.proxysite.com/process.php?d=5VyWYcoQl%2BVF0BYOuOavtvjOloFUZz2BJ%2Fepiusk6Nz7PV%2B9i8rs7cFviGftrBNll%2B0a3qO7UiDkTt4qwCa0fDES&b=1 - chapter = epub.EpubHtml( - title=title, - file_name=f"{cidx}_{part['id']}.xhtml", # See issue #30 - lang=self.data["language"]["name"], - uid=str(part["id"]).encode(), - ) - - str_content = content.prettify() - if download_images: - soup = content - - async with CachedSession( - headers=headers, cache=None - ) as session: # Don't cache images. - for idx, image in enumerate(soup.find_all("img")): - if not image["src"]: - continue - # Find all image tags and filter for those with sources - - async with session.get(image["src"]) as response: - img = epub.EpubImage( - media_type="image/jpeg", - content=await response.read(), - file_name=f"static/{cidx}/{idx}.jpeg", - ) - self.epub.add_item(img) - # Fetch image and pack - - str_content = str_content.replace( - str(image["src"]), f"static/{cidx}/{idx}.jpeg" - ) - - chapter.set_content(str_content) - self.epub.add_item(chapter) - - chapters.append(chapter) - - yield title - - self.epub.toc = chapters - - # Thanks https://github.com/aerkalov/ebooklib/blob/master/samples/09_create_image/create.py - self.epub.add_item(epub.EpubNcx()) - self.epub.add_item(epub.EpubNav()) - - # create spine - self.epub.spine = ["nav"] + chapters - - def dump(self) -> BytesIO: - # Thanks https://stackoverflow.com/a/75398222 - buffer = BytesIO() - epub.write_epub(buffer, self.epub) - - buffer.seek(0) - - return buffer - - -class PDFGenerator: - """PDF Generation utilities""" - - def __init__(self, data: Story, cover: bytes): - """Initialize PDGenerator, create PDF Temporary file.""" - self.data = data - self.file = tempfile.NamedTemporaryFile(suffix=".pdf", delete=True) - self.cover = cover - self.content: str = "" - self.copyright = { - 1: { - "name": "All Rights Reserved", - "statement": "©️ {published_year} by {username}. All Rights Reserved.", - "freedoms": "No reuse, redistribution, or modification without permission.", - "printing": "Not allowed without explicit permission.", - "image_url": None, - }, - 2: { - "name": "Public Domain", - "statement": "This work is in the public domain. Originally published in {published_year} by {username}.", - "freedoms": "Free to use for any purpose without permission.", - "printing": "Allowed for personal or commercial purposes.", - "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/cc-zero.png", - }, - 3: { - "name": "Creative Commons Attribution (CC-BY)", - "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution 4.0 International License.", - "freedoms": "Allows reuse, redistribution, and modification with credit to the author.", - "printing": "Allowed with proper credit.", - "image_url": "https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by.png", - }, - 4: { - "name": "CC Attribution NonCommercial (CC-BY-NC)", - "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.", - "freedoms": "Allows reuse and modification for non-commercial purposes with credit.", - "printing": "Allowed for non-commercial purposes with proper credit.", - "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc.png", - }, - 5: { - "name": "CC Attribution NonCommercial NoDerivs (CC-BY-NC-ND)", - "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 4.0 International License.", - "freedoms": "Allows sharing in original form for non-commercial purposes with credit; no modifications allowed.", - "printing": "Allowed for non-commercial purposes in original form with proper credit.", - "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc-nd.png", - }, - 6: { - "name": "CC Attribution NonCommercial ShareAlike (CC-BY-NC-SA)", - "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.", - "freedoms": "Allows reuse and modification for non-commercial purposes under the same license, with credit.", - "printing": "Allowed for non-commercial purposes with proper credit under the same license.", - "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc-sa.png", - }, - 7: { - "name": "CC Attribution ShareAlike (CC-BY-SA)", - "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.", - "freedoms": "Allows reuse and modification for any purpose under the same license, with credit.", - "printing": "Allowed with proper credit under the same license.", - "image_url": "https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-sa.png", - }, - 8: { - "name": "CC Attribution NoDerivs (CC-BY-ND)", - "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NoDerivs 4.0 International License.", - "freedoms": "Allows sharing in original form for any purpose with credit; no modifications allowed.", - "printing": "Allowed in original form with proper credit.", - "image_url": "https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nd.png", - }, - } - - with open("./pdf/stylesheet.css") as reader: - self.stylesheet = reader.read() - with open("./pdf/book.html") as reader: - self.template = reader.read() - - async def generate_cover_and_copyright_html( - self, - ) -> str: - """Generate Cover and Copyright file, fetch copyright image (cached), use self.cover for cover.""" - - copyright_data = self.copyright[self.data["copyright"]] - - template = self.template - about_copyright = ( - template.replace( - "{statement}", - copyright_data["statement"].format( - username=self.data["user"]["username"], - published_year=self.data["createDate"].split("-", 2)[0], - ), - ) - .replace("{author}", self.data["user"]["username"]) - .replace("{freedoms}", copyright_data["freedoms"]) - .replace( - "{printing}", - copyright_data["printing"], - ) - .replace("{book_id}", self.data["id"]) - .replace("{book_title}", self.data["title"]) - ) - - copyright_image = ( - await fetch_image(copyright_data["image_url"], should_cache=True) - if copyright_data["image_url"] - else None - ) - image_block = ( - """""".format( - image_url=f"data:image/jpg;base64,{b64encode(copyright_image).decode()}", - name=copyright_data["name"], - ) - if copyright_image - else "" - ) - about_copyright = ( - about_copyright.replace( - "{copyright_image}", - image_block, - ) - if image_block - else about_copyright.replace("{copyright_image}", "") - ) - about_copyright = about_copyright.replace( - "{cover}", f"data:image/jpg;base64,{b64encode(self.cover).decode()}" - ) - - self.template = about_copyright - return about_copyright - - async def generate_about_author_chapter(self) -> str: - """Generate About the Author file, fetch avatar.""" - author_avatar = ( - await fetch_image( - self.data["user"]["avatar"].replace("128", "512") - ) # Increase image resolution - if self.data["user"]["avatar"] - else None - ) - about_author = self.template.replace( - "{username}", self.data["user"]["username"] - ).replace("{description}", smart_trim(self.data["user"]["description"])) - - about_author = ( - about_author.replace( - "{avatar}", - f""" - Author's profile picture""", - ) - if author_avatar - else about_author.replace("{avatar}", "") - ) - - self.template = about_author - return about_author - - def generate_toc(self): - ids = [part["id"] for part in self.data["parts"]] - clean = BeautifulSoup( - """ -
-

Table of Contents

- -
- """, - "html.parser", - ) # html.parser doesn't create / tags automatically - - ul = cast(bs4.Tag, clean.find("ul")) - for part_id in ids: - li = clean.new_tag("li") - a = clean.new_tag("a") - a["href"] = f"#{part_id}" - li.append(a) - ul.append(li) - - insert_point = cast(bs4.Tag, self.tree.find("div", {"id": "book"})) - insert_point.append(clean) - return str(clean) - - async def add_chapters( - self, contents: List[bs4.Tag], download_images: bool = False - ): - """Add chapters to the PDF, downloading images if necessary. Also add Cover, Copyright, and About the Author pages.""" - - # # Cover and Copyright Page - await self.generate_cover_and_copyright_html() - await self.generate_about_author_chapter() - self.tree = BeautifulSoup(self.template, "lxml") - - self.generate_toc() - for part, content in zip(self.data["parts"], contents): - insert_point = cast(bs4.Tag, self.tree.find("div", {"id": "book"})) - insert_point.append(content) - - yield part["title"] - - # # About the Author page - # about_author_html = await self.generate_about_author_chapter() - - # chapters.insert(0, cover_and_copyright_html) - # chapters.append(about_author_html) - - with start_action( - action_type="generate_pdf", - output_filename=self.file.name, - title=self.data["title"], - ): - # PDF Generation with wkhtmltopdf, written to self.file - - # At this stage, we have a bunch of HTML Files representing all the chapters that need to be generated. PDFKit handles ToC generation, so that's not included. - - font_config = FontConfiguration() - - stylesheet_obj = CSS(string=self.stylesheet, font_config=font_config) - - html_obj = HTML(string=str(self.tree)) - html_obj.write_pdf( - self.file.name, stylesheets=[stylesheet_obj], font_config=font_config - ) - - with start_action(action_type="add_metadata") as action: - # Metadata generation with Exiftool - clean_description = ( - self.data["description"].strip().replace("\n", "$/") - ) # exiftool doesn't parse \ns correctly, they support $/ for the same instead. ` ` is another option. - - action.log(f"clean_description: {clean_description}") - - metadata = { - "Author": self.data["user"]["username"], - "Title": self.data["title"], - "Subject": clean_description, - "CreationDate": self.data["createDate"], - "ModDate": self.data["modifyDate"], - "Keywords": ",".join(self.data["tags"]), - "Language": self.data["language"]["name"], - "Completed": self.data["completed"], - "MatureContent": self.data["mature"], - "Producer": "Dhanush Rambhatla (TheOnlyWayUp - https://rambhat.la) and WattpadDownloader", - } # As per https://exiftool.org/TagNames/PDF.html - - action.log(f"options: {metadata}") - - with ExifTool( - config_file="../exiftool.config", logger=exiftool_logger - ) as et: - # Custom configuration adds Completed and MatureContent tags. - # exiftool logger logs executed command - et.execute( - *( - [f"-{key}={value}" for key, value in metadata.items()] - + [ - "-overwrite_original", - self.file.file.name, - ] - ) - ) - - def dump(self) -> BytesIO: - self.file.seek(0) - buffer = BytesIO(self.file.read()) - self.file.close() - - return buffer - - -# ------ # diff --git a/src/api/src/create_book/__init__.py b/src/api/src/create_book/__init__.py new file mode 100644 index 0000000..5450f75 --- /dev/null +++ b/src/api/src/create_book/__init__.py @@ -0,0 +1,10 @@ +from .create_book import ( + fetch_story, + fetch_story_from_partId, + fetch_story_content_zip, + fetch_image, + fetch_cookies, +) +from generators import PDFGenerator, EPUBGenerator +from exceptions import WattpadError, StoryNotFoundError, PartNotFoundError +from utils import generate_clean_part_html, slugify, logger diff --git a/src/api/src/create_book/config.py b/src/api/src/create_book/config.py new file mode 100644 index 0000000..efddf2e --- /dev/null +++ b/src/api/src/create_book/config.py @@ -0,0 +1,45 @@ +from enum import Enum +from pydantic import model_validator, field_validator +from pydantic_settings import BaseSettings + + +class CacheTypes(Enum): + file = "file" + redis = "redis" + + +class Config(BaseSettings): + # Values can be overriden by envvars. + + USE_CACHE: bool = True + CACHE_TYPE: CacheTypes = CacheTypes.file + REDIS_CONNECTION_URL: str = "" + + @field_validator("USE_CACHE", mode="before") + def validate_use_cache(cls, value): + # Return default if value is an empty string + if value == "": + return True # Default value for USE_CACHE + return value + + @field_validator("CACHE_TYPE", mode="before") + def validate_cache_type(cls, value): + # Thanks https://stackoverflow.com/a/78157474 + if value == "": + return "file" + return value + + @model_validator(mode="after") + def prevent_mismatched_redis_url(self): + match self.CACHE_TYPE: + case CacheTypes.file: + if self.REDIS_CONNECTION_URL: + raise ValueError( + "REDIS_CONNECTION_URL provided when File cache selected. To use Redis as a cache, set CACHE_TYPE=redis." + ) + case CacheTypes.redis: + if not self.REDIS_CONNECTION_URL: + raise ValueError( + "REDIS_CONNECTION_URL not provided when Redis cache selected. To use File cache, set CACHE_TYPE=file." + ) + return self diff --git a/src/api/src/create_book/create_book.py b/src/api/src/create_book/create_book.py new file mode 100644 index 0000000..c1e7f9e --- /dev/null +++ b/src/api/src/create_book/create_book.py @@ -0,0 +1,165 @@ +from __future__ import annotations +from typing import Optional, Tuple +from io import BytesIO +import backoff +from pydantic import TypeAdapter +from config import Config, CacheTypes +from logs import logger +from eliot import start_action +from dotenv import load_dotenv +from aiohttp import ClientResponseError +from aiohttp_client_cache.session import CachedSession +from aiohttp_client_cache import FileBackend, RedisBackend +from models import Story +from exceptions import PartNotFoundError, StoryNotFoundError + +load_dotenv(override=True) + +config = Config() +story_ta = TypeAdapter(Story) + +# --- # + +headers = { + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" +} + +if config.USE_CACHE: + match config.CACHE_TYPE: + case CacheTypes.file: + cache = FileBackend(use_temp=True, expire_after=43200) # 12 hours + case CacheTypes.redis: + cache = RedisBackend( + cache_name="wpd-aiohttp-cache", + address=config.REDIS_CONNECTION_URL, + expire_after=43200, # 12 hours + ) +else: + cache = None + +logger.info(f"Using {cache=}") + + +async def fetch_cookies(username: str, password: str) -> dict: + # source: https://github.com/TheOnlyWayUp/WP-DM-Export/blob/dd4c7c51cb43f2108e0f63fc10a66cd24a740e4e/src/API/src/main.py#L25-L58 + """Retrieves authorization cookies from Wattpad by logging in with user creds. + + Args: + username (str): Username. + password (str): Password. + + Raises: + ValueError: Bad status code. + ValueError: No cookies returned. + + Returns: + dict: Authorization cookies. + """ + with start_action(action_type="api_fetch_cookies"): + async with CachedSession(headers=headers, cache=None) as session: + async with session.post( + "https://www.wattpad.com/auth/login?nextUrl=%2F&_data=routes%2Fauth.login", + data={ + "username": username.lower(), + "password": password, + }, # the username.lower() is for caching + ) as response: + if response.status != 204: + raise ValueError("Not a 204.") + + cookies = { + k: v.value + for k, v in response.cookies.items() # Thanks https://stackoverflow.com/a/32281245 + } + + if not cookies: + raise ValueError("No cookies.") + + return cookies + + +# --- API Calls --- # + + +@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) +async def fetch_story_from_partId( + part_id: int, cookies: Optional[dict] = None +) -> Tuple[int, Story]: + """Fetch Story metadata from a Part ID.""" + with start_action(action_type="api_fetch_storyFromPartId"): + async with CachedSession( + headers=headers, cache=None if cookies else cache + ) as session: # Don't cache requests with Cookies. + async with session.get( + f"https://www.wattpad.com/api/v3/story_parts/{part_id}?fields=groupId,group(tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username,avatar,description),parts(id,title),cover,copyright)" + ) as response: + body = await response.json() + + if response.status == 400: + match body.get("error_code"): + case 1020: # "Story part not found" + logger.info(f"{part_id=} not found on Wattpad, returning.") + raise PartNotFoundError() + + response.raise_for_status() + + return int(body["groupId"]), story_ta.validate_python(body["group"]) + + +@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) +async def fetch_story(story_id: int, cookies: Optional[dict] = None) -> Story: + """Fetch Story metadata from a Story ID.""" + with start_action(action_type="api_fetch_story", story_id=story_id): + async with CachedSession( + headers=headers, cookies=cookies, cache=None if cookies else cache + ) as session: + async with session.get( + f"https://www.wattpad.com/api/v3/stories/{story_id}?fields=tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username,avatar,description),parts(id,title),cover,copyright" + ) as response: + body = await response.json() + + if response.status == 400: + match body.get("error_code"): + case 1017: # "Story not found" + logger.info(f"{story_id=} not found on Wattpad, returning.") + raise StoryNotFoundError() + + response.raise_for_status() + + return story_ta.validate_python(body) + + +@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) +async def fetch_story_content_zip( + story_id: int, cookies: Optional[dict] = None +) -> BytesIO: + """BytesIO Stream of an Archive of Part Contents for a Story.""" + with start_action(action_type="api_fetch_storyZip", story_id=story_id): + async with CachedSession( + headers=headers, + cookies=cookies, + cache=None if cookies else cache, + ) as session: + async with session.get( + f"https://www.wattpad.com/apiv2/?m=storytext&group_id={story_id}&output=zip" + ) as response: + response.raise_for_status() + + bytes_stream = BytesIO(await response.read()) + + return bytes_stream + + +@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) +async def fetch_image(url: str, should_cache: bool = False) -> bytes: + """Fetch image bytes.""" + with start_action(action_type="api_fetch_image", url=url): + async with CachedSession( + headers=headers, cache=cache if should_cache else None + ) as session: # Don't cache images. + async with session.get(url) as response: + response.raise_for_status() + + body = await response.read() + + return body diff --git a/src/api/src/create_book/exceptions.py b/src/api/src/create_book/exceptions.py new file mode 100644 index 0000000..50225d7 --- /dev/null +++ b/src/api/src/create_book/exceptions.py @@ -0,0 +1,11 @@ +class WattpadError(Exception): + """Base Exception class for Wattpad related errors.""" + + +class StoryNotFoundError(WattpadError): + """Display the "This story was not found" error to the user.""" + + ... + + +class PartNotFoundError(StoryNotFoundError): ... diff --git a/src/api/src/create_book/generators/__init__.py b/src/api/src/create_book/generators/__init__.py new file mode 100644 index 0000000..e4c891e --- /dev/null +++ b/src/api/src/create_book/generators/__init__.py @@ -0,0 +1,2 @@ +from epub import EPUBGenerator +from pdf import PDFGenerator diff --git a/src/api/src/create_book/generators/epub.py b/src/api/src/create_book/generators/epub.py new file mode 100644 index 0000000..1c919ee --- /dev/null +++ b/src/api/src/create_book/generators/epub.py @@ -0,0 +1,115 @@ +from ebooklib import epub +from typing import List +from models import Story +from io import BytesIO +import bs4 +from aiohttp_client_cache.session import CachedSession + +headers = {} + + +class EPUBGenerator: + """EPUB Generation utilities""" + + def __init__(self, data: Story, cover: bytes): + """Initialize EPUBGenerator. Create epub.EpubBook() and set metadata and cover.""" + self.epub = epub.EpubBook() + self.data = data + self.cover = cover + + # set metadata, defined in https://www.dublincore.org/specifications/dublin-core/dcmi-terms/#section-2 + self.epub.add_author(data["user"]["username"]) + + self.epub.add_metadata("DC", "title", data["title"]) + self.epub.add_metadata("DC", "description", data["description"]) + self.epub.add_metadata("DC", "date", data["createDate"]) + self.epub.add_metadata("DC", "modified", data["modifyDate"]) + self.epub.add_metadata("DC", "language", data["language"]["name"]) + + self.epub.add_metadata( + None, "meta", "", {"name": "tags", "content": ", ".join(data["tags"])} + ) + self.epub.add_metadata( + None, "meta", "", {"name": "mature", "content": str(int(data["mature"]))} + ) + self.epub.add_metadata( + None, + "meta", + "", + {"name": "completed", "content": str(int(data["completed"]))}, + ) + + # Set cover + self.epub.set_cover("cover.jpg", cover) + cover_chapter = epub.EpubHtml( + file_name="titlepage.xhtml", # Standard for cover page + ) + cover_chapter.set_content('') + self.epub.add_item(cover_chapter) + + async def add_chapters( + self, contents: List[bs4.Tag], download_images: bool = False + ): + """Add chapters to the Epub, downloading images if necessary. Sets the table of contents and spine.""" + chapters: List[epub.EpubHtml] = [] + + for cidx, (part, content) in enumerate(zip(self.data["parts"], contents)): + title = part["title"] + + # Thanks https://eu17.proxysite.com/process.php?d=5VyWYcoQl%2BVF0BYOuOavtvjOloFUZz2BJ%2Fepiusk6Nz7PV%2B9i8rs7cFviGftrBNll%2B0a3qO7UiDkTt4qwCa0fDES&b=1 + chapter = epub.EpubHtml( + title=title, + file_name=f"{cidx}_{part['id']}.xhtml", # See issue #30 + lang=self.data["language"]["name"], + uid=str(part["id"]).encode(), + ) + + str_content = content.prettify() + if download_images: # ! TODO : Download images elsewhere + soup = content + + async with CachedSession( + headers=headers, cache=None + ) as session: # Don't cache images. + for idx, image in enumerate(soup.find_all("img")): + if not image["src"]: + continue + # Find all image tags and filter for those with sources + + async with session.get(image["src"]) as response: + img = epub.EpubImage( + media_type="image/jpeg", + content=await response.read(), + file_name=f"static/{cidx}/{idx}.jpeg", + ) + self.epub.add_item(img) + # Fetch image and pack + + str_content = str_content.replace( + str(image["src"]), f"static/{cidx}/{idx}.jpeg" + ) + + chapter.set_content(str_content) + self.epub.add_item(chapter) + + chapters.append(chapter) + + yield title + + self.epub.toc = chapters + + # Thanks https://github.com/aerkalov/ebooklib/blob/master/samples/09_create_image/create.py + self.epub.add_item(epub.EpubNcx()) + self.epub.add_item(epub.EpubNav()) + + # create spine + self.epub.spine = ["nav"] + chapters + + def dump(self) -> BytesIO: + # Thanks https://stackoverflow.com/a/75398222 + buffer = BytesIO() + epub.write_epub(buffer, self.epub) + + buffer.seek(0) + + return buffer diff --git a/src/api/src/create_book/generators/pdf.py b/src/api/src/create_book/generators/pdf.py new file mode 100644 index 0000000..dd49fea --- /dev/null +++ b/src/api/src/create_book/generators/pdf.py @@ -0,0 +1,286 @@ +from typing import List, cast +import tempfile +from base64 import b64encode +import bs4 +from weasyprint import HTML, CSS +from weasyprint.text.fonts import FontConfiguration +from exiftool import ExifTool +from logs import exiftool_logger +from bs4 import BeautifulSoup +from utils import smart_trim +from models import Story +from eliot import start_action +from io import BytesIO + + +async def fetch_image(*args, **kwargs): + # TODO + raise NotImplementedError() + + +class PDFGenerator: + """PDF Generation utilities""" + + def __init__(self, data: Story, cover: bytes): + """Initialize PDGenerator, create PDF Temporary file.""" + self.data = data + self.file = tempfile.NamedTemporaryFile(suffix=".pdf", delete=True) + self.cover = cover + self.content: str = "" + self.copyright = { + 1: { + "name": "All Rights Reserved", + "statement": "©️ {published_year} by {username}. All Rights Reserved.", + "freedoms": "No reuse, redistribution, or modification without permission.", + "printing": "Not allowed without explicit permission.", + "image_url": None, + }, + 2: { + "name": "Public Domain", + "statement": "This work is in the public domain. Originally published in {published_year} by {username}.", + "freedoms": "Free to use for any purpose without permission.", + "printing": "Allowed for personal or commercial purposes.", + "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/cc-zero.png", + }, + 3: { + "name": "Creative Commons Attribution (CC-BY)", + "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution 4.0 International License.", + "freedoms": "Allows reuse, redistribution, and modification with credit to the author.", + "printing": "Allowed with proper credit.", + "image_url": "https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by.png", + }, + 4: { + "name": "CC Attribution NonCommercial (CC-BY-NC)", + "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.", + "freedoms": "Allows reuse and modification for non-commercial purposes with credit.", + "printing": "Allowed for non-commercial purposes with proper credit.", + "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc.png", + }, + 5: { + "name": "CC Attribution NonCommercial NoDerivs (CC-BY-NC-ND)", + "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 4.0 International License.", + "freedoms": "Allows sharing in original form for non-commercial purposes with credit; no modifications allowed.", + "printing": "Allowed for non-commercial purposes in original form with proper credit.", + "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc-nd.png", + }, + 6: { + "name": "CC Attribution NonCommercial ShareAlike (CC-BY-NC-SA)", + "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.", + "freedoms": "Allows reuse and modification for non-commercial purposes under the same license, with credit.", + "printing": "Allowed for non-commercial purposes with proper credit under the same license.", + "image_url": "http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc-sa.png", + }, + 7: { + "name": "CC Attribution ShareAlike (CC-BY-SA)", + "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.", + "freedoms": "Allows reuse and modification for any purpose under the same license, with credit.", + "printing": "Allowed with proper credit under the same license.", + "image_url": "https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-sa.png", + }, + 8: { + "name": "CC Attribution NoDerivs (CC-BY-ND)", + "statement": "©️ {published_year} by {username}. This work is licensed under a Creative Commons Attribution-NoDerivs 4.0 International License.", + "freedoms": "Allows sharing in original form for any purpose with credit; no modifications allowed.", + "printing": "Allowed in original form with proper credit.", + "image_url": "https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nd.png", + }, + } + + with open("./pdf/stylesheet.css") as reader: + self.stylesheet = reader.read() + with open("./pdf/book.html") as reader: + self.template = reader.read() + + async def generate_cover_and_copyright_html( + self, + ) -> str: + """Generate Cover and Copyright file, fetch copyright image (cached), use self.cover for cover.""" + + copyright_data = self.copyright[self.data["copyright"]] + + template = self.template + about_copyright = ( + template.replace( + "{statement}", + copyright_data["statement"].format( + username=self.data["user"]["username"], + published_year=self.data["createDate"].split("-", 2)[0], + ), + ) + .replace("{author}", self.data["user"]["username"]) + .replace("{freedoms}", copyright_data["freedoms"]) + .replace( + "{printing}", + copyright_data["printing"], + ) + .replace("{book_id}", self.data["id"]) + .replace("{book_title}", self.data["title"]) + ) + + copyright_image = ( + await fetch_image(copyright_data["image_url"], should_cache=True) + if copyright_data["image_url"] + else None + ) + image_block = ( + """""".format( + image_url=f"data:image/jpg;base64,{b64encode(copyright_image).decode()}", + name=copyright_data["name"], + ) + if copyright_image + else "" + ) + about_copyright = ( + about_copyright.replace( + "{copyright_image}", + image_block, + ) + if image_block + else about_copyright.replace("{copyright_image}", "") + ) + about_copyright = about_copyright.replace( + "{cover}", f"data:image/jpg;base64,{b64encode(self.cover).decode()}" + ) + + self.template = about_copyright + return about_copyright + + async def generate_about_author_chapter(self) -> str: + """Generate About the Author file, fetch avatar.""" + author_avatar = ( + await fetch_image( + self.data["user"]["avatar"].replace("128", "512") + ) # Increase image resolution + if self.data["user"]["avatar"] + else None + ) + about_author = self.template.replace( + "{username}", self.data["user"]["username"] + ).replace("{description}", smart_trim(self.data["user"]["description"])) + + about_author = ( + about_author.replace( + "{avatar}", + f""" + Author's profile picture""", + ) + if author_avatar + else about_author.replace("{avatar}", "") + ) + + self.template = about_author + return about_author + + def generate_toc(self): + ids = [part["id"] for part in self.data["parts"]] + clean = BeautifulSoup( + """ +
+

Table of Contents

+ +
+ """, + "html.parser", + ) # html.parser doesn't create / tags automatically + + ul = cast(bs4.Tag, clean.find("ul")) + for part_id in ids: + li = clean.new_tag("li") + a = clean.new_tag("a") + a["href"] = f"#{part_id}" + li.append(a) + ul.append(li) + + insert_point = cast(bs4.Tag, self.tree.find("div", {"id": "book"})) + insert_point.append(clean) + return str(clean) + + async def add_chapters( + self, contents: List[bs4.Tag], download_images: bool = False + ): + """Add chapters to the PDF, downloading images if necessary. Also add Cover, Copyright, and About the Author pages.""" + + # # Cover and Copyright Page + await self.generate_cover_and_copyright_html() + await self.generate_about_author_chapter() + self.tree = BeautifulSoup(self.template, "lxml") + + self.generate_toc() + for part, content in zip(self.data["parts"], contents): + insert_point = cast(bs4.Tag, self.tree.find("div", {"id": "book"})) + insert_point.append(content) + + yield part["title"] + + # # About the Author page + # about_author_html = await self.generate_about_author_chapter() + + # chapters.insert(0, cover_and_copyright_html) + # chapters.append(about_author_html) + + with start_action( + action_type="generate_pdf", + output_filename=self.file.name, + title=self.data["title"], + ): + # PDF Generation with wkhtmltopdf, written to self.file + + # At this stage, we have a bunch of HTML Files representing all the chapters that need to be generated. PDFKit handles ToC generation, so that's not included. + + font_config = FontConfiguration() + + stylesheet_obj = CSS(string=self.stylesheet, font_config=font_config) + + html_obj = HTML(string=str(self.tree)) + html_obj.write_pdf( + self.file.name, stylesheets=[stylesheet_obj], font_config=font_config + ) + + with start_action(action_type="add_metadata") as action: + # Metadata generation with Exiftool + clean_description = ( + self.data["description"].strip().replace("\n", "$/") + ) # exiftool doesn't parse \ns correctly, they support $/ for the same instead. ` ` is another option. + + action.log(f"clean_description: {clean_description}") + + metadata = { + "Author": self.data["user"]["username"], + "Title": self.data["title"], + "Subject": clean_description, + "CreationDate": self.data["createDate"], + "ModDate": self.data["modifyDate"], + "Keywords": ",".join(self.data["tags"]), + "Language": self.data["language"]["name"], + "Completed": self.data["completed"], + "MatureContent": self.data["mature"], + "Producer": "Dhanush Rambhatla (TheOnlyWayUp - https://rambhat.la) and WattpadDownloader", + } # As per https://exiftool.org/TagNames/PDF.html + + action.log(f"options: {metadata}") + + with ExifTool( + config_file="../exiftool.config", logger=exiftool_logger + ) as et: + # Custom configuration adds Completed and MatureContent tags. + # exiftool logger logs executed command + et.execute( + *( + [f"-{key}={value}" for key, value in metadata.items()] + + [ + "-overwrite_original", + self.file.file.name, + ] + ) + ) + + def dump(self) -> BytesIO: + self.file.seek(0) + buffer = BytesIO(self.file.read()) + self.file.close() + + return buffer diff --git a/src/api/src/create_book/logs.py b/src/api/src/create_book/logs.py new file mode 100644 index 0000000..6f4381d --- /dev/null +++ b/src/api/src/create_book/logs.py @@ -0,0 +1,18 @@ +import logging +from os import environ +from eliot import to_file +from eliot.stdlib import EliotHandler + +handler = EliotHandler() + +logging.getLogger("fastapi").setLevel(logging.INFO) +logging.getLogger("fastapi").addHandler(handler) + +exiftool_logger = logging.getLogger("exiftool") +exiftool_logger.addHandler(handler) + +logger = logging.Logger("wpd") +logger.addHandler(handler) + +if environ.get("DEBUG"): + to_file(open("eliot.log", "wb")) diff --git a/src/api/src/create_book/models.py b/src/api/src/create_book/models.py new file mode 100644 index 0000000..9b26357 --- /dev/null +++ b/src/api/src/create_book/models.py @@ -0,0 +1,42 @@ +from typing import TypedDict, Optional, List + + +class CopyrightData(TypedDict): + name: str + statement: str + freedoms: str + printing: str + image_url: Optional[str] + + +class Language(TypedDict): + name: str + + +class User(TypedDict): + username: str + avatar: str + description: str + + +class Part(TypedDict): + id: int + title: str + + +class Story(TypedDict): + id: str + title: str + createDate: str + modifyDate: str + language: Language + user: User + description: str + cover: str + completed: bool + tags: List[str] + mature: bool + url: str + parts: List[Part] + isPaywalled: bool + copyright: int diff --git a/src/api/src/create_book/utils.py b/src/api/src/create_book/utils.py new file mode 100644 index 0000000..4bf1075 --- /dev/null +++ b/src/api/src/create_book/utils.py @@ -0,0 +1,108 @@ +import re +import bs4 +import unicodedata +from bs4 import BeautifulSoup +from typing import cast +from models import Part + + +def smart_trim(text: str, max_length: int = 400) -> str: + """Truncate a string intelligently at newlines. Coherence and max-length adherence.""" + chunks = [t for t in text.split("\n") if t] + + to_return = "" + for chunk in chunks: + if len(to_return) + len(chunk) < max_length: + to_return = chunk + "
" + else: + to_return = to_return.rstrip("
") + break + + return to_return + + +def generate_clean_part_html(part: Part, content: str) -> bs4.Tag: + """Rebuild HTML Structure for a Part.""" + chapter_title = part["title"] + chapter_id = part["id"] + + clean = BeautifulSoup( + f""" +
+

{chapter_title}

+
+ """, + "html.parser", + ) # html.parser doesn't create / tags automatically + + html = BeautifulSoup(content, "lxml") + for br in html.find_all("br"): + # Check if no content after br + if not br.next_sibling or br.next_sibling.name in ["br", None]: + br.decompose() + + section = cast(bs4.Tag, clean.find("section")) + if not section: + raise Exception() + + for child in html.find_all("p"): + current_paragraph = clean.new_tag("p") + + # Attempt to carry over paragraph styling + current_paragraph["style"] = child.get("style", "text-align: left;") + + for p_child in list(child.children): + if not p_child: + continue + if isinstance(p_child, bs4.element.Tag): + if p_child.name == "br": + p_child.decompose() + elif p_child.name == "img": + src = p_child["src"] + img_tag = clean.new_tag("img") + img_tag["src"] = src + section.append(img_tag) + section.append(clean.new_tag("br")) + elif p_child.name in ["b", "i"]: + styled_tag = clean.new_tag(p_child.name) + styled_content = clean.new_string(p_child.text) + styled_tag.append(styled_content) + current_paragraph.append(styled_tag) + else: + # Append any other tags as-is + current_paragraph.append(p_child) + elif isinstance(p_child, bs4.element.NavigableString): + content = clean.new_string(p_child) + current_paragraph.append(content) + + if current_paragraph.contents: + section.append(current_paragraph) + + if not list(child.children): + # Some p tags only contain brs, once brs are removed, they are empty and can be removed as well. + child.decompose() + + return section + + +def slugify(value, allow_unicode=False) -> str: + """ + Taken from https://github.com/django/django/blob/master/django/utils/text.py + Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated + dashes to single dashes. Remove characters that aren't alphanumerics, + underscores, or hyphens. Convert to lowercase. Also strip leading and + trailing whitespace, dashes, and underscores. + + Thanks https://stackoverflow.com/a/295466. + """ + value = str(value) + if allow_unicode: + value = unicodedata.normalize("NFKC", value) + else: + value = ( + unicodedata.normalize("NFKD", value) + .encode("ascii", "ignore") + .decode("ascii") + ) + value = re.sub(r"[^\w\s-]", "", value.lower()) + return re.sub(r"[-\s]+", "-", value).strip("-_") From 10d8a8f3086cc4559ce45a0b9d887255405b71ae Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Wed, 4 Jun 2025 11:55:23 +0000 Subject: [PATCH 02/38] fix(api/linter): Ignore module imports in init --- src/api/pyproject.toml | 2 +- src/api/src/create_book/__init__.py | 2 ++ src/api/src/create_book/generators/__init__.py | 2 ++ src/api/src/main.py | 1 - 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/api/pyproject.toml b/src/api/pyproject.toml index 9aadd5e..c0ac869 100644 --- a/src/api/pyproject.toml +++ b/src/api/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ ] [tool.ruff.lint] -ignore = ['E402'] +ignore = ['E402'] # module import not at top of file [tool.uv.sources] aiohttp-client-cache = { git = "https://github.com/TheOnlyWayUp/aiohttp-client-cache.git", rev = "keydb-ttl" } diff --git a/src/api/src/create_book/__init__.py b/src/api/src/create_book/__init__.py index 5450f75..8070176 100644 --- a/src/api/src/create_book/__init__.py +++ b/src/api/src/create_book/__init__.py @@ -1,3 +1,5 @@ +# ruff: noqa: F401 + from .create_book import ( fetch_story, fetch_story_from_partId, diff --git a/src/api/src/create_book/generators/__init__.py b/src/api/src/create_book/generators/__init__.py index e4c891e..6487b83 100644 --- a/src/api/src/create_book/generators/__init__.py +++ b/src/api/src/create_book/generators/__init__.py @@ -1,2 +1,4 @@ +# ruff: noqa: F401 + from epub import EPUBGenerator from pdf import PDFGenerator diff --git a/src/api/src/main.py b/src/api/src/main.py index 915b6c1..5f63c15 100644 --- a/src/api/src/main.py +++ b/src/api/src/main.py @@ -17,7 +17,6 @@ from fastapi.responses import ( from fastapi.staticfiles import StaticFiles from create_book import ( EPUBGenerator, - PDFGenerator, fetch_story, fetch_story_from_partId, fetch_story_content_zip, From 65eb0061971885a834982ef57a7cf12353b2f728 Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Wed, 4 Jun 2025 12:16:13 +0000 Subject: [PATCH 03/38] Upgrade to Python 3.13 --- src/api/.python-version | 2 +- src/api/pyproject.toml | 4 +- src/api/src/create_book/__init__.py | 7 +- src/api/src/create_book/create_book.py | 8 +- .../src/create_book/generators/__init__.py | 4 +- src/api/src/create_book/generators/epub.py | 2 +- src/api/src/create_book/generators/pdf.py | 6 +- src/api/src/create_book/utils.py | 2 +- src/api/uv.lock | 672 +----------------- 9 files changed, 20 insertions(+), 687 deletions(-) diff --git a/src/api/.python-version b/src/api/.python-version index c8cfe39..24ee5b1 100644 --- a/src/api/.python-version +++ b/src/api/.python-version @@ -1 +1 @@ -3.10 +3.13 diff --git a/src/api/pyproject.toml b/src/api/pyproject.toml index c0ac869..248c283 100644 --- a/src/api/pyproject.toml +++ b/src/api/pyproject.toml @@ -3,7 +3,7 @@ name = "api" version = "0.1.0" description = "Wattpad Downloader API" readme = "../../README.md" -requires-python = ">=3.10" +requires-python = ">=3.13" dependencies = [ "aiohttp>=3.9.1", "rich>=13.9.4", @@ -25,4 +25,4 @@ dependencies = [ ignore = ['E402'] # module import not at top of file [tool.uv.sources] -aiohttp-client-cache = { git = "https://github.com/TheOnlyWayUp/aiohttp-client-cache.git", rev = "keydb-ttl" } +aiohttp-client-cache = { git = "https://github.com/TheOnlyWayUp/aiohttp-client-cache.git", rev = "keydb-ttl" } # Fork which leverages keydb's EXPIREMEMBER feature for TTLs on Hash members. diff --git a/src/api/src/create_book/__init__.py b/src/api/src/create_book/__init__.py index 8070176..ef54aa5 100644 --- a/src/api/src/create_book/__init__.py +++ b/src/api/src/create_book/__init__.py @@ -7,6 +7,7 @@ from .create_book import ( fetch_image, fetch_cookies, ) -from generators import PDFGenerator, EPUBGenerator -from exceptions import WattpadError, StoryNotFoundError, PartNotFoundError -from utils import generate_clean_part_html, slugify, logger +from .generators import PDFGenerator, EPUBGenerator +from .exceptions import WattpadError, StoryNotFoundError, PartNotFoundError +from .utils import generate_clean_part_html, slugify +from .logs import logger diff --git a/src/api/src/create_book/create_book.py b/src/api/src/create_book/create_book.py index c1e7f9e..d94a375 100644 --- a/src/api/src/create_book/create_book.py +++ b/src/api/src/create_book/create_book.py @@ -3,15 +3,15 @@ from typing import Optional, Tuple from io import BytesIO import backoff from pydantic import TypeAdapter -from config import Config, CacheTypes -from logs import logger +from .config import Config, CacheTypes +from .logs import logger from eliot import start_action from dotenv import load_dotenv from aiohttp import ClientResponseError from aiohttp_client_cache.session import CachedSession from aiohttp_client_cache import FileBackend, RedisBackend -from models import Story -from exceptions import PartNotFoundError, StoryNotFoundError +from .models import Story +from .exceptions import PartNotFoundError, StoryNotFoundError load_dotenv(override=True) diff --git a/src/api/src/create_book/generators/__init__.py b/src/api/src/create_book/generators/__init__.py index 6487b83..0996838 100644 --- a/src/api/src/create_book/generators/__init__.py +++ b/src/api/src/create_book/generators/__init__.py @@ -1,4 +1,4 @@ # ruff: noqa: F401 -from epub import EPUBGenerator -from pdf import PDFGenerator +from .epub import EPUBGenerator +from .pdf import PDFGenerator diff --git a/src/api/src/create_book/generators/epub.py b/src/api/src/create_book/generators/epub.py index 1c919ee..a0218bf 100644 --- a/src/api/src/create_book/generators/epub.py +++ b/src/api/src/create_book/generators/epub.py @@ -1,6 +1,6 @@ from ebooklib import epub from typing import List -from models import Story +from ..models import Story from io import BytesIO import bs4 from aiohttp_client_cache.session import CachedSession diff --git a/src/api/src/create_book/generators/pdf.py b/src/api/src/create_book/generators/pdf.py index dd49fea..d3ae9ac 100644 --- a/src/api/src/create_book/generators/pdf.py +++ b/src/api/src/create_book/generators/pdf.py @@ -5,10 +5,10 @@ import bs4 from weasyprint import HTML, CSS from weasyprint.text.fonts import FontConfiguration from exiftool import ExifTool -from logs import exiftool_logger +from ..logs import exiftool_logger from bs4 import BeautifulSoup -from utils import smart_trim -from models import Story +from ..utils import smart_trim +from ..models import Story from eliot import start_action from io import BytesIO diff --git a/src/api/src/create_book/utils.py b/src/api/src/create_book/utils.py index 4bf1075..ef9e7c1 100644 --- a/src/api/src/create_book/utils.py +++ b/src/api/src/create_book/utils.py @@ -3,7 +3,7 @@ import bs4 import unicodedata from bs4 import BeautifulSoup from typing import cast -from models import Part +from .models import Part def smart_trim(text: str, max_length: int = 400) -> str: diff --git a/src/api/uv.lock b/src/api/uv.lock index dc9a091..92cdc3e 100644 --- a/src/api/uv.lock +++ b/src/api/uv.lock @@ -1,5 +1,5 @@ version = 1 -requires-python = ">=3.10" +requires-python = ">=3.13" [[package]] name = "aioboto3" @@ -59,7 +59,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, @@ -68,51 +67,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/3f/24/d5c0aed3ed90896f8505786e3a1e348fd9c61284ef21f54ee9cdf8b92e4f/aiohttp-3.11.9.tar.gz", hash = "sha256:a9266644064779840feec0e34f10a89b3ff1d2d6b751fe90017abcad1864fa7c", size = 7668012 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/e1/c8b50b37bc70dde633152d0e0ccb3fced624f39fa1e2a0385cf5bc71d13d/aiohttp-3.11.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0411777249f25d11bd2964a230b3ffafcbed6cd65d0f2b132bc2b8f5b8c347c7", size = 707560 }, - { url = "https://files.pythonhosted.org/packages/b1/e7/5ed51f97ed2a8cc0f64ba68c325a0f495950e7dc87f7fc5b7d290a8fb8ad/aiohttp-3.11.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:499368eb904566fbdf1a3836a1532000ef1308f34a1bcbf36e6351904cced771", size = 467441 }, - { url = "https://files.pythonhosted.org/packages/2e/b9/50cf7f016ac63cdfc36c2d2b4f3fc2a2927fb7053e72b6bfa5ee8d5c5fe5/aiohttp-3.11.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0b5a5009b0159a8f707879dc102b139466d8ec6db05103ec1520394fdd8ea02c", size = 454604 }, - { url = "https://files.pythonhosted.org/packages/e0/01/a7d0cd764e59d3cd6d4330690f95338ae970839b33ced3d3a64cfd7459c8/aiohttp-3.11.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176f8bb8931da0613bb0ed16326d01330066bb1e172dd97e1e02b1c27383277b", size = 1583627 }, - { url = "https://files.pythonhosted.org/packages/cb/cc/77e62f4597ac379aab7416622756dcb257650b1abfbda4591f8942a9eeeb/aiohttp-3.11.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6435a66957cdba1a0b16f368bde03ce9c79c57306b39510da6ae5312a1a5b2c1", size = 1631359 }, - { url = "https://files.pythonhosted.org/packages/b9/83/d638d0df80d9c8d7897d33ce638a72604d97d1aead04ded9ebc6323f312e/aiohttp-3.11.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:202f40fb686e5f93908eee0c75d1e6fbe50a43e9bd4909bf3bf4a56b560ca180", size = 1667311 }, - { url = "https://files.pythonhosted.org/packages/d3/04/46c63d99c45464a16f35d6bfb52c0aa1dec239c867f46f81aaa2e4dd1ce4/aiohttp-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39625703540feb50b6b7f938b3856d1f4886d2e585d88274e62b1bd273fae09b", size = 1588542 }, - { url = "https://files.pythonhosted.org/packages/10/d1/52fb2e2ab05bde5745ca1b189d91e0244327b3000c010bf82942c5870ddf/aiohttp-3.11.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6beeac698671baa558e82fa160be9761cf0eb25861943f4689ecf9000f8ebd0", size = 1543578 }, - { url = "https://files.pythonhosted.org/packages/83/85/ae424b30bd30fa6b2369a852ddc80b02cb6eeabd386abf968e8cb70b821e/aiohttp-3.11.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:96726839a42429318017e67a42cca75d4f0d5248a809b3cc2e125445edd7d50d", size = 1528248 }, - { url = "https://files.pythonhosted.org/packages/78/2f/0721b62cf6fb6c508e62ed513dead398deccdc9c2bb7bbd357b9bc31c8a1/aiohttp-3.11.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3f5461c77649358610fb9694e790956b4238ac5d9e697a17f63619c096469afe", size = 1535590 }, - { url = "https://files.pythonhosted.org/packages/fb/0d/7f0d1b6a2f6897982b31b3abacb1ed572d81408de1656e0f6fb0df5dfe4c/aiohttp-3.11.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4313f3bc901255b22f01663eeeae167468264fdae0d32c25fc631d5d6e15b502", size = 1606442 }, - { url = "https://files.pythonhosted.org/packages/ff/e5/17b17ad7ce5d3bce32089329077a07d0fa104cc9a57244f5a7a5bf5fbbcd/aiohttp-3.11.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d6e274661c74195708fc4380a4ef64298926c5a50bb10fbae3d01627d7a075b7", size = 1627801 }, - { url = "https://files.pythonhosted.org/packages/69/84/56d931915fd478989c99cfe3737e476c462b6863f35fdb2f7d4b8ce708bf/aiohttp-3.11.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:db2914de2559809fdbcf3e48f41b17a493b58cb7988d3e211f6b63126c55fe82", size = 1563290 }, - { url = "https://files.pythonhosted.org/packages/fc/e8/918d584e729c5a839e8af51d899a35e5b049b92fd4c95b930adb5c7bb125/aiohttp-3.11.9-cp310-cp310-win32.whl", hash = "sha256:27935716f8d62c1c73010428db310fd10136002cfc6d52b0ba7bdfa752d26066", size = 415588 }, - { url = "https://files.pythonhosted.org/packages/a0/b0/1e565ef4590525f21b06ce6e97ba88f787d64fea3e21b189d74075ae19b6/aiohttp-3.11.9-cp310-cp310-win_amd64.whl", hash = "sha256:afbe85b50ade42ddff5669947afde9e8a610e64d2c80be046d67ec4368e555fa", size = 440995 }, - { url = "https://files.pythonhosted.org/packages/3e/ec/d65424fb507f414fb363b210dff29406462ba1e15893ccaabf9dbb1eaf13/aiohttp-3.11.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:afcda759a69c6a8be3aae764ec6733155aa4a5ad9aad4f398b52ba4037942fe3", size = 707624 }, - { url = "https://files.pythonhosted.org/packages/23/3d/7d2797b1b0bd60d548ab927c879fada2bfad0705c6055f250eefd1790bb9/aiohttp-3.11.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5bba6b83fde4ca233cfda04cbd4685ab88696b0c8eaf76f7148969eab5e248a", size = 467506 }, - { url = "https://files.pythonhosted.org/packages/9f/41/5796191183588f3ed469db3a32e13aa23da51693b65ac66890d66e1f9b98/aiohttp-3.11.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:442356e8924fe1a121f8c87866b0ecdc785757fd28924b17c20493961b3d6697", size = 454577 }, - { url = "https://files.pythonhosted.org/packages/1c/6c/03753bf70534c442635480b91f0d9bf98dc726cccd6a707a384bfef40875/aiohttp-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f737fef6e117856400afee4f17774cdea392b28ecf058833f5eca368a18cf1bf", size = 1684693 }, - { url = "https://files.pythonhosted.org/packages/84/1b/40e3866a0f0851c7406779b0c010efb6d135814a1107deda2c72c14a527e/aiohttp-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea142255d4901b03f89cb6a94411ecec117786a76fc9ab043af8f51dd50b5313", size = 1742652 }, - { url = "https://files.pythonhosted.org/packages/cf/77/1ce991ea0ba2acac23df8ade94e554c5d077e7c3b0110a7495ce4d4d1c92/aiohttp-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1e9e447856e9b7b3d38e1316ae9a8c92e7536ef48373de758ea055edfd5db5", size = 1784415 }, - { url = "https://files.pythonhosted.org/packages/fb/91/43a53cc3b559b0edf863fd2dde69ab8fec58602fbe94484a687dc375d41b/aiohttp-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7f6173302f8a329ca5d1ee592af9e628d3ade87816e9958dcf7cdae2841def7", size = 1674140 }, - { url = "https://files.pythonhosted.org/packages/88/64/6893b99cb4fa43e92d39cc788ceb003ffd9aa3e5aa4f9a73ba796be14a3e/aiohttp-3.11.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c6147c6306f537cff59409609508a1d2eff81199f0302dd456bb9e7ea50c39", size = 1618798 }, - { url = "https://files.pythonhosted.org/packages/44/0f/f1d62912c4507411b84bb1f651c0029bc99848dcf36f89787843789940c1/aiohttp-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e9d036a9a41fc78e8a3f10a86c2fc1098fca8fab8715ba9eb999ce4788d35df0", size = 1652997 }, - { url = "https://files.pythonhosted.org/packages/54/71/9ef035c1ac7b8c1f54925396be4b3f633d757ab06fb7f45c975e10303e82/aiohttp-3.11.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2ac9fd83096df36728da8e2f4488ac3b5602238f602706606f3702f07a13a409", size = 1649014 }, - { url = "https://files.pythonhosted.org/packages/4e/66/3dcf6ca727dbf20ac79ef09ad367e6d41ae06943423800f21b8749fca205/aiohttp-3.11.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d3108f0ad5c6b6d78eec5273219a5bbd884b4aacec17883ceefaac988850ce6e", size = 1731893 }, - { url = "https://files.pythonhosted.org/packages/79/3b/b6ee96bef06f8bae0764c0fd8ecbd363e79fac2056b0fa79ede2a8673e30/aiohttp-3.11.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:96bbec47beb131bbf4bae05d8ef99ad9e5738f12717cfbbf16648b78b0232e87", size = 1754135 }, - { url = "https://files.pythonhosted.org/packages/f0/42/9a44c25105c232f1bbed50664ebc30de740e08d1d8de880836536ae5bc92/aiohttp-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fc726c3fa8f606d07bd2b500e5dc4c0fd664c59be7788a16b9e34352c50b6b6b", size = 1691731 }, - { url = "https://files.pythonhosted.org/packages/23/18/6d0d5873f6e1b2ce24520d4473998c246b3849724b4522cd3839e20f829f/aiohttp-3.11.9-cp311-cp311-win32.whl", hash = "sha256:5720ebbc7a1b46c33a42d489d25d36c64c419f52159485e55589fbec648ea49a", size = 415406 }, - { url = "https://files.pythonhosted.org/packages/f4/e9/472aa43749d48b3de28e4b16a5a663555e7b832d3b7fa9a3ceb766b1287e/aiohttp-3.11.9-cp311-cp311-win_amd64.whl", hash = "sha256:17af09d963fa1acd7e4c280e9354aeafd9e3d47eaa4a6bfbd2171ad7da49f0c5", size = 441501 }, - { url = "https://files.pythonhosted.org/packages/fa/43/b3c28a7e8f8b5e8ef0bea9fcabe8e99787c70fa526e5bc8185fd89f46434/aiohttp-3.11.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c1f2d7fd583fc79c240094b3e7237d88493814d4b300d013a42726c35a734bc9", size = 703661 }, - { url = "https://files.pythonhosted.org/packages/f3/2c/be4624671e5ed344fca9196d0823eb6a17383cbe13d051d22d3a1f6ecbf7/aiohttp-3.11.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4b8a1b6c7a68c73191f2ebd3bf66f7ce02f9c374e309bdb68ba886bbbf1b938", size = 463054 }, - { url = "https://files.pythonhosted.org/packages/d6/21/8d14fa0bdae468ebe419df1764583ecc9e995a2ccd8a11ee8146a09fb5e5/aiohttp-3.11.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd3f711f4c99da0091ced41dccdc1bcf8be0281dc314d6d9c6b6cf5df66f37a9", size = 455006 }, - { url = "https://files.pythonhosted.org/packages/42/de/3fc5e94a24bf079709e9fed3572ebb5efb32f0995baf08a985ee9f517b0b/aiohttp-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cb1a1326a0264480a789e6100dc3e07122eb8cd1ad6b784a3d47d13ed1d89c", size = 1681364 }, - { url = "https://files.pythonhosted.org/packages/69/e0/bd9346efcdd3344284e4b4088bc2c720065176bd9180517bdc7097218903/aiohttp-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a7ddf981a0b953ade1c2379052d47ccda2f58ab678fca0671c7c7ca2f67aac2", size = 1735986 }, - { url = "https://files.pythonhosted.org/packages/9b/a5/549ce29e21ebf555dcf5c81e19e6eb30eb8de26f8da304f05a28d6d66d8c/aiohttp-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ffa45cc55b18d4ac1396d1ddb029f139b1d3480f1594130e62bceadf2e1a838", size = 1792263 }, - { url = "https://files.pythonhosted.org/packages/7a/2b/23124c04701e0d2e215be59bf445c33602b1ccc4d9acb7bccc2ec20c892d/aiohttp-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cca505829cdab58c2495ff418c96092d225a1bbd486f79017f6de915580d3c44", size = 1690838 }, - { url = "https://files.pythonhosted.org/packages/af/a6/ebb8be53787c57dd7dd8b9617357af60d603ccd2fbf7a9e306f33178894b/aiohttp-3.11.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44d323aa80a867cb6db6bebb4bbec677c6478e38128847f2c6b0f70eae984d72", size = 1618311 }, - { url = "https://files.pythonhosted.org/packages/9b/3c/cb8e5af30e33775539b4a6ea818eb16b0b01f68ce7a2fa77dff5df3dee80/aiohttp-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b2fab23003c4bb2249729a7290a76c1dda38c438300fdf97d4e42bf78b19c810", size = 1640417 }, - { url = "https://files.pythonhosted.org/packages/16/2d/62593ce65e5811ea46e521644e03d0c47345bf9b6c2e6efcb759915d6aa3/aiohttp-3.11.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:be0c7c98e38a1e3ad7a6ff64af8b6d6db34bf5a41b1478e24c3c74d9e7f8ed42", size = 1645507 }, - { url = "https://files.pythonhosted.org/packages/4f/6b/810981c99932665a225d7bdffacbda512dde6f11364ce11477662e457115/aiohttp-3.11.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5cc5e0d069c56645446c45a4b5010d4b33ac6c5ebfd369a791b5f097e46a3c08", size = 1701090 }, - { url = "https://files.pythonhosted.org/packages/1c/01/79c8d156534c034207ccbb94a51f1ae4a625834a31e27670175f1e1e79b2/aiohttp-3.11.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9bcf97b971289be69638d8b1b616f7e557e1342debc7fc86cf89d3f08960e411", size = 1733598 }, - { url = "https://files.pythonhosted.org/packages/c0/8f/873f0d3a47ec203ccd04dbd623f2428b6010ba6b11107aa9b44ad0ebfc86/aiohttp-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c7333e7239415076d1418dbfb7fa4df48f3a5b00f8fdf854fca549080455bc14", size = 1693573 }, - { url = "https://files.pythonhosted.org/packages/2f/8c/a4964108383eb8f0e5a85ee0fdc00f9f0bdf28bb6a751be05a63c047ccbe/aiohttp-3.11.9-cp312-cp312-win32.whl", hash = "sha256:9384b07cfd3045b37b05ed002d1c255db02fb96506ad65f0f9b776b762a7572e", size = 410354 }, - { url = "https://files.pythonhosted.org/packages/c8/9e/79aed1b3e110a02081ca47ba4a27d7e20040af241643a2e527c668634f22/aiohttp-3.11.9-cp312-cp312-win_amd64.whl", hash = "sha256:f5252ba8b43906f206048fa569debf2cd0da0316e8d5b4d25abe53307f573941", size = 436657 }, { url = "https://files.pythonhosted.org/packages/33/ec/217d8918032703639d64360e4534a33899cc1a5eda89268d4fa621e18b67/aiohttp-3.11.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:282e0a7ddd36ebc411f156aeaa0491e8fe7f030e2a95da532cf0c84b0b70bc66", size = 696994 }, { url = "https://files.pythonhosted.org/packages/48/e4/262211b96cba78614be9bae7086af0dba8e8050c43996f2912992173eb57/aiohttp-3.11.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebd3e6b0c7d4954cca59d241970011f8d3327633d555051c430bd09ff49dc494", size = 459669 }, { url = "https://files.pythonhosted.org/packages/51/f5/ef76735af2d69671aa8cb185c07da84973a2ca74bb44af9fdb980207118f/aiohttp-3.11.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30f9f89ae625d412043f12ca3771b2ccec227cc93b93bb1f994db6e1af40a7d3", size = 451949 }, @@ -198,10 +152,8 @@ name = "anyio" version = "4.6.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ @@ -247,15 +199,6 @@ requires-dist = [ { name = "weasyprint", specifier = ">=63.0" }, ] -[[package]] -name = "async-timeout" -version = "4.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 }, -] - [[package]] name = "attrs" version = "23.1.0" @@ -329,56 +272,6 @@ version = "1.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2f/c2/f9e977608bdf958650638c3f1e28f85a1b075f075ebbe77db8555463787b/Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", size = 7372270 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/3a/dbf4fb970c1019a57b5e492e1e0eae745d32e59ba4d6161ab5422b08eefe/Brotli-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752", size = 873045 }, - { url = "https://files.pythonhosted.org/packages/dd/11/afc14026ea7f44bd6eb9316d800d439d092c8d508752055ce8d03086079a/Brotli-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9", size = 446218 }, - { url = "https://files.pythonhosted.org/packages/36/83/7545a6e7729db43cb36c4287ae388d6885c85a86dd251768a47015dfde32/Brotli-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3", size = 2903872 }, - { url = "https://files.pythonhosted.org/packages/32/23/35331c4d9391fcc0f29fd9bec2c76e4b4eeab769afbc4b11dd2e1098fb13/Brotli-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d", size = 2941254 }, - { url = "https://files.pythonhosted.org/packages/3b/24/1671acb450c902edb64bd765d73603797c6c7280a9ada85a195f6b78c6e5/Brotli-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e", size = 2857293 }, - { url = "https://files.pythonhosted.org/packages/d5/00/40f760cc27007912b327fe15bf6bfd8eaecbe451687f72a8abc587d503b3/Brotli-1.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da", size = 3002385 }, - { url = "https://files.pythonhosted.org/packages/b8/cb/8aaa83f7a4caa131757668c0fb0c4b6384b09ffa77f2fba9570d87ab587d/Brotli-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80", size = 2911104 }, - { url = "https://files.pythonhosted.org/packages/bc/c4/65456561d89d3c49f46b7fbeb8fe6e449f13bdc8ea7791832c5d476b2faf/Brotli-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d", size = 2809981 }, - { url = "https://files.pythonhosted.org/packages/05/1b/cf49528437bae28abce5f6e059f0d0be6fecdcc1d3e33e7c54b3ca498425/Brotli-1.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0", size = 2935297 }, - { url = "https://files.pythonhosted.org/packages/81/ff/190d4af610680bf0c5a09eb5d1eac6e99c7c8e216440f9c7cfd42b7adab5/Brotli-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e", size = 2930735 }, - { url = "https://files.pythonhosted.org/packages/80/7d/f1abbc0c98f6e09abd3cad63ec34af17abc4c44f308a7a539010f79aae7a/Brotli-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c", size = 2933107 }, - { url = "https://files.pythonhosted.org/packages/34/ce/5a5020ba48f2b5a4ad1c0522d095ad5847a0be508e7d7569c8630ce25062/Brotli-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1", size = 2845400 }, - { url = "https://files.pythonhosted.org/packages/44/89/fa2c4355ab1eecf3994e5a0a7f5492c6ff81dfcb5f9ba7859bd534bb5c1a/Brotli-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2", size = 3031985 }, - { url = "https://files.pythonhosted.org/packages/af/a4/79196b4a1674143d19dca400866b1a4d1a089040df7b93b88ebae81f3447/Brotli-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec", size = 2927099 }, - { url = "https://files.pythonhosted.org/packages/e9/54/1c0278556a097f9651e657b873ab08f01b9a9ae4cac128ceb66427d7cd20/Brotli-1.1.0-cp310-cp310-win32.whl", hash = "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2", size = 333172 }, - { url = "https://files.pythonhosted.org/packages/f7/65/b785722e941193fd8b571afd9edbec2a9b838ddec4375d8af33a50b8dab9/Brotli-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128", size = 357255 }, - { url = "https://files.pythonhosted.org/packages/96/12/ad41e7fadd5db55459c4c401842b47f7fee51068f86dd2894dd0dcfc2d2a/Brotli-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc", size = 873068 }, - { url = "https://files.pythonhosted.org/packages/95/4e/5afab7b2b4b61a84e9c75b17814198ce515343a44e2ed4488fac314cd0a9/Brotli-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6", size = 446244 }, - { url = "https://files.pythonhosted.org/packages/9d/e6/f305eb61fb9a8580c525478a4a34c5ae1a9bcb12c3aee619114940bc513d/Brotli-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd", size = 2906500 }, - { url = "https://files.pythonhosted.org/packages/3e/4f/af6846cfbc1550a3024e5d3775ede1e00474c40882c7bf5b37a43ca35e91/Brotli-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf", size = 2943950 }, - { url = "https://files.pythonhosted.org/packages/b3/e7/ca2993c7682d8629b62630ebf0d1f3bb3d579e667ce8e7ca03a0a0576a2d/Brotli-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61", size = 2918527 }, - { url = "https://files.pythonhosted.org/packages/b3/96/da98e7bedc4c51104d29cc61e5f449a502dd3dbc211944546a4cc65500d3/Brotli-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327", size = 2845489 }, - { url = "https://files.pythonhosted.org/packages/e8/ef/ccbc16947d6ce943a7f57e1a40596c75859eeb6d279c6994eddd69615265/Brotli-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd", size = 2914080 }, - { url = "https://files.pythonhosted.org/packages/80/d6/0bd38d758d1afa62a5524172f0b18626bb2392d717ff94806f741fcd5ee9/Brotli-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9", size = 2813051 }, - { url = "https://files.pythonhosted.org/packages/14/56/48859dd5d129d7519e001f06dcfbb6e2cf6db92b2702c0c2ce7d97e086c1/Brotli-1.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265", size = 2938172 }, - { url = "https://files.pythonhosted.org/packages/3d/77/a236d5f8cd9e9f4348da5acc75ab032ab1ab2c03cc8f430d24eea2672888/Brotli-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8", size = 2933023 }, - { url = "https://files.pythonhosted.org/packages/f1/87/3b283efc0f5cb35f7f84c0c240b1e1a1003a5e47141a4881bf87c86d0ce2/Brotli-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f", size = 2935871 }, - { url = "https://files.pythonhosted.org/packages/f3/eb/2be4cc3e2141dc1a43ad4ca1875a72088229de38c68e842746b342667b2a/Brotli-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757", size = 2847784 }, - { url = "https://files.pythonhosted.org/packages/66/13/b58ddebfd35edde572ccefe6890cf7c493f0c319aad2a5badee134b4d8ec/Brotli-1.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0", size = 3034905 }, - { url = "https://files.pythonhosted.org/packages/84/9c/bc96b6c7db824998a49ed3b38e441a2cae9234da6fa11f6ed17e8cf4f147/Brotli-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b", size = 2929467 }, - { url = "https://files.pythonhosted.org/packages/e7/71/8f161dee223c7ff7fea9d44893fba953ce97cf2c3c33f78ba260a91bcff5/Brotli-1.1.0-cp311-cp311-win32.whl", hash = "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50", size = 333169 }, - { url = "https://files.pythonhosted.org/packages/02/8a/fece0ee1057643cb2a5bbf59682de13f1725f8482b2c057d4e799d7ade75/Brotli-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1", size = 357253 }, - { url = "https://files.pythonhosted.org/packages/5c/d0/5373ae13b93fe00095a58efcbce837fd470ca39f703a235d2a999baadfbc/Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28", size = 815693 }, - { url = "https://files.pythonhosted.org/packages/8e/48/f6e1cdf86751300c288c1459724bfa6917a80e30dbfc326f92cea5d3683a/Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f", size = 422489 }, - { url = "https://files.pythonhosted.org/packages/06/88/564958cedce636d0f1bed313381dfc4b4e3d3f6015a63dae6146e1b8c65c/Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", size = 873081 }, - { url = "https://files.pythonhosted.org/packages/58/79/b7026a8bb65da9a6bb7d14329fd2bd48d2b7f86d7329d5cc8ddc6a90526f/Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", size = 446244 }, - { url = "https://files.pythonhosted.org/packages/e5/18/c18c32ecea41b6c0004e15606e274006366fe19436b6adccc1ae7b2e50c2/Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", size = 2906505 }, - { url = "https://files.pythonhosted.org/packages/08/c8/69ec0496b1ada7569b62d85893d928e865df29b90736558d6c98c2031208/Brotli-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", size = 2944152 }, - { url = "https://files.pythonhosted.org/packages/ab/fb/0517cea182219d6768113a38167ef6d4eb157a033178cc938033a552ed6d/Brotli-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", size = 2919252 }, - { url = "https://files.pythonhosted.org/packages/c7/53/73a3431662e33ae61a5c80b1b9d2d18f58dfa910ae8dd696e57d39f1a2f5/Brotli-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", size = 2845955 }, - { url = "https://files.pythonhosted.org/packages/55/ac/bd280708d9c5ebdbf9de01459e625a3e3803cce0784f47d633562cf40e83/Brotli-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", size = 2914304 }, - { url = "https://files.pythonhosted.org/packages/76/58/5c391b41ecfc4527d2cc3350719b02e87cb424ef8ba2023fb662f9bf743c/Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", size = 2814452 }, - { url = "https://files.pythonhosted.org/packages/c7/4e/91b8256dfe99c407f174924b65a01f5305e303f486cc7a2e8a5d43c8bec3/Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", size = 2938751 }, - { url = "https://files.pythonhosted.org/packages/5a/a6/e2a39a5d3b412938362bbbeba5af904092bf3f95b867b4a3eb856104074e/Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", size = 2933757 }, - { url = "https://files.pythonhosted.org/packages/13/f0/358354786280a509482e0e77c1a5459e439766597d280f28cb097642fc26/Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9", size = 2936146 }, - { url = "https://files.pythonhosted.org/packages/80/f7/daf538c1060d3a88266b80ecc1d1c98b79553b3f117a485653f17070ea2a/Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb", size = 2848055 }, - { url = "https://files.pythonhosted.org/packages/ad/cf/0eaa0585c4077d3c2d1edf322d8e97aabf317941d3a72d7b3ad8bce004b0/Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111", size = 3035102 }, - { url = "https://files.pythonhosted.org/packages/d8/63/1c1585b2aa554fe6dbce30f0c18bdbc877fa9a1bf5ff17677d9cca0ac122/Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839", size = 2930029 }, - { url = "https://files.pythonhosted.org/packages/5f/3b/4e3fd1893eb3bbfef8e5a80d4508bec17a57bb92d586c85c12d28666bb13/Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", size = 333276 }, - { url = "https://files.pythonhosted.org/packages/3d/d5/942051b45a9e883b5b6e98c041698b1eb2012d25e5948c58d6bf85b1bb43/Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", size = 357255 }, { url = "https://files.pythonhosted.org/packages/0a/9f/fb37bb8ffc52a8da37b1c03c459a8cd55df7a57bdccd8831d500e994a0ca/Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5", size = 815681 }, { url = "https://files.pythonhosted.org/packages/06/b3/dbd332a988586fefb0aa49c779f59f47cae76855c2d00f450364bb574cac/Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8", size = 422475 }, { url = "https://files.pythonhosted.org/packages/bb/80/6aaddc2f63dbcf2d93c2d204e49c11a9ec93a8c7c63261e2b4bd35198283/Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f", size = 2906173 }, @@ -408,11 +301,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cd/15/695b1409264143be3c933f708a3f81d53c4a1e1ebbc06f46331decbf6563/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84763dbdef5dd5c24b75597a77e1b30c66604725707565188ba54bab4f114820", size = 2851834 }, { url = "https://files.pythonhosted.org/packages/b4/40/b961a702463b6005baf952794c2e9e0099bde657d0d7e007f923883b907f/brotlicffi-1.1.0.0-cp37-abi3-win32.whl", hash = "sha256:1b12b50e07c3911e1efa3a8971543e7648100713d4e0971b13631cce22c587eb", size = 341731 }, { url = "https://files.pythonhosted.org/packages/1c/fa/5408a03c041114ceab628ce21766a4ea882aa6f6f0a800e04ee3a30ec6b9/brotlicffi-1.1.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:994a4f0681bb6c6c3b0925530a1926b7a189d878e6e5e38fae8efa47c5d9c613", size = 366783 }, - { url = "https://files.pythonhosted.org/packages/e5/3b/bd4f3d2bcf2306ae66b0346f5b42af1962480b200096ffc7abc3bd130eca/brotlicffi-1.1.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2e4aeb0bd2540cb91b069dbdd54d458da8c4334ceaf2d25df2f4af576d6766ca", size = 397397 }, - { url = "https://files.pythonhosted.org/packages/54/10/1fd57864449360852c535c2381ee7120ba8f390aa3869df967c44ca7eba1/brotlicffi-1.1.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b7b0033b0d37bb33009fb2fef73310e432e76f688af76c156b3594389d81391", size = 379698 }, - { url = "https://files.pythonhosted.org/packages/e5/95/15aa422aa6450e6556e54a5fd1650ff59f470aed77ac739aa90ab63dc611/brotlicffi-1.1.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54a07bb2374a1eba8ebb52b6fafffa2afd3c4df85ddd38fcc0511f2bb387c2a8", size = 378635 }, - { url = "https://files.pythonhosted.org/packages/6c/a7/f254e13b2cb43337d6d99a4ec10394c134e41bfda8a2eff15b75627f4a3d/brotlicffi-1.1.0.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7901a7dc4b88f1c1475de59ae9be59799db1007b7d059817948d8e4f12e24e35", size = 385719 }, - { url = "https://files.pythonhosted.org/packages/72/a9/0971251c4427c14b2a827dba3d910d4d3330dabf23d4278bf6d06a978847/brotlicffi-1.1.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce01c7316aebc7fce59da734286148b1d1b9455f89cf2c8a4dfce7d41db55c2d", size = 361760 }, ] [[package]] @@ -436,41 +324,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, @@ -489,7 +342,7 @@ name = "click" version = "8.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } wheels = [ @@ -552,15 +405,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/f8/b3d7c70a8f19eb767f8e1172c5e984b72f0f5f6b19ec73e3c50f2a8cd1d7/eliot-1.16.0-py3-none-any.whl", hash = "sha256:b83ac0ffd63b7b2d64a1097bb06dfeef4d68d39783d7eaf31aeadc7441ac39c5", size = 112034 }, ] -[[package]] -name = "exceptiongroup" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, -] - [[package]] name = "fastapi" version = "0.115.5" @@ -581,30 +425,6 @@ version = "4.55.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f4/3a/6ab28db8f90c99e6b502436fb642912b590c352d5ba83e0b22b46db209da/fonttools-4.55.2.tar.gz", hash = "sha256:45947e7b3f9673f91df125d375eb57b9a23f2a603f438a1aebf3171bffa7a205", size = 3492954 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/76/c4f463c4bde3983a0c2f4a6a9cfc3d17028a3bddb86fd2113492ab6768cd/fonttools-4.55.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bef0f8603834643b1a6419d57902f18e7d950ec1a998fb70410635c598dc1a1e", size = 2759007 }, - { url = "https://files.pythonhosted.org/packages/49/18/ec95143fcf6a03db383f0daea73c12dc5fdf9c3df0270fbcd139923ff52c/fonttools-4.55.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:944228b86d472612d3b48bcc83b31c25c2271e63fdc74539adfcfa7a96d487fb", size = 2288860 }, - { url = "https://files.pythonhosted.org/packages/3c/94/b1e43d401d0b9fa41e7ab73314f1f313bcf7f4710e9e8be66e0efba7274e/fonttools-4.55.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f0e55f5da594b85f269cfbecd2f6bd3e07d0abba68870bc3f34854de4fa4678", size = 4565270 }, - { url = "https://files.pythonhosted.org/packages/41/b8/cb3627cbf322aabd288d0a8f44328c69071bbcb9082d41b46054d7c3c959/fonttools-4.55.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b1a6e576db0c83c1b91925bf1363478c4bb968dbe8433147332fb5782ce6190", size = 4607444 }, - { url = "https://files.pythonhosted.org/packages/ae/2f/6d64b170e9a2da03ee853238df9b7630da910677a10567426bc5cbfba946/fonttools-4.55.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:616368b15716781bc84df5c2191dc0540137aaef56c2771eb4b89b90933f347a", size = 4559704 }, - { url = "https://files.pythonhosted.org/packages/0d/8a/8f50a44607466728905fe83e5dbb2a718cbbbfe1b5abf9730bd0dbb991e3/fonttools-4.55.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7bbae4f3915225c2c37670da68e2bf18a21206060ad31dfb95fec91ef641caa7", size = 4731573 }, - { url = "https://files.pythonhosted.org/packages/ed/f9/fb5efdb62aa60d702dba7537061b70bb11ecec8a168df072bf1d1ff06148/fonttools-4.55.2-cp310-cp310-win32.whl", hash = "sha256:8b02b10648d69d67a7eb055f4d3eedf4a85deb22fb7a19fbd9acbae7c7538199", size = 2164139 }, - { url = "https://files.pythonhosted.org/packages/7d/4a/850e8a0af45ed8fa953a3b7ae340e9a5940f564862d53e4e73df0f55a064/fonttools-4.55.2-cp310-cp310-win_amd64.whl", hash = "sha256:bbea0ab841113ac8e8edde067e099b7288ffc6ac2dded538b131c2c0595d5f77", size = 2208448 }, - { url = "https://files.pythonhosted.org/packages/d4/9b/bce708f6293dce086d7e5ecc223da8e57474537a8d7172cd62af5337bb27/fonttools-4.55.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d34525e8141286fa976e14806639d32294bfb38d28bbdb5f6be9f46a1cd695a6", size = 2760153 }, - { url = "https://files.pythonhosted.org/packages/d6/7c/45dc1e5dfa99636acbcd1613914c6892c3c9bd0fe1541070222f29ee72e6/fonttools-4.55.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ecd1c2b1c2ec46bb73685bc5473c72e16ed0930ef79bc2919ccadc43a99fb16", size = 2289801 }, - { url = "https://files.pythonhosted.org/packages/8c/8d/79e099350cb33fbf75903619e2a9933827b67a87f972400645a3eb222db9/fonttools-4.55.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9008438ad59e5a8e403a62fbefef2b2ff377eb3857d90a3f2a5f4d674ff441b2", size = 4866709 }, - { url = "https://files.pythonhosted.org/packages/ff/e3/46a0a2925d71ccf3d804df8a88c93ee645ad9f5d47327b229e4efdb354ed/fonttools-4.55.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:131591ac8d7a47043aaf29581aba755ae151d46e49d2bf49608601efd71e8b4d", size = 4895476 }, - { url = "https://files.pythonhosted.org/packages/40/2e/02607daff1b2e38aec0f321d691bdf835b39c950f90ce3fae1db3eec0871/fonttools-4.55.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4c83381c3e3e3d9caa25527c4300543578341f21aae89e4fbbb4debdda8d82a2", size = 4877249 }, - { url = "https://files.pythonhosted.org/packages/f4/aa/6b3d069968ffb7fa7b3184c6951851fcd79f097f392fecf2b6df9973930d/fonttools-4.55.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:42aca564b575252fd9954ed0d91d97a24de24289a16ce8ff74ed0bdf5ecebf11", size = 5046125 }, - { url = "https://files.pythonhosted.org/packages/4c/dd/fb1f66fbac4c0f7bc3ef206d08b490f9b3dd5eb89879d1f1c1e41ef2937c/fonttools-4.55.2-cp311-cp311-win32.whl", hash = "sha256:c6457f650ebe15baa17fc06e256227f0a47f46f80f27ec5a0b00160de8dc2c13", size = 2162949 }, - { url = "https://files.pythonhosted.org/packages/86/b1/1198970a2b0ebccceae5fc8963e2e9c2a2aae23bd2f5a9be603dc3894f31/fonttools-4.55.2-cp311-cp311-win_amd64.whl", hash = "sha256:5cfa67414d7414442a5635ff634384101c54f53bb7b0e04aa6a61b013fcce194", size = 2209371 }, - { url = "https://files.pythonhosted.org/packages/3c/62/7ac990a52c2bb249e9de6de0036a24eba5a5a8e8446819ab5a5751a0a45e/fonttools-4.55.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:18f082445b8fe5e91c53e6184f4c1c73f3f965c8bcc614c6cd6effd573ce6c1a", size = 2754521 }, - { url = "https://files.pythonhosted.org/packages/4a/bd/a8034bf5d685f825cec0aca6759639277b1d3b0b1d38842b5f30edfb4176/fonttools-4.55.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c0f91adbbd706e8acd1db73e3e510118e62d0ffb651864567dccc5b2339f90", size = 2287092 }, - { url = "https://files.pythonhosted.org/packages/70/ad/edf4f4e0efdda8205893007d30d62da09f92d3f0b0f1a3faf85bd5df9952/fonttools-4.55.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d8ccce035320d63dba0c35f52499322f5531dbe85bba1514c7cea26297e4c54", size = 4782490 }, - { url = "https://files.pythonhosted.org/packages/7a/5f/f757e5860cc4f187fdf8eacf53abc92613cdbc55355e13ba07e2c937d217/fonttools-4.55.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96e126df9615df214ec7f04bebcf60076297fbc10b75c777ce58b702d7708ffb", size = 4854787 }, - { url = "https://files.pythonhosted.org/packages/92/1b/c647b89e5603f9ae9b8f14885dfaf523351eb9d0b5dcbafaf1512d0d4d97/fonttools-4.55.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:508ebb42956a7a931c4092dfa2d9b4ffd4f94cea09b8211199090d2bd082506b", size = 4763330 }, - { url = "https://files.pythonhosted.org/packages/57/09/117e2b5b2d2fcd607b360e241939a652505577c752f9ca15b2fb9e4fc540/fonttools-4.55.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1b9de46ef7b683d50400abf9f1578eaceee271ff51c36bf4b7366f2be29f498", size = 4990999 }, - { url = "https://files.pythonhosted.org/packages/b9/e5/9be5bd4bfb83187fb83f46b9be6676f653c08a430b975e0a3355fd248c37/fonttools-4.55.2-cp312-cp312-win32.whl", hash = "sha256:2df61d9fc15199cc86dad29f64dd686874a3a52dda0c2d8597d21f509f95c332", size = 2151234 }, - { url = "https://files.pythonhosted.org/packages/f3/c5/0eda5db19bd5fe3f6b8dc30ca5be512999b4923268b9b82fd14c211217b5/fonttools-4.55.2-cp312-cp312-win_amd64.whl", hash = "sha256:d337ec087da8216a828574aa0525d869df0a2ac217a2efc1890974ddd1fbc5b9", size = 2198133 }, { url = "https://files.pythonhosted.org/packages/2d/94/f941fa68a1d4a0f2facd5e6476ae91c5683aea7b7cc30d3ef49187cbbc67/fonttools-4.55.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:10aff204e2edee1d312fa595c06f201adf8d528a3b659cfb34cd47eceaaa6a26", size = 2741975 }, { url = "https://files.pythonhosted.org/packages/c5/61/00015fe3ccc8171b4d4afb0fa5155064f68948138ef5e1a5ac9cb49082c4/fonttools-4.55.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:09fe922a3eff181fd07dd724cdb441fb6b9fc355fd1c0f1aa79aca60faf1fbdd", size = 2280680 }, { url = "https://files.pythonhosted.org/packages/4e/fe/9bb6cedc47a9e3872e138e4328475d4ff4faea7d87a2316dc5e5e4cd305e/fonttools-4.55.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:487e1e8b524143a799bda0169c48b44a23a6027c1bb1957d5a172a7d3a1dd704", size = 4760147 }, @@ -629,51 +449,6 @@ version = "1.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cf/3d/2102257e7acad73efc4a0c306ad3953f68c504c16982bbdfee3ad75d8085/frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", size = 37820 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/35/1328c7b0f780d34f8afc1d87ebdc2bb065a123b24766a0b475f0d67da637/frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", size = 94315 }, - { url = "https://files.pythonhosted.org/packages/f4/d6/ca016b0adcf8327714ccef969740688808c86e0287bf3a639ff582f24e82/frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", size = 53805 }, - { url = "https://files.pythonhosted.org/packages/ae/83/bcdaa437a9bd693ba658a0310f8cdccff26bd78e45fccf8e49897904a5cd/frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", size = 52163 }, - { url = "https://files.pythonhosted.org/packages/d4/e9/759043ab7d169b74fe05ebfbfa9ee5c881c303ebc838e308346204309cd0/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", size = 238595 }, - { url = "https://files.pythonhosted.org/packages/f8/ce/b9de7dc61e753dc318cf0de862181b484178210c5361eae6eaf06792264d/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", size = 262428 }, - { url = "https://files.pythonhosted.org/packages/36/ce/dc6f29e0352fa34ebe45421960c8e7352ca63b31630a576e8ffb381e9c08/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", size = 258867 }, - { url = "https://files.pythonhosted.org/packages/51/47/159ac53faf8a11ae5ee8bb9db10327575557504e549cfd76f447b969aa91/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", size = 229412 }, - { url = "https://files.pythonhosted.org/packages/ec/25/0c87df2e53c0c5d90f7517ca0ff7aca78d050a8ec4d32c4278e8c0e52e51/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", size = 239539 }, - { url = "https://files.pythonhosted.org/packages/97/94/a1305fa4716726ae0abf3b1069c2d922fcfd442538cb850f1be543f58766/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", size = 253379 }, - { url = "https://files.pythonhosted.org/packages/53/82/274e19f122e124aee6d113188615f63b0736b4242a875f482a81f91e07e2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", size = 245901 }, - { url = "https://files.pythonhosted.org/packages/b8/28/899931015b8cffbe155392fe9ca663f981a17e1adc69589ee0e1e7cdc9a2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", size = 263797 }, - { url = "https://files.pythonhosted.org/packages/6e/4f/b8a5a2f10c4a58c52a52a40cf6cf1ffcdbf3a3b64f276f41dab989bf3ab5/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", size = 264415 }, - { url = "https://files.pythonhosted.org/packages/b0/2c/7be3bdc59dbae444864dbd9cde82790314390ec54636baf6b9ce212627ad/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", size = 253964 }, - { url = "https://files.pythonhosted.org/packages/2e/ec/4fb5a88f6b9a352aed45ab824dd7ce4801b7bcd379adcb927c17a8f0a1a8/frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", size = 44559 }, - { url = "https://files.pythonhosted.org/packages/61/15/2b5d644d81282f00b61e54f7b00a96f9c40224107282efe4cd9d2bf1433a/frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", size = 50434 }, - { url = "https://files.pythonhosted.org/packages/01/bc/8d33f2d84b9368da83e69e42720cff01c5e199b5a868ba4486189a4d8fa9/frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", size = 97060 }, - { url = "https://files.pythonhosted.org/packages/af/b2/904500d6a162b98a70e510e743e7ea992241b4f9add2c8063bf666ca21df/frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", size = 55347 }, - { url = "https://files.pythonhosted.org/packages/5b/9c/f12b69997d3891ddc0d7895999a00b0c6a67f66f79498c0e30f27876435d/frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", size = 53374 }, - { url = "https://files.pythonhosted.org/packages/ac/6e/e0322317b7c600ba21dec224498c0c5959b2bce3865277a7c0badae340a9/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", size = 273288 }, - { url = "https://files.pythonhosted.org/packages/a7/76/180ee1b021568dad5b35b7678616c24519af130ed3fa1e0f1ed4014e0f93/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", size = 284737 }, - { url = "https://files.pythonhosted.org/packages/05/08/40159d706a6ed983c8aca51922a93fc69f3c27909e82c537dd4054032674/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", size = 280267 }, - { url = "https://files.pythonhosted.org/packages/e0/18/9f09f84934c2b2aa37d539a322267939770362d5495f37783440ca9c1b74/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", size = 258778 }, - { url = "https://files.pythonhosted.org/packages/b3/c9/0bc5ee7e1f5cc7358ab67da0b7dfe60fbd05c254cea5c6108e7d1ae28c63/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", size = 272276 }, - { url = "https://files.pythonhosted.org/packages/12/5d/147556b73a53ad4df6da8bbb50715a66ac75c491fdedac3eca8b0b915345/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", size = 272424 }, - { url = "https://files.pythonhosted.org/packages/83/61/2087bbf24070b66090c0af922685f1d0596c24bb3f3b5223625bdeaf03ca/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", size = 260881 }, - { url = "https://files.pythonhosted.org/packages/a8/be/a235bc937dd803258a370fe21b5aa2dd3e7bfe0287a186a4bec30c6cccd6/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", size = 282327 }, - { url = "https://files.pythonhosted.org/packages/5d/e7/b2469e71f082948066b9382c7b908c22552cc705b960363c390d2e23f587/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74", size = 281502 }, - { url = "https://files.pythonhosted.org/packages/db/1b/6a5b970e55dffc1a7d0bb54f57b184b2a2a2ad0b7bca16a97ca26d73c5b5/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", size = 272292 }, - { url = "https://files.pythonhosted.org/packages/1a/05/ebad68130e6b6eb9b287dacad08ea357c33849c74550c015b355b75cc714/frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", size = 44446 }, - { url = "https://files.pythonhosted.org/packages/b3/21/c5aaffac47fd305d69df46cfbf118768cdf049a92ee6b0b5cb029d449dcf/frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", size = 50459 }, - { url = "https://files.pythonhosted.org/packages/b4/db/4cf37556a735bcdb2582f2c3fa286aefde2322f92d3141e087b8aeb27177/frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", size = 93937 }, - { url = "https://files.pythonhosted.org/packages/46/03/69eb64642ca8c05f30aa5931d6c55e50b43d0cd13256fdd01510a1f85221/frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", size = 53656 }, - { url = "https://files.pythonhosted.org/packages/3f/ab/c543c13824a615955f57e082c8a5ee122d2d5368e80084f2834e6f4feced/frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", size = 51868 }, - { url = "https://files.pythonhosted.org/packages/a9/b8/438cfd92be2a124da8259b13409224d9b19ef8f5a5b2507174fc7e7ea18f/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", size = 280652 }, - { url = "https://files.pythonhosted.org/packages/54/72/716a955521b97a25d48315c6c3653f981041ce7a17ff79f701298195bca3/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", size = 286739 }, - { url = "https://files.pythonhosted.org/packages/65/d8/934c08103637567084568e4d5b4219c1016c60b4d29353b1a5b3587827d6/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", size = 289447 }, - { url = "https://files.pythonhosted.org/packages/70/bb/d3b98d83ec6ef88f9bd63d77104a305d68a146fd63a683569ea44c3085f6/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", size = 265466 }, - { url = "https://files.pythonhosted.org/packages/0b/f2/b8158a0f06faefec33f4dff6345a575c18095a44e52d4f10c678c137d0e0/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", size = 281530 }, - { url = "https://files.pythonhosted.org/packages/ea/a2/20882c251e61be653764038ece62029bfb34bd5b842724fff32a5b7a2894/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", size = 281295 }, - { url = "https://files.pythonhosted.org/packages/4c/f9/8894c05dc927af2a09663bdf31914d4fb5501653f240a5bbaf1e88cab1d3/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", size = 268054 }, - { url = "https://files.pythonhosted.org/packages/37/ff/a613e58452b60166507d731812f3be253eb1229808e59980f0405d1eafbf/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", size = 286904 }, - { url = "https://files.pythonhosted.org/packages/cc/6e/0091d785187f4c2020d5245796d04213f2261ad097e0c1cf35c44317d517/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", size = 290754 }, - { url = "https://files.pythonhosted.org/packages/a5/c2/e42ad54bae8bcffee22d1e12a8ee6c7717f7d5b5019261a8c861854f4776/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", size = 282602 }, - { url = "https://files.pythonhosted.org/packages/b6/61/56bad8cb94f0357c4bc134acc30822e90e203b5cb8ff82179947de90c17f/frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", size = 44063 }, - { url = "https://files.pythonhosted.org/packages/3e/dc/96647994a013bc72f3d453abab18340b7f5e222b7b7291e3697ca1fcfbd5/frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", size = 50452 }, { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] @@ -719,57 +494,6 @@ version = "5.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/6b/20c3a4b24751377aaa6307eb230b66701024012c29dd374999cc92983269/lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", size = 3679318 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ce/2789e39eddf2b13fac29878bfa465f0910eb6b0096e29090e5176bc8cf43/lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", size = 8124570 }, - { url = "https://files.pythonhosted.org/packages/24/a8/f4010166a25d41715527129af2675981a50d3bbf7df09c5d9ab8ca24fbf9/lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", size = 4413042 }, - { url = "https://files.pythonhosted.org/packages/41/a4/7e45756cecdd7577ddf67a68b69c1db0f5ddbf0c9f65021ee769165ffc5a/lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", size = 5139213 }, - { url = "https://files.pythonhosted.org/packages/02/e2/ecf845b12323c92748077e1818b64e8b4dba509a4cb12920b3762ebe7552/lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8", size = 4838814 }, - { url = "https://files.pythonhosted.org/packages/12/91/619f9fb72cf75e9ceb8700706f7276f23995f6ad757e6d400fbe35ca4990/lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", size = 5425084 }, - { url = "https://files.pythonhosted.org/packages/25/3b/162a85a8f0fd2a3032ec3f936636911c6e9523a8e263fffcfd581ce98b54/lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", size = 4875993 }, - { url = "https://files.pythonhosted.org/packages/43/af/dd3f58cc7d946da6ae42909629a2b1d5dd2d1b583334d4af9396697d6863/lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", size = 5012462 }, - { url = "https://files.pythonhosted.org/packages/69/c1/5ea46b2d4c98f5bf5c83fffab8a0ad293c9bc74df9ecfbafef10f77f7201/lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", size = 4815288 }, - { url = "https://files.pythonhosted.org/packages/1d/51/a0acca077ad35da458f4d3f729ef98effd2b90f003440d35fc36323f8ae6/lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", size = 5472435 }, - { url = "https://files.pythonhosted.org/packages/4d/6b/0989c9368986961a6b0f55b46c80404c4b758417acdb6d87bfc3bd5f4967/lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", size = 4976354 }, - { url = "https://files.pythonhosted.org/packages/05/9e/87492d03ff604fbf656ed2bf3e2e8d28f5d58ea1f00ff27ac27b06509079/lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", size = 5029973 }, - { url = "https://files.pythonhosted.org/packages/f9/cc/9ae1baf5472af88e19e2c454b3710c1be9ecafb20eb474eeabcd88a055d2/lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", size = 4888837 }, - { url = "https://files.pythonhosted.org/packages/d2/10/5594ffaec8c120d75b17e3ad23439b740a51549a9b5fd7484b2179adfe8f/lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", size = 5530555 }, - { url = "https://files.pythonhosted.org/packages/ea/9b/de17f05377c8833343b629905571fb06cff2028f15a6f58ae2267662e341/lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", size = 5405314 }, - { url = "https://files.pythonhosted.org/packages/8a/b4/227be0f1f3cca8255925985164c3838b8b36e441ff0cc10c1d3c6bdba031/lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", size = 5079303 }, - { url = "https://files.pythonhosted.org/packages/5c/ee/19abcebb7fc40319bb71cd6adefa1ad94d09b5660228715854d6cc420713/lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", size = 3475126 }, - { url = "https://files.pythonhosted.org/packages/a1/35/183d32551447e280032b2331738cd850da435a42f850b71ebeaab42c1313/lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", size = 3805065 }, - { url = "https://files.pythonhosted.org/packages/5c/a8/449faa2a3cbe6a99f8d38dcd51a3ee8844c17862841a6f769ea7c2a9cd0f/lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b", size = 8141056 }, - { url = "https://files.pythonhosted.org/packages/ac/8a/ae6325e994e2052de92f894363b038351c50ee38749d30cc6b6d96aaf90f/lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18", size = 4425238 }, - { url = "https://files.pythonhosted.org/packages/f8/fb/128dddb7f9086236bce0eeae2bfb316d138b49b159f50bc681d56c1bdd19/lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442", size = 5095197 }, - { url = "https://files.pythonhosted.org/packages/b4/f9/a181a8ef106e41e3086629c8bdb2d21a942f14c84a0e77452c22d6b22091/lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4", size = 4809809 }, - { url = "https://files.pythonhosted.org/packages/25/2f/b20565e808f7f6868aacea48ddcdd7e9e9fb4c799287f21f1a6c7c2e8b71/lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f", size = 5407593 }, - { url = "https://files.pythonhosted.org/packages/23/0e/caac672ec246d3189a16c4d364ed4f7d6bf856c080215382c06764058c08/lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e", size = 4866657 }, - { url = "https://files.pythonhosted.org/packages/67/a4/1f5fbd3f58d4069000522196b0b776a014f3feec1796da03e495cf23532d/lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c", size = 4967017 }, - { url = "https://files.pythonhosted.org/packages/ee/73/623ecea6ca3c530dd0a4ed0d00d9702e0e85cd5624e2d5b93b005fe00abd/lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16", size = 4810730 }, - { url = "https://files.pythonhosted.org/packages/1d/ce/fb84fb8e3c298f3a245ae3ea6221c2426f1bbaa82d10a88787412a498145/lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79", size = 5455154 }, - { url = "https://files.pythonhosted.org/packages/b1/72/4d1ad363748a72c7c0411c28be2b0dc7150d91e823eadad3b91a4514cbea/lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080", size = 4969416 }, - { url = "https://files.pythonhosted.org/packages/42/07/b29571a58a3a80681722ea8ed0ba569211d9bb8531ad49b5cacf6d409185/lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654", size = 5013672 }, - { url = "https://files.pythonhosted.org/packages/b9/93/bde740d5a58cf04cbd38e3dd93ad1e36c2f95553bbf7d57807bc6815d926/lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d", size = 4878644 }, - { url = "https://files.pythonhosted.org/packages/56/b5/645c8c02721d49927c93181de4017164ec0e141413577687c3df8ff0800f/lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763", size = 5511531 }, - { url = "https://files.pythonhosted.org/packages/85/3f/6a99a12d9438316f4fc86ef88c5d4c8fb674247b17f3173ecadd8346b671/lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec", size = 5402065 }, - { url = "https://files.pythonhosted.org/packages/80/8a/df47bff6ad5ac57335bf552babfb2408f9eb680c074ec1ba412a1a6af2c5/lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be", size = 5069775 }, - { url = "https://files.pythonhosted.org/packages/08/ae/e7ad0f0fbe4b6368c5ee1e3ef0c3365098d806d42379c46c1ba2802a52f7/lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9", size = 3474226 }, - { url = "https://files.pythonhosted.org/packages/c3/b5/91c2249bfac02ee514ab135e9304b89d55967be7e53e94a879b74eec7a5c/lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1", size = 3814971 }, - { url = "https://files.pythonhosted.org/packages/eb/6d/d1f1c5e40c64bf62afd7a3f9b34ce18a586a1cccbf71e783cd0a6d8e8971/lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859", size = 8171753 }, - { url = "https://files.pythonhosted.org/packages/bd/83/26b1864921869784355459f374896dcf8b44d4af3b15d7697e9156cb2de9/lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e", size = 4441955 }, - { url = "https://files.pythonhosted.org/packages/e0/d2/e9bff9fb359226c25cda3538f664f54f2804f4b37b0d7c944639e1a51f69/lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f", size = 5050778 }, - { url = "https://files.pythonhosted.org/packages/88/69/6972bfafa8cd3ddc8562b126dd607011e218e17be313a8b1b9cc5a0ee876/lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e", size = 4748628 }, - { url = "https://files.pythonhosted.org/packages/5d/ea/a6523c7c7f6dc755a6eed3d2f6d6646617cad4d3d6d8ce4ed71bfd2362c8/lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179", size = 5322215 }, - { url = "https://files.pythonhosted.org/packages/99/37/396fbd24a70f62b31d988e4500f2068c7f3fd399d2fd45257d13eab51a6f/lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a", size = 4813963 }, - { url = "https://files.pythonhosted.org/packages/09/91/e6136f17459a11ce1757df864b213efbeab7adcb2efa63efb1b846ab6723/lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3", size = 4923353 }, - { url = "https://files.pythonhosted.org/packages/1d/7c/2eeecf87c9a1fca4f84f991067c693e67340f2b7127fc3eca8fa29d75ee3/lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1", size = 4740541 }, - { url = "https://files.pythonhosted.org/packages/3b/ed/4c38ba58defca84f5f0d0ac2480fdcd99fc7ae4b28fc417c93640a6949ae/lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d", size = 5346504 }, - { url = "https://files.pythonhosted.org/packages/a5/22/bbd3995437e5745cb4c2b5d89088d70ab19d4feabf8a27a24cecb9745464/lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c", size = 4898077 }, - { url = "https://files.pythonhosted.org/packages/0a/6e/94537acfb5b8f18235d13186d247bca478fea5e87d224644e0fe907df976/lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99", size = 4946543 }, - { url = "https://files.pythonhosted.org/packages/8d/e8/4b15df533fe8e8d53363b23a41df9be907330e1fa28c7ca36893fad338ee/lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff", size = 4816841 }, - { url = "https://files.pythonhosted.org/packages/1a/e7/03f390ea37d1acda50bc538feb5b2bda6745b25731e4e76ab48fae7106bf/lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a", size = 5417341 }, - { url = "https://files.pythonhosted.org/packages/ea/99/d1133ab4c250da85a883c3b60249d3d3e7c64f24faff494cf0fd23f91e80/lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8", size = 5327539 }, - { url = "https://files.pythonhosted.org/packages/7d/ed/e6276c8d9668028213df01f598f385b05b55a4e1b4662ee12ef05dab35aa/lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", size = 5012542 }, - { url = "https://files.pythonhosted.org/packages/36/88/684d4e800f5aa28df2a991a6a622783fb73cf0e46235cfa690f9776f032e/lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", size = 3486454 }, - { url = "https://files.pythonhosted.org/packages/fc/82/ace5a5676051e60355bd8fb945df7b1ba4f4fb8447f2010fb816bfd57724/lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", size = 3816857 }, { url = "https://files.pythonhosted.org/packages/94/6a/42141e4d373903bfea6f8e94b2f554d05506dfda522ada5343c651410dc8/lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", size = 8156284 }, { url = "https://files.pythonhosted.org/packages/91/5e/fa097f0f7d8b3d113fb7312c6308af702f2667f22644441715be961f2c7e/lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", size = 4432407 }, { url = "https://files.pythonhosted.org/packages/2d/a1/b901988aa6d4ff937f2e5cfc114e4ec561901ff00660c3e56713642728da/lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", size = 5048331 }, @@ -787,12 +511,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/17/71e9984cf0570cd202ac0a1c9ed5c1b8889b0fc8dc736f5ef0ffb181c284/lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", size = 5011053 }, { url = "https://files.pythonhosted.org/packages/69/68/9f7e6d3312a91e30829368c2b3217e750adef12a6f8eb10498249f4e8d72/lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", size = 3485634 }, { url = "https://files.pythonhosted.org/packages/7d/db/214290d58ad68c587bd5d6af3d34e56830438733d0d0856c0275fde43652/lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", size = 3814417 }, - { url = "https://files.pythonhosted.org/packages/99/f7/b73a431c8500565aa500e99e60b448d305eaf7c0b4c893c7c5a8a69cc595/lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", size = 3925431 }, - { url = "https://files.pythonhosted.org/packages/db/48/4a206623c0d093d0e3b15f415ffb4345b0bdf661a3d0b15a112948c033c7/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", size = 4216683 }, - { url = "https://files.pythonhosted.org/packages/54/47/577820c45dd954523ae8453b632d91e76da94ca6d9ee40d8c98dd86f916b/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", size = 4326732 }, - { url = "https://files.pythonhosted.org/packages/68/de/96cb6d3269bc994b4f5ede8ca7bf0840f5de0a278bc6e50cb317ff71cafa/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", size = 4218377 }, - { url = "https://files.pythonhosted.org/packages/a5/43/19b1ef6cbffa4244a217f95cc5f41a6cb4720fed33510a49670b03c5f1a0/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", size = 4351237 }, - { url = "https://files.pythonhosted.org/packages/ba/b2/6a22fb5c0885da3b00e116aee81f0b829ec9ac8f736cd414b4a09413fc7d/lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", size = 3487557 }, ] [[package]] @@ -833,38 +551,6 @@ name = "multidict" version = "6.0.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4a/15/bd620f7a6eb9aa5112c4ef93e7031bcd071e0611763d8e17706ef8ba65e0/multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49", size = 51304 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/e4/ea5687129b0cb781aba596bd08abb2aca3c8051e41aabf989c966e93af04/multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8", size = 48600 }, - { url = "https://files.pythonhosted.org/packages/fc/54/8e025ae4e31d899e4528a570941eb7048512392b454acccf69c2dccfcb0d/multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171", size = 29092 }, - { url = "https://files.pythonhosted.org/packages/eb/97/05b51bd39ba10ad7ae6530ae05e050a1cac91d42dcafd40c40d388e057b4/multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7", size = 29232 }, - { url = "https://files.pythonhosted.org/packages/d0/21/d737fe1cac90fb89b0959194d12747024ea95d52032daef9d2ac3cf18ce0/multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b", size = 116588 }, - { url = "https://files.pythonhosted.org/packages/f5/cf/416f84a8c7954c571881b01c839312ec81e222b3986c8baedc57f476cc1b/multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547", size = 122044 }, - { url = "https://files.pythonhosted.org/packages/8f/f9/e14b11f78b937d2a5982593d5a238058679bd120979b2c5b94ea8ba125fc/multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569", size = 117432 }, - { url = "https://files.pythonhosted.org/packages/56/b5/ac112889bfc68e6cf4eda1e4325789b166c51c6cd29d5633e28fb2c2f966/multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93", size = 114509 }, - { url = "https://files.pythonhosted.org/packages/42/b6/61cb83e174e77e4e2607f60f26ff8e975eb7961e143fa01682b8c3acb201/multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98", size = 108507 }, - { url = "https://files.pythonhosted.org/packages/b0/6d/03a5b702a0ad4d3aa4cf101acd8758ff8438fef0311bf90e7c72a80152ef/multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0", size = 138547 }, - { url = "https://files.pythonhosted.org/packages/25/1f/b10a0abdfc33069b6c92935cff81b97dd7d034149b05025a92326972b371/multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988", size = 131645 }, - { url = "https://files.pythonhosted.org/packages/96/9a/96830785d7eb3c72782fda15572ea9ed31fd67a071eab0ffad6859458e4d/multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc", size = 143342 }, - { url = "https://files.pythonhosted.org/packages/1a/5a/e31fc5799b6d8929da4db92cc166d9257e7f85b4d6c7245143c0dae29413/multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0", size = 139212 }, - { url = "https://files.pythonhosted.org/packages/e1/2b/e2b9ff85a5f973c7636d07e58ede554262a75b435eb6fe53e67ec4749953/multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5", size = 134785 }, - { url = "https://files.pythonhosted.org/packages/bd/50/7beeed47a950011ea0abf50541fecd67d6880719ac0e797b3dc214d6f102/multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8", size = 25663 }, - { url = "https://files.pythonhosted.org/packages/24/d1/56b6d5eb964161c55a8a7ad53fe4c93a694e44d04fd1405f3c1b98de5627/multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc", size = 28131 }, - { url = "https://files.pythonhosted.org/packages/bb/ec/ea3435f339cfad0d0a5e9e533a362d230325029deea9cdba6730fcfc1e00/multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03", size = 48546 }, - { url = "https://files.pythonhosted.org/packages/3c/b3/1c8b525a7243c395a73d0ba35f4625333315c5261d01acc3bcde852a9548/multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3", size = 29055 }, - { url = "https://files.pythonhosted.org/packages/59/28/e50cc24c56609d11f7232606f73981620e94e3445791d9501e21c4c73a61/multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba", size = 29212 }, - { url = "https://files.pythonhosted.org/packages/27/ce/2207d548200d42c3a0b3cb11b8957f4d29f82f95977ae2cc8276a7d719e5/multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9", size = 120078 }, - { url = "https://files.pythonhosted.org/packages/4d/1f/83656180657d0d359b12866b9af77dbb58f46cb5f454301d2c37ec97a9e1/multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982", size = 125577 }, - { url = "https://files.pythonhosted.org/packages/e4/41/ade43649e3c35178a81827eb960a7480842fe36c51d4a16a2a68e396e0d6/multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe", size = 120706 }, - { url = "https://files.pythonhosted.org/packages/9d/5a/34bd606569178ad8a931ea4d59cda926b046cfa4c01b0191c2e04cfd44c2/multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710", size = 117391 }, - { url = "https://files.pythonhosted.org/packages/fc/5b/0a4205a1248fb152f596a03c971c6ef1585d0c98e56b6886dc35d084e366/multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c", size = 111378 }, - { url = "https://files.pythonhosted.org/packages/5f/eb/2023167c9533d62e2afcba7acb0dc98420bcf9fc27eff5a83c2bbd013b65/multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4", size = 141033 }, - { url = "https://files.pythonhosted.org/packages/e4/18/79a66879c57c37a2a721ca1aea18953f0f291ea8a8e7334fe5091a4c3111/multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a", size = 133669 }, - { url = "https://files.pythonhosted.org/packages/d5/eb/22de4f5935f4d754b0f53d323643a1b4b7fa796e02bf3a0df7dec150269f/multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c", size = 145889 }, - { url = "https://files.pythonhosted.org/packages/b4/7a/3f0b0e533fd1b73662723cb45869f4d32df643458d78c2fa7b946be98494/multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed", size = 141694 }, - { url = "https://files.pythonhosted.org/packages/5c/4d/976b2e5fadc2b6e5e6208fb1566669460adde3f41d7622db3afa90fb2dbf/multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461", size = 137257 }, - { url = "https://files.pythonhosted.org/packages/47/a4/69f7255bc1398caa2c1eecf4c937d3ed6ae483327f39f8b1115b578905bb/multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636", size = 25666 }, - { url = "https://files.pythonhosted.org/packages/3d/22/35539dddb1971eb8dc88bb19d22d636eb9efe1ad7549d2f319a7951cbbe7/multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0", size = 28131 }, -] [[package]] name = "orjson" @@ -872,45 +558,6 @@ version = "3.10.12" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e0/04/bb9f72987e7f62fb591d6c880c0caaa16238e4e530cbc3bdc84a7372d75f/orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff", size = 5438647 } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/d2/78652b67f86d093dca984ce3fa5bf819ee1462627da83e7d0b784a9a7c45/orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d", size = 248688 }, - { url = "https://files.pythonhosted.org/packages/70/cb/f8b6a52f3bc724edf8a62d8d1d8ee17cf19d6ae1cac89f077f0e7c30f396/orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7", size = 136952 }, - { url = "https://files.pythonhosted.org/packages/a6/43/c55700df9814545bc8c35d87395ec4b9ee473a3c1f5ed72f8d3ad0298ee9/orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e", size = 149089 }, - { url = "https://files.pythonhosted.org/packages/07/da/e7e7d73bd971710b736fbd8330b8830c5fa4fc0ac003b31af61f03b26dfc/orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced", size = 140479 }, - { url = "https://files.pythonhosted.org/packages/08/49/c9dfddba56ff24eecfacf2f01a76cae4d249ac2995b1359bf63a74b1b318/orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56", size = 156564 }, - { url = "https://files.pythonhosted.org/packages/96/df/174d2eff227dc23b4540a0c2efa6ec8fe406c442c4b7f0f556242f026d1f/orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2", size = 131282 }, - { url = "https://files.pythonhosted.org/packages/6a/96/8628c53a52e2a0a1ee861d809092df72aabbd312c71de9ad6d49e2c039ab/orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13", size = 139764 }, - { url = "https://files.pythonhosted.org/packages/38/17/08becb49e59e7bb7b29dc1dad19bc0c48635e627ee27e60eb5b64efcf7b1/orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05", size = 131913 }, - { url = "https://files.pythonhosted.org/packages/2a/05/f32acc2500e3fafee9445eb8b2a6ff19c4641035e6059c6c8d7bdb3abc9e/orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85", size = 415782 }, - { url = "https://files.pythonhosted.org/packages/06/03/6cc740d998d8bb60e75d4b7e228d18964475239ac842cc1865d49d092545/orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885", size = 142383 }, - { url = "https://files.pythonhosted.org/packages/f8/30/39cac82547fe021615376245c558b216d3ae8c99bd6b2274f312e49f1c94/orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2", size = 130661 }, - { url = "https://files.pythonhosted.org/packages/95/29/c6837f4fc1eaa742eaf5abcd767ab6805493f44fe1f72b37c1743706c1d8/orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3", size = 143625 }, - { url = "https://files.pythonhosted.org/packages/f6/62/c6b955f2144421108fa441b5471e1d5f8654a7df9840b261106e04d5d15c/orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509", size = 135075 }, - { url = "https://files.pythonhosted.org/packages/d3/48/7c3cd094488f5a3bc58488555244609a8c4d105bc02f2b77e509debf0450/orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74", size = 248687 }, - { url = "https://files.pythonhosted.org/packages/ff/90/e55f0e25c7fdd1f82551fe787f85df6f378170caca863c04c810cd8f2730/orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23", size = 136953 }, - { url = "https://files.pythonhosted.org/packages/2a/b3/109c020cf7fee747d400de53b43b183ca9d3ebda3906ad0b858eb5479718/orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252", size = 149090 }, - { url = "https://files.pythonhosted.org/packages/96/d4/35c0275dc1350707d182a1b5da16d1184b9439848060af541285407f18f9/orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef", size = 140480 }, - { url = "https://files.pythonhosted.org/packages/3b/79/f863ff460c291ad2d882cc3b580cc444bd4ec60c9df55f6901e6c9a3f519/orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252", size = 156564 }, - { url = "https://files.pythonhosted.org/packages/98/7e/8d5835449ddd873424ee7b1c4ba73a0369c1055750990d824081652874d6/orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4", size = 131279 }, - { url = "https://files.pythonhosted.org/packages/46/f5/d34595b6d7f4f984c6fef289269a7f98abcdc2445ebdf90e9273487dda6b/orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae", size = 139764 }, - { url = "https://files.pythonhosted.org/packages/b3/5b/ee6e9ddeab54a7b7806768151c2090a2d36025bc346a944f51cf172ef7f7/orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b", size = 131915 }, - { url = "https://files.pythonhosted.org/packages/c4/45/febee5951aef6db5cd8cdb260548101d7ece0ca9d4ddadadf1766306b7a4/orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da", size = 415783 }, - { url = "https://files.pythonhosted.org/packages/27/a5/5a8569e49f3a6c093bee954a3de95062a231196f59e59df13a48e2420081/orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07", size = 142387 }, - { url = "https://files.pythonhosted.org/packages/6e/05/02550fb38c5bf758f3994f55401233a2ef304e175f473f2ac6dbf464cc8b/orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd", size = 130664 }, - { url = "https://files.pythonhosted.org/packages/8c/f4/ba31019d0646ce51f7ac75af6dabf98fd89dbf8ad87a9086da34710738e7/orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79", size = 143623 }, - { url = "https://files.pythonhosted.org/packages/83/fe/babf08842b989acf4c46103fefbd7301f026423fab47e6f3ba07b54d7837/orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8", size = 135074 }, - { url = "https://files.pythonhosted.org/packages/a1/2f/989adcafad49afb535da56b95d8f87d82e748548b2a86003ac129314079c/orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d", size = 248678 }, - { url = "https://files.pythonhosted.org/packages/69/b9/8c075e21a50c387649db262b618ebb7e4d40f4197b949c146fc225dd23da/orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f", size = 136763 }, - { url = "https://files.pythonhosted.org/packages/87/d3/78edf10b4ab14c19f6d918cf46a145818f4aca2b5a1773c894c5490d3a4c/orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70", size = 149137 }, - { url = "https://files.pythonhosted.org/packages/16/81/5db8852bdf990a0ddc997fa8f16b80895b8cc77c0fe3701569ed2b4b9e78/orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69", size = 140567 }, - { url = "https://files.pythonhosted.org/packages/fa/a6/9ce1e3e3db918512efadad489630c25841eb148513d21dab96f6b4157fa1/orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9", size = 156620 }, - { url = "https://files.pythonhosted.org/packages/47/d4/05133d6bea24e292d2f7628b1e19986554f7d97b6412b3e51d812e38db2d/orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192", size = 131555 }, - { url = "https://files.pythonhosted.org/packages/b9/7a/b3fbffda8743135c7811e95dc2ab7cdbc5f04999b83c2957d046f1b3fac9/orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559", size = 139743 }, - { url = "https://files.pythonhosted.org/packages/b5/13/95bbcc9a6584aa083da5ce5004ce3d59ea362a542a0b0938d884fd8790b6/orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc", size = 131733 }, - { url = "https://files.pythonhosted.org/packages/e8/29/dddbb2ea6e7af426fcc3da65a370618a88141de75c6603313d70768d1df1/orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f", size = 415788 }, - { url = "https://files.pythonhosted.org/packages/53/df/4aea59324ac539975919b4705ee086aced38e351a6eb3eea0f5071dd5661/orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be", size = 142347 }, - { url = "https://files.pythonhosted.org/packages/55/55/a52d83d7c49f8ff44e0daab10554490447d6c658771569e1c662aa7057fe/orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c", size = 130829 }, - { url = "https://files.pythonhosted.org/packages/a1/8b/b1beb1624dd4adf7d72e2d9b73c4b529e7851c0c754f17858ea13e368b33/orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708", size = 143659 }, - { url = "https://files.pythonhosted.org/packages/13/91/634c9cd0bfc6a857fc8fab9bf1a1bd9f7f3345e0d6ca5c3d4569ceb6dcfa/orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb", size = 135221 }, { url = "https://files.pythonhosted.org/packages/1b/bb/3f560735f46fa6f875a9d7c4c2171a58cfb19f56a633d5ad5037a924f35f/orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543", size = 248662 }, { url = "https://files.pythonhosted.org/packages/a3/df/54817902350636cc9270db20486442ab0e4db33b38555300a1159b439d16/orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296", size = 126055 }, { url = "https://files.pythonhosted.org/packages/2e/77/55835914894e00332601a74540840f7665e81f20b3e2b9a97614af8565ed/orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e", size = 131507 }, @@ -928,39 +575,6 @@ version = "10.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, - { url = "https://files.pythonhosted.org/packages/a7/62/c9449f9c3043c37f73e7487ec4ef0c03eb9c9afc91a92b977a67b3c0bbc5/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", size = 3509265 }, - { url = "https://files.pythonhosted.org/packages/f4/5f/491dafc7bbf5a3cc1845dc0430872e8096eb9e2b6f8161509d124594ec2d/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", size = 3375655 }, - { url = "https://files.pythonhosted.org/packages/73/d5/c4011a76f4207a3c151134cd22a1415741e42fa5ddecec7c0182887deb3d/pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", size = 4340304 }, - { url = "https://files.pythonhosted.org/packages/ac/10/c67e20445a707f7a610699bba4fe050583b688d8cd2d202572b257f46600/pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", size = 4452804 }, - { url = "https://files.pythonhosted.org/packages/a9/83/6523837906d1da2b269dee787e31df3b0acb12e3d08f024965a3e7f64665/pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", size = 4365126 }, - { url = "https://files.pythonhosted.org/packages/ba/e5/8c68ff608a4203085158cff5cc2a3c534ec384536d9438c405ed6370d080/pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", size = 4533541 }, - { url = "https://files.pythonhosted.org/packages/f4/7c/01b8dbdca5bc6785573f4cee96e2358b0918b7b2c7b60d8b6f3abf87a070/pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", size = 4471616 }, - { url = "https://files.pythonhosted.org/packages/c8/57/2899b82394a35a0fbfd352e290945440e3b3785655a03365c0ca8279f351/pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", size = 4600802 }, - { url = "https://files.pythonhosted.org/packages/4d/d7/a44f193d4c26e58ee5d2d9db3d4854b2cfb5b5e08d360a5e03fe987c0086/pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", size = 2235213 }, - { url = "https://files.pythonhosted.org/packages/c1/d0/5866318eec2b801cdb8c82abf190c8343d8a1cd8bf5a0c17444a6f268291/pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", size = 2554498 }, - { url = "https://files.pythonhosted.org/packages/d4/c8/310ac16ac2b97e902d9eb438688de0d961660a87703ad1561fd3dfbd2aa0/pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", size = 2243219 }, - { url = "https://files.pythonhosted.org/packages/05/cb/0353013dc30c02a8be34eb91d25e4e4cf594b59e5a55ea1128fde1e5f8ea/pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", size = 3509350 }, - { url = "https://files.pythonhosted.org/packages/e7/cf/5c558a0f247e0bf9cec92bff9b46ae6474dd736f6d906315e60e4075f737/pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", size = 3374980 }, - { url = "https://files.pythonhosted.org/packages/84/48/6e394b86369a4eb68b8a1382c78dc092245af517385c086c5094e3b34428/pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", size = 4343799 }, - { url = "https://files.pythonhosted.org/packages/3b/f3/a8c6c11fa84b59b9df0cd5694492da8c039a24cd159f0f6918690105c3be/pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", size = 4459973 }, - { url = "https://files.pythonhosted.org/packages/7d/1b/c14b4197b80150fb64453585247e6fb2e1d93761fa0fa9cf63b102fde822/pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", size = 4370054 }, - { url = "https://files.pythonhosted.org/packages/55/77/40daddf677897a923d5d33329acd52a2144d54a9644f2a5422c028c6bf2d/pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", size = 4539484 }, - { url = "https://files.pythonhosted.org/packages/40/54/90de3e4256b1207300fb2b1d7168dd912a2fb4b2401e439ba23c2b2cabde/pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", size = 4477375 }, - { url = "https://files.pythonhosted.org/packages/13/24/1bfba52f44193860918ff7c93d03d95e3f8748ca1de3ceaf11157a14cf16/pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", size = 4608773 }, - { url = "https://files.pythonhosted.org/packages/55/04/5e6de6e6120451ec0c24516c41dbaf80cce1b6451f96561235ef2429da2e/pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", size = 2235690 }, - { url = "https://files.pythonhosted.org/packages/74/0a/d4ce3c44bca8635bd29a2eab5aa181b654a734a29b263ca8efe013beea98/pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", size = 2554951 }, - { url = "https://files.pythonhosted.org/packages/b5/ca/184349ee40f2e92439be9b3502ae6cfc43ac4b50bc4fc6b3de7957563894/pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", size = 2243427 }, { url = "https://files.pythonhosted.org/packages/c3/00/706cebe7c2c12a6318aabe5d354836f54adff7156fd9e1bd6c89f4ba0e98/pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", size = 3525685 }, { url = "https://files.pythonhosted.org/packages/cf/76/f658cbfa49405e5ecbfb9ba42d07074ad9792031267e782d409fd8fe7c69/pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", size = 3374883 }, { url = "https://files.pythonhosted.org/packages/46/2b/99c28c4379a85e65378211971c0b430d9c7234b1ec4d59b2668f6299e011/pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", size = 4339837 }, @@ -972,13 +586,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/f9/cfaa5082ca9bc4a6de66ffe1c12c2d90bf09c309a5f52b27759a596900e7/pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", size = 2235603 }, { url = "https://files.pythonhosted.org/packages/01/6a/30ff0eef6e0c0e71e55ded56a38d4859bf9d3634a94a88743897b5f96936/pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", size = 2554972 }, { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, ] [[package]] @@ -987,54 +594,6 @@ version = "0.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/a5/0ea64c9426959ef145a938e38c832fc551843481d356713ececa9a8a64e8/propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", size = 79296 }, - { url = "https://files.pythonhosted.org/packages/76/5a/916db1aba735f55e5eca4733eea4d1973845cf77dfe67c2381a2ca3ce52d/propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", size = 45622 }, - { url = "https://files.pythonhosted.org/packages/2d/62/685d3cf268b8401ec12b250b925b21d152b9d193b7bffa5fdc4815c392c2/propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", size = 45133 }, - { url = "https://files.pythonhosted.org/packages/4d/3d/31c9c29ee7192defc05aa4d01624fd85a41cf98e5922aaed206017329944/propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212", size = 204809 }, - { url = "https://files.pythonhosted.org/packages/10/a1/e4050776f4797fc86140ac9a480d5dc069fbfa9d499fe5c5d2fa1ae71f07/propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", size = 219109 }, - { url = "https://files.pythonhosted.org/packages/c9/c0/e7ae0df76343d5e107d81e59acc085cea5fd36a48aa53ef09add7503e888/propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", size = 217368 }, - { url = "https://files.pythonhosted.org/packages/fc/e1/e0a2ed6394b5772508868a977d3238f4afb2eebaf9976f0b44a8d347ad63/propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", size = 205124 }, - { url = "https://files.pythonhosted.org/packages/50/c1/e388c232d15ca10f233c778bbdc1034ba53ede14c207a72008de45b2db2e/propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", size = 195463 }, - { url = "https://files.pythonhosted.org/packages/0a/fd/71b349b9def426cc73813dbd0f33e266de77305e337c8c12bfb0a2a82bfb/propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", size = 198358 }, - { url = "https://files.pythonhosted.org/packages/02/f2/d7c497cd148ebfc5b0ae32808e6c1af5922215fe38c7a06e4e722fe937c8/propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", size = 195560 }, - { url = "https://files.pythonhosted.org/packages/bb/57/f37041bbe5e0dfed80a3f6be2612a3a75b9cfe2652abf2c99bef3455bbad/propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", size = 196895 }, - { url = "https://files.pythonhosted.org/packages/83/36/ae3cc3e4f310bff2f064e3d2ed5558935cc7778d6f827dce74dcfa125304/propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", size = 207124 }, - { url = "https://files.pythonhosted.org/packages/8c/c4/811b9f311f10ce9d31a32ff14ce58500458443627e4df4ae9c264defba7f/propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", size = 210442 }, - { url = "https://files.pythonhosted.org/packages/18/dd/a1670d483a61ecac0d7fc4305d91caaac7a8fc1b200ea3965a01cf03bced/propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", size = 203219 }, - { url = "https://files.pythonhosted.org/packages/f9/2d/30ced5afde41b099b2dc0c6573b66b45d16d73090e85655f1a30c5a24e07/propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", size = 40313 }, - { url = "https://files.pythonhosted.org/packages/23/84/bd9b207ac80da237af77aa6e153b08ffa83264b1c7882495984fcbfcf85c/propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", size = 44428 }, - { url = "https://files.pythonhosted.org/packages/bc/0f/2913b6791ebefb2b25b4efd4bb2299c985e09786b9f5b19184a88e5778dd/propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", size = 79297 }, - { url = "https://files.pythonhosted.org/packages/cf/73/af2053aeccd40b05d6e19058419ac77674daecdd32478088b79375b9ab54/propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", size = 45611 }, - { url = "https://files.pythonhosted.org/packages/3c/09/8386115ba7775ea3b9537730e8cf718d83bbf95bffe30757ccf37ec4e5da/propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", size = 45146 }, - { url = "https://files.pythonhosted.org/packages/03/7a/793aa12f0537b2e520bf09f4c6833706b63170a211ad042ca71cbf79d9cb/propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", size = 232136 }, - { url = "https://files.pythonhosted.org/packages/f1/38/b921b3168d72111769f648314100558c2ea1d52eb3d1ba7ea5c4aa6f9848/propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", size = 239706 }, - { url = "https://files.pythonhosted.org/packages/14/29/4636f500c69b5edea7786db3c34eb6166f3384b905665ce312a6e42c720c/propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", size = 238531 }, - { url = "https://files.pythonhosted.org/packages/85/14/01fe53580a8e1734ebb704a3482b7829a0ef4ea68d356141cf0994d9659b/propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", size = 231063 }, - { url = "https://files.pythonhosted.org/packages/33/5c/1d961299f3c3b8438301ccfbff0143b69afcc30c05fa28673cface692305/propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", size = 220134 }, - { url = "https://files.pythonhosted.org/packages/00/d0/ed735e76db279ba67a7d3b45ba4c654e7b02bc2f8050671ec365d8665e21/propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", size = 220009 }, - { url = "https://files.pythonhosted.org/packages/75/90/ee8fab7304ad6533872fee982cfff5a53b63d095d78140827d93de22e2d4/propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", size = 212199 }, - { url = "https://files.pythonhosted.org/packages/eb/ec/977ffaf1664f82e90737275873461695d4c9407d52abc2f3c3e24716da13/propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", size = 214827 }, - { url = "https://files.pythonhosted.org/packages/57/48/031fb87ab6081764054821a71b71942161619549396224cbb242922525e8/propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", size = 228009 }, - { url = "https://files.pythonhosted.org/packages/1a/06/ef1390f2524850838f2390421b23a8b298f6ce3396a7cc6d39dedd4047b0/propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", size = 231638 }, - { url = "https://files.pythonhosted.org/packages/38/2a/101e6386d5a93358395da1d41642b79c1ee0f3b12e31727932b069282b1d/propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", size = 222788 }, - { url = "https://files.pythonhosted.org/packages/db/81/786f687951d0979007e05ad9346cd357e50e3d0b0f1a1d6074df334b1bbb/propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", size = 40170 }, - { url = "https://files.pythonhosted.org/packages/cf/59/7cc7037b295d5772eceb426358bb1b86e6cab4616d971bd74275395d100d/propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", size = 44404 }, - { url = "https://files.pythonhosted.org/packages/4c/28/1d205fe49be8b1b4df4c50024e62480a442b1a7b818e734308bb0d17e7fb/propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", size = 79588 }, - { url = "https://files.pythonhosted.org/packages/21/ee/fc4d893f8d81cd4971affef2a6cb542b36617cd1d8ce56b406112cb80bf7/propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", size = 45825 }, - { url = "https://files.pythonhosted.org/packages/4a/de/bbe712f94d088da1d237c35d735f675e494a816fd6f54e9db2f61ef4d03f/propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", size = 45357 }, - { url = "https://files.pythonhosted.org/packages/7f/14/7ae06a6cf2a2f1cb382586d5a99efe66b0b3d0c6f9ac2f759e6f7af9d7cf/propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", size = 241869 }, - { url = "https://files.pythonhosted.org/packages/cc/59/227a78be960b54a41124e639e2c39e8807ac0c751c735a900e21315f8c2b/propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", size = 247884 }, - { url = "https://files.pythonhosted.org/packages/84/58/f62b4ffaedf88dc1b17f04d57d8536601e4e030feb26617228ef930c3279/propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", size = 248486 }, - { url = "https://files.pythonhosted.org/packages/1c/07/ebe102777a830bca91bbb93e3479cd34c2ca5d0361b83be9dbd93104865e/propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", size = 243649 }, - { url = "https://files.pythonhosted.org/packages/ed/bc/4f7aba7f08f520376c4bb6a20b9a981a581b7f2e385fa0ec9f789bb2d362/propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", size = 229103 }, - { url = "https://files.pythonhosted.org/packages/fe/d5/04ac9cd4e51a57a96f78795e03c5a0ddb8f23ec098b86f92de028d7f2a6b/propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", size = 226607 }, - { url = "https://files.pythonhosted.org/packages/e3/f0/24060d959ea41d7a7cc7fdbf68b31852331aabda914a0c63bdb0e22e96d6/propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", size = 221153 }, - { url = "https://files.pythonhosted.org/packages/77/a7/3ac76045a077b3e4de4859a0753010765e45749bdf53bd02bc4d372da1a0/propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", size = 222151 }, - { url = "https://files.pythonhosted.org/packages/e7/af/5e29da6f80cebab3f5a4dcd2a3240e7f56f2c4abf51cbfcc99be34e17f0b/propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", size = 233812 }, - { url = "https://files.pythonhosted.org/packages/8c/89/ebe3ad52642cc5509eaa453e9f4b94b374d81bae3265c59d5c2d98efa1b4/propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", size = 238829 }, - { url = "https://files.pythonhosted.org/packages/e9/2f/6b32f273fa02e978b7577159eae7471b3cfb88b48563b1c2578b2d7ca0bb/propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", size = 230704 }, - { url = "https://files.pythonhosted.org/packages/5c/2e/f40ae6ff5624a5f77edd7b8359b208b5455ea113f68309e2b00a2e1426b6/propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", size = 40050 }, - { url = "https://files.pythonhosted.org/packages/3b/77/a92c3ef994e47180862b9d7d11e37624fb1c00a16d61faf55115d970628b/propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", size = 44117 }, { url = "https://files.pythonhosted.org/packages/0f/2a/329e0547cf2def8857157f9477669043e75524cc3e6251cef332b3ff256f/propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", size = 77002 }, { url = "https://files.pythonhosted.org/packages/12/2d/c4df5415e2382f840dc2ecbca0eeb2293024bc28e57a80392f2012b4708c/propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", size = 44639 }, { url = "https://files.pythonhosted.org/packages/d0/5a/21aaa4ea2f326edaa4e240959ac8b8386ea31dedfdaa636a3544d9e7a408/propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", size = 44049 }, @@ -1086,47 +645,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/a6/9f/7de1f19b6aea45aeb441838782d68352e71bfa98ee6fa048d5041991b33e/pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235", size = 412785 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/ce/60fd96895c09738648c83f3f00f595c807cb6735c70d3306b548cc96dd49/pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a", size = 1897984 }, - { url = "https://files.pythonhosted.org/packages/fd/b9/84623d6b6be98cc209b06687d9bca5a7b966ffed008d15225dd0d20cce2e/pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b", size = 1807491 }, - { url = "https://files.pythonhosted.org/packages/01/72/59a70165eabbc93b1111d42df9ca016a4aa109409db04304829377947028/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278", size = 1831953 }, - { url = "https://files.pythonhosted.org/packages/7c/0c/24841136476adafd26f94b45bb718a78cb0500bd7b4f8d667b67c29d7b0d/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05", size = 1856071 }, - { url = "https://files.pythonhosted.org/packages/53/5e/c32957a09cceb2af10d7642df45d1e3dbd8596061f700eac93b801de53c0/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4", size = 2038439 }, - { url = "https://files.pythonhosted.org/packages/e4/8f/979ab3eccd118b638cd6d8f980fea8794f45018255a36044dea40fe579d4/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f", size = 2787416 }, - { url = "https://files.pythonhosted.org/packages/02/1d/00f2e4626565b3b6d3690dab4d4fe1a26edd6a20e53749eb21ca892ef2df/pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08", size = 2134548 }, - { url = "https://files.pythonhosted.org/packages/9d/46/3112621204128b90898adc2e721a3cd6cf5626504178d6f32c33b5a43b79/pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6", size = 1989882 }, - { url = "https://files.pythonhosted.org/packages/49/ec/557dd4ff5287ffffdf16a31d08d723de6762bb1b691879dc4423392309bc/pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807", size = 1995829 }, - { url = "https://files.pythonhosted.org/packages/6e/b2/610dbeb74d8d43921a7234555e4c091cb050a2bdb8cfea86d07791ce01c5/pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c", size = 2091257 }, - { url = "https://files.pythonhosted.org/packages/8c/7f/4bf8e9d26a9118521c80b229291fa9558a07cdd9a968ec2d5c1026f14fbc/pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206", size = 2143894 }, - { url = "https://files.pythonhosted.org/packages/1f/1c/875ac7139c958f4390f23656fe696d1acc8edf45fb81e4831960f12cd6e4/pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c", size = 1816081 }, - { url = "https://files.pythonhosted.org/packages/d7/41/55a117acaeda25ceae51030b518032934f251b1dac3704a53781383e3491/pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17", size = 1981109 }, - { url = "https://files.pythonhosted.org/packages/27/39/46fe47f2ad4746b478ba89c561cafe4428e02b3573df882334bd2964f9cb/pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8", size = 1895553 }, - { url = "https://files.pythonhosted.org/packages/1c/00/0804e84a78b7fdb394fff4c4f429815a10e5e0993e6ae0e0b27dd20379ee/pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330", size = 1807220 }, - { url = "https://files.pythonhosted.org/packages/01/de/df51b3bac9820d38371f5a261020f505025df732ce566c2a2e7970b84c8c/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52", size = 1829727 }, - { url = "https://files.pythonhosted.org/packages/5f/d9/c01d19da8f9e9fbdb2bf99f8358d145a312590374d0dc9dd8dbe484a9cde/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4", size = 1854282 }, - { url = "https://files.pythonhosted.org/packages/5f/84/7db66eb12a0dc88c006abd6f3cbbf4232d26adfd827a28638c540d8f871d/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c", size = 2037437 }, - { url = "https://files.pythonhosted.org/packages/34/ac/a2537958db8299fbabed81167d58cc1506049dba4163433524e06a7d9f4c/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de", size = 2780899 }, - { url = "https://files.pythonhosted.org/packages/4a/c1/3e38cd777ef832c4fdce11d204592e135ddeedb6c6f525478a53d1c7d3e5/pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025", size = 2135022 }, - { url = "https://files.pythonhosted.org/packages/7a/69/b9952829f80fd555fe04340539d90e000a146f2a003d3fcd1e7077c06c71/pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e", size = 1987969 }, - { url = "https://files.pythonhosted.org/packages/05/72/257b5824d7988af43460c4e22b63932ed651fe98804cc2793068de7ec554/pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919", size = 1994625 }, - { url = "https://files.pythonhosted.org/packages/73/c3/78ed6b7f3278a36589bcdd01243189ade7fc9b26852844938b4d7693895b/pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c", size = 2090089 }, - { url = "https://files.pythonhosted.org/packages/8d/c8/b4139b2f78579960353c4cd987e035108c93a78371bb19ba0dc1ac3b3220/pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc", size = 2142496 }, - { url = "https://files.pythonhosted.org/packages/3e/f8/171a03e97eb36c0b51981efe0f78460554a1d8311773d3d30e20c005164e/pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9", size = 1811758 }, - { url = "https://files.pythonhosted.org/packages/6a/fe/4e0e63c418c1c76e33974a05266e5633e879d4061f9533b1706a86f77d5b/pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5", size = 1980864 }, - { url = "https://files.pythonhosted.org/packages/50/fc/93f7238a514c155a8ec02fc7ac6376177d449848115e4519b853820436c5/pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89", size = 1864327 }, - { url = "https://files.pythonhosted.org/packages/be/51/2e9b3788feb2aebff2aa9dfbf060ec739b38c05c46847601134cc1fed2ea/pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f", size = 1895239 }, - { url = "https://files.pythonhosted.org/packages/7b/9e/f8063952e4a7d0127f5d1181addef9377505dcce3be224263b25c4f0bfd9/pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02", size = 1805070 }, - { url = "https://files.pythonhosted.org/packages/2c/9d/e1d6c4561d262b52e41b17a7ef8301e2ba80b61e32e94520271029feb5d8/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c", size = 1828096 }, - { url = "https://files.pythonhosted.org/packages/be/65/80ff46de4266560baa4332ae3181fffc4488ea7d37282da1a62d10ab89a4/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac", size = 1857708 }, - { url = "https://files.pythonhosted.org/packages/d5/ca/3370074ad758b04d9562b12ecdb088597f4d9d13893a48a583fb47682cdf/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb", size = 2037751 }, - { url = "https://files.pythonhosted.org/packages/b1/e2/4ab72d93367194317b99d051947c071aef6e3eb95f7553eaa4208ecf9ba4/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529", size = 2733863 }, - { url = "https://files.pythonhosted.org/packages/8a/c6/8ae0831bf77f356bb73127ce5a95fe115b10f820ea480abbd72d3cc7ccf3/pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35", size = 2161161 }, - { url = "https://files.pythonhosted.org/packages/f1/f4/b2fe73241da2429400fc27ddeaa43e35562f96cf5b67499b2de52b528cad/pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089", size = 1993294 }, - { url = "https://files.pythonhosted.org/packages/77/29/4bb008823a7f4cc05828198153f9753b3bd4c104d93b8e0b1bfe4e187540/pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381", size = 2001468 }, - { url = "https://files.pythonhosted.org/packages/f2/a9/0eaceeba41b9fad851a4107e0cf999a34ae8f0d0d1f829e2574f3d8897b0/pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb", size = 2091413 }, - { url = "https://files.pythonhosted.org/packages/d8/36/eb8697729725bc610fd73940f0d860d791dc2ad557faaefcbb3edbd2b349/pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae", size = 2154735 }, - { url = "https://files.pythonhosted.org/packages/52/e5/4f0fbd5c5995cc70d3afed1b5c754055bb67908f55b5cb8000f7112749bf/pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c", size = 1833633 }, - { url = "https://files.pythonhosted.org/packages/ee/f2/c61486eee27cae5ac781305658779b4a6b45f9cc9d02c90cb21b940e82cc/pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16", size = 1986973 }, - { url = "https://files.pythonhosted.org/packages/df/a6/e3f12ff25f250b02f7c51be89a294689d175ac76e1096c32bf278f29ca1e/pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e", size = 1883215 }, { url = "https://files.pythonhosted.org/packages/0f/d6/91cb99a3c59d7b072bded9959fbeab0a9613d5a4935773c0801f1764c156/pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073", size = 1895033 }, { url = "https://files.pythonhosted.org/packages/07/42/d35033f81a28b27dedcade9e967e8a40981a765795c9ebae2045bcef05d3/pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08", size = 1807542 }, { url = "https://files.pythonhosted.org/packages/41/c2/491b59e222ec7e72236e512108ecad532c7f4391a14e971c963f624f7569/pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf", size = 1827854 }, @@ -1141,15 +659,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/d8/c080592d80edd3441ab7f88f865f51dae94a157fc64283c680e9f32cf6da/pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05", size = 1833713 }, { url = "https://files.pythonhosted.org/packages/83/84/5ab82a9ee2538ac95a66e51f6838d6aba6e0a03a42aa185ad2fe404a4e8f/pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337", size = 1987897 }, { url = "https://files.pythonhosted.org/packages/df/c3/b15fb833926d91d982fde29c0624c9f225da743c7af801dace0d4e187e71/pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5", size = 1882983 }, - { url = "https://files.pythonhosted.org/packages/7c/60/e5eb2d462595ba1f622edbe7b1d19531e510c05c405f0b87c80c1e89d5b1/pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6", size = 1894016 }, - { url = "https://files.pythonhosted.org/packages/61/20/da7059855225038c1c4326a840908cc7ca72c7198cb6addb8b92ec81c1d6/pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676", size = 1771648 }, - { url = "https://files.pythonhosted.org/packages/8f/fc/5485cf0b0bb38da31d1d292160a4d123b5977841ddc1122c671a30b76cfd/pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d", size = 1826929 }, - { url = "https://files.pythonhosted.org/packages/a1/ff/fb1284a210e13a5f34c639efc54d51da136074ffbe25ec0c279cf9fbb1c4/pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c", size = 1980591 }, - { url = "https://files.pythonhosted.org/packages/f1/14/77c1887a182d05af74f6aeac7b740da3a74155d3093ccc7ee10b900cc6b5/pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27", size = 1981326 }, - { url = "https://files.pythonhosted.org/packages/06/aa/6f1b2747f811a9c66b5ef39d7f02fbb200479784c75e98290d70004b1253/pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f", size = 1989205 }, - { url = "https://files.pythonhosted.org/packages/7a/d2/8ce2b074d6835f3c88d85f6d8a399790043e9fdb3d0e43455e72d19df8cc/pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed", size = 2079616 }, - { url = "https://files.pythonhosted.org/packages/65/71/af01033d4e58484c3db1e5d13e751ba5e3d6b87cc3368533df4c50932c8b/pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f", size = 2133265 }, - { url = "https://files.pythonhosted.org/packages/33/72/f881b5e18fbb67cf2fb4ab253660de3c6899dbb2dba409d0b757e3559e3d/pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c", size = 2001864 }, ] [[package]] @@ -1201,33 +710,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/fb/43/d5e8993bd43e6f9cbe985e8ae1398eb73309e88694ac2ea618eacbc9cea2/pymongo-4.9.2.tar.gz", hash = "sha256:3e63535946f5df7848307b9031aa921f82bb0cbe45f9b0c3296f2173f9283eb0", size = 1889366 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/af/1ce26b971e520de621239842f2be302749eb752a5cb29dd253f4c210eb0a/pymongo-4.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab8d54529feb6e29035ba8f0570c99ad36424bc26486c238ad7ce28597bc43c8", size = 833709 }, - { url = "https://files.pythonhosted.org/packages/a6/bd/7bc8224ae96fd9ffe8b2a193469200b9c75787178c5b1955bd20e5d024c7/pymongo-4.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f928bdc152a995cbd0b563fab201b2df873846d11f7a41d1f8cc8a01b35591ab", size = 833974 }, - { url = "https://files.pythonhosted.org/packages/87/2e/3cc96aec7a1d6151677bb108af606ea220205a47255ed53255bfe1d8f31f/pymongo-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6e7251d59fa3dcbb1399a71a3aec63768cebc6b22180b671601c2195fe1f90a", size = 1405440 }, - { url = "https://files.pythonhosted.org/packages/e8/9c/2d5db2fcabc873daead275729c17ddeb2b437010858fe101e8d59a276209/pymongo-4.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e759ed0459e7264a11b6896016f616341a8e4c6ab7f71ae651bd21ffc7e9524", size = 1454720 }, - { url = "https://files.pythonhosted.org/packages/6f/84/b382e7f817fd39dcd02ae69e21afd538251acf5de1904606a9908d8895fe/pymongo-4.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f3fc60f242191840ccf02b898bc615b5141fbb70064f38f7e60fcaa35d3b5efd", size = 1431625 }, - { url = "https://files.pythonhosted.org/packages/87/f5/653f9af6a7625353138bded4548a5a48729352b963fc2a059e07241b37c2/pymongo-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c798351666ac97a0ddaa823689061c3af949c2d6acf7fb2d9ab0a7f465ced79", size = 1409027 }, - { url = "https://files.pythonhosted.org/packages/36/26/f4159209cf6229ce0a5ac37f093dab49495c51daad8ca835279f0058b060/pymongo-4.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aac78b5fdd49ed8cae49adf76befacb02293a23b412676775c4715148e166d85", size = 1378524 }, - { url = "https://files.pythonhosted.org/packages/57/3c/78c60e721a975b836922467410dd4b9616ac84f096eec00f7bde9e889b2b/pymongo-4.9.2-cp310-cp310-win32.whl", hash = "sha256:bf77bf175c315e299a91332c2bbebc097c4d4fcc8713e513a9861684aa39023a", size = 810564 }, - { url = "https://files.pythonhosted.org/packages/71/cf/790c8da7fdd55e5e824b08eaf63355732bbf278ebcb98615e723feb05702/pymongo-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:c42b5aad8971256365bfd0a545fb1c7a199c93db80decd298ea2f987419e2a6d", size = 825019 }, - { url = "https://files.pythonhosted.org/packages/a8/b4/7af80304a0798526fac959e3de651b0747472c049c8b89a6c15fed2026f6/pymongo-4.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:99e40f44877b32bf4b3c46ceed2228f08c222cf7dec8a4366dd192a1429143fa", size = 887499 }, - { url = "https://files.pythonhosted.org/packages/33/ee/5389229774f842bd92a123fd3ea4f2d72b474bde9315ff00e889fe104a0d/pymongo-4.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6f6834d575ed87edc7dfcab4501d961b6a423b3839edd29ecb1382eee7736777", size = 887755 }, - { url = "https://files.pythonhosted.org/packages/d4/fd/3f0ae0fd3a7049ec67ab8f952020bc9fad841791d52d8c51405bd91b3c9b/pymongo-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3010018f5672e5b7e8d096dea9f1ea6545b05345ff0eb1754f6ee63785550773", size = 1647336 }, - { url = "https://files.pythonhosted.org/packages/00/b7/0472d51778e9e22b2ffd5ae9a401888525c4872cb2073f1bff8d5ae9659b/pymongo-4.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69394ee9f0ce38ff71266bad01b7e045cd75e58500ebad5d72187cbabf2e652a", size = 1713193 }, - { url = "https://files.pythonhosted.org/packages/8c/ac/aa41cb291107bb16bae286d7b9f2c868e393765830bc173609ae4dc9a3ae/pymongo-4.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87b18094100f21615d9db99c255dcd9e93e476f10fb03c1d3632cf4b82d201d2", size = 1681720 }, - { url = "https://files.pythonhosted.org/packages/dc/70/ac12eb58bd46a7254daaa4d39e7c4109983ee2227dac44df6587954fe345/pymongo-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3039e093d28376d6a54bdaa963ca12230c8a53d7b19c8e6368e19bcfbd004176", size = 1652109 }, - { url = "https://files.pythonhosted.org/packages/d3/20/38f71e0f1c7878b287305b2965cebe327fc5626ecca83ea52a272968cbe2/pymongo-4.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ab42d9ee93fe6b90020c42cba5bfb43a2b4660951225d137835efc21940da48", size = 1611503 }, - { url = "https://files.pythonhosted.org/packages/9b/4c/d3b26e1040c9538b9c8aed005ec18af7515c6dd3091aabfbf6c30a3b3b1a/pymongo-4.9.2-cp311-cp311-win32.whl", hash = "sha256:a663ca60e187a248d370c58961e40f5463077d2b43831eb92120ea28a79ecf96", size = 855570 }, - { url = "https://files.pythonhosted.org/packages/40/3d/7de1a4cf51bf2b10bb9f43ffa208acad0d64c18994ca8d83f490edef6834/pymongo-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:24e7b6887bbfefd05afed26a99a2c69459e2daa351a43a410de0d6c0ee3cce4e", size = 874715 }, - { url = "https://files.pythonhosted.org/packages/a1/08/7d95aab0463dc5a2c460a0b4e50a45a743afbe20986f47f87a9a88f43c0c/pymongo-4.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8083bbe8cb10bb33dca4d93f8223dd8d848215250bb73867374650bac5fe69e1", size = 941617 }, - { url = "https://files.pythonhosted.org/packages/bb/28/40613d8d97fc33bf2b9187446a6746925623aa04a9a27c9b058e97076f7a/pymongo-4.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1b8c636bf557c7166e3799bbf1120806ca39e3f06615b141c88d9c9ceae4d8c", size = 941394 }, - { url = "https://files.pythonhosted.org/packages/df/b2/7f1a0d75f538c0dcaa004ea69e28706fa3ca72d848e0a5a7dafd30939fff/pymongo-4.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8aac5dce28454f47576063fbad31ea9789bba67cab86c95788f97aafd810e65b", size = 1907396 }, - { url = "https://files.pythonhosted.org/packages/ba/70/9304bae47a361a4b12adb5be714bad41478c0e5bc3d6cf403b328d6398a0/pymongo-4.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1d5e7123af1fddf15b2b53e58f20bf5242884e671bcc3860f5e954fe13aeddd", size = 1986029 }, - { url = "https://files.pythonhosted.org/packages/ae/51/ac0378d001995c4a705da64a4a2b8e1732f95de5080b752d69f452930cc7/pymongo-4.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe97c847b56d61e533a7af0334193d6b28375b9189effce93129c7e4733794a9", size = 1949088 }, - { url = "https://files.pythonhosted.org/packages/1a/30/e93dc808039dc29fc47acee64f128aa650aacae3e4b57b68e01ff1001cda/pymongo-4.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ad54433a996e2d1985a9cd8fc82538ca8747c95caae2daf453600cc8c317f9", size = 1910516 }, - { url = "https://files.pythonhosted.org/packages/2b/34/895b9cad3bd5342d5ab51a853ed3a814840ce281d55c6928968e9f3f49f5/pymongo-4.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98b9cade40f5b13e04492a42ae215c3721099be1014ddfe0fbd23f27e4f62c0c", size = 1860499 }, - { url = "https://files.pythonhosted.org/packages/24/7e/167818f324bf2122d45551680671a3c6406a345d3fcace4e737f57bda4e4/pymongo-4.9.2-cp312-cp312-win32.whl", hash = "sha256:dde6068ae7c62ea8ee2c5701f78c6a75618cada7e11f03893687df87709558de", size = 901282 }, - { url = "https://files.pythonhosted.org/packages/12/6b/b7ffa7114177fc1c60ae529512b82629ff7e25d19be88e97f2d0ddd16717/pymongo-4.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:e1ab6cd7cd2d38ffc7ccdc79fdc166c7a91a63f844a96e3e6b2079c054391c68", size = 924925 }, { url = "https://files.pythonhosted.org/packages/5b/d6/b57ef5f376e2e171218a98b8c30dfd001aa5cac6338aa7f3ca76e6315667/pymongo-4.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1ad79d6a74f439a068caf9a1e2daeabc20bf895263435484bbd49e90fbea7809", size = 995233 }, { url = "https://files.pythonhosted.org/packages/32/80/4ec79e36e99f86a063d297a334883fb5115ad70e9af46142b8dc33f636fa/pymongo-4.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:877699e21703717507cbbea23e75b419f81a513b50b65531e1698df08b2d7094", size = 995025 }, { url = "https://files.pythonhosted.org/packages/c4/fd/8f5464321fdf165700f10aec93b07a75c3537be593291ac2f8c8f5f69bd0/pymongo-4.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc9322ce7cf116458a637ac10517b0c5926a8211202be6dbdc51dab4d4a9afc8", size = 2167429 }, @@ -1254,24 +736,6 @@ version = "0.20.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ce/3a/5031723c09068e9c8c2f0bc25c3a9245f2b1d1aea8396c787a408f2b95ca/pyrsistent-0.20.0.tar.gz", hash = "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", size = 103642 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/19/c343b14061907b629b765444b6436b160e2bd4184d17d4804bbe6381f6be/pyrsistent-0.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", size = 83416 }, - { url = "https://files.pythonhosted.org/packages/9f/4f/8342079ea331031ef9ed57edd312a9ad283bcc8adfaf268931ae356a09a6/pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", size = 118021 }, - { url = "https://files.pythonhosted.org/packages/d7/b7/64a125c488243965b7c5118352e47c6f89df95b4ac306d31cee409153d57/pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", size = 117747 }, - { url = "https://files.pythonhosted.org/packages/fe/a5/43c67bd5f80df9e7583042398d12113263ec57f27c0607abe9d78395d18f/pyrsistent-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", size = 114524 }, - { url = "https://files.pythonhosted.org/packages/8a/98/b382a87e89ca839106d874f7bf78d226b3eedb26735eb6f751f1a3375f21/pyrsistent-0.20.0-cp310-cp310-win32.whl", hash = "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", size = 60780 }, - { url = "https://files.pythonhosted.org/packages/37/8a/23e2193f7adea6901262e3cf39c7fe18ac0c446176c0ff0e19aeb2e9681e/pyrsistent-0.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", size = 63310 }, - { url = "https://files.pythonhosted.org/packages/df/63/7544dc7d0953294882a5c587fb1b10a26e0c23d9b92281a14c2514bac1f7/pyrsistent-0.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", size = 83481 }, - { url = "https://files.pythonhosted.org/packages/ae/a0/49249bc14d71b1bf2ffe89703acfa86f2017c25cfdabcaea532b8c8a5810/pyrsistent-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", size = 120222 }, - { url = "https://files.pythonhosted.org/packages/a1/94/9808e8c9271424120289b9028a657da336ad7e43da0647f62e4f6011d19b/pyrsistent-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", size = 120002 }, - { url = "https://files.pythonhosted.org/packages/3f/f6/9ecfb78b2fc8e2540546db0fe19df1fae0f56664a5958c21ff8861b0f8da/pyrsistent-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", size = 116850 }, - { url = "https://files.pythonhosted.org/packages/83/c8/e6d28bc27a0719f8eaae660357df9757d6e9ca9be2691595721de9e8adfc/pyrsistent-0.20.0-cp311-cp311-win32.whl", hash = "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", size = 60775 }, - { url = "https://files.pythonhosted.org/packages/98/87/c6ef52ff30388f357922d08de012abdd3dc61e09311d88967bdae23ab657/pyrsistent-0.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", size = 63306 }, - { url = "https://files.pythonhosted.org/packages/15/ee/ff2ed52032ac1ce2e7ba19e79bd5b05d152ebfb77956cf08fcd6e8d760ea/pyrsistent-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", size = 83537 }, - { url = "https://files.pythonhosted.org/packages/80/f1/338d0050b24c3132bcfc79b68c3a5f54bce3d213ecef74d37e988b971d8a/pyrsistent-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", size = 122615 }, - { url = "https://files.pythonhosted.org/packages/07/3a/e56d6431b713518094fae6ff833a04a6f49ad0fbe25fb7c0dc7408e19d20/pyrsistent-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", size = 122335 }, - { url = "https://files.pythonhosted.org/packages/4a/bb/5f40a4d5e985a43b43f607250e766cdec28904682c3505eb0bd343a4b7db/pyrsistent-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", size = 118510 }, - { url = "https://files.pythonhosted.org/packages/1c/13/e6a22f40f5800af116c02c28e29f15c06aa41cb2036f6a64ab124647f28b/pyrsistent-0.20.0-cp312-cp312-win32.whl", hash = "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", size = 60865 }, - { url = "https://files.pythonhosted.org/packages/75/ef/2fa3b55023ec07c22682c957808f9a41836da4cd006b5f55ec76bf0fbfa6/pyrsistent-0.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", size = 63239 }, { url = "https://files.pythonhosted.org/packages/23/88/0acd180010aaed4987c85700b7cc17f9505f3edb4e5873e4dc67f613e338/pyrsistent-0.20.0-py3-none-any.whl", hash = "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", size = 58106 }, ] @@ -1300,9 +764,6 @@ wheels = [ name = "redis" version = "5.2.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/53/17/2f4a87ffa4cd93714cf52edfa3ea94589e9de65f71e9f99cbcfa84347a53/redis-5.2.0.tar.gz", hash = "sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0", size = 4607878 } wheels = [ { url = "https://files.pythonhosted.org/packages/12/f5/ffa560ecc4bafbf25f7961c3d6f50d627a90186352e27e7d0ba5b1f6d87d/redis-5.2.0-py3-none-any.whl", hash = "sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897", size = 261428 }, @@ -1315,7 +776,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ @@ -1452,7 +912,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/3c/21dba3e7d76138725ef307e3d7ddd29b763119b3aa459d02cc05fefcff75/uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175", size = 77630 } wheels = [ @@ -1493,33 +952,6 @@ version = "1.17.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/24/a1/fc03dca9b0432725c2e8cdbf91a349d2194cf03d8523c124faebe581de09/wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", size = 55542 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/f9/85220321e9bb1a5f72ccce6604395ae75fcb463d87dad0014dc1010bd1f1/wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8", size = 38766 }, - { url = "https://files.pythonhosted.org/packages/ff/71/ff624ff3bde91ceb65db6952cdf8947bc0111d91bd2359343bc2fa7c57fd/wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d", size = 83262 }, - { url = "https://files.pythonhosted.org/packages/9f/0a/814d4a121a643af99cfe55a43e9e6dd08f4a47cdac8e8f0912c018794715/wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df", size = 74990 }, - { url = "https://files.pythonhosted.org/packages/cd/c7/b8c89bf5ca5c4e6a2d0565d149d549cdb4cffb8916d1d1b546b62fb79281/wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d", size = 82712 }, - { url = "https://files.pythonhosted.org/packages/19/7c/5977aefa8460906c1ff914fd42b11cf6c09ded5388e46e1cc6cea4ab15e9/wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea", size = 81705 }, - { url = "https://files.pythonhosted.org/packages/ae/e7/233402d7bd805096bb4a8ec471f5a141421a01de3c8c957cce569772c056/wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb", size = 74636 }, - { url = "https://files.pythonhosted.org/packages/93/81/b6c32d8387d9cfbc0134f01585dee7583315c3b46dfd3ae64d47693cd078/wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301", size = 81299 }, - { url = "https://files.pythonhosted.org/packages/d1/c3/1fae15d453468c98f09519076f8d401b476d18d8d94379e839eed14c4c8b/wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22", size = 36425 }, - { url = "https://files.pythonhosted.org/packages/c6/f4/77e0886c95556f2b4caa8908ea8eb85f713fc68296a2113f8c63d50fe0fb/wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575", size = 38748 }, - { url = "https://files.pythonhosted.org/packages/0e/40/def56538acddc2f764c157d565b9f989072a1d2f2a8e384324e2e104fc7d/wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", size = 38766 }, - { url = "https://files.pythonhosted.org/packages/89/e2/8c299f384ae4364193724e2adad99f9504599d02a73ec9199bf3f406549d/wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", size = 83730 }, - { url = "https://files.pythonhosted.org/packages/29/ef/fcdb776b12df5ea7180d065b28fa6bb27ac785dddcd7202a0b6962bbdb47/wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", size = 75470 }, - { url = "https://files.pythonhosted.org/packages/55/b5/698bd0bf9fbb3ddb3a2feefbb7ad0dea1205f5d7d05b9cbab54f5db731aa/wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", size = 83168 }, - { url = "https://files.pythonhosted.org/packages/ce/07/701a5cee28cb4d5df030d4b2649319e36f3d9fdd8000ef1d84eb06b9860d/wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", size = 82307 }, - { url = "https://files.pythonhosted.org/packages/42/92/c48ba92cda6f74cb914dc3c5bba9650dc80b790e121c4b987f3a46b028f5/wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", size = 75101 }, - { url = "https://files.pythonhosted.org/packages/8a/0a/9276d3269334138b88a2947efaaf6335f61d547698e50dff672ade24f2c6/wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", size = 81835 }, - { url = "https://files.pythonhosted.org/packages/b9/4c/39595e692753ef656ea94b51382cc9aea662fef59d7910128f5906486f0e/wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", size = 36412 }, - { url = "https://files.pythonhosted.org/packages/63/bb/c293a67fb765a2ada48f48cd0f2bb957da8161439da4c03ea123b9894c02/wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", size = 38744 }, - { url = "https://files.pythonhosted.org/packages/85/82/518605474beafff11f1a34759f6410ab429abff9f7881858a447e0d20712/wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", size = 38904 }, - { url = "https://files.pythonhosted.org/packages/80/6c/17c3b2fed28edfd96d8417c865ef0b4c955dc52c4e375d86f459f14340f1/wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", size = 88622 }, - { url = "https://files.pythonhosted.org/packages/4a/11/60ecdf3b0fd3dca18978d89acb5d095a05f23299216e925fcd2717c81d93/wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", size = 80920 }, - { url = "https://files.pythonhosted.org/packages/d2/50/dbef1a651578a3520d4534c1e434989e3620380c1ad97e309576b47f0ada/wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", size = 89170 }, - { url = "https://files.pythonhosted.org/packages/44/a2/78c5956bf39955288c9e0dd62e807b308c3aa15a0f611fbff52aa8d6b5ea/wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", size = 86748 }, - { url = "https://files.pythonhosted.org/packages/99/49/2ee413c78fc0bdfebe5bee590bf3becdc1fab0096a7a9c3b5c9666b2415f/wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", size = 79734 }, - { url = "https://files.pythonhosted.org/packages/c0/8c/4221b7b270e36be90f0930fe15a4755a6ea24093f90b510166e9ed7861ea/wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", size = 87552 }, - { url = "https://files.pythonhosted.org/packages/4c/6b/1aaccf3efe58eb95e10ce8e77c8909b7a6b0da93449a92c4e6d6d10b3a3d/wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", size = 36647 }, - { url = "https://files.pythonhosted.org/packages/b3/4f/243f88ac49df005b9129194c6511b3642818b3e6271ddea47a15e2ee4934/wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", size = 38830 }, { url = "https://files.pythonhosted.org/packages/67/9c/38294e1bb92b055222d1b8b6591604ca4468b77b1250f59c15256437644f/wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", size = 38904 }, { url = "https://files.pythonhosted.org/packages/78/b6/76597fb362cbf8913a481d41b14b049a8813cd402a5d2f84e57957c813ae/wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", size = 88608 }, { url = "https://files.pythonhosted.org/packages/bc/69/b500884e45b3881926b5f69188dc542fb5880019d15c8a0df1ab1dfda1f7/wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", size = 80879 }, @@ -1552,54 +984,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/98/e005bc608765a8a5569f58e650961314873c8469c333616eb40bff19ae97/yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", size = 141458 }, - { url = "https://files.pythonhosted.org/packages/df/5d/f8106b263b8ae8a866b46d9be869ac01f9b3fb7f2325f3ecb3df8003f796/yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", size = 94365 }, - { url = "https://files.pythonhosted.org/packages/56/3e/d8637ddb9ba69bf851f765a3ee288676f7cf64fb3be13760c18cbc9d10bd/yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", size = 92181 }, - { url = "https://files.pythonhosted.org/packages/76/f9/d616a5c2daae281171de10fba41e1c0e2d8207166fc3547252f7d469b4e1/yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", size = 315349 }, - { url = "https://files.pythonhosted.org/packages/bb/b4/3ea5e7b6f08f698b3769a06054783e434f6d59857181b5c4e145de83f59b/yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", size = 330494 }, - { url = "https://files.pythonhosted.org/packages/55/f1/e0fc810554877b1b67420568afff51b967baed5b53bcc983ab164eebf9c9/yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", size = 326927 }, - { url = "https://files.pythonhosted.org/packages/a9/42/b1753949b327b36f210899f2dd0a0947c0c74e42a32de3f8eb5c7d93edca/yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", size = 319703 }, - { url = "https://files.pythonhosted.org/packages/f0/6d/e87c62dc9635daefb064b56f5c97df55a2e9cc947a2b3afd4fd2f3b841c7/yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", size = 310246 }, - { url = "https://files.pythonhosted.org/packages/e3/ef/e2e8d1785cdcbd986f7622d7f0098205f3644546da7919c24b95790ec65a/yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", size = 319730 }, - { url = "https://files.pythonhosted.org/packages/fc/15/8723e22345bc160dfde68c4b3ae8b236e868f9963c74015f1bc8a614101c/yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", size = 321681 }, - { url = "https://files.pythonhosted.org/packages/86/09/bf764e974f1516efa0ae2801494a5951e959f1610dd41edbfc07e5e0f978/yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62", size = 324812 }, - { url = "https://files.pythonhosted.org/packages/f6/4c/20a0187e3b903c97d857cf0272d687c1b08b03438968ae8ffc50fe78b0d6/yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", size = 337011 }, - { url = "https://files.pythonhosted.org/packages/c9/71/6244599a6e1cc4c9f73254a627234e0dad3883ece40cc33dce6265977461/yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", size = 338132 }, - { url = "https://files.pythonhosted.org/packages/af/f5/e0c3efaf74566c4b4a41cb76d27097df424052a064216beccae8d303c90f/yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", size = 331849 }, - { url = "https://files.pythonhosted.org/packages/8a/b8/3d16209c2014c2f98a8f658850a57b716efb97930aebf1ca0d9325933731/yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", size = 84309 }, - { url = "https://files.pythonhosted.org/packages/fd/b7/2e9a5b18eb0fe24c3a0e8bae994e812ed9852ab4fd067c0107fadde0d5f0/yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", size = 90484 }, - { url = "https://files.pythonhosted.org/packages/40/93/282b5f4898d8e8efaf0790ba6d10e2245d2c9f30e199d1a85cae9356098c/yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", size = 141555 }, - { url = "https://files.pythonhosted.org/packages/6d/9c/0a49af78df099c283ca3444560f10718fadb8a18dc8b3edf8c7bd9fd7d89/yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", size = 94351 }, - { url = "https://files.pythonhosted.org/packages/5a/a1/205ab51e148fdcedad189ca8dd587794c6f119882437d04c33c01a75dece/yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", size = 92286 }, - { url = "https://files.pythonhosted.org/packages/ed/fe/88b690b30f3f59275fb674f5f93ddd4a3ae796c2b62e5bb9ece8a4914b83/yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", size = 340649 }, - { url = "https://files.pythonhosted.org/packages/07/eb/3b65499b568e01f36e847cebdc8d7ccb51fff716dbda1ae83c3cbb8ca1c9/yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", size = 356623 }, - { url = "https://files.pythonhosted.org/packages/33/46/f559dc184280b745fc76ec6b1954de2c55595f0ec0a7614238b9ebf69618/yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", size = 354007 }, - { url = "https://files.pythonhosted.org/packages/af/ba/1865d85212351ad160f19fb99808acf23aab9a0f8ff31c8c9f1b4d671fc9/yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", size = 344145 }, - { url = "https://files.pythonhosted.org/packages/94/cb/5c3e975d77755d7b3d5193e92056b19d83752ea2da7ab394e22260a7b824/yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", size = 336133 }, - { url = "https://files.pythonhosted.org/packages/19/89/b77d3fd249ab52a5c40859815765d35c91425b6bb82e7427ab2f78f5ff55/yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", size = 347967 }, - { url = "https://files.pythonhosted.org/packages/35/bd/f6b7630ba2cc06c319c3235634c582a6ab014d52311e7d7c22f9518189b5/yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", size = 346397 }, - { url = "https://files.pythonhosted.org/packages/18/1a/0b4e367d5a72d1f095318344848e93ea70da728118221f84f1bf6c1e39e7/yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", size = 350206 }, - { url = "https://files.pythonhosted.org/packages/b5/cf/320fff4367341fb77809a2d8d7fe75b5d323a8e1b35710aafe41fdbf327b/yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", size = 362089 }, - { url = "https://files.pythonhosted.org/packages/57/cf/aadba261d8b920253204085268bad5e8cdd86b50162fcb1b10c10834885a/yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", size = 366267 }, - { url = "https://files.pythonhosted.org/packages/54/58/fb4cadd81acdee6dafe14abeb258f876e4dd410518099ae9a35c88d8097c/yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", size = 359141 }, - { url = "https://files.pythonhosted.org/packages/9a/7a/4c571597589da4cd5c14ed2a0b17ac56ec9ee7ee615013f74653169e702d/yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", size = 84402 }, - { url = "https://files.pythonhosted.org/packages/ae/7b/8600250b3d89b625f1121d897062f629883c2f45339623b69b1747ec65fa/yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", size = 91030 }, - { url = "https://files.pythonhosted.org/packages/33/85/bd2e2729752ff4c77338e0102914897512e92496375e079ce0150a6dc306/yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", size = 142644 }, - { url = "https://files.pythonhosted.org/packages/ff/74/1178322cc0f10288d7eefa6e4a85d8d2e28187ccab13d5b844e8b5d7c88d/yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", size = 94962 }, - { url = "https://files.pythonhosted.org/packages/be/75/79c6acc0261e2c2ae8a1c41cf12265e91628c8c58ae91f5ff59e29c0787f/yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", size = 92795 }, - { url = "https://files.pythonhosted.org/packages/6b/32/927b2d67a412c31199e83fefdce6e645247b4fb164aa1ecb35a0f9eb2058/yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", size = 332368 }, - { url = "https://files.pythonhosted.org/packages/19/e5/859fca07169d6eceeaa4fde1997c91d8abde4e9a7c018e371640c2da2b71/yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", size = 342314 }, - { url = "https://files.pythonhosted.org/packages/08/75/76b63ccd91c9e03ab213ef27ae6add2e3400e77e5cdddf8ed2dbc36e3f21/yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", size = 341987 }, - { url = "https://files.pythonhosted.org/packages/1a/e1/a097d5755d3ea8479a42856f51d97eeff7a3a7160593332d98f2709b3580/yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", size = 336914 }, - { url = "https://files.pythonhosted.org/packages/0b/42/e1b4d0e396b7987feceebe565286c27bc085bf07d61a59508cdaf2d45e63/yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", size = 325765 }, - { url = "https://files.pythonhosted.org/packages/7e/18/03a5834ccc9177f97ca1bbb245b93c13e58e8225276f01eedc4cc98ab820/yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", size = 344444 }, - { url = "https://files.pythonhosted.org/packages/c8/03/a713633bdde0640b0472aa197b5b86e90fbc4c5bc05b727b714cd8a40e6d/yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", size = 340760 }, - { url = "https://files.pythonhosted.org/packages/eb/99/f6567e3f3bbad8fd101886ea0276c68ecb86a2b58be0f64077396cd4b95e/yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", size = 346484 }, - { url = "https://files.pythonhosted.org/packages/8e/a9/84717c896b2fc6cb15bd4eecd64e34a2f0a9fd6669e69170c73a8b46795a/yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", size = 359864 }, - { url = "https://files.pythonhosted.org/packages/1e/2e/d0f5f1bef7ee93ed17e739ec8dbcb47794af891f7d165fa6014517b48169/yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", size = 364537 }, - { url = "https://files.pythonhosted.org/packages/97/8a/568d07c5d4964da5b02621a517532adb8ec5ba181ad1687191fffeda0ab6/yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", size = 357861 }, - { url = "https://files.pythonhosted.org/packages/7d/e3/924c3f64b6b3077889df9a1ece1ed8947e7b61b0a933f2ec93041990a677/yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", size = 84097 }, - { url = "https://files.pythonhosted.org/packages/34/45/0e055320daaabfc169b21ff6174567b2c910c45617b0d79c68d7ab349b02/yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", size = 90399 }, { url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789 }, { url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144 }, { url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974 }, @@ -1628,24 +1012,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/30/93/9210e7606be57a2dfc6277ac97dcc864fd8d39f142ca194fdc186d596fda/zope.interface-7.2.tar.gz", hash = "sha256:8b49f1a3d1ee4cdaf5b32d2e738362c7f5e40ac8b46dd7d1a65e82a4872728fe", size = 252960 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/71/e6177f390e8daa7e75378505c5ab974e0bf59c1d3b19155638c7afbf4b2d/zope.interface-7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce290e62229964715f1011c3dbeab7a4a1e4971fd6f31324c4519464473ef9f2", size = 208243 }, - { url = "https://files.pythonhosted.org/packages/52/db/7e5f4226bef540f6d55acfd95cd105782bc6ee044d9b5587ce2c95558a5e/zope.interface-7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05b910a5afe03256b58ab2ba6288960a2892dfeef01336dc4be6f1b9ed02ab0a", size = 208759 }, - { url = "https://files.pythonhosted.org/packages/28/ea/fdd9813c1eafd333ad92464d57a4e3a82b37ae57c19497bcffa42df673e4/zope.interface-7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550f1c6588ecc368c9ce13c44a49b8d6b6f3ca7588873c679bd8fd88a1b557b6", size = 254922 }, - { url = "https://files.pythonhosted.org/packages/3b/d3/0000a4d497ef9fbf4f66bb6828b8d0a235e690d57c333be877bec763722f/zope.interface-7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ef9e2f865721553c6f22a9ff97da0f0216c074bd02b25cf0d3af60ea4d6931d", size = 249367 }, - { url = "https://files.pythonhosted.org/packages/3e/e5/0b359e99084f033d413419eff23ee9c2bd33bca2ca9f4e83d11856f22d10/zope.interface-7.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27f926f0dcb058211a3bb3e0e501c69759613b17a553788b2caeb991bed3b61d", size = 254488 }, - { url = "https://files.pythonhosted.org/packages/7b/90/12d50b95f40e3b2fc0ba7f7782104093b9fd62806b13b98ef4e580f2ca61/zope.interface-7.2-cp310-cp310-win_amd64.whl", hash = "sha256:144964649eba4c5e4410bb0ee290d338e78f179cdbfd15813de1a664e7649b3b", size = 211947 }, - { url = "https://files.pythonhosted.org/packages/98/7d/2e8daf0abea7798d16a58f2f3a2bf7588872eee54ac119f99393fdd47b65/zope.interface-7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1909f52a00c8c3dcab6c4fad5d13de2285a4b3c7be063b239b8dc15ddfb73bd2", size = 208776 }, - { url = "https://files.pythonhosted.org/packages/a0/2a/0c03c7170fe61d0d371e4c7ea5b62b8cb79b095b3d630ca16719bf8b7b18/zope.interface-7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:80ecf2451596f19fd607bb09953f426588fc1e79e93f5968ecf3367550396b22", size = 209296 }, - { url = "https://files.pythonhosted.org/packages/49/b4/451f19448772b4a1159519033a5f72672221e623b0a1bd2b896b653943d8/zope.interface-7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:033b3923b63474800b04cba480b70f6e6243a62208071fc148354f3f89cc01b7", size = 260997 }, - { url = "https://files.pythonhosted.org/packages/65/94/5aa4461c10718062c8f8711161faf3249d6d3679c24a0b81dd6fc8ba1dd3/zope.interface-7.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a102424e28c6b47c67923a1f337ede4a4c2bba3965b01cf707978a801fc7442c", size = 255038 }, - { url = "https://files.pythonhosted.org/packages/9f/aa/1a28c02815fe1ca282b54f6705b9ddba20328fabdc37b8cf73fc06b172f0/zope.interface-7.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25e6a61dcb184453bb00eafa733169ab6d903e46f5c2ace4ad275386f9ab327a", size = 259806 }, - { url = "https://files.pythonhosted.org/packages/a7/2c/82028f121d27c7e68632347fe04f4a6e0466e77bb36e104c8b074f3d7d7b/zope.interface-7.2-cp311-cp311-win_amd64.whl", hash = "sha256:3f6771d1647b1fc543d37640b45c06b34832a943c80d1db214a37c31161a93f1", size = 212305 }, - { url = "https://files.pythonhosted.org/packages/68/0b/c7516bc3bad144c2496f355e35bd699443b82e9437aa02d9867653203b4a/zope.interface-7.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:086ee2f51eaef1e4a52bd7d3111a0404081dadae87f84c0ad4ce2649d4f708b7", size = 208959 }, - { url = "https://files.pythonhosted.org/packages/a2/e9/1463036df1f78ff8c45a02642a7bf6931ae4a38a4acd6a8e07c128e387a7/zope.interface-7.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:21328fcc9d5b80768bf051faa35ab98fb979080c18e6f84ab3f27ce703bce465", size = 209357 }, - { url = "https://files.pythonhosted.org/packages/07/a8/106ca4c2add440728e382f1b16c7d886563602487bdd90004788d45eb310/zope.interface-7.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6dd02ec01f4468da0f234da9d9c8545c5412fef80bc590cc51d8dd084138a89", size = 264235 }, - { url = "https://files.pythonhosted.org/packages/fc/ca/57286866285f4b8a4634c12ca1957c24bdac06eae28fd4a3a578e30cf906/zope.interface-7.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e7da17f53e25d1a3bde5da4601e026adc9e8071f9f6f936d0fe3fe84ace6d54", size = 259253 }, - { url = "https://files.pythonhosted.org/packages/96/08/2103587ebc989b455cf05e858e7fbdfeedfc3373358320e9c513428290b1/zope.interface-7.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cab15ff4832580aa440dc9790b8a6128abd0b88b7ee4dd56abacbc52f212209d", size = 264702 }, - { url = "https://files.pythonhosted.org/packages/5f/c7/3c67562e03b3752ba4ab6b23355f15a58ac2d023a6ef763caaca430f91f2/zope.interface-7.2-cp312-cp312-win_amd64.whl", hash = "sha256:29caad142a2355ce7cfea48725aa8bcf0067e2b5cc63fcf5cd9f97ad12d6afb5", size = 212466 }, { url = "https://files.pythonhosted.org/packages/c6/3b/e309d731712c1a1866d61b5356a069dd44e5b01e394b6cb49848fa2efbff/zope.interface-7.2-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:3e0350b51e88658d5ad126c6a57502b19d5f559f6cb0a628e3dc90442b53dd98", size = 208961 }, { url = "https://files.pythonhosted.org/packages/49/65/78e7cebca6be07c8fc4032bfbb123e500d60efdf7b86727bb8a071992108/zope.interface-7.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15398c000c094b8855d7d74f4fdc9e73aa02d4d0d5c775acdef98cdb1119768d", size = 209356 }, { url = "https://files.pythonhosted.org/packages/11/b1/627384b745310d082d29e3695db5f5a9188186676912c14b61a78bbc6afe/zope.interface-7.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:802176a9f99bd8cc276dcd3b8512808716492f6f557c11196d42e26c01a69a4c", size = 264196 }, @@ -1660,36 +1026,6 @@ version = "0.2.3.post1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/5e/7c/a8f6696e694709e2abcbccd27d05ef761e9b6efae217e11d977471555b62/zopfli-0.2.3.post1.tar.gz", hash = "sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99", size = 175629 } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/5b/7f21751e0da525a78a0269600c1d45dee565f9f0a9f875e1374b00778a82/zopfli-0.2.3.post1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0137dd64a493ba6a4be37405cfd6febe650a98cc1e9dca8f6b8c63b1db11b41", size = 296334 }, - { url = "https://files.pythonhosted.org/packages/96/a9/b9bcac622a66ecfef22e2c735feefd3b9f31b8a45ca2ef8c1438604d2157/zopfli-0.2.3.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aa588b21044f8a74e423d8c8a4c7fc9988501878aacced793467010039c50734", size = 163885 }, - { url = "https://files.pythonhosted.org/packages/79/b6/02dcb076ceb3120dc7a7e1cb197add5189c265ef9424b595430f19583dad/zopfli-0.2.3.post1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9f4a7ec2770e6af05f5a02733fd3900f30a9cd58e5d6d3727e14c5bcd6e7d587", size = 790653 }, - { url = "https://files.pythonhosted.org/packages/74/b5/720b8a6a0a103caee1c10deb52139ba25aa0b37263cd423521bc6c416ce2/zopfli-0.2.3.post1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f7d69c1a7168ad0e9cb864e8663acb232986a0c9c9cb9801f56bf6214f53a54d", size = 849105 }, - { url = "https://files.pythonhosted.org/packages/e7/a6/74f03eb4c0243bc418634ebdceb4715a28db8ab281c89cde1b7d2c243c13/zopfli-0.2.3.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c2d2bc8129707e34c51f9352c4636ca313b52350bbb7e04637c46c1818a2a70", size = 825695 }, - { url = "https://files.pythonhosted.org/packages/f0/5c/eb1cb5a4e3c7becb5576944e225f3df05198c6d3ad20e4c762eb505c59b8/zopfli-0.2.3.post1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39e576f93576c5c223b41d9c780bbb91fd6db4babf3223d2a4fe7bf568e2b5a8", size = 1753293 }, - { url = "https://files.pythonhosted.org/packages/57/15/04d1b212e8932acfb0ec3a513f13bfdc5cfb874ba2c23ee0771dffb1063d/zopfli-0.2.3.post1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cbe6df25807227519debd1a57ab236f5f6bad441500e85b13903e51f93a43214", size = 1904912 }, - { url = "https://files.pythonhosted.org/packages/88/d5/dd458a9053129bc6cf6cd2554c595020f463ba7438f32313b70a697850f2/zopfli-0.2.3.post1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7cce242b5df12b2b172489daf19c32e5577dd2fac659eb4b17f6a6efb446fd5c", size = 1834445 }, - { url = "https://files.pythonhosted.org/packages/a9/c2/f1ddc57f8458fae8c54df9acd079fbd3a7ebaa12d839576719262a942cba/zopfli-0.2.3.post1-cp310-cp310-win32.whl", hash = "sha256:f815fcc2b2a457977724bad97fb4854022980f51ce7b136925e336b530545ae1", size = 82633 }, - { url = "https://files.pythonhosted.org/packages/2c/f5/6b750c8326c00c46e486c180efb0f2d23cd0e43ecf8e0c9947586dda664a/zopfli-0.2.3.post1-cp310-cp310-win_amd64.whl", hash = "sha256:0cc20b02a9531559945324c38302fd4ba763311632d0ec8a1a0aa9c10ea363e6", size = 99343 }, - { url = "https://files.pythonhosted.org/packages/92/6d/c8224a8fc77c1dff6caaa2dc63794a40ea284c82ac20030fb2521092dca6/zopfli-0.2.3.post1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:518f1f4ed35dd69ce06b552f84e6d081f07c552b4c661c5312d950a0b764a58a", size = 296334 }, - { url = "https://files.pythonhosted.org/packages/f8/da/df0f87a489d223f184d69e9e88c80c1314be43b2361acffefdc09659e00d/zopfli-0.2.3.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:615a8ac9dda265e9cc38b2a76c3142e4a9f30fea4a79c85f670850783bc6feb4", size = 163886 }, - { url = "https://files.pythonhosted.org/packages/39/b7/14529a7ae608cedddb2f791cbc13a392a246e2e6d9c9b4b8bcda707d08d8/zopfli-0.2.3.post1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a82fc2dbebe6eb908b9c665e71496f8525c1bc4d2e3a7a7722ef2b128b6227c8", size = 823654 }, - { url = "https://files.pythonhosted.org/packages/57/48/217c7bd720553d9e68b96926c02820e8b6184ef6dbac937823abad85b154/zopfli-0.2.3.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37d011e92f7b9622742c905fdbed9920a1d0361df84142807ea2a528419dea7f", size = 826188 }, - { url = "https://files.pythonhosted.org/packages/2f/8b/5ab8c4c6db2564a0c3369e584090c101ffad4f9d0a39396e0d3e80c98413/zopfli-0.2.3.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e63d558847166543c2c9789e6f985400a520b7eacc4b99181668b2c3aeadd352", size = 850573 }, - { url = "https://files.pythonhosted.org/packages/33/f8/f52ec5c713f3325c852f19af7c8e3f98109ddcd1ce400dc39005072a2fea/zopfli-0.2.3.post1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60db20f06c3d4c5934b16cfa62a2cc5c3f0686bffe0071ed7804d3c31ab1a04e", size = 1754164 }, - { url = "https://files.pythonhosted.org/packages/92/24/6a6018125e1cc6ee5880a0ae60456fdc8a2da43f2f14b487cf49439a3448/zopfli-0.2.3.post1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:716cdbfc57bfd3d3e31a58e6246e8190e6849b7dbb7c4ce39ef8bbf0edb8f6d5", size = 1906135 }, - { url = "https://files.pythonhosted.org/packages/87/ad/697521dac8b46f0e0d081a3da153687d7583f3a2cd5466af1ddb9928394f/zopfli-0.2.3.post1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3a89277ed5f8c0fb2d0b46d669aa0633123aa7381f1f6118c12f15e0fb48f8ca", size = 1835047 }, - { url = "https://files.pythonhosted.org/packages/95/00/042c0cdba957343d7a83e572fc5ffe62de03d57c43075c8cf920b8b542e6/zopfli-0.2.3.post1-cp311-cp311-win32.whl", hash = "sha256:75a26a2307b10745a83b660c404416e984ee6fca515ec7f0765f69af3ce08072", size = 82635 }, - { url = "https://files.pythonhosted.org/packages/e6/cc/07119cba00db12d7ef0472637b7d71a95f2c8e9a20ed460d759acd274887/zopfli-0.2.3.post1-cp311-cp311-win_amd64.whl", hash = "sha256:81c341d9bb87a6dbbb0d45d6e272aca80c7c97b4b210f9b6e233bf8b87242f29", size = 99345 }, - { url = "https://files.pythonhosted.org/packages/3f/ce/b6441cc01881d06e0b5883f32c44e7cc9772e0d04e3e59277f59f80b9a19/zopfli-0.2.3.post1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3f0197b6aa6eb3086ae9e66d6dd86c4d502b6c68b0ec490496348ae8c05ecaef", size = 295489 }, - { url = "https://files.pythonhosted.org/packages/93/f0/24dd708f00ae0a925bc5c9edae858641c80f6a81a516810dc4d21688a930/zopfli-0.2.3.post1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fcfc0dc2761e4fcc15ad5d273b4d58c2e8e059d3214a7390d4d3c8e2aee644e", size = 163010 }, - { url = "https://files.pythonhosted.org/packages/65/57/0378eeeb5e3e1e83b1b0958616b2bf954f102ba5b0755b9747dafbd8cb72/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cac2b37ab21c2b36a10b685b1893ebd6b0f83ae26004838ac817680881576567", size = 823649 }, - { url = "https://files.pythonhosted.org/packages/ab/8a/3ab8a616d4655acf5cf63c40ca84e434289d7d95518a1a42d28b4a7228f8/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d5ab297d660b75c159190ce6d73035502310e40fd35170aed7d1a1aea7ddd65", size = 826557 }, - { url = "https://files.pythonhosted.org/packages/ed/4d/7f6820af119c4fec6efaf007bffee7bc9052f695853a711a951be7afd26b/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba214f4f45bec195ee8559651154d3ac2932470b9d91c5715fc29c013349f8c", size = 851127 }, - { url = "https://files.pythonhosted.org/packages/e1/db/1ef5353ab06f9f2fb0c25ed0cddf1418fe275cc2ee548bc4a29340c44fe1/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1e0ed5d84ffa2d677cc9582fc01e61dab2e7ef8b8996e055f0a76167b1b94df", size = 1754183 }, - { url = "https://files.pythonhosted.org/packages/39/03/44f8f39950354d330fa798e4bab1ac8e38ec787d3fde25d5b9c7770065a2/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bfa1eb759e07d8b7aa7a310a2bc535e127ee70addf90dc8d4b946b593c3e51a8", size = 1905945 }, - { url = "https://files.pythonhosted.org/packages/74/7b/94b920c33cc64255f59e3cfc77c829b5c6e60805d189baeada728854a342/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cd2c002f160502608dcc822ed2441a0f4509c52e86fcfd1a09e937278ed1ca14", size = 1835885 }, - { url = "https://files.pythonhosted.org/packages/ad/89/c869ac844351e285a6165e2da79b715b0619a122e3160d183805adf8ab45/zopfli-0.2.3.post1-cp312-cp312-win32.whl", hash = "sha256:7be5cc6732eb7b4df17305d8a7b293223f934a31783a874a01164703bc1be6cd", size = 82743 }, - { url = "https://files.pythonhosted.org/packages/29/e6/c98912fd3a589d8a7316c408fd91519f72c237805c4400b753e3942fda0b/zopfli-0.2.3.post1-cp312-cp312-win_amd64.whl", hash = "sha256:4e50ffac74842c1c1018b9b73875a0d0a877c066ab06bf7cccbaa84af97e754f", size = 99403 }, { url = "https://files.pythonhosted.org/packages/2b/24/0e552e2efce9a20625b56e9609d1e33c2966be33fc008681121ec267daec/zopfli-0.2.3.post1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecb7572df5372abce8073df078207d9d1749f20b8b136089916a4a0868d56051", size = 295485 }, { url = "https://files.pythonhosted.org/packages/08/83/b2564369fb98797a617fe2796097b1d719a4937234375757ad2a3febc04b/zopfli-0.2.3.post1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1cf720896d2ce998bc8e051d4b4ce0d8bec007aab6243102e8e1d22a0b2fb3f", size = 163000 }, { url = "https://files.pythonhosted.org/packages/3c/55/81d419739c2aab35e19b58bce5498dcb58e6446e5eb69f2d3c748b1c9151/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aad740b4d4fcbaaae4887823925166ffd062db3b248b3f432198fc287381d1a", size = 823699 }, @@ -1700,8 +1036,4 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/a5/817ac1ecc888723e91dc172e8c6eeab9f48a1e52285803b965084e11bbd5/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2768c877f76c8a0e7519b1c86c93757f3c01492ddde55751e9988afb7eff64e1", size = 1835907 }, { url = "https://files.pythonhosted.org/packages/cd/35/2525f90c972d8aafc39784a8c00244eeee8e8221b26cbc576748ee9dc1cd/zopfli-0.2.3.post1-cp313-cp313-win32.whl", hash = "sha256:71390dbd3fbf6ebea9a5d85ffed8c26ee1453ee09248e9b88486e30e0397b775", size = 82742 }, { url = "https://files.pythonhosted.org/packages/2f/c6/49b27570923956d52d37363e8f5df3a31a61bd7719bb8718527a9df3ae5f/zopfli-0.2.3.post1-cp313-cp313-win_amd64.whl", hash = "sha256:a86eb88e06bd87e1fff31dac878965c26b0c26db59ddcf78bb0379a954b120de", size = 99408 }, - { url = "https://files.pythonhosted.org/packages/da/92/62942d9b44b3d56e2d223924b759e2c2219f925da15a8acb103061e362ea/zopfli-0.2.3.post1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4c1226a7e2c7105ac31503a9bb97454743f55d88164d6d46bc138051b77f609b", size = 155889 }, - { url = "https://files.pythonhosted.org/packages/61/db/9502c4256f126ccf0fc4686f1f59f2696cdaec079d7d57231bf120422ba6/zopfli-0.2.3.post1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48dba9251060289101343110ab47c0756f66f809bb4d1ddbb6d5c7e7752115c5", size = 130129 }, - { url = "https://files.pythonhosted.org/packages/a3/7d/1e8c36825798269a9271ac4477b592622fddc2948772fd2fcaceb54a7178/zopfli-0.2.3.post1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89899641d4de97dbad8e0cde690040d078b6aea04066dacaab98e0b5a23573f2", size = 126242 }, - { url = "https://files.pythonhosted.org/packages/7e/6a/2c1ae9972f2745c074938d6a610e71ed47c36f911220d592f1e403822084/zopfli-0.2.3.post1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3654bfc927bc478b1c3f3ff5056ed7b20a1a37fa108ca503256d0a699c03bbb1", size = 99378 }, ] From 46319507e4bf191ae3d229942e6873f00693b98f Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Wed, 4 Jun 2025 23:15:01 +0000 Subject: [PATCH 04/38] feat(api): Add HTML Parser --- src/api/pyproject.toml | 5 + src/api/src/create_book/parser.py | 50 ++++ src/api/uv.lock | 364 ++++++++++++++++++++++++++++++ 3 files changed, 419 insertions(+) create mode 100644 src/api/src/create_book/parser.py diff --git a/src/api/pyproject.toml b/src/api/pyproject.toml index 248c283..856cfdb 100644 --- a/src/api/pyproject.toml +++ b/src/api/pyproject.toml @@ -26,3 +26,8 @@ ignore = ['E402'] # module import not at top of file [tool.uv.sources] aiohttp-client-cache = { git = "https://github.com/TheOnlyWayUp/aiohttp-client-cache.git", rev = "keydb-ttl" } # Fork which leverages keydb's EXPIREMEMBER feature for TTLs on Hash members. + +[dependency-groups] +dev = [ + "ipykernel>=6.29.5", +] diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py new file mode 100644 index 0000000..9a14017 --- /dev/null +++ b/src/api/src/create_book/parser.py @@ -0,0 +1,50 @@ +from bs4 import BeautifulSoup, Tag + + +def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: + original_soup = BeautifulSoup(body) + new_soup = BeautifulSoup(""" +

{title}

+
+""") + + insert_at = new_soup.find("section") + + for tag in list(original_soup.find("body").children): + if tag.name != "p": # Casted to lower + print(tag.name) + continue + + style = tag.attrs.get("style") + for child in tag.children: + # tag is a

enclosing either text, media, or a break + + if child.name in [None, "b", "i", "u"]: + # text is enclosed, can be italic, bold, underlined, or a mix + tag.attrs = {} + p_tag = tag + if style: + p_tag["style"] = style + insert_at.append(p_tag) + break + + elif child.name == "img": + # image is enclosed + img_tag = Tag(name="img") + img_tag.attrs = { + "height": child.attrs.get("data-original-height"), + "width": child.attrs.get("data-original-width"), + "src": child["src"], + } + if style: + img_tag["style"] = style + insert_at.append(img_tag) + + elif child.name == "br": + # br tag is enclosed + br_tag = Tag(name="br", can_be_empty_element=True) + if style: + br_tag["style"] = style + insert_at.append(br_tag) + + return new_soup diff --git a/src/api/uv.lock b/src/api/uv.lock index 92cdc3e..89cb03b 100644 --- a/src/api/uv.lock +++ b/src/api/uv.lock @@ -181,6 +181,11 @@ dependencies = [ { name = "weasyprint" }, ] +[package.dev-dependencies] +dev = [ + { name = "ipykernel" }, +] + [package.metadata] requires-dist = [ { name = "aiohttp", specifier = ">=3.9.1" }, @@ -199,6 +204,27 @@ requires-dist = [ { name = "weasyprint", specifier = ">=63.0" }, ] +[package.metadata.requires-dev] +dev = [{ name = "ipykernel", specifier = ">=6.29.5" }] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, +] + [[package]] name = "attrs" version = "23.1.0" @@ -358,6 +384,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] +[[package]] +name = "comm" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180 }, +] + [[package]] name = "cssselect2" version = "0.7.0" @@ -371,6 +409,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/3a/e39436efe51894243ff145a37c4f9a030839b97779ebcc4f13b3ba21c54e/cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969", size = 15586 }, ] +[[package]] +name = "debugpy" +version = "1.8.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/75/087fe07d40f490a78782ff3b0a30e3968936854105487decdb33446d4b0e/debugpy-1.8.14.tar.gz", hash = "sha256:7cd287184318416850aa8b60ac90105837bb1e59531898c07569d197d2ed5322", size = 1641444 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/e4/395c792b243f2367d84202dc33689aa3d910fb9826a7491ba20fc9e261f5/debugpy-1.8.14-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:329a15d0660ee09fec6786acdb6e0443d595f64f5d096fc3e3ccf09a4259033f", size = 2485676 }, + { url = "https://files.pythonhosted.org/packages/ba/f1/6f2ee3f991327ad9e4c2f8b82611a467052a0fb0e247390192580e89f7ff/debugpy-1.8.14-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f920c7f9af409d90f5fd26e313e119d908b0dd2952c2393cd3247a462331f15", size = 4217514 }, + { url = "https://files.pythonhosted.org/packages/79/28/b9d146f8f2dc535c236ee09ad3e5ac899adb39d7a19b49f03ac95d216beb/debugpy-1.8.14-cp313-cp313-win32.whl", hash = "sha256:3784ec6e8600c66cbdd4ca2726c72d8ca781e94bce2f396cc606d458146f8f4e", size = 5254756 }, + { url = "https://files.pythonhosted.org/packages/e0/62/a7b4a57013eac4ccaef6977966e6bec5c63906dd25a86e35f155952e29a1/debugpy-1.8.14-cp313-cp313-win_amd64.whl", hash = "sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e", size = 5297119 }, + { url = "https://files.pythonhosted.org/packages/97/1a/481f33c37ee3ac8040d3d51fc4c4e4e7e61cb08b8bc8971d6032acc2279f/debugpy-1.8.14-py2.py3-none-any.whl", hash = "sha256:5cd9a579d553b6cb9759a7908a41988ee6280b961f24f63336835d9418216a20", size = 5256230 }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, +] + [[package]] name = "dnspython" version = "2.7.0" @@ -405,6 +465,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/f8/b3d7c70a8f19eb767f8e1172c5e984b72f0f5f6b19ec73e3c50f2a8cd1d7/eliot-1.16.0-py3-none-any.whl", hash = "sha256:b83ac0ffd63b7b2d64a1097bb06dfeef4d68d39783d7eaf31aeadc7441ac39c5", size = 112034 }, ] +[[package]] +name = "executing" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702 }, +] + [[package]] name = "fastapi" version = "0.115.5" @@ -470,6 +539,63 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567 }, ] +[[package]] +name = "ipykernel" +version = "6.29.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173 }, +] + +[[package]] +name = "ipython" +version = "9.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/09/4c7e06b96fbd203e06567b60fb41b06db606b6a82db6db7b2c85bb72a15c/ipython-9.3.0.tar.gz", hash = "sha256:79eb896f9f23f50ad16c3bc205f686f6e030ad246cc309c6279a242b14afe9d8", size = 4426460 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/99/9ed3d52d00f1846679e3aa12e2326ac7044b5e7f90dc822b60115fa533ca/ipython-9.3.0-py3-none-any.whl", hash = "sha256:1a0b6dd9221a1f5dddf725b57ac0cb6fddc7b5f470576231ae9162b9b3455a04", size = 605320 }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074 }, +] + [[package]] name = "itsdangerous" version = "2.2.0" @@ -479,6 +605,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, ] +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, +] + [[package]] name = "jmespath" version = "1.0.1" @@ -488,6 +626,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, ] +[[package]] +name = "jupyter-client" +version = "8.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105 }, +] + +[[package]] +name = "jupyter-core" +version = "5.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/1b/72906d554acfeb588332eaaa6f61577705e9ec752ddb486f302dafa292d9/jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941", size = 88923 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0", size = 28880 }, +] + [[package]] name = "lxml" version = "5.3.0" @@ -525,6 +693,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, ] +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -552,6 +732,15 @@ version = "6.0.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4a/15/bd620f7a6eb9aa5112c4ef93e7031bcd071e0611763d8e17706ef8ba65e0/multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49", size = 51304 } +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, +] + [[package]] name = "orjson" version = "3.10.12" @@ -569,6 +758,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/05/7d768fa3ca23c9b3e1e09117abeded1501119f1d8de0ab722938c91ab25d/orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825", size = 134944 }, ] +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, +] + [[package]] name = "pillow" version = "10.4.0" @@ -588,6 +807,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, ] +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567 }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.51" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810 }, +] + [[package]] name = "propcache" version = "0.2.1" @@ -613,6 +853,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 }, ] +[[package]] +name = "psutil" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051 }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535 }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004 }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986 }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544 }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053 }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, +] + [[package]] name = "pycparser" version = "2.22" @@ -760,6 +1033,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, ] +[[package]] +name = "pywin32" +version = "310" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384 }, + { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039 }, + { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152 }, +] + +[[package]] +name = "pyzmq" +version = "26.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/11/b9213d25230ac18a71b39b3723494e57adebe36e066397b961657b3b41c1/pyzmq-26.4.0.tar.gz", hash = "sha256:4bd13f85f80962f91a651a7356fe0472791a5f7a92f227822b5acf44795c626d", size = 278293 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/20/fb2c92542488db70f833b92893769a569458311a76474bda89dc4264bd18/pyzmq-26.4.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:c43fac689880f5174d6fc864857d1247fe5cfa22b09ed058a344ca92bf5301e3", size = 1339484 }, + { url = "https://files.pythonhosted.org/packages/58/29/2f06b9cabda3a6ea2c10f43e67ded3e47fc25c54822e2506dfb8325155d4/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902aca7eba477657c5fb81c808318460328758e8367ecdd1964b6330c73cae43", size = 666106 }, + { url = "https://files.pythonhosted.org/packages/77/e4/dcf62bd29e5e190bd21bfccaa4f3386e01bf40d948c239239c2f1e726729/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e48a830bfd152fe17fbdeaf99ac5271aa4122521bf0d275b6b24e52ef35eb6", size = 902056 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/b36b3d7aea236087d20189bec1a87eeb2b66009731d7055e5c65f845cdba/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31be2b6de98c824c06f5574331f805707c667dc8f60cb18580b7de078479891e", size = 860148 }, + { url = "https://files.pythonhosted.org/packages/18/a6/f048826bc87528c208e90604c3bf573801e54bd91e390cbd2dfa860e82dc/pyzmq-26.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6332452034be001bbf3206ac59c0d2a7713de5f25bb38b06519fc6967b7cf771", size = 855983 }, + { url = "https://files.pythonhosted.org/packages/0a/27/454d34ab6a1d9772a36add22f17f6b85baf7c16e14325fa29e7202ca8ee8/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:da8c0f5dd352136853e6a09b1b986ee5278dfddfebd30515e16eae425c872b30", size = 1197274 }, + { url = "https://files.pythonhosted.org/packages/f4/3d/7abfeab6b83ad38aa34cbd57c6fc29752c391e3954fd12848bd8d2ec0df6/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f4ccc1a0a2c9806dda2a2dd118a3b7b681e448f3bb354056cad44a65169f6d86", size = 1507120 }, + { url = "https://files.pythonhosted.org/packages/13/ff/bc8d21dbb9bc8705126e875438a1969c4f77e03fc8565d6901c7933a3d01/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1c0b5fceadbab461578daf8d1dcc918ebe7ddd2952f748cf30c7cf2de5d51101", size = 1406738 }, + { url = "https://files.pythonhosted.org/packages/f5/5d/d4cd85b24de71d84d81229e3bbb13392b2698432cf8fdcea5afda253d587/pyzmq-26.4.0-cp313-cp313-win32.whl", hash = "sha256:28e2b0ff5ba4b3dd11062d905682bad33385cfa3cc03e81abd7f0822263e6637", size = 577826 }, + { url = "https://files.pythonhosted.org/packages/c6/6c/f289c1789d7bb6e5a3b3bef7b2a55089b8561d17132be7d960d3ff33b14e/pyzmq-26.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b", size = 640406 }, + { url = "https://files.pythonhosted.org/packages/b3/99/676b8851cb955eb5236a0c1e9ec679ea5ede092bf8bf2c8a68d7e965cac3/pyzmq-26.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:1edb0385c7f025045d6e0f759d4d3afe43c17a3d898914ec6582e6f464203c08", size = 556216 }, + { url = "https://files.pythonhosted.org/packages/65/c2/1fac340de9d7df71efc59d9c50fc7a635a77b103392d1842898dd023afcb/pyzmq-26.4.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:93a29e882b2ba1db86ba5dd5e88e18e0ac6b627026c5cfbec9983422011b82d4", size = 1333769 }, + { url = "https://files.pythonhosted.org/packages/5c/c7/6c03637e8d742c3b00bec4f5e4cd9d1c01b2f3694c6f140742e93ca637ed/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45684f276f57110bb89e4300c00f1233ca631f08f5f42528a5c408a79efc4a", size = 658826 }, + { url = "https://files.pythonhosted.org/packages/a5/97/a8dca65913c0f78e0545af2bb5078aebfc142ca7d91cdaffa1fbc73e5dbd/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f72073e75260cb301aad4258ad6150fa7f57c719b3f498cb91e31df16784d89b", size = 891650 }, + { url = "https://files.pythonhosted.org/packages/7d/7e/f63af1031eb060bf02d033732b910fe48548dcfdbe9c785e9f74a6cc6ae4/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be37e24b13026cfedd233bcbbccd8c0bcd2fdd186216094d095f60076201538d", size = 849776 }, + { url = "https://files.pythonhosted.org/packages/f6/fa/1a009ce582802a895c0d5fe9413f029c940a0a8ee828657a3bb0acffd88b/pyzmq-26.4.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:237b283044934d26f1eeff4075f751b05d2f3ed42a257fc44386d00df6a270cf", size = 842516 }, + { url = "https://files.pythonhosted.org/packages/6e/bc/f88b0bad0f7a7f500547d71e99f10336f2314e525d4ebf576a1ea4a1d903/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:b30f862f6768b17040929a68432c8a8be77780317f45a353cb17e423127d250c", size = 1189183 }, + { url = "https://files.pythonhosted.org/packages/d9/8c/db446a3dd9cf894406dec2e61eeffaa3c07c3abb783deaebb9812c4af6a5/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:c80fcd3504232f13617c6ab501124d373e4895424e65de8b72042333316f64a8", size = 1495501 }, + { url = "https://files.pythonhosted.org/packages/05/4c/bf3cad0d64c3214ac881299c4562b815f05d503bccc513e3fd4fdc6f67e4/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:26a2a7451606b87f67cdeca2c2789d86f605da08b4bd616b1a9981605ca3a364", size = 1395540 }, +] + [[package]] name = "redis" version = "5.2.0" @@ -830,6 +1143,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, ] +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, +] + [[package]] name = "starlette" version = "0.41.3" @@ -866,6 +1193,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/de/27c57899297163a4a84104d5cec0af3b1ac5faf62f44667e506373c6b8ce/tinyhtml5-2.0.0-py3-none-any.whl", hash = "sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e", size = 39793 }, ] +[[package]] +name = "tornado" +version = "6.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/89/c72771c81d25d53fe33e3dca61c233b665b2780f21820ba6fd2c6793c12b/tornado-6.5.1.tar.gz", hash = "sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c", size = 509934 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/89/f4532dee6843c9e0ebc4e28d4be04c67f54f60813e4bf73d595fe7567452/tornado-6.5.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7", size = 441948 }, + { url = "https://files.pythonhosted.org/packages/15/9a/557406b62cffa395d18772e0cdcf03bed2fff03b374677348eef9f6a3792/tornado-6.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6", size = 440112 }, + { url = "https://files.pythonhosted.org/packages/55/82/7721b7319013a3cf881f4dffa4f60ceff07b31b394e459984e7a36dc99ec/tornado-6.5.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888", size = 443672 }, + { url = "https://files.pythonhosted.org/packages/7d/42/d11c4376e7d101171b94e03cef0cbce43e823ed6567ceda571f54cf6e3ce/tornado-6.5.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331", size = 443019 }, + { url = "https://files.pythonhosted.org/packages/7d/f7/0c48ba992d875521ac761e6e04b0a1750f8150ae42ea26df1852d6a98942/tornado-6.5.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e", size = 443252 }, + { url = "https://files.pythonhosted.org/packages/89/46/d8d7413d11987e316df4ad42e16023cd62666a3c0dfa1518ffa30b8df06c/tornado-6.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401", size = 443930 }, + { url = "https://files.pythonhosted.org/packages/78/b2/f8049221c96a06df89bed68260e8ca94beca5ea532ffc63b1175ad31f9cc/tornado-6.5.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692", size = 443351 }, + { url = "https://files.pythonhosted.org/packages/76/ff/6a0079e65b326cc222a54720a748e04a4db246870c4da54ece4577bfa702/tornado-6.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a", size = 443328 }, + { url = "https://files.pythonhosted.org/packages/49/18/e3f902a1d21f14035b5bc6246a8c0f51e0eef562ace3a2cea403c1fb7021/tornado-6.5.1-cp39-abi3-win32.whl", hash = "sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365", size = 444396 }, + { url = "https://files.pythonhosted.org/packages/7b/09/6526e32bf1049ee7de3bebba81572673b19a2a8541f795d887e92af1a8bc/tornado-6.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b", size = 444840 }, + { url = "https://files.pythonhosted.org/packages/55/a7/535c44c7bea4578e48281d83c615219f3ab19e6abc67625ef637c73987be/tornado-6.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7", size = 443596 }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, +] + [[package]] name = "type-extensions" version = "0.1.2" @@ -918,6 +1273,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/c1/2d27b0a15826c2b71dcf6e2f5402181ef85acf439617bb2f1453125ce1f3/uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e", size = 63828 }, ] +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, +] + [[package]] name = "weasyprint" version = "63.0" From fa55e6e1e999bd39b8d104df4db80aa8c0f4b6ed Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Wed, 4 Jun 2025 23:31:42 +0000 Subject: [PATCH 05/38] feat(api): Parallelize image downloads --- src/api/src/create_book/create_book.py | 41 +------------------------- src/api/src/create_book/parser.py | 31 +++++++++++++++++++ src/api/src/create_book/vars.py | 28 ++++++++++++++++++ 3 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 src/api/src/create_book/vars.py diff --git a/src/api/src/create_book/create_book.py b/src/api/src/create_book/create_book.py index d94a375..700a47d 100644 --- a/src/api/src/create_book/create_book.py +++ b/src/api/src/create_book/create_book.py @@ -3,42 +3,18 @@ from typing import Optional, Tuple from io import BytesIO import backoff from pydantic import TypeAdapter -from .config import Config, CacheTypes from .logs import logger from eliot import start_action -from dotenv import load_dotenv from aiohttp import ClientResponseError from aiohttp_client_cache.session import CachedSession -from aiohttp_client_cache import FileBackend, RedisBackend from .models import Story from .exceptions import PartNotFoundError, StoryNotFoundError +from .vars import headers, cache -load_dotenv(override=True) - -config = Config() story_ta = TypeAdapter(Story) # --- # -headers = { - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" -} - -if config.USE_CACHE: - match config.CACHE_TYPE: - case CacheTypes.file: - cache = FileBackend(use_temp=True, expire_after=43200) # 12 hours - case CacheTypes.redis: - cache = RedisBackend( - cache_name="wpd-aiohttp-cache", - address=config.REDIS_CONNECTION_URL, - expire_after=43200, # 12 hours - ) -else: - cache = None - -logger.info(f"Using {cache=}") - async def fetch_cookies(username: str, password: str) -> dict: # source: https://github.com/TheOnlyWayUp/WP-DM-Export/blob/dd4c7c51cb43f2108e0f63fc10a66cd24a740e4e/src/API/src/main.py#L25-L58 @@ -148,18 +124,3 @@ async def fetch_story_content_zip( bytes_stream = BytesIO(await response.read()) return bytes_stream - - -@backoff.on_exception(backoff.expo, ClientResponseError, max_time=15) -async def fetch_image(url: str, should_cache: bool = False) -> bytes: - """Fetch image bytes.""" - with start_action(action_type="api_fetch_image", url=url): - async with CachedSession( - headers=headers, cache=cache if should_cache else None - ) as session: # Don't cache images. - async with session.get(url) as response: - response.raise_for_status() - - body = await response.read() - - return body diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index 9a14017..08533f4 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -1,4 +1,11 @@ +from typing import List, Tuple +from aiohttp import ClientSession from bs4 import BeautifulSoup, Tag +from itertools import batched, chain + +import asyncio +from .vars import headers +from eliot import start_action def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: @@ -48,3 +55,27 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: insert_at.append(br_tag) return new_soup + + +async def fetch_image(url: str) -> bytes | None: + """Fetch image bytes.""" + with start_action(action_type="api_fetch_image", url=url): + async with ClientSession(headers=headers) as session: # Don't cache images. + async with session.get(url) as response: + if not response.ok: + return None + + body = await response.read() + + return body + + +async def download_tree_images(tree: BeautifulSoup) -> Tuple[bytes]: + image_urls = [img["src"] for img in tree.find_all("img")] + downloaded_images: List[bytes] = list( + chain( + await asyncio.gather(*[fetch_image(url) for url in chunk]) + for chunk in batched(image_urls, 3) + ) + ) + return downloaded_images diff --git a/src/api/src/create_book/vars.py b/src/api/src/create_book/vars.py new file mode 100644 index 0000000..8cedbe6 --- /dev/null +++ b/src/api/src/create_book/vars.py @@ -0,0 +1,28 @@ +from .config import Config, CacheTypes +from aiohttp_client_cache.session import CachedSession +from aiohttp_client_cache import FileBackend, RedisBackend +from dotenv import load_dotenv +from .logs import logger + +headers = { + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" +} + +load_dotenv(override=True) + +config = Config() + +if config.USE_CACHE: + match config.CACHE_TYPE: + case CacheTypes.file: + cache = FileBackend(use_temp=True, expire_after=43200) # 12 hours + case CacheTypes.redis: + cache = RedisBackend( + cache_name="wpd-aiohttp-cache", + address=config.REDIS_CONNECTION_URL, + expire_after=43200, # 12 hours + ) +else: + cache = None + +logger.info(f"Using {cache=}") From 684e59cb0076e70b2dd2b8cd4c9071cbca7e2f3c Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Thu, 5 Jun 2025 10:22:06 +0000 Subject: [PATCH 06/38] refactor(api): Rewrite EPUBGenerator --- .../src/create_book/generators/new_epub.py | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/api/src/create_book/generators/new_epub.py diff --git a/src/api/src/create_book/generators/new_epub.py b/src/api/src/create_book/generators/new_epub.py new file mode 100644 index 0000000..443420d --- /dev/null +++ b/src/api/src/create_book/generators/new_epub.py @@ -0,0 +1,105 @@ +from io import BytesIO +from typing import List + +from bs4 import BeautifulSoup +from ebooklib import epub + +from ..models import Story + + +class EPUBGenerator: + def __init__( + self, + metadata: Story, + part_trees: List[BeautifulSoup], + cover: bytes, + images: List[List[bytes]] | None, + ): + self.story = metadata + self.parts = part_trees + self.cover = cover + self.images = images + + self.book = epub.EpubBook() + + def add_metadata(self): + self.book.add_author(self.story["user"]["username"]) + + self.book.add_metadata("DC", "title", self.story["title"]) + self.book.add_metadata("DC", "description", self.story["description"]) + self.book.add_metadata("DC", "date", self.story["createDate"]) + self.book.add_metadata("DC", "modified", self.story["modifyDate"]) + self.book.add_metadata("DC", "language", self.story["language"]["name"]) + + self.book.add_metadata( + None, "meta", "", {"name": "tags", "content": ", ".join(self.story["tags"])} + ) + self.book.add_metadata( + None, + "meta", + "", + {"name": "mature", "content": str(int(self.story["mature"]))}, + ) + self.book.add_metadata( + None, + "meta", + "", + {"name": "completed", "content": str(int(self.story["completed"]))}, + ) + + def add_cover(self): + self.book.set_cover("cover.jpg", self.cover) + cover_chapter = epub.EpubHtml( + file_name="titlepage.xhtml", # Standard for cover page + ) + cover_chapter.set_content('') + self.book.add_item(cover_chapter) + + def add_chapters(self): + chapters = [] + + for idx, (part, tree) in enumerate(zip(self.story["parts"], self.parts)): + chapter = epub.EpubHtml( + title=part["title"], file_name=f"{idx}_{part['id']}" + ) + + if self.images: + for img_idx, (img_data, img_tag) in enumerate( + zip(self.images[idx], tree.find_all("img")) + ): + path = f"static/{idx}_{part['id']}/{img_idx}.jpeg" + img = epub.EpubImage( + media_type="image/jpeg", content=img_data, file_name=path + ) + self.book.add_item(img) + + img_tag["src"] = path + + chapter.set_content(tree.prettify()) + self.book.add_item(chapter) + chapters.append(chapter) + + # ! Review, are these needed? #11 + self.book.toc = chapters + + # Thanks https://github.com/aerkalov/ebooklib/blob/master/samples/09_create_image/create.py + self.epub.add_item(epub.EpubNcx()) + self.epub.add_item(epub.EpubNav()) + + # create spine + self.epub.spine = ["nav"] + chapters + + def compile(self): + self.add_metadata() + self.add_cover() + self.add_chapters() + return True + + def dump(self) -> BytesIO: + # Thanks https://stackoverflow.com/a/75398222 + buffer = BytesIO() + epub.write_epub(buffer, self.book) + + buffer.seek(0) + + return buffer From fec7a83d1cf4e4a53ebcfa2186c4186e643a9499 Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Thu, 5 Jun 2025 10:31:52 +0000 Subject: [PATCH 07/38] feat(api): Add AbstractGenerator type --- .../src/create_book/generators/new_epub.py | 6 ++- src/api/src/create_book/generators/types.py | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/api/src/create_book/generators/types.py diff --git a/src/api/src/create_book/generators/new_epub.py b/src/api/src/create_book/generators/new_epub.py index 443420d..49ec1b5 100644 --- a/src/api/src/create_book/generators/new_epub.py +++ b/src/api/src/create_book/generators/new_epub.py @@ -5,9 +5,10 @@ from bs4 import BeautifulSoup from ebooklib import epub from ..models import Story +from .types import AbstractGenerator -class EPUBGenerator: +class EPUBGenerator(AbstractGenerator): def __init__( self, metadata: Story, @@ -23,6 +24,7 @@ class EPUBGenerator: self.book = epub.EpubBook() def add_metadata(self): + """Add metadata to epub.""" self.book.add_author(self.story["user"]["username"]) self.book.add_metadata("DC", "title", self.story["title"]) @@ -48,6 +50,7 @@ class EPUBGenerator: ) def add_cover(self): + """Add cover to epub.""" self.book.set_cover("cover.jpg", self.cover) cover_chapter = epub.EpubHtml( file_name="titlepage.xhtml", # Standard for cover page @@ -56,6 +59,7 @@ class EPUBGenerator: self.book.add_item(cover_chapter) def add_chapters(self): + """Add chapters to epub, replacing references to image urls to static image paths if images are provided during initialization.""" chapters = [] for idx, (part, tree) in enumerate(zip(self.story["parts"], self.parts)): diff --git a/src/api/src/create_book/generators/types.py b/src/api/src/create_book/generators/types.py new file mode 100644 index 0000000..d79b0da --- /dev/null +++ b/src/api/src/create_book/generators/types.py @@ -0,0 +1,47 @@ +from io import BytesIO +from tempfile import NamedTemporaryFile +from typing import List, Literal + +from bs4 import BeautifulSoup +from ebooklib.epub import EpubBook + +from ..models import Story + + +class AbstractGenerator: + """Compile parsed part trees to a file. + + Args: + metadata (Story): Story Metadata. + part_trees (List[BeautifulSoup]): Parsed part trees. + cover (bytes): Cover image. + images (List[List[bytes]] | None): An array of images for each chapter, if images have been downloaded. + """ + + def __init__( + self, + metadata: Story, + part_trees: List[BeautifulSoup], + cover: bytes, + images: List[List[bytes]] | None, + ): + self.story = metadata + self.parts = part_trees + self.cover = cover + self.images = images + + self.book: EpubBook | NamedTemporaryFile = None + + def compile(self) -> Literal[True]: + """Compile the part trees into the corresponding in-memory representation of the generator format. + + Returns: + Literal[True]: Compiled successfully. + """ + return True + + def dump(self) -> BytesIO: + """Return a Buffer of the compiled file.""" + buffer = BytesIO() + + return buffer From cfef986f46ec4016eeaccfc629e8453392eccbdd Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:18:08 -0400 Subject: [PATCH 08/38] Update base image to python:3.13-slim --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5912f97..d89872d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ COPY src/frontend/. . RUN npm run build # Thanks https://stackoverflow.com/q/76988450 -FROM python:3.10-slim +FROM python:3.13-slim WORKDIR /app From 6a9b703f5095516c4c2b71b36b2729ab7bf55325 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:22:12 -0400 Subject: [PATCH 09/38] fix(api): Import fetch_image() from correct file --- src/api/src/create_book/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/src/create_book/__init__.py b/src/api/src/create_book/__init__.py index ef54aa5..9f74c06 100644 --- a/src/api/src/create_book/__init__.py +++ b/src/api/src/create_book/__init__.py @@ -4,10 +4,10 @@ from .create_book import ( fetch_story, fetch_story_from_partId, fetch_story_content_zip, - fetch_image, fetch_cookies, ) from .generators import PDFGenerator, EPUBGenerator from .exceptions import WattpadError, StoryNotFoundError, PartNotFoundError from .utils import generate_clean_part_html, slugify from .logs import logger +from .parser import fetch_image From 8457d3786fa7431a3a601bea6af727d30fc87383 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:26:39 -0400 Subject: [PATCH 10/38] fix(api): Remove redundant definition of headers --- src/api/src/main.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/api/src/main.py b/src/api/src/main.py index 5f63c15..aa27f56 100644 --- a/src/api/src/main.py +++ b/src/api/src/main.py @@ -33,10 +33,6 @@ from create_book import ( app = FastAPI() BUILD_PATH = Path(__file__).parent / "build" -headers = { - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" -} - class RequestCancelledMiddleware: # Thanks https://github.com/fastapi/fastapi/discussions/11360#discussion-6427734 From 0ec0a65afc711704bacaf7eaf8a18332202467a5 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:29:39 -0400 Subject: [PATCH 11/38] fix(api): Remove unused import --- src/api/src/create_book/vars.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/src/create_book/vars.py b/src/api/src/create_book/vars.py index 8cedbe6..7cf0fe3 100644 --- a/src/api/src/create_book/vars.py +++ b/src/api/src/create_book/vars.py @@ -1,5 +1,4 @@ from .config import Config, CacheTypes -from aiohttp_client_cache.session import CachedSession from aiohttp_client_cache import FileBackend, RedisBackend from dotenv import load_dotenv from .logs import logger From 3810b4661c14395dd67dac5081ec16aba4d7aa5c Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Mon, 9 Jun 2025 14:19:26 +0000 Subject: [PATCH 12/38] api: Move PDF Generation assets --- .../src/{ => create_book/generators}/pdf/book.html | 2 +- .../create_book/generators/pdf}/exiftool.config | 0 .../{ => create_book/generators}/pdf/fonts/OFL.txt | 0 .../generators}/pdf/fonts/PTSerif-Bold.ttf | Bin .../generators}/pdf/fonts/PTSerif-BoldItalic.ttf | Bin .../generators}/pdf/fonts/PTSerif-Italic.ttf | Bin .../generators}/pdf/fonts/PTSerif-Regular.ttf | Bin .../{ => create_book/generators}/pdf/stylesheet.css | 8 ++++++++ .../src/{ => create_book/generators}/pdf/toc.xsl | 0 9 files changed, 9 insertions(+), 1 deletion(-) rename src/api/src/{ => create_book/generators}/pdf/book.html (88%) rename src/api/{ => src/create_book/generators/pdf}/exiftool.config (100%) rename src/api/src/{ => create_book/generators}/pdf/fonts/OFL.txt (100%) rename src/api/src/{ => create_book/generators}/pdf/fonts/PTSerif-Bold.ttf (100%) rename src/api/src/{ => create_book/generators}/pdf/fonts/PTSerif-BoldItalic.ttf (100%) rename src/api/src/{ => create_book/generators}/pdf/fonts/PTSerif-Italic.ttf (100%) rename src/api/src/{ => create_book/generators}/pdf/fonts/PTSerif-Regular.ttf (100%) rename src/api/src/{ => create_book/generators}/pdf/stylesheet.css (98%) rename src/api/src/{ => create_book/generators}/pdf/toc.xsl (100%) diff --git a/src/api/src/pdf/book.html b/src/api/src/create_book/generators/pdf/book.html similarity index 88% rename from src/api/src/pdf/book.html rename to src/api/src/create_book/generators/pdf/book.html index 5fa8482..cd77187 100644 --- a/src/api/src/pdf/book.html +++ b/src/api/src/create_book/generators/pdf/book.html @@ -30,7 +30,7 @@

- + diff --git a/src/api/exiftool.config b/src/api/src/create_book/generators/pdf/exiftool.config similarity index 100% rename from src/api/exiftool.config rename to src/api/src/create_book/generators/pdf/exiftool.config diff --git a/src/api/src/pdf/fonts/OFL.txt b/src/api/src/create_book/generators/pdf/fonts/OFL.txt similarity index 100% rename from src/api/src/pdf/fonts/OFL.txt rename to src/api/src/create_book/generators/pdf/fonts/OFL.txt diff --git a/src/api/src/pdf/fonts/PTSerif-Bold.ttf b/src/api/src/create_book/generators/pdf/fonts/PTSerif-Bold.ttf similarity index 100% rename from src/api/src/pdf/fonts/PTSerif-Bold.ttf rename to src/api/src/create_book/generators/pdf/fonts/PTSerif-Bold.ttf diff --git a/src/api/src/pdf/fonts/PTSerif-BoldItalic.ttf b/src/api/src/create_book/generators/pdf/fonts/PTSerif-BoldItalic.ttf similarity index 100% rename from src/api/src/pdf/fonts/PTSerif-BoldItalic.ttf rename to src/api/src/create_book/generators/pdf/fonts/PTSerif-BoldItalic.ttf diff --git a/src/api/src/pdf/fonts/PTSerif-Italic.ttf b/src/api/src/create_book/generators/pdf/fonts/PTSerif-Italic.ttf similarity index 100% rename from src/api/src/pdf/fonts/PTSerif-Italic.ttf rename to src/api/src/create_book/generators/pdf/fonts/PTSerif-Italic.ttf diff --git a/src/api/src/pdf/fonts/PTSerif-Regular.ttf b/src/api/src/create_book/generators/pdf/fonts/PTSerif-Regular.ttf similarity index 100% rename from src/api/src/pdf/fonts/PTSerif-Regular.ttf rename to src/api/src/create_book/generators/pdf/fonts/PTSerif-Regular.ttf diff --git a/src/api/src/pdf/stylesheet.css b/src/api/src/create_book/generators/pdf/stylesheet.css similarity index 98% rename from src/api/src/pdf/stylesheet.css rename to src/api/src/create_book/generators/pdf/stylesheet.css index 4d04b10..14149a6 100644 --- a/src/api/src/pdf/stylesheet.css +++ b/src/api/src/create_book/generators/pdf/stylesheet.css @@ -389,6 +389,14 @@ a:hover { } +#book-link { + font-size: 14px; + color: #666; + margin: 8px 0; + text-align: center; + +} + #copyright-separator { width: 100%; max-width: 400px; diff --git a/src/api/src/pdf/toc.xsl b/src/api/src/create_book/generators/pdf/toc.xsl similarity index 100% rename from src/api/src/pdf/toc.xsl rename to src/api/src/create_book/generators/pdf/toc.xsl From c7cc857306980fe3279e62be7d7a1580857d64a9 Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Mon, 9 Jun 2025 14:20:23 +0000 Subject: [PATCH 13/38] api: Add copyright logos to assets --- .gitignore | 4 ++-- .../generators/pdf/assets/by-nc-nd.png | Bin 0 -> 20935 bytes .../generators/pdf/assets/by-nc-sa.png | Bin 0 -> 22475 bytes .../create_book/generators/pdf/assets/by-nc.png | Bin 0 -> 17637 bytes .../create_book/generators/pdf/assets/by-nd.png | Bin 0 -> 16192 bytes .../create_book/generators/pdf/assets/by-sa.png | Bin 0 -> 17594 bytes .../create_book/generators/pdf/assets/by.png | Bin 0 -> 12588 bytes .../generators/pdf/assets/cc-zero.png | Bin 0 -> 6447 bytes 8 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/api/src/create_book/generators/pdf/assets/by-nc-nd.png create mode 100644 src/api/src/create_book/generators/pdf/assets/by-nc-sa.png create mode 100644 src/api/src/create_book/generators/pdf/assets/by-nc.png create mode 100644 src/api/src/create_book/generators/pdf/assets/by-nd.png create mode 100644 src/api/src/create_book/generators/pdf/assets/by-sa.png create mode 100644 src/api/src/create_book/generators/pdf/assets/by.png create mode 100644 src/api/src/create_book/generators/pdf/assets/cc-zero.png diff --git a/.gitignore b/.gitignore index 080e30a..4b78fae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ __pycache__ venv *epub -*pdf -*html +*.pdf +# *html data *ipynb build diff --git a/src/api/src/create_book/generators/pdf/assets/by-nc-nd.png b/src/api/src/create_book/generators/pdf/assets/by-nc-nd.png new file mode 100644 index 0000000000000000000000000000000000000000..5a8dbd0652e37cc2d89b4899e307abcac8bda553 GIT binary patch literal 20935 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 V_bKxY2;ODV(a=9ucJy?}e*pE>jWz%P literal 0 HcmV?d00001 diff --git a/src/api/src/create_book/generators/pdf/assets/by-nc.png b/src/api/src/create_book/generators/pdf/assets/by-nc.png new file mode 100644 index 0000000000000000000000000000000000000000..25e284099a07df1ba95e4140fbfe7a8d1740fdc5 GIT binary patch literal 17637 zcmYLR1yEIMv_?f~B&16~knS#}JEgmk2I&$6q(eGHL_|`$JETEC6iI0br5mZY&V4iQ z?HR9LhO^H;d;kAhU#%0VrXq`lPKu6%goGt8C#8XebSnw|9gBJo{`;anO$`1*c9W3T zM1{j2)iMJ9AI(Kh&kYHQjRo=N7PftY1N@N0U0T=unX|RKm)Q#|Brh*7Hd`lqHw!Zt zD>mmBHg9)CNRf~pBFRgMYkFsGzw^?4phFZMIKI4B zgl@;8OIueMNnr8$TVcclKUw5YjD%9+cPrJC=Z9Vf?ukDa7H$^CXdY@At&Zn%8!`(L zJk9n)59u-gAclF*0yD@JiRBjYoj13!;7~Rw!0g~g;za7wW%)VrkDsJ=FtpRu9cd3G zsEC!78u2T!{rmTk?h{5IQ=GMPoww8Y+|KbUiIS0ogI2*G$#l@XvTc$nsT#@9ZkLIH zp<}QY{Z~!X$AD(f(#Q1woj^@ZT`%&e=6*z6l#IBz_?5v;l`f0UJtPz)>RO#xUy{yQ zFUDl8WCML|Qp7?1nEx?R^Q9LJBWKaIl`I;Pgc~A|R?_i6DhSvNOt-$oY~Gchnu`klZlG|J9-4#aXl5bI}*jkyH%m{Xs7a4nlJ<4}>s z$5V}~Yiad-*F{H1-}qk6KFl&~YUhM5O(z}oiQq|F;6>coly`SeH}!sxV)BEuJsy>2 z&+ReE0+eBvucp>!_Z;6*nsN|7P@MI&bsNm9sd?bj=+po8tF*C7>%`X^om5`tuPvDb zD%-^}(j*EBQED36Wd_>}%*>OYJy(Bkn8Dy8DE$N znO%6dn7V=`6W%5<@14JBTVFhhooxtM;hU+oN3kcfSIS-s9x)Qa@ON?zy_Lg;a@8Vz z$YDO*ul*oA5FR1UA;Z1YcCjGHaMx*PI*0GX}-~KmcA+! zIfC5v>aC9R!^Njhe@&WyP%17iMm*_=3*3n4IB6drANy#{@Um>SdzhpVRQIls;Leq@ zVk^@sL@DCnJ&37LG-GYsTa@B2-ANY;Kp!q;5#T3OU$$6r{dZ=YR}k>rQJwT59o=2O zzDk#W-_WY6s!Cbo)M&H^^IBTS>z(Iho~xl&RaY4pkV~X1(K~EAEFFF1ZnE=qbab5& zfyZj^DIBE#f%0h1#->Q7PPTD$ zLoZ* )qEM3BX%M9NWgRO_B(1S+!|F;!C~0` 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 literal 0 HcmV?d00001 diff --git a/src/api/src/create_book/generators/pdf/assets/by-nd.png b/src/api/src/create_book/generators/pdf/assets/by-nd.png new file mode 100644 index 0000000000000000000000000000000000000000..fc3d26789a0b4f529a132bcae501dca6ce208f45 GIT binary patch literal 16192 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 D++ZVC literal 0 HcmV?d00001 diff --git a/src/api/src/create_book/generators/pdf/assets/by-sa.png b/src/api/src/create_book/generators/pdf/assets/by-sa.png new file mode 100644 index 0000000000000000000000000000000000000000..8770732928cb20d8aeafee32bec9c5de89d51238 GIT binary patch literal 17594 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 H&)EL~wS8Yu literal 0 HcmV?d00001 From 80be6e0b32dfc4c5558a8d33008671a0d940073f Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Mon, 9 Jun 2025 14:21:14 +0000 Subject: [PATCH 14/38] refactor(api): PDF Template uses Jinja2 --- src/api/pyproject.toml | 2 + .../src/create_book/generators/pdf/book.html | 58 ++++++++++----- src/api/uv.lock | 73 ++++++++++++++++++- 3 files changed, 112 insertions(+), 21 deletions(-) diff --git a/src/api/pyproject.toml b/src/api/pyproject.toml index 856cfdb..ad6344c 100644 --- a/src/api/pyproject.toml +++ b/src/api/pyproject.toml @@ -19,6 +19,7 @@ dependencies = [ "uvicorn>=0.32.1", "pyexiftool>=0.5.6", "weasyprint>=63.0", + "jinja2>=3.1.6", ] [tool.ruff.lint] @@ -30,4 +31,5 @@ aiohttp-client-cache = { git = "https://github.com/TheOnlyWayUp/aiohttp-client-c [dependency-groups] dev = [ "ipykernel>=6.29.5", + "ruff>=0.11.12", ] diff --git a/src/api/src/create_book/generators/pdf/book.html b/src/api/src/create_book/generators/pdf/book.html index cd77187..69e6934 100644 --- a/src/api/src/create_book/generators/pdf/book.html +++ b/src/api/src/create_book/generators/pdf/book.html @@ -1,20 +1,20 @@ - + - {book_title} + {{ book_title }}
- Cover -
+ Cover + - diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index 0f8be61..d71e2fa 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -15,7 +15,8 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: f"""

{title}

-""" +""", + parser="html.parser", # head/body tags aren't generated ) insert_at = cast(Tag, new_soup.find("section")) From db899aafdeced66d49eb3b35a0c53ff500dbf819 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:55:09 -0400 Subject: [PATCH 31/38] fix(api): Justify PDF ToC page numbers to the right side of the page --- src/api/src/create_book/generators/pdf/stylesheet.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/src/create_book/generators/pdf/stylesheet.css b/src/api/src/create_book/generators/pdf/stylesheet.css index 14149a6..f2ca7ac 100644 --- a/src/api/src/create_book/generators/pdf/stylesheet.css +++ b/src/api/src/create_book/generators/pdf/stylesheet.css @@ -205,6 +205,8 @@ section { #contents a { color: inherit; text-decoration: none; + display: flex; + justify-content: space-between; } #contents a::before { content: target-counter(attr(href), h2-counter) '. ' target-text(attr(href)); From 403ee8dd541751386d8767af4da9fe68cff1edfb Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:11:37 -0400 Subject: [PATCH 32/38] fix(api): Add support for strong and em tags --- src/api/src/create_book/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index d71e2fa..36cf3e1 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -31,7 +31,7 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: for child in cast(list[Tag], tag.children): # tag is a

enclosing either text, media, or a break - if child.name in [None, "b", "i", "u"]: + if child.name in [None, "b", "i", "u","strong","em"]: # text is enclosed, can be italic, bold, underlined, or a mix tag.attrs = {} p_tag = tag From 1baeb3f97514a8443cce30d602d9501110c4aab7 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:50:51 -0400 Subject: [PATCH 33/38] fix(api): Use correct class in ToC for chapter title --- src/api/src/create_book/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index 36cf3e1..3ecc3a6 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -13,7 +13,7 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: original_soup = BeautifulSoup(body) new_soup = BeautifulSoup( f""" -

{title}

+

{title}

""", parser="html.parser", # head/body tags aren't generated From b36dc92718a895456db519f2ae903cf232f6c4c1 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:58:42 -0400 Subject: [PATCH 34/38] fix(api): Explicitly specficy html parser --- src/api/src/create_book/parser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index 3ecc3a6..c97018f 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -10,13 +10,14 @@ from .vars import headers def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: - original_soup = BeautifulSoup(body) + original_soup = BeautifulSoup(body, features="lxml") new_soup = BeautifulSoup( f"""

{title}

""", parser="html.parser", # head/body tags aren't generated + features="lxml", ) insert_at = cast(Tag, new_soup.find("section")) From 1db3f82f155a0eb8090a0d1b073f46664f8bfbce Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:59:10 -0400 Subject: [PATCH 35/38] fix(api): Remove debug print statement --- src/api/src/create_book/parser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index c97018f..46531d5 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -25,7 +25,6 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: children = cast(Tag, original_soup.find("body")).children for tag in cast(list[Tag], list(children)): if tag.name != "p": # Casted to lower - print(tag.name) continue style = tag.attrs.get("style") From 6e93f743f3a1c13dff856a5c78ea937c93558322 Mon Sep 17 00:00:00 2001 From: AaronBenDaniel <144371000+AaronBenDaniel@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:06:23 -0400 Subject: [PATCH 36/38] fix(api): Code formatting --- src/api/src/create_book/generators/pdf.py | 14 ++++++++------ src/api/src/create_book/parser.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/api/src/create_book/generators/pdf.py b/src/api/src/create_book/generators/pdf.py index adf4274..b6c2c08 100644 --- a/src/api/src/create_book/generators/pdf.py +++ b/src/api/src/create_book/generators/pdf.py @@ -111,9 +111,9 @@ class PDFGenerator(AbstractGenerator): if not img_data: continue - img_tag[ - "src" - ] = f"data:image/jpg;base64,{b64encode(img_data).decode()}" + img_tag["src"] = ( + f"data:image/jpg;base64,{b64encode(img_data).decode()}" + ) data[part["id"]] = tree.prettify() @@ -137,9 +137,11 @@ class PDFGenerator(AbstractGenerator): "description": self.story["description"], "avatar": b64encode(self.author).decode(), "copyright": { - "data": b64encode(copyright["asset"].read_bytes()).decode() - if copyright["asset"] - else "", + "data": ( + b64encode(copyright["asset"].read_bytes()).decode() + if copyright["asset"] + else "" + ), "name": copyright["name"], }, "parts": parts, diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index 46531d5..005551e 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -31,7 +31,7 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup: for child in cast(list[Tag], tag.children): # tag is a

enclosing either text, media, or a break - if child.name in [None, "b", "i", "u","strong","em"]: + if child.name in [None, "b", "i", "u", "strong", "em"]: # text is enclosed, can be italic, bold, underlined, or a mix tag.attrs = {} p_tag = tag From c132b5de18728cb1c24a35a78c83be8bbcd392f1 Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Tue, 10 Jun 2025 19:56:56 +0000 Subject: [PATCH 37/38] fix(api): Use latest bs4 syntax for declaring parser --- src/api/src/create_book/parser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/api/src/create_book/parser.py b/src/api/src/create_book/parser.py index 005551e..eafb1c5 100644 --- a/src/api/src/create_book/parser.py +++ b/src/api/src/create_book/parser.py @@ -16,8 +16,7 @@ def clean_tree(title: str, id: int, body: str) -> BeautifulSoup:

{title}

""", - parser="html.parser", # head/body tags aren't generated - features="lxml", + features="html.parser", # head/body tags aren't generated ) insert_at = cast(Tag, new_soup.find("section")) From 551e91cb7fd4eac721805839efade6dad22167e5 Mon Sep 17 00:00:00 2001 From: TheOnlyWayUp Date: Tue, 10 Jun 2025 19:57:15 +0000 Subject: [PATCH 38/38] api: Remove toc.xsl --- .../src/create_book/generators/pdf/toc.xsl | 120 ------------------ 1 file changed, 120 deletions(-) delete mode 100644 src/api/src/create_book/generators/pdf/toc.xsl diff --git a/src/api/src/create_book/generators/pdf/toc.xsl b/src/api/src/create_book/generators/pdf/toc.xsl deleted file mode 100644 index ae7bbe7..0000000 --- a/src/api/src/create_book/generators/pdf/toc.xsl +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - -

Table of Contents

-
- - -
- -
  • - - - -
      - added to prevent self-closing tags in QtXmlPatterns - -
    -
  • -
    -