feat/python-checks (#5651)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
port the bash precommit hooks to python in a nice extensible way. It should have feature parity and be much easier to read and maintain. It also allows for reducing the number of dependencies in the pre commit docker image. I have tested that the checks can both pass and fail correctly, but it is somewhat possible there might be some edge cases and bugs I have missed. So for a short while after merging if failing ci look at it a little more carefully, in case the checks need some tuning. Co-authored-by: Darragh Elliott <me@delliott.net> Reviewed-on: #5651 Reviewed-by: tobiasd <tobiasd@fsfe.org> Co-authored-by: delliott <delliott@fsfe.org> Co-committed-by: delliott <delliott@fsfe.org>
This commit was merged in pull request #5651.
This commit is contained in:
@@ -63,22 +63,8 @@ pre-commit:
|
||||
ty:
|
||||
glob: "*.py"
|
||||
run: ty check {staged_files}
|
||||
structure:
|
||||
glob:
|
||||
- "*.xml"
|
||||
- "*.xhtml"
|
||||
run: tools/ci-checks/compare-xml-structure.py {staged_files}
|
||||
general:
|
||||
glob:
|
||||
- "*.html"
|
||||
- "*.xml"
|
||||
- "*.xhtml"
|
||||
run: tools/ci-checks/general.sh {staged_files}
|
||||
non-en-frontpage-news:
|
||||
glob:
|
||||
- "*.xml"
|
||||
- "*.xhtml"
|
||||
run: tools/ci-checks/check-non-en-frontpage.sh {staged_files}
|
||||
general-checks:
|
||||
run: tools/ci-checks/run_checks.py {staged_files}
|
||||
simple-syntax:
|
||||
glob:
|
||||
- "*.xml"
|
||||
|
||||
@@ -5,16 +5,12 @@ COPY --from=ghcr.io/astral-sh/uv /uv /uvx /bin/
|
||||
# Install deps
|
||||
RUN apt-get update && apt-get install --yes --no-install-recommends \
|
||||
composer \
|
||||
curl \
|
||||
file \
|
||||
git \
|
||||
libxml2 \
|
||||
libxml2-utils \
|
||||
libxslt1.1 \
|
||||
mediainfo \
|
||||
node-less \
|
||||
npm \
|
||||
perl-base \
|
||||
php-zip \
|
||||
rsync \
|
||||
shfmt \
|
||||
|
||||
@@ -20,6 +20,8 @@ build = "fsfe_website_build:build"
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"lefthook", # pre-commit hook
|
||||
"pillow", # image processing
|
||||
"pyright", # python typechecker
|
||||
"pytest", # python test runner
|
||||
"pytest-mock", # helper for mocking in pytest
|
||||
"reuse", # for enforcing licensing
|
||||
@@ -33,9 +35,11 @@ dev = [
|
||||
requires = ["uv_build"]
|
||||
build-backend = "uv_build"
|
||||
|
||||
[tool.uv.build-backend]
|
||||
module-name = "fsfe_website_build"
|
||||
module-root = "build"
|
||||
[tool.pytest]
|
||||
addopts = ["--import-mode=importlib"]
|
||||
python_files = ["*_test.py"]
|
||||
python_functions = ["*_test"]
|
||||
testpaths = ["build/fsfe_website_build_tests*"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
# See https://docs.astral.sh/ruff/rules/ for information
|
||||
@@ -84,9 +88,10 @@ ignore = [
|
||||
"TRY003", # Dont worry about big exceptions in tests
|
||||
"S101", # Allow asserts in tests
|
||||
]
|
||||
"tools/**" = [
|
||||
"TRY003", # Allow large exception messages in code cli scripting things
|
||||
]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = ["--import-mode=importlib"]
|
||||
python_files = ["*_test.py"]
|
||||
python_functions = ["*_test"]
|
||||
testpaths = ["build/fsfe_website_build_tests*"]
|
||||
[tool.uv.build-backend]
|
||||
module-name = "fsfe_website_build"
|
||||
module-root = "build"
|
||||
|
||||
@@ -30,9 +30,6 @@ in
|
||||
libffi
|
||||
go
|
||||
# Packages for git hooks
|
||||
mediainfo
|
||||
perl
|
||||
file
|
||||
shfmt
|
||||
prettier
|
||||
php84Packages.php-cs-fixer
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Check is there are any frontpage news items that do not have an english translation
|
||||
#
|
||||
|
||||
# select all items which have the front-page tag
|
||||
exit=0
|
||||
matched_files="$(grep "<tag.*front-page" --files-with-matches "$@" || true)"
|
||||
|
||||
for file in $matched_files; do
|
||||
base="${file%.*}" # file.xx
|
||||
base="${base%.*}" # file
|
||||
sfx=${file##*.} # xhtml
|
||||
en="$base.en.$sfx" # file.en.xhtml
|
||||
if [[ ! -f "$en" ]]; then
|
||||
echo "$file has no english version"
|
||||
exit=1
|
||||
fi
|
||||
done
|
||||
|
||||
exit $exit
|
||||
5
tools/ci-checks/checks/__init__.py
Normal file
5
tools/ci-checks/checks/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
"""Module folder of checks."""
|
||||
48
tools/ci-checks/checks/check_absolute_links.py
Normal file
48
tools/ci-checks/checks/check_absolute_links.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not use absolute links to fsfe.org."""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for absolute links."""
|
||||
absolute_regex = re.compile("https?://fsfe(urope)?.org")
|
||||
failed_files_links: list[str] = []
|
||||
for file in files:
|
||||
failed_files_links.extend(
|
||||
f"{file} has absolute link {href}"
|
||||
for href in etree.parse(file).xpath("//*/@href")
|
||||
if absolute_regex.match(href)
|
||||
)
|
||||
|
||||
return len(failed_files_links) == 0, (
|
||||
"\n".join(failed_files_links)
|
||||
+ textwrap.dedent("""
|
||||
Please do not use links containing "https://fsfe.org". So instead of
|
||||
|
||||
<a href="https://fsfe.org/freesoftware/">link</a>
|
||||
|
||||
you should use:
|
||||
|
||||
<a href="/freesoftware">link</a>
|
||||
|
||||
More information about the why and how:
|
||||
https://docs.fsfe.org/en/techdocs/mainpage/editing/bestpractices#no-absolute-links-to-fsfeorg""")
|
||||
)
|
||||
36
tools/ci-checks/checks/check_encoding.py
Normal file
36
tools/ci-checks/checks/check_encoding.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files have the proper encoding."""
|
||||
|
||||
import logging
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fsfe_website_build.lib.misc import run_command
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml", "xsl"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check correct encoding."""
|
||||
failed_files: list[str] = []
|
||||
for file in files:
|
||||
encoding_result = run_command(["file", "-b", "--mime-encoding", str(file)])
|
||||
if encoding_result not in ["utf-8", "ascii"]:
|
||||
failed_files.append(f"{file} has invalid encoding {encoding_result}")
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
For the FSFE website, we strongly prefer UTF-8 encoded files.
|
||||
Everything else creates problems. Please change the file encoding in
|
||||
your text editor or with a special tool.""")
|
||||
)
|
||||
51
tools/ci-checks/checks/check_fixed_languages.py
Normal file
51
tools/ci-checks/checks/check_fixed_languages.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not use fixed language links."""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for fixed language links."""
|
||||
absolute_regex = re.compile(
|
||||
r"(https?://fsfe(urope)?.org)?/.*\.[a-z]{2}(\.html)?(#.*)?$"
|
||||
)
|
||||
failed_files_links: list[str] = []
|
||||
for file in files:
|
||||
failed_files_links.extend(
|
||||
f"{file} has absolute language link {href}"
|
||||
for href in etree.parse(file).xpath("//*/@href")
|
||||
if absolute_regex.match(href)
|
||||
)
|
||||
|
||||
return len(failed_files_links) == 0, (
|
||||
"\n".join(failed_files_links)
|
||||
+ textwrap.dedent("""
|
||||
Please do not preset a language in your links to resources on fsfe.org.
|
||||
So instead of:
|
||||
|
||||
<a href="/contribute/web.en.html">link</a>
|
||||
|
||||
you should use:
|
||||
|
||||
<a href="/contribute/web.html">link</a>
|
||||
|
||||
More information about the why and how:
|
||||
https://docs.fsfe.org/en/techdocs/mainpage/editing/bestpractices#no-fixed-language-in-internal-links""")
|
||||
)
|
||||
47
tools/ci-checks/checks/check_image_alt.py
Normal file
47
tools/ci-checks/checks/check_image_alt.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files have alt text for images."""
|
||||
|
||||
import logging
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "informational"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for images having alt text."""
|
||||
failed_files: list[str] = [
|
||||
f"{file} has an image without alt text"
|
||||
for file in files
|
||||
if (parsedFile := etree.parse(file)).xpath(
|
||||
"//img[not(@alt) or string-length(normalize-space(@alt))=0]"
|
||||
)
|
||||
or (
|
||||
parsedFile.xpath(
|
||||
"//image[not(@alt) or string-length(normalize-space(@alt))=0]"
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
This attribute is important if the image cannot be displayed, and for visually
|
||||
impaired people. You should describe the image so that it makes sense even if
|
||||
you cannot see it.
|
||||
|
||||
More information on alternative text for images:
|
||||
https://docs.fsfe.org/en/techdocs/mainpage/editing/bestpractices#alternative-text-for-images""")
|
||||
)
|
||||
73
tools/ci-checks/checks/check_image_ratio.py
Normal file
73
tools/ci-checks/checks/check_image_ratio.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files have the correct ratio for images."""
|
||||
|
||||
import io
|
||||
import logging
|
||||
import re
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import requests
|
||||
from lxml import etree
|
||||
from PIL import Image
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def _check_image_ratio(image_bytes: bytes) -> bool:
|
||||
with Image.open(io.BytesIO(image_bytes)) as img:
|
||||
width, height = img.size
|
||||
|
||||
ideal_ratio = 16 / 9
|
||||
actual_ratio = width / height
|
||||
|
||||
tolerance = 0.005 * ideal_ratio
|
||||
return (ideal_ratio - tolerance) <= actual_ratio <= (ideal_ratio + tolerance)
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for if images have the right ratio."""
|
||||
fileregex = re.compile(r"^fsfe.org/(news/|events/).*")
|
||||
failed_files: list[str] = []
|
||||
for file in [file for file in files if fileregex.match(str(file))]:
|
||||
for imageurl in etree.parse(file).xpath("//image/@url"):
|
||||
# the url may be to a remote or local image
|
||||
is_remote = imageurl.startswith(("http://", "https://"))
|
||||
image = b""
|
||||
if is_remote:
|
||||
response = requests.get(imageurl, timeout=10)
|
||||
if not response.ok:
|
||||
message = "Failed to fetch image"
|
||||
logger.error(message)
|
||||
raise RuntimeError(message)
|
||||
image: bytes = response.content
|
||||
else:
|
||||
# we should not be committing news or events files
|
||||
# with images in repo anymore
|
||||
# and figuring out how to open paths correctly is
|
||||
# actually a little tricky
|
||||
# so not implementing this for now, and can be done later if needed
|
||||
message = "Image ratio check requires remote images"
|
||||
logger.error(message)
|
||||
raise RuntimeError(message)
|
||||
if not _check_image_ratio(image):
|
||||
failed_files.append(f"{file} has {imageurl=} with invalid ratio")
|
||||
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
16:9 ratio for preview is mandatory for news items.
|
||||
|
||||
More information on preview images:
|
||||
https://docs.fsfe.org/en/techdocs/mainpage/editing/bestpractices#preview-image""")
|
||||
)
|
||||
74
tools/ci-checks/checks/check_name_newsdate_match.py
Normal file
74
tools/ci-checks/checks/check_name_newsdate_match.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files have matching filenames and newsdates."""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for mismatched file names and newsdates."""
|
||||
fileregex = re.compile(
|
||||
r"^fsfe.org/(news/20[0-9]{2}/|news/nl/|news/podcast/20[0-9]{2}/|events/20[0-9]{2}/).*"
|
||||
)
|
||||
|
||||
naming_regex = re.compile(
|
||||
""
|
||||
r"^((nl-20[0-9]{4})|episode-(special-)?[0-9]{1,3}"
|
||||
r"|(news|event)-20[0-9]{6}-[0-9]{2})\.[a-z]{2}\.(xml|xhtml)$"
|
||||
)
|
||||
newsdate_regex = re.compile(r"^20[0-9]{2}-[0-9]{2}-[0-9]{2}$")
|
||||
|
||||
failed_file_names: list[str] = []
|
||||
failed_file_newsdate: list[str] = []
|
||||
for file in [file for file in files if fileregex.match(str(file))]:
|
||||
# check filename
|
||||
if not naming_regex.match(file.name):
|
||||
failed_file_names.append(f"{file} is named incorrectly")
|
||||
# check file newsdate
|
||||
failed_file_newsdate.extend(
|
||||
f"{file} has invalid newsdate"
|
||||
for file in files
|
||||
if any(
|
||||
not newsdate_regex.match(newsdate)
|
||||
for newsdate in etree.parse(file).xpath("//html/@newsdate")
|
||||
)
|
||||
)
|
||||
# TODO: implement a way to compare date from name to date in newsdate
|
||||
# and ensure they are the same
|
||||
# Maybe use a date parser on different substrings in the name based on source?
|
||||
|
||||
return (
|
||||
len(failed_file_names) == 0 and len(failed_file_newsdate) == 0,
|
||||
"\n".join(failed_file_names)
|
||||
+ textwrap.dedent("""
|
||||
The scheme is:
|
||||
* "news-20YYMMDD-01.en.xhtml" for news
|
||||
* "nl-20YYMM.en.xhtml" for newsletters
|
||||
* "episode-N.en.xhtml" for podcast episodes
|
||||
* "event-20YYMMDD-01.en.xml" for events
|
||||
|
||||
If there is more than one news item per date, count the "-01"
|
||||
onwards. Of course, the ".en" can also be the code for another
|
||||
language we support.
|
||||
""")
|
||||
+ "\n".join(failed_file_newsdate)
|
||||
+ textwrap.dedent("""
|
||||
The scheme is \"20YY-MM-DD\", so the respective line should look
|
||||
something like this: <html newsdate=\"2020-01-01\">"""),
|
||||
)
|
||||
83
tools/ci-checks/checks/check_new_tags.py
Normal file
83
tools/ci-checks/checks/check_new_tags.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not add new tags."""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "informational"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml", "xsl"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for newly added tags."""
|
||||
fileregex = re.compile(r"^fsfe.org/(news/|events/).*")
|
||||
|
||||
new_tags: list[str] = [] # List of new tag messages
|
||||
|
||||
# Get all relevant files in the news and events directories
|
||||
# For seeing if tags already exist
|
||||
base_dir = Path()
|
||||
relevant_files: list[Path] = []
|
||||
for pattern in [
|
||||
"fsfe.org/news/**/*.xhtml",
|
||||
"fsfe.org/news/**/*.xml",
|
||||
"fsfe.org/news/**/*.xsl",
|
||||
"fsfe.org/events/**/*.xhtml",
|
||||
"fsfe.org/events/**/*.xml",
|
||||
"fsfe.org/events/**/*.xsl",
|
||||
]:
|
||||
relevant_files.extend(base_dir.glob(pattern))
|
||||
|
||||
for file in files:
|
||||
if not fileregex.match(str(file)):
|
||||
continue
|
||||
# parse the current file
|
||||
tree = etree.parse(file)
|
||||
|
||||
# iterate over tag keys
|
||||
for tag_key in tree.xpath("//tag/@key"):
|
||||
# Check if this tag exists in any other file
|
||||
found_in_other = False
|
||||
for other_file in relevant_files:
|
||||
# Ignore the file itself
|
||||
if other_file == file.relative_to(base_dir):
|
||||
continue
|
||||
|
||||
other_tree = etree.parse(
|
||||
other_file,
|
||||
)
|
||||
# check if there are kays with the key in the other file
|
||||
other_tags = other_tree.xpath(f'//tag[@key="{tag_key}"]')
|
||||
if other_tags:
|
||||
found_in_other = True
|
||||
|
||||
if not found_in_other:
|
||||
new_tags.append(f"{file} adds new tag: {tag_key}")
|
||||
|
||||
return len(new_tags) == 0, (
|
||||
"\n".join(new_tags)
|
||||
+ textwrap.dedent("""
|
||||
Please make sure that you use already used tags, and only introduce a
|
||||
new tag e.g. if it's about a new campaign that will be more often
|
||||
mentioned in news or events. If you feel unsure, please ask
|
||||
<web@lists.fsfe.org>.
|
||||
|
||||
Here you will find the currently used tags:
|
||||
https://fsfe.org/tags/tags.html
|
||||
|
||||
Please make another commit to replace a new tag with an already
|
||||
existing one unless you are really sure. Thank you.""")
|
||||
)
|
||||
42
tools/ci-checks/checks/check_non_en_frontpage_news.py
Normal file
42
tools/ci-checks/checks/check_non_en_frontpage_news.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not have frontpage news in non english."""
|
||||
|
||||
import logging
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fsfe_website_build.lib.misc import (
|
||||
get_basepath,
|
||||
)
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for frontpage news."""
|
||||
failed_files: list[str] = [
|
||||
str(file)
|
||||
for file in files
|
||||
if etree.parse(file).xpath("//tag[@key='front-page']")
|
||||
and not (
|
||||
(file_path := Path(file)).parent
|
||||
/ f"{get_basepath(file_path).name}.en{file_path.suffix}"
|
||||
).exists()
|
||||
]
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
The above files have no english version
|
||||
and are marked for the front page:""")
|
||||
)
|
||||
40
tools/ci-checks/checks/check_plain_email.py
Normal file
40
tools/ci-checks/checks/check_plain_email.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not have unobfustucated emails."""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "informational"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml", "xsl"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for plaintext emails."""
|
||||
email_regex = re.compile(
|
||||
r"[A-Za-z-+]*@fsfe.org(?!<\/email)", re.IGNORECASE | re.MULTILINE
|
||||
)
|
||||
failed_files: list[str] = [
|
||||
f"{file} has plaintext email"
|
||||
for file in files
|
||||
if email_regex.search(file.read_text())
|
||||
]
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
Plaintext email addresses are trivial to crawl for by bots:
|
||||
There is a simple solution: wrap the email address(es) in <email>...</email>.
|
||||
|
||||
More information on obfuscated email addresses:
|
||||
https://fsfe.org/contribute/web/features.html#emails""")
|
||||
)
|
||||
42
tools/ci-checks/checks/check_style_attrib.py
Normal file
42
tools/ci-checks/checks/check_style_attrib.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not use style elements."""
|
||||
|
||||
import logging
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "informational"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for style elements."""
|
||||
failed_files: list[str] = [
|
||||
f"{file} contains a style element"
|
||||
for file in files
|
||||
if etree.parse(file).xpath("//*[@style]")
|
||||
]
|
||||
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
Please do not use style attributes to design an element. So instead of:
|
||||
|
||||
<p style="color: red;">text</p>
|
||||
|
||||
use CSS classes instead, or create them if necessary.
|
||||
|
||||
More information why this is bad style, and what to do instead:
|
||||
https://docs.fsfe.org/en/techdocs/mainpage/editing/bestpractices#no-in-line-css""")
|
||||
)
|
||||
38
tools/ci-checks/checks/check_style_elem.py
Normal file
38
tools/ci-checks/checks/check_style_elem.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files do not use style elements."""
|
||||
|
||||
import logging
|
||||
import textwrap
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for style elements."""
|
||||
failed_files: list[str] = [
|
||||
f"{file} contains a style element"
|
||||
for file in files
|
||||
if etree.parse(file).xpath("//style")
|
||||
]
|
||||
|
||||
return len(failed_files) == 0, (
|
||||
"\n".join(failed_files)
|
||||
+ textwrap.dedent("""
|
||||
Please do not use <style> elements to define CSS rules for a file.
|
||||
|
||||
More information why this is bad style, and what to do instead:
|
||||
https://docs.fsfe.org/en/techdocs/mainpage/editing/bestpractices#no-in-line-css""")
|
||||
)
|
||||
32
tools/ci-checks/checks/check_versions.py
Normal file
32
tools/ci-checks/checks/check_versions.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files have one version and that it is an integer."""
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from lxml import etree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]: # noqa: ARG001
|
||||
"""Check for missing/too many/non integer versions."""
|
||||
invalid_files: list[str] = [
|
||||
f"{file} has missing/too many/non integer version attribute"
|
||||
for file in files
|
||||
if (versions := etree.parse(file).xpath("/*/version")) is None
|
||||
or len(versions) != 1
|
||||
or not versions[0].text.isdigit()
|
||||
]
|
||||
|
||||
return len(invalid_files) == 0, "\n".join(invalid_files)
|
||||
81
tools/ci-checks/checks/check_xml_structure.py
Normal file
81
tools/ci-checks/checks/check_xml_structure.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files match xml structure across languages."""
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fsfe_website_build.lib.checks import (
|
||||
compare_files,
|
||||
)
|
||||
from fsfe_website_build.lib.misc import (
|
||||
get_basepath,
|
||||
get_version,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import multiprocessing.pool
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHECK_TYPE = "critical"
|
||||
ALLOWED_EXTENSIONS = {".xhtml", ".xml"}
|
||||
|
||||
|
||||
def _job(master: Path, other: Path, whitelist: set[str]) -> str | None:
|
||||
"""Return a result string for starmap."""
|
||||
try:
|
||||
if get_version(master) != get_version(other):
|
||||
return None
|
||||
errs = compare_files(master, other, whitelist)
|
||||
return (
|
||||
f"There were differences between {master} and {other}:\n{'\n'.join(errs)}"
|
||||
if errs
|
||||
else None
|
||||
)
|
||||
except Exception as e:
|
||||
return f"Exception occurred comparing {master} and {other}: ERROR {e}"
|
||||
|
||||
|
||||
def check(files: list[Path], pool: multiprocessing.pool.Pool) -> tuple[bool, str]:
|
||||
"""Check for xml structure differences."""
|
||||
whitelist = {
|
||||
"//discussion/@href", # Mastodon links can be in different langs
|
||||
"/html/translator", # the translator
|
||||
"//image/@alt", # Image alt text for title image
|
||||
"//img/@alt", # Image alt text
|
||||
"//input[@name='language']", # Input language types
|
||||
"//label[@for='address']",
|
||||
"//label[@for='email']",
|
||||
"//label[@for='name']", # city and many others
|
||||
"//label[@for='phone']",
|
||||
"//label[@for='zip']", # zip code localisation
|
||||
"//profileimage/@alt", # Profilemage alt text for about/people images
|
||||
"//track/@label", # Language label, used in some track elements
|
||||
"//track/@srclang", # Languages, used in some track elements
|
||||
}
|
||||
groups: defaultdict[tuple[Path, str], list[Path]] = defaultdict(list)
|
||||
for file in files:
|
||||
path = file.resolve()
|
||||
groups[(get_basepath(path), path.suffix)].append(path)
|
||||
|
||||
tasks: list[tuple[Path, Path, set[str]]] = []
|
||||
for path_data, paths in groups.items():
|
||||
basepath, suffix = path_data
|
||||
if (master := basepath.parent / f"{basepath.name}.en{suffix}").exists():
|
||||
tasks.extend((master, path, whitelist) for path in paths if path != master)
|
||||
else:
|
||||
logger.warning(
|
||||
"No english translation of %s with suffix %s exists - skipping",
|
||||
basepath,
|
||||
suffix,
|
||||
)
|
||||
|
||||
filtered_results = [
|
||||
result for result in pool.starmap(_job, tasks) if result is not None
|
||||
]
|
||||
return len(filtered_results) == 0, "\n".join(filtered_results)
|
||||
@@ -1,127 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Check that the passed files match xml structure across languages."""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import multiprocessing
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
from fsfe_website_build.lib.checks import (
|
||||
compare_files,
|
||||
)
|
||||
from fsfe_website_build.lib.misc import (
|
||||
get_basepath,
|
||||
get_version,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _job(master: Path, other: Path, whitelist: set[str]) -> str | None:
|
||||
"""Return a result string for starmap."""
|
||||
try:
|
||||
if get_version(master) != get_version(other):
|
||||
return None
|
||||
errs = compare_files(master, other, whitelist)
|
||||
return (
|
||||
f"There were differences between {master} and {other}:\n{'\n'.join(errs)}"
|
||||
if errs
|
||||
else None
|
||||
)
|
||||
except Exception as e:
|
||||
return f"Exception occurred comparing {master} and {other}: ERROR {e}"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Check that the passed files match xml structure across languages."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Compare XML structure and attributes. "
|
||||
"Use --multi for space-separated list + parallel compares.",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument("files", nargs="*", help="XML file(s)")
|
||||
parser.add_argument(
|
||||
"-w",
|
||||
"--whitelist",
|
||||
nargs="+",
|
||||
type=str,
|
||||
default=[
|
||||
"//body/@class", # Top level body classes
|
||||
"//discussion/@href", # Mastodon links can be in different langs
|
||||
"//image/@alt", # Image alt text for title image
|
||||
"//img/@alt", # Image alt text
|
||||
"//input[@name='language']", # Input language types
|
||||
"//label[@for='address']",
|
||||
"//label[@for='email']",
|
||||
"//label[@for='name']", # city and many others
|
||||
"//label[@for='phone']",
|
||||
"//label[@for='zip']", # zip code localisation
|
||||
"//profileimage/@alt", # Profilemage alt text for about/people images
|
||||
"//track/@label", # Language label, used in some track elements
|
||||
"//track/@srclang", # Languages, used in some track elements
|
||||
"/html/translator", # the translator
|
||||
],
|
||||
help="XPATHS that we then ignore.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--log-level",
|
||||
type=str,
|
||||
default="INFO",
|
||||
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||
help="Set the logging level",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--jobs",
|
||||
type=int,
|
||||
default=multiprocessing.cpu_count(),
|
||||
help="Parallel workers",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
level=args.log_level,
|
||||
)
|
||||
|
||||
groups: defaultdict[tuple[Path, str], list[Path]] = defaultdict(list)
|
||||
for file in args.files:
|
||||
path = Path(file).resolve()
|
||||
groups[(get_basepath(path), path.suffix)].append(path)
|
||||
|
||||
tasks: list[tuple[Path, Path, set[str]]] = []
|
||||
for path_data, paths in groups.items():
|
||||
basepath, suffix = path_data
|
||||
if (master := basepath.parent / f"{basepath.name}.en{suffix}").exists():
|
||||
tasks.extend(
|
||||
(master, path, args.whitelist) for path in paths if path != master
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"No english translation of %s with suffix %s exists - skipping",
|
||||
basepath,
|
||||
suffix,
|
||||
)
|
||||
|
||||
with multiprocessing.Pool(processes=args.jobs) as pool:
|
||||
filtered_results = [
|
||||
result for result in pool.starmap(_job, tasks) if result is not None
|
||||
]
|
||||
if filtered_results:
|
||||
for result in filtered_results:
|
||||
logger.info(result)
|
||||
logger.error("Some comparisons failed, exiting")
|
||||
sys.exit(1)
|
||||
|
||||
logger.info("All comparisons succeeded, success")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
167
tools/ci-checks/run_checks.py
Executable file
167
tools/ci-checks/run_checks.py
Executable file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-FileCopyrightText: Free Software Foundation Europe e.V. <https://fsfe.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""Runs a variety of checks."""
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import logging
|
||||
import multiprocessing
|
||||
import multiprocessing.pool
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from types import ModuleType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def load_check_modules(check_dir: Path) -> tuple[list[ModuleType], list[ModuleType]]:
|
||||
"""Dynamically load all check modules from a directory."""
|
||||
# Ensure the check_dir is in sys.path so it's importable
|
||||
if str(check_dir) not in sys.path:
|
||||
sys.path.insert(0, str(check_dir))
|
||||
|
||||
critical_modules: list[ModuleType] = []
|
||||
informational_modules: list[ModuleType] = []
|
||||
if not check_dir.exists() or not check_dir.is_dir():
|
||||
raise FileNotFoundError(f"Check directory not found: {check_dir}")
|
||||
|
||||
for file in sorted(check_dir.iterdir()):
|
||||
if file.name.startswith("check_") and file.suffix == ".py":
|
||||
module_name = f"checks.{file.stem}"
|
||||
|
||||
# Load module from file
|
||||
spec = importlib.util.spec_from_file_location(module_name, file)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError("Failed to load %s.", file)
|
||||
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
# Register it to prevent pickle issues
|
||||
sys.modules[module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
# Ensure it has the required function
|
||||
if (
|
||||
not hasattr(module, "check")
|
||||
or not hasattr(module, "ALLOWED_EXTENSIONS")
|
||||
or not hasattr(module, "CHECK_TYPE")
|
||||
or module.CHECK_TYPE not in ["critical", "informational"]
|
||||
or not callable(module.check)
|
||||
):
|
||||
raise RuntimeError("%s. missing some required attr", file)
|
||||
if module.CHECK_TYPE == "critical":
|
||||
critical_modules.append(module)
|
||||
elif module.CHECK_TYPE == "informational":
|
||||
informational_modules.append(module)
|
||||
else:
|
||||
raise RuntimeError("%s CHECK_TYPE invalid", file)
|
||||
|
||||
return critical_modules, informational_modules
|
||||
|
||||
|
||||
def run_module_list(
|
||||
files: list[Path], modules: list[ModuleType], pool: multiprocessing.pool.Pool
|
||||
) -> bool:
|
||||
"""Run a list of modules on passed files, using passed pool."""
|
||||
all_passed = True
|
||||
for module in modules:
|
||||
# Filter files by extension based on ALLOWED_EXTENSIONS
|
||||
filtered_files: list[Path] = [
|
||||
file for file in files if file.suffix in module.ALLOWED_EXTENSIONS
|
||||
]
|
||||
# Skip check if no relevant files
|
||||
if not filtered_files:
|
||||
logger.debug("%s: no relevant files, skipping", module)
|
||||
continue
|
||||
logger.debug("%s: Running", module)
|
||||
success, message = module.check(filtered_files, pool)
|
||||
if not success:
|
||||
logger.error(message)
|
||||
all_passed = False
|
||||
else:
|
||||
logger.debug("Check Passed!")
|
||||
return all_passed
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Check the passed files."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Check passed files.",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument("files", nargs="*", type=Path, help="Files to be checked")
|
||||
parser.add_argument(
|
||||
"--log-level",
|
||||
type=str,
|
||||
default="INFO",
|
||||
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||
help="Set the logging level",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--jobs",
|
||||
type=int,
|
||||
default=multiprocessing.cpu_count(),
|
||||
help="Parallel workers",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
level=args.log_level,
|
||||
)
|
||||
try:
|
||||
critical_modules, informational_modules = load_check_modules(
|
||||
Path("./tools/ci-checks/checks")
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Error loading check modules: %s")
|
||||
sys.exit(1)
|
||||
with multiprocessing.Pool(processes=args.jobs) as pool:
|
||||
# Run each check
|
||||
try:
|
||||
logger.info("Beginning Informational checks!")
|
||||
logger.info(
|
||||
"One may commit if these fail,"
|
||||
" but should consider fixing the issues raised!\n\n"
|
||||
)
|
||||
informational_checks_successful = run_module_list(
|
||||
args.files, informational_modules, pool
|
||||
)
|
||||
logger.info("Informational Checks finished!\n\n")
|
||||
logger.info("Beginning Critical checks!")
|
||||
logger.info("One must fix raised issues before being able to commit!\n\n")
|
||||
critical_checks_successful = run_module_list(
|
||||
args.files, critical_modules, pool
|
||||
)
|
||||
logger.info("Critical Checks finished!\n\n")
|
||||
if not informational_checks_successful:
|
||||
logger.warning(
|
||||
"Some informational checks failed,"
|
||||
" check messages and consider errors!"
|
||||
)
|
||||
else:
|
||||
logger.info("All informational checks passed.")
|
||||
|
||||
if not critical_checks_successful:
|
||||
logger.error(
|
||||
"Some critical checks failed, check messages and fix errors!"
|
||||
)
|
||||
sys.exit(1)
|
||||
else:
|
||||
logger.info("All critical checks passed.")
|
||||
sys.exit(0)
|
||||
|
||||
except Exception:
|
||||
logger.exception("Check failed to run correctly: %s")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
369
uv.lock
generated
369
uv.lock
generated
@@ -13,15 +13,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.14.2"
|
||||
version = "4.14.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "soupsieve" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -35,11 +35,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.11.12"
|
||||
version = "2026.1.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -102,14 +102,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.0"
|
||||
version = "8.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -123,11 +123,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "cssselect"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/0a/c3ea9573b1dc2e151abfe88c7fe0c26d1892fe6ed02d0cdb30f0d57029d5/cssselect-1.3.0.tar.gz", hash = "sha256:57f8a99424cfab289a1b6a816a43075a4b00948c86b4dcf3ef4ee7e15f7ab0c7", size = 42870, upload-time = "2025-03-10T09:30:29.638Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ec/2e/cdfd8b01c37cbf4f9482eefd455853a3cf9c995029a46acd31dfaa9c1dd6/cssselect-1.4.0.tar.gz", hash = "sha256:fdaf0a1425e17dfe8c5cf66191d211b357cf7872ae8afc4c6762ddd8ac47fc92", size = 40589, upload-time = "2026-01-29T07:00:26.701Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/58/257350f7db99b4ae12b614a36256d9cc870d71d9e451e79c2dc3b23d7c3c/cssselect-1.3.0-py3-none-any.whl", hash = "sha256:56d1bf3e198080cc1667e137bc51de9cadfca259f03c2d4e09037b3e01e30f0d", size = 18786, upload-time = "2025-03-10T09:30:28.048Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/0c/7bb51e3acfafd16c48875bf3db03607674df16f5b6ef8d056586af7e2b8b/cssselect-1.4.0-py3-none-any.whl", hash = "sha256:c0ec5c0191c8ee39fcc8afc1540331d8b55b0183478c50e9c8a79d44dbceb1d8", size = 18540, upload-time = "2026-01-29T07:00:24.994Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -156,6 +156,8 @@ dependencies = [
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "lefthook" },
|
||||
{ name = "pillow" },
|
||||
{ name = "pyright" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-mock" },
|
||||
{ name = "reuse" },
|
||||
@@ -179,6 +181,8 @@ requires-dist = [
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "lefthook" },
|
||||
{ name = "pillow" },
|
||||
{ name = "pyright" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-mock" },
|
||||
{ name = "reuse" },
|
||||
@@ -220,20 +224,20 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "joblib"
|
||||
version = "1.5.2"
|
||||
version = "1.5.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lefthook"
|
||||
version = "2.0.4"
|
||||
version = "2.0.15"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fa/9b/51e950ae394e77b606cd220a2cfbe5216b9df52abe4ac3491408c6665b8d/lefthook-2.0.4.tar.gz", hash = "sha256:4962717a4db4474929ca269e8f4766ca99a6cf88db399f98ffc36d49939f3359", size = 54466984, upload-time = "2025-11-13T09:08:23.148Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7c/8f/e90724128f481c637b7e9343b6535622cfa136541959a49f8a3de0d0e7a5/lefthook-2.0.15.tar.gz", hash = "sha256:8a32c9f2d44f0ff0f3e3ab48f9802ca10f1222b491f3f14e03f577ec175b6649", size = 50175274, upload-time = "2026-01-13T10:02:58.76Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/7f/dc7c506d1df93affb720910c7ca57a45064a997ea551966734063f8c7512/lefthook-2.0.4-py3-none-any.whl", hash = "sha256:2aa8c4d3ccd3b9d12d31967d58817c54390bc175034e699143bc29d81add57eb", size = 54721020, upload-time = "2025-11-13T09:08:18.644Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/d5/243d967f541d422a7252f92dbcc201cfd588bd404a66935baacc83be49c5/lefthook-2.0.15-py3-none-any.whl", hash = "sha256:54b174520f18a4fa2545ff1e5eae4c4d2515539fb25b8c4fe04b9224a2ff07ee", size = 50416709, upload-time = "2026-01-13T10:02:55.761Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -338,21 +342,63 @@ wheels = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
name = "nodeenv"
|
||||
version = "1.10.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, upload-time = "2025-04-19T11:48:59.673Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "26.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.5.0"
|
||||
version = "4.9.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -366,11 +412,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.23"
|
||||
version = "3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -382,9 +428,22 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.408"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nodeenv" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.1"
|
||||
version = "9.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
@@ -393,9 +452,9 @@ dependencies = [
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -412,23 +471,23 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "python-debian"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "charset-normalizer" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/4b/3c4cf635311b6203f17c2d693dc15e898969983dd3f729bee3c428aa60d4/python-debian-1.0.1.tar.gz", hash = "sha256:3ada9b83a3d671b58081782c0969cffa0102f6ce433fbbc7cf21275b8b5cc771", size = 127249, upload-time = "2025-03-11T12:27:27.245Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/f4/ec7ba072029399a89a2670bcef4df79c52f2efaa672f86e0a86252313333/python_debian-1.1.0.tar.gz", hash = "sha256:afe3c7267d81c29c79ab44d803a0756d0796b0e41bb0a05c5cafcdd2b980d4e6", size = 127848, upload-time = "2026-02-09T02:13:24.491Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/15/e8096189b18dda72e4923622abc10b021ecff723b397e22eff29fb86637b/python_debian-1.0.1-py3-none-any.whl", hash = "sha256:8f137c230c1d9279c2ac892b35915068b2aca090c9fd3da5671ff87af32af12c", size = 137453, upload-time = "2025-03-11T12:27:25.014Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/66/af49103279c07900b89b7ebac53111910aa8eb6d898be0b47220036b0b03/python_debian-1.1.0-py3-none-any.whl", hash = "sha256:3e553b6d0b886272a26649e13106e33c382bcd21c80b09f5c0c81fc7c8c8c743", size = 137984, upload-time = "2026-02-09T02:13:22.54Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-iso639"
|
||||
version = "2025.11.11"
|
||||
version = "2026.1.31"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/89/6f/45bc5ae1c132ab7852a8642d66d25ffff6e4b398195127ac66158d3b5f4d/python_iso639-2025.11.11.tar.gz", hash = "sha256:75fab30f1a0f46b4e8161eafb84afe4ecd07eaada05e2c5364f14b0f9c864477", size = 173897, upload-time = "2025-11-11T15:23:00.893Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a3/da/701fc47ea3b0579a8ae489d50d5b54f2ef3aeb7768afd31db1d1cfe9f24e/python_iso639-2026.1.31.tar.gz", hash = "sha256:55a1612c15e5fbd3a1fa269a309cbf1e7c13019356e3d6f75bb435ed44c45ddb", size = 174144, upload-time = "2026-01-31T15:04:48.105Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/03/69/081960288e4cd541cbdb90e1768373e1198b040bf2ae40cd25b9c9799205/python_iso639-2025.11.11-py3-none-any.whl", hash = "sha256:02ea4cfca2c189b5665e4e8adc8c17c62ab6e4910932541a23baddea33207ea2", size = 167723, upload-time = "2025-11-11T15:22:59.819Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/3a/03ee682b04099e6b02b591955851b0347deb2e3691ae850112000c54ba12/python_iso639-2026.1.31-py3-none-any.whl", hash = "sha256:b2c48fa1300af1299dff4f1e1995ad1059996ed9f22270ea2d6d6bdc5fb03d4c", size = 167757, upload-time = "2026-01-31T15:04:46.458Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -442,38 +501,42 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "2025.11.3"
|
||||
version = "2026.1.15"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669, upload-time = "2025-11-03T21:34:22.089Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0b/86/07d5056945f9ec4590b518171c4254a5925832eb727b56d3c38a7476f316/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5", size = 414811, upload-time = "2026-01-14T23:18:02.775Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089, upload-time = "2025-11-03T21:32:50.027Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059, upload-time = "2025-11-03T21:32:51.682Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900, upload-time = "2025-11-03T21:32:53.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010, upload-time = "2025-11-03T21:32:55.222Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893, upload-time = "2025-11-03T21:32:57.239Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522, upload-time = "2025-11-03T21:32:59.274Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272, upload-time = "2025-11-03T21:33:01.393Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958, upload-time = "2025-11-03T21:33:03.379Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289, upload-time = "2025-11-03T21:33:05.374Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026, upload-time = "2025-11-03T21:33:07.131Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499, upload-time = "2025-11-03T21:33:09.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604, upload-time = "2025-11-03T21:33:10.9Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320, upload-time = "2025-11-03T21:33:12.572Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372, upload-time = "2025-11-03T21:33:14.219Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985, upload-time = "2025-11-03T21:33:16.555Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669, upload-time = "2025-11-03T21:33:18.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030, upload-time = "2025-11-03T21:33:20.048Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674, upload-time = "2025-11-03T21:33:21.797Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451, upload-time = "2025-11-03T21:33:23.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980, upload-time = "2025-11-03T21:33:25.999Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852, upload-time = "2025-11-03T21:33:27.852Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566, upload-time = "2025-11-03T21:33:32.364Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463, upload-time = "2025-11-03T21:33:34.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694, upload-time = "2025-11-03T21:33:36.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691, upload-time = "2025-11-03T21:33:39.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583, upload-time = "2025-11-03T21:33:41.302Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286, upload-time = "2025-11-03T21:33:43.324Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741, upload-time = "2025-11-03T21:33:45.557Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/0a/47fa888ec7cbbc7d62c5f2a6a888878e76169170ead271a35239edd8f0e8/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac", size = 489170, upload-time = "2026-01-14T23:16:19.835Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/c4/d000e9b7296c15737c9301708e9e7fbdea009f8e93541b6b43bdb8219646/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6", size = 291146, upload-time = "2026-01-14T23:16:21.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/b6/921cc61982e538682bdf3bdf5b2c6ab6b34368da1f8e98a6c1ddc503c9cf/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2", size = 288986, upload-time = "2026-01-14T23:16:23.381Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/33/eb7383dde0bbc93f4fb9d03453aab97e18ad4024ac7e26cef8d1f0a2cff0/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846", size = 799098, upload-time = "2026-01-14T23:16:25.088Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/56/b664dccae898fc8d8b4c23accd853f723bde0f026c747b6f6262b688029c/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b", size = 864980, upload-time = "2026-01-14T23:16:27.297Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/40/0999e064a170eddd237bae9ccfcd8f28b3aa98a38bf727a086425542a4fc/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e", size = 911607, upload-time = "2026-01-14T23:16:29.235Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/78/c77f644b68ab054e5a674fb4da40ff7bffb2c88df58afa82dbf86573092d/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde", size = 803358, upload-time = "2026-01-14T23:16:31.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/31/d4292ea8566eaa551fafc07797961c5963cf5235c797cc2ae19b85dfd04d/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5", size = 775833, upload-time = "2026-01-14T23:16:33.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/b2/cff3bf2fea4133aa6fb0d1e370b37544d18c8350a2fa118c7e11d1db0e14/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34", size = 788045, upload-time = "2026-01-14T23:16:35.005Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/99/2cb9b69045372ec877b6f5124bda4eb4253bc58b8fe5848c973f752bc52c/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75", size = 859374, upload-time = "2026-01-14T23:16:36.919Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/16/710b0a5abe8e077b1729a562d2f297224ad079f3a66dce46844c193416c8/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e", size = 763940, upload-time = "2026-01-14T23:16:38.685Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/d1/7585c8e744e40eb3d32f119191969b91de04c073fca98ec14299041f6e7e/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160", size = 850112, upload-time = "2026-01-14T23:16:40.646Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/d6/43e1dd85df86c49a347aa57c1f69d12c652c7b60e37ec162e3096194a278/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1", size = 789586, upload-time = "2026-01-14T23:16:42.799Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/38/77142422f631e013f316aaae83234c629555729a9fbc952b8a63ac91462a/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1", size = 271691, upload-time = "2026-01-14T23:16:44.671Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/a9/ab16b4649524ca9e05213c1cdbb7faa85cc2aa90a0230d2f796cbaf22736/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903", size = 280422, upload-time = "2026-01-14T23:16:46.607Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/2a/20fd057bf3521cb4791f69f869635f73e0aaf2b9ad2d260f728144f9047c/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705", size = 273467, upload-time = "2026-01-14T23:16:48.967Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/77/0b1e81857060b92b9cad239104c46507dd481b3ff1fa79f8e7f865aae38a/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8", size = 492073, upload-time = "2026-01-14T23:16:51.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/f3/f8302b0c208b22c1e4f423147e1913fd475ddd6230565b299925353de644/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf", size = 292757, upload-time = "2026-01-14T23:16:53.08Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/f0/ef55de2460f3b4a6da9d9e7daacd0cb79d4ef75c64a2af316e68447f0df0/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d", size = 291122, upload-time = "2026-01-14T23:16:55.383Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/55/bb8ccbacabbc3a11d863ee62a9f18b160a83084ea95cdfc5d207bfc3dd75/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84", size = 807761, upload-time = "2026-01-14T23:16:57.251Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/84/f75d937f17f81e55679a0509e86176e29caa7298c38bd1db7ce9c0bf6075/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df", size = 873538, upload-time = "2026-01-14T23:16:59.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/d9/0da86327df70349aa8d86390da91171bd3ca4f0e7c1d1d453a9c10344da3/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434", size = 915066, upload-time = "2026-01-14T23:17:01.607Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/5e/f660fb23fc77baa2a61aa1f1fe3a4eea2bbb8a286ddec148030672e18834/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a", size = 812938, upload-time = "2026-01-14T23:17:04.366Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/33/a47a29bfecebbbfd1e5cd3f26b28020a97e4820f1c5148e66e3b7d4b4992/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10", size = 781314, upload-time = "2026-01-14T23:17:06.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/ec/7ec2bbfd4c3f4e494a24dec4c6943a668e2030426b1b8b949a6462d2c17b/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac", size = 795652, upload-time = "2026-01-14T23:17:08.521Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/79/a5d8651ae131fe27d7c521ad300aa7f1c7be1dbeee4d446498af5411b8a9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea", size = 868550, upload-time = "2026-01-14T23:17:10.573Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/b7/25635d2809664b79f183070786a5552dd4e627e5aedb0065f4e3cf8ee37d/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e", size = 769981, upload-time = "2026-01-14T23:17:12.871Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/8b/fc3fcbb2393dcfa4a6c5ffad92dc498e842df4581ea9d14309fcd3c55fb9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521", size = 854780, upload-time = "2026-01-14T23:17:14.837Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/38/dde117c76c624713c8a2842530be9c93ca8b606c0f6102d86e8cd1ce8bea/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db", size = 799778, upload-time = "2026-01-14T23:17:17.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload-time = "2026-01-14T23:17:19.301Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload-time = "2026-01-14T23:17:21.231Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload-time = "2026-01-14T23:17:23.146Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -508,153 +571,153 @@ sdist = { url = "https://files.pythonhosted.org/packages/05/35/298d9410b3635107c
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.14.5"
|
||||
version = "0.15.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/fa/fbb67a5780ae0f704876cb8ac92d6d76da41da4dc72b7ed3565ab18f2f52/ruff-0.14.5.tar.gz", hash = "sha256:8d3b48d7d8aad423d3137af7ab6c8b1e38e4de104800f0d596990f6ada1a9fc1", size = 5615944, upload-time = "2025-11-13T19:58:51.155Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/68/31/c07e9c535248d10836a94e4f4e8c5a31a1beed6f169b31405b227872d4f4/ruff-0.14.5-py3-none-linux_armv6l.whl", hash = "sha256:f3b8248123b586de44a8018bcc9fefe31d23dda57a34e6f0e1e53bd51fd63594", size = 13171630, upload-time = "2025-11-13T19:57:54.894Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/5c/283c62516dca697cd604c2796d1487396b7a436b2f0ecc3fd412aca470e0/ruff-0.14.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f7a75236570318c7a30edd7f5491945f0169de738d945ca8784500b517163a72", size = 13413925, upload-time = "2025-11-13T19:57:59.181Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/f3/aa319f4afc22cb6fcba2b9cdfc0f03bbf747e59ab7a8c5e90173857a1361/ruff-0.14.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d146132d1ee115f8802356a2dc9a634dbf58184c51bff21f313e8cd1c74899a", size = 12574040, upload-time = "2025-11-13T19:58:02.056Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/7f/cb5845fcc7c7e88ed57f58670189fc2ff517fe2134c3821e77e29fd3b0c8/ruff-0.14.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2380596653dcd20b057794d55681571a257a42327da8894b93bbd6111aa801f", size = 13009755, upload-time = "2025-11-13T19:58:05.172Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/d2/bcbedbb6bcb9253085981730687ddc0cc7b2e18e8dc13cf4453de905d7a0/ruff-0.14.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d1fa985a42b1f075a098fa1ab9d472b712bdb17ad87a8ec86e45e7fa6273e68", size = 12937641, upload-time = "2025-11-13T19:58:08.345Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/58/e25de28a572bdd60ffc6bb71fc7fd25a94ec6a076942e372437649cbb02a/ruff-0.14.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88f0770d42b7fa02bbefddde15d235ca3aa24e2f0137388cc15b2dcbb1f7c7a7", size = 13610854, upload-time = "2025-11-13T19:58:11.419Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/24/43bb3fd23ecee9861970978ea1a7a63e12a204d319248a7e8af539984280/ruff-0.14.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3676cb02b9061fee7294661071c4709fa21419ea9176087cb77e64410926eb78", size = 15061088, upload-time = "2025-11-13T19:58:14.551Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/44/a022f288d61c2f8c8645b24c364b719aee293ffc7d633a2ca4d116b9c716/ruff-0.14.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b595bedf6bc9cab647c4a173a61acf4f1ac5f2b545203ba82f30fcb10b0318fb", size = 14734717, upload-time = "2025-11-13T19:58:17.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/58/81/5c6ba44de7e44c91f68073e0658109d8373b0590940efe5bd7753a2585a3/ruff-0.14.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f55382725ad0bdb2e8ee2babcbbfb16f124f5a59496a2f6a46f1d9d99d93e6e2", size = 14028812, upload-time = "2025-11-13T19:58:20.533Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/ef/41a8b60f8462cb320f68615b00299ebb12660097c952c600c762078420f8/ruff-0.14.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497d19dce23976bdaca24345ae131a1d38dcfe1b0850ad8e9e6e4fa321a6e19", size = 13825656, upload-time = "2025-11-13T19:58:23.345Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/00/207e5de737fdb59b39eb1fac806904fe05681981b46d6a6db9468501062e/ruff-0.14.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:410e781f1122d6be4f446981dd479470af86537fb0b8857f27a6e872f65a38e4", size = 13959922, upload-time = "2025-11-13T19:58:26.537Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/7e/fa1f5c2776db4be405040293618846a2dece5c70b050874c2d1f10f24776/ruff-0.14.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c01be527ef4c91a6d55e53b337bfe2c0f82af024cc1a33c44792d6844e2331e1", size = 12932501, upload-time = "2025-11-13T19:58:29.822Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/d8/d86bf784d693a764b59479a6bbdc9515ae42c340a5dc5ab1dabef847bfaa/ruff-0.14.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f66e9bb762e68d66e48550b59c74314168ebb46199886c5c5aa0b0fbcc81b151", size = 12927319, upload-time = "2025-11-13T19:58:32.923Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/de/ee0b304d450ae007ce0cb3e455fe24fbcaaedae4ebaad6c23831c6663651/ruff-0.14.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d93be8f1fa01022337f1f8f3bcaa7ffee2d0b03f00922c45c2207954f351f465", size = 13206209, upload-time = "2025-11-13T19:58:35.952Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/aa/193ca7e3a92d74f17d9d5771a765965d2cf42c86e6f0fd95b13969115723/ruff-0.14.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c135d4b681f7401fe0e7312017e41aba9b3160861105726b76cfa14bc25aa367", size = 13953709, upload-time = "2025-11-13T19:58:39.002Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/f1/7119e42aa1d3bf036ffc9478885c2e248812b7de9abea4eae89163d2929d/ruff-0.14.5-py3-none-win32.whl", hash = "sha256:c83642e6fccfb6dea8b785eb9f456800dcd6a63f362238af5fc0c83d027dd08b", size = 12925808, upload-time = "2025-11-13T19:58:42.779Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/9d/7c0a255d21e0912114784e4a96bf62af0618e2190cae468cd82b13625ad2/ruff-0.14.5-py3-none-win_amd64.whl", hash = "sha256:9d55d7af7166f143c94eae1db3312f9ea8f95a4defef1979ed516dbb38c27621", size = 14331546, upload-time = "2025-11-13T19:58:45.691Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/80/69756670caedcf3b9be597a6e12276a6cf6197076eb62aad0c608f8efce0/ruff-0.14.5-py3-none-win_arm64.whl", hash = "sha256:4b700459d4649e2594b31f20a9de33bc7c19976d4746d8d0798ad959621d64a4", size = 13433331, upload-time = "2025-11-13T19:58:48.434Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soupsieve"
|
||||
version = "2.8"
|
||||
version = "2.8.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tdewolff-minify"
|
||||
version = "2.24.7"
|
||||
version = "2.24.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/6d/0bfb7ac55546690fdb5c3f8fa5d43e1618bff4e688bbd8ebcc58487f260d/tdewolff_minify-2.24.7.tar.gz", hash = "sha256:63b7066a67c6f117934fc64dd3609a6fb5f8f9186b385343efaeb6693aded627", size = 3694070, upload-time = "2025-11-08T08:56:28.217Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1c/aa/69091c2f8499bb95e0b46578e71eaf5292e9b21637a9df12057efd285624/tdewolff_minify-2.24.8.tar.gz", hash = "sha256:1f4163f6bb8fdfb27438d531fc63933cc535508f4a57c7f9217888d786ad763e", size = 3694071, upload-time = "2025-12-08T13:08:03.963Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/0a/adc88fdb484ca4b710a34117227fd0e22df6a65e87f58f581a9cad5e0c62/tdewolff_minify-2.24.7-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:34227ec8a78f4cfc76c7b5c6879a3c680953923fbab0d83a2d117140cd40f093", size = 2084470, upload-time = "2025-11-08T08:55:58.327Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/6f/bf20d2d9b856a19f9a359caf4882aa9a8cab82659d45819f8805e5047ee8/tdewolff_minify-2.24.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19f79615af84b9d465cb8f881b2b4d0054d9c69416d752f78f59d36acbe72e7a", size = 3902309, upload-time = "2025-11-08T08:55:59.768Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/2b/0d27d777a3f0e3c7232def747fbb404390956debae69a4ede46b723cf636/tdewolff_minify-2.24.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:795ee7c22a4c2860f6687de8a77bead70ca944207f39a9675b5122f441f0e860", size = 3620150, upload-time = "2025-11-08T08:56:00.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/c8/8b000b99f15e564cb940f5179e1481b7a3b88483bde650999dd28c42829f/tdewolff_minify-2.24.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2cc97500de2e85734f1f2ecaeba4dfb4e413e1c029c196d0657098db75336ddf", size = 3438232, upload-time = "2025-11-08T08:56:02.479Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/0e/864c5e51c26e78564a25d62aedfde83f5f16f2fe08337fd3ad7fd95af0b8/tdewolff_minify-2.24.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:097bb7bb110b8d47224696479d90068428a859b46e0369649fe61340748a8ecc", size = 3715723, upload-time = "2025-11-08T08:56:03.659Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/9f/6d31aefede6a0cc0f484dbaca4d2770ec9253a0a1e33a2267ee4ea566a4e/tdewolff_minify-2.24.7-cp314-cp314-win_amd64.whl", hash = "sha256:c033ba059995246626debba0843bf87b2dd167c989f02168e94611bb694f0093", size = 3716828, upload-time = "2025-11-08T08:56:04.879Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/00/664f2279f0d8bcd37c9893aa16a967b1bde40fc62264dad4421aea086d49/tdewolff_minify-2.24.7-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7db0bbc94d483f5d59fea87860d9c0a7691cc361df66e8a137bc1d57c69e5507", size = 2084472, upload-time = "2025-11-08T08:56:06.092Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/5d/c88f400623e5ed8d00a34d3f4958a51502c5c80127fdd9c2e54729e10d03/tdewolff_minify-2.24.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:385ccc7df026dcc6057785b9ec0cd7ebf27b1df5afd87a3899da165b3aa2a7ef", size = 3902309, upload-time = "2025-11-08T08:56:07.26Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/ef/b6ff62120a0de435aea4440be390501ca43021fcdeec2a5efb49a6c9a856/tdewolff_minify-2.24.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6965e983e351bc73445025d45f874165683403b74611560458e7fdcf2064ed9", size = 3620152, upload-time = "2025-11-08T08:56:08.386Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/4d/d2cb974ca67af741736377c62c57c3466ce223005e0caa36377fd87a9052/tdewolff_minify-2.24.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fed2c8794b12aa950a61307e41837e9e1ca35820158b8bb196666ad7570850bf", size = 3438233, upload-time = "2025-11-08T08:56:09.589Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/e8/a04c25a5801349e53e2df143c1f1a77703f8dabeb5a6053c304e59d13be7/tdewolff_minify-2.24.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2d68fd60d94fcc7ccec2d3b734120c0a38c85f24b696e6cae7c4081919770cea", size = 3715725, upload-time = "2025-11-08T08:56:10.806Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/fb/d0c03ee765639ff4c4ba06b247b56edb8314623fe7efb3f06d7e1c3a2a33/tdewolff_minify-2.24.7-cp314-cp314t-win_amd64.whl", hash = "sha256:7338637f1c7b7a2f3d6b354ecae04e4dcf76e3b2e4089f38192efc0793d280dc", size = 3716829, upload-time = "2025-11-08T08:56:12.352Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/f0/bf9c33414175226e1d92d478350f59f2e0ff5ff273d45d73b9bafd4dda3d/tdewolff_minify-2.24.8-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9eaf43b301a3915956dae933a2671927bdad371987beb6550b464aa776f4ddb", size = 2084437, upload-time = "2025-12-08T13:07:29.512Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/b3/f6b322cdf6f64d35f1ad8bb227da9eb7070ba4256192705eac0cc9b36a53/tdewolff_minify-2.24.8-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:287769c6c88bc70d8929fd68d9e74f90fe08f2b767bbad8eaecc0dbea21a4436", size = 3977290, upload-time = "2025-12-08T13:07:31.16Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/a4/371a54b28b8f9d18c2a9b0edccc8c0693885f2881e6966c4066bf05dabbd/tdewolff_minify-2.24.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e9637198c46f8105a16b982c56a478be35e956652a62335a20aa1345c2edfe2", size = 3651688, upload-time = "2025-12-08T13:07:32.67Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/c3/67baa7c0230c5224c93eeca3dab3a57a2c099d64243908369e5f1212d541/tdewolff_minify-2.24.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d5db2b229a84889bb2362aa02c44a99010d3ec4913461c1cc55473c5a83f1ac0", size = 3437790, upload-time = "2025-12-08T13:07:34.085Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/57/c6face693639ebdc730e39a53cbb0c3ebea23ad0c2015cc0e9b05a302780/tdewolff_minify-2.24.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0319f803cd26b5b6d1956fdc0c2a2b723377fc9d4bcc7a746c555e7121d79d51", size = 3715504, upload-time = "2025-12-08T13:07:35.761Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/5a/27b7e1f515ce421e64d3e181246a7442f5e3a728df7ecbd2059cd7d95e76/tdewolff_minify-2.24.8-cp314-cp314-win_amd64.whl", hash = "sha256:4af0d853e860a312707d257058965987eb61e1957c342fb0596b6dbadd256add", size = 3716533, upload-time = "2025-12-08T13:07:37.142Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/2c/6506f074b4ba4fd5775c7efb445d624e8af11ec1485281d2c72f7e824d4f/tdewolff_minify-2.24.8-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:dd956508971c1e37416afad5ff6d13d5afb4163b6b2a4c1be8be887b13ee7944", size = 2084438, upload-time = "2025-12-08T13:07:38.761Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/50/03d71acd6c9cca5bd0ad41c0bd2ed566218b7ca4aca1a9bb445ff8b65aae/tdewolff_minify-2.24.8-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cc27b832fc8e2e2b9db9f30f2250fc16b8b57643854d10864580f317dc496b9f", size = 3977291, upload-time = "2025-12-08T13:07:40.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/8c/06cff11585cb697fa7015be01313329f902a69a63f0f4ecfec834eb807c5/tdewolff_minify-2.24.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efd02e17985b8ae15173387b50ff4d7d87f811c281be9cd3dc454164e02058f9", size = 3651688, upload-time = "2025-12-08T13:07:41.7Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/54/97c1439deda48a728b8538414af9c1deb3e290c383ee614d720ac568f450/tdewolff_minify-2.24.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49acc327d36eb654973bc0035b187fa44ad89cd0fc3912624315882b56391faf", size = 3437789, upload-time = "2025-12-08T13:07:43.112Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/82/7e7bdc2c3c85081a5b30835c7cdca38f304762957093dda11a05a147381c/tdewolff_minify-2.24.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d922d51ea91222f76e52015c02b73b67fd2ae9f6b67f06047d47086dd67f27b6", size = 3715505, upload-time = "2025-12-08T13:07:44.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/21/f923f8079f7d53c78ad6fc87b9bf4c6aef88802e357c099474f9564e1838/tdewolff_minify-2.24.8-cp314-cp314t-win_amd64.whl", hash = "sha256:6d166afc3444737dfaa20ee16f9526b3f81ab689757f49bf23933f33ed8d93a2", size = 3716535, upload-time = "2025-12-08T13:07:45.873Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tombi"
|
||||
version = "0.7.11"
|
||||
version = "0.7.31"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/df/2d28eef46563798d4ca17f0d0826b94e8eb430edef15f5b7efc3b44aadec/tombi-0.7.11.tar.gz", hash = "sha256:82d1c41d34da3a6a7c4e11b181edc26fb2fd13bf76ea5f3447a53a0444fbc091", size = 472046, upload-time = "2025-12-25T16:14:59.71Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ea/e6/f32e480e8b164b3439bd31c73b3d87a18bc5e3c3d02ac7f5d352266befc7/tombi-0.7.31.tar.gz", hash = "sha256:5332a7462568daf344c97a0c60cc35e51f2a5cf8e697b251db5e4371eb134ff6", size = 493144, upload-time = "2026-02-17T17:10:45.412Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/47/f077bf798d6af40c2669b6a9533978993193d51bca75613959679fe76c73/tombi-0.7.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f0e6305c12f8a5e471a9159064bacbab4fd93de328b5db6c828aa7da15ca2acc", size = 9064434, upload-time = "2025-12-25T16:14:50.292Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/d9/290d506d6685849ccd6012f4253de1bb10037def31925cf6c182da42a1c2/tombi-0.7.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:65475db4d1f68c3bfa8e5119db733071184489fb9120d666e8d6f0cad821f087", size = 8770616, upload-time = "2025-12-25T16:14:48.444Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/87/cf0268e9986241fb867b7269fb77a2429987dccf7e2843e7c47f044de6dd/tombi-0.7.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69d55708c1ccf651ae626bad6a5ba0e7f6b5102373905e48ffc76a7fdf37cfab", size = 8971843, upload-time = "2025-12-25T16:14:37.976Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/73/772385c3fbf5598cc1521716ef6f3d71eac54fcffd1d67c8d1553f3e903b/tombi-0.7.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f8243d31259804009a1960ee3e8cdf5aec3151a6625be5109937b118c8d36d2", size = 10098451, upload-time = "2025-12-25T16:14:44.093Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/54/00c278fecb341fff0b08e4c24b0f9af59356b9cefe79e784842e9c187ff5/tombi-0.7.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1307059a1cbed9a9a4add2f6a340986156aeee3830b9c6686ba5b88baabdfb6c", size = 10197359, upload-time = "2025-12-25T16:14:39.871Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/11/d47663b128497a9b290f78d49925d1e2b6d8117d49148dbf15c50850a316/tombi-0.7.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b42adcc15025e81818686313d830b0ef47c505f0451768574ddd1e4198a63724", size = 9108951, upload-time = "2025-12-25T16:14:41.969Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/ff/6b85c162e27de3232e8548ef18fd49a87da43886cad28f48358d8004959e/tombi-0.7.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55fc218065d33b34cf1dbcafb0d5e9be0dcc5a346a00df420130cadb36c18029", size = 9405453, upload-time = "2025-12-25T16:14:46.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/91/f59cb04601ac6edcb63a2e6c3f98c788adddf6893e2f788b7029acc29fa7/tombi-0.7.11-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:234a1624959d6adb89e10cad7847e6270a28c40fb1f3c0444c7f2e9519a5de49", size = 9245316, upload-time = "2025-12-25T16:14:35.679Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/98/ac113e7aa01b89150ab689555b56f7d70c169156e153dfab6095d09cc2b5/tombi-0.7.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e05862a896913de66ffb152c354d793376a1ab74c2241c2fb7255820b2a081b9", size = 9266952, upload-time = "2025-12-25T16:14:52.237Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/14/33cbfc9d3ba013e74453dfd6cace2cf1d118161ded758325c4ecd46b58e3/tombi-0.7.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:bdfbf018b6f7bd39a3f572d98ced85d77b91b86736623d728b271f168165ac45", size = 8992879, upload-time = "2025-12-25T16:14:54.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/e0/91aaaa7435a8d5cab49e10066be37b908016a38dd7ecb89398d92907dec5/tombi-0.7.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f295d870c7f6f2e88bcce69a4cb527a3f821f55b42e010c5e1fd81e3c7eed253", size = 9570488, upload-time = "2025-12-25T16:14:56.361Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/ec/dbe8c4d937a82a0d04a44b8e34b05ce8bfc489fec04f4489e5562292705b/tombi-0.7.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:510daab10c7f77329cb2c1c6c64a3692ddf4e04746a08e9f642d19a4b5000f68", size = 9633925, upload-time = "2025-12-25T16:14:58.138Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/8a/c2c8205b0cde7472df2b7377eb853edf6f8d2f2320478059d383e0ca92ac/tombi-0.7.11-py3-none-win32.whl", hash = "sha256:f1f7f35dc60302adf64a3e16b7125f8d56a4c445a37e71d58d363cc45a30cb1d", size = 7142499, upload-time = "2025-12-25T16:15:03.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/86/d1762e54e3372713efaf18318a90673f810567e5c7a3e7936e74485be1ab/tombi-0.7.11-py3-none-win_amd64.whl", hash = "sha256:50a969d00d0fc4e85d84e01353afa603014550dc2e56a5a502f4ebd614bb03b2", size = 8326898, upload-time = "2025-12-25T16:15:01.276Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/4d/2242fba01383cd6d92f350f0277e4d89e1ff2dc87d23dcf8ff7d0839ae0b/tombi-0.7.31-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8dc17f29fe752e21d6c4c3eddff3b34ff765111633483850d0c5edd7c03ca854", size = 8886445, upload-time = "2026-02-17T17:10:36.991Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/48/ec6a8e3d6884926833fc20703088fb1915fd0385fe6340cc40547e81faca/tombi-0.7.31-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a42e3a1625e966c4eef01293d3243730c041059b9073816968b62d57b586130f", size = 8609324, upload-time = "2026-02-17T17:10:35.237Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/12/989502e3b01620ed5e267456d91e7eb1fa678232273c57205db625b6453f/tombi-0.7.31-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d29e2e497a53ab961ddaef125a3bea8b67f55605a5256a1f7c5846594cba5e52", size = 8817624, upload-time = "2026-02-17T17:10:25.846Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/27/1e25d654cfc7ba59b13d08ccc4f6bd5253da23fefb7e9eb7e2560caa9841/tombi-0.7.31-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55bc8abfe7fcb01974a0f6911dddd948f98bf98221cb8eba426bd4fe362af91f", size = 9952445, upload-time = "2026-02-17T17:10:31.38Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/9e/ff6d710505afc5ea873178d92a7cc4a50a89eb548a48718dfad6c460ba5f/tombi-0.7.31-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a46f066e1f0ca63f723a83b52dbdfec8fcd21fad23eb4d76d24192da4975967c", size = 10068931, upload-time = "2026-02-17T17:10:27.519Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/91/bece25790fc299376255babf527063b6d33821511986135c1060c36babc5/tombi-0.7.31-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86131c017ce128308b22a41923217c3b27dfe8cf6ea6a7c78045aab82b49d3cc", size = 8987347, upload-time = "2026-02-17T17:10:29.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/29/3fd9e83e1c2e28f019199ff42c5c14750a82190863f391536aa7681b76a0/tombi-0.7.31-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54ee818268d67cf0ec6a1148abaffcd64e217f9d4ddc1bbbcbaeca2f3596775a", size = 9255182, upload-time = "2026-02-17T17:10:33.585Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/90/ef4f2347f9486c9968ddcb5a79ce2aad38f3d0ee01db9e90e8d82684fe92/tombi-0.7.31-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:1d12b33f7eea8404d1448f5f29d2b3765fed6a819e379c81430a219d671471ee", size = 9080726, upload-time = "2026-02-17T17:10:23.715Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/cf/1740726f506fc1cb1773b038b07a43f9c07c43196f0abeaa04ae9c093b38/tombi-0.7.31-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d33efd3aa9b5b404cee597c92cc6e4e9c7492cf5353ca965cfe4277e99bfc3d3", size = 9117347, upload-time = "2026-02-17T17:10:38.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/62/d0eb5a80726aa53223535ea9b5a01a89ac36611d74dbf1e6563266ca1d2d/tombi-0.7.31-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ecaa051f3424e4571e8489cc08ca075654310d20eed6bd209ba040014096b588", size = 8863022, upload-time = "2026-02-17T17:10:40.472Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/09/ccadf98ad7ef3c24f70ffe27b59e5423c9f2f712eac172679abdb425ee4a/tombi-0.7.31-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b54c28e321f8dbfee2561d224159d35285edcfcc7f4c83772c1b6314a826fc2", size = 9425178, upload-time = "2026-02-17T17:10:42.125Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/b3/6b459b1ae8a78eb4e0acfb9dabdcda9a5e6463d4272b3becbc9378e9af2f/tombi-0.7.31-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8f44cba5198e445a629e6c525b1a5ba32bb283d357e25ac2aaf5d997e0d10f40", size = 9461979, upload-time = "2026-02-17T17:10:43.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/d3/23dd2fbde00368707a16d6587be4581b2cd979624858440b2d762e5471df/tombi-0.7.31-py3-none-win32.whl", hash = "sha256:c740e03ee70018edf948447c4b0b44b2ac57d148b7b6355ef258902eb6563ebe", size = 7024683, upload-time = "2026-02-17T17:10:48.648Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/27/acafcf84790b85286b1563bab3d2026aba35a1894a4b98c21d041f8005c2/tombi-0.7.31-py3-none-win_amd64.whl", hash = "sha256:5af24999a185bb1d003dc28429ad4549e65aa986b92410a35ffa4306233116d3", size = 8171473, upload-time = "2026-02-17T17:10:46.479Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.13.3"
|
||||
version = "0.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tqdm"
|
||||
version = "4.67.1"
|
||||
version = "4.67.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty"
|
||||
version = "0.0.14"
|
||||
version = "0.0.17"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/af/57/22c3d6bf95c2229120c49ffc2f0da8d9e8823755a1c3194da56e51f1cc31/ty-0.0.14.tar.gz", hash = "sha256:a691010565f59dd7f15cf324cdcd1d9065e010c77a04f887e1ea070ba34a7de2", size = 5036573, upload-time = "2026-01-27T00:57:31.427Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/c3/41ae6346443eedb65b96761abfab890a48ce2aa5a8a27af69c5c5d99064d/ty-0.0.17.tar.gz", hash = "sha256:847ed6c120913e280bf9b54d8eaa7a1049708acb8824ad234e71498e8ad09f97", size = 5167209, upload-time = "2026-02-13T13:26:36.835Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/99/cb/cc6d1d8de59beb17a41f9a614585f884ec2d95450306c173b3b7cc090d2e/ty-0.0.14-py3-none-linux_armv6l.whl", hash = "sha256:32cf2a7596e693094621d3ae568d7ee16707dce28c34d1762947874060fdddaa", size = 10034228, upload-time = "2026-01-27T00:57:53.133Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/96/dd42816a2075a8f31542296ae687483a8d047f86a6538dfba573223eaf9a/ty-0.0.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f971bf9805f49ce8c0968ad53e29624d80b970b9eb597b7cbaba25d8a18ce9a2", size = 9939162, upload-time = "2026-01-27T00:57:43.857Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/b4/73c4859004e0f0a9eead9ecb67021438b2e8e5fdd8d03e7f5aca77623992/ty-0.0.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:45448b9e4806423523268bc15e9208c4f3f2ead7c344f615549d2e2354d6e924", size = 9418661, upload-time = "2026-01-27T00:58:03.411Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/58/35/839c4551b94613db4afa20ee555dd4f33bfa7352d5da74c5fa416ffa0fd2/ty-0.0.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee94a9b747ff40114085206bdb3205a631ef19a4d3fb89e302a88754cbbae54c", size = 9837872, upload-time = "2026-01-27T00:57:23.718Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/2b/bbecf7e2faa20c04bebd35fc478668953ca50ee5847ce23e08acf20ea119/ty-0.0.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6756715a3c33182e9ab8ffca2bb314d3c99b9c410b171736e145773ee0ae41c3", size = 9848819, upload-time = "2026-01-27T00:57:58.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/60/3c0ba0f19c0f647ad9d2b5b5ac68c0f0b4dc899001bd53b3a7537fb247a2/ty-0.0.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89d0038a2f698ba8b6fec5cf216a4e44e2f95e4a5095a8c0f57fe549f87087c2", size = 10324371, upload-time = "2026-01-27T00:57:29.291Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/32/99d0a0b37d0397b0a989ffc2682493286aa3bc252b24004a6714368c2c3d/ty-0.0.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c64a83a2d669b77f50a4957039ca1450626fb474619f18f6f8a3eb885bf7544", size = 10865898, upload-time = "2026-01-27T00:57:33.542Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/88/30b583a9e0311bb474269cfa91db53350557ebec09002bfc3fb3fc364e8c/ty-0.0.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:242488bfb547ef080199f6fd81369ab9cb638a778bb161511d091ffd49c12129", size = 10555777, upload-time = "2026-01-27T00:58:05.853Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/a2/cb53fb6325dcf3d40f2b1d0457a25d55bfbae633c8e337bde8ec01a190eb/ty-0.0.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4790c3866f6c83a4f424fc7d09ebdb225c1f1131647ba8bdc6fcdc28f09ed0ff", size = 10412913, upload-time = "2026-01-27T00:57:38.834Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/8f/f2f5202d725ed1e6a4e5ffaa32b190a1fe70c0b1a2503d38515da4130b4c/ty-0.0.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:950f320437f96d4ea9a2332bbfb5b68f1c1acd269ebfa4c09b6970cc1565bd9d", size = 9837608, upload-time = "2026-01-27T00:57:55.898Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/ba/59a2a0521640c489dafa2c546ae1f8465f92956fede18660653cce73b4c5/ty-0.0.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4a0ec3ee70d83887f86925bbc1c56f4628bd58a0f47f6f32ddfe04e1f05466df", size = 9884324, upload-time = "2026-01-27T00:57:46.786Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/95/8d2a49880f47b638743212f011088552ecc454dd7a665ddcbdabea25772a/ty-0.0.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1a4e6b6da0c58b34415955279eff754d6206b35af56a18bb70eb519d8d139ef", size = 10033537, upload-time = "2026-01-27T00:58:01.149Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/40/4523b36f2ce69f92ccf783855a9e0ebbbd0f0bb5cdce6211ee1737159ed3/ty-0.0.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dc04384e874c5de4c5d743369c277c8aa73d1edea3c7fc646b2064b637db4db3", size = 10495910, upload-time = "2026-01-27T00:57:26.691Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/d5/655beb51224d1bfd4f9ddc0bb209659bfe71ff141bcf05c418ab670698f0/ty-0.0.14-py3-none-win32.whl", hash = "sha256:b20e22cf54c66b3e37e87377635da412d9a552c9bf4ad9fc449fed8b2e19dad2", size = 9507626, upload-time = "2026-01-27T00:57:41.43Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/d9/c569c9961760e20e0a4bc008eeb1415754564304fd53997a371b7cf3f864/ty-0.0.14-py3-none-win_amd64.whl", hash = "sha256:e312ff9475522d1a33186657fe74d1ec98e4a13e016d66f5758a452c90ff6409", size = 10437980, upload-time = "2026-01-27T00:57:36.422Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/0c/186829654f5bfd9a028f6648e9caeb11271960a61de97484627d24443f91/ty-0.0.14-py3-none-win_arm64.whl", hash = "sha256:b6facdbe9b740cb2c15293a1d178e22ffc600653646452632541d01c36d5e378", size = 9885831, upload-time = "2026-01-27T00:57:49.747Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/01/0ef15c22a1c54b0f728ceff3f62d478dbf8b0dcf8ff7b80b954f79584f3e/ty-0.0.17-py3-none-linux_armv6l.whl", hash = "sha256:64a9a16555cc8867d35c2647c2f1afbd3cae55f68fd95283a574d1bb04fe93e0", size = 10192793, upload-time = "2026-02-13T13:27:13.943Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/2c/f4c322d9cded56edc016b1092c14b95cf58c8a33b4787316ea752bb9418e/ty-0.0.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eb2dbd8acd5c5a55f4af0d479523e7c7265a88542efe73ed3d696eb1ba7b6454", size = 10051977, upload-time = "2026-02-13T13:26:57.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/a5/43746c1ff81e784f5fc303afc61fe5bcd85d0fcf3ef65cb2cef78c7486c7/ty-0.0.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f18f5fd927bc628deb9ea2df40f06b5f79c5ccf355db732025a3e8e7152801f6", size = 9564639, upload-time = "2026-02-13T13:26:42.781Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/b8/280b04e14a9c0474af574f929fba2398b5e1c123c1e7735893b4cd73d13c/ty-0.0.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5383814d1d7a5cc53b3b07661856bab04bb2aac7a677c8d33c55169acdaa83df", size = 10061204, upload-time = "2026-02-13T13:27:00.152Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/d7/493e1607d8dfe48288d8a768a2adc38ee27ef50e57f0af41ff273987cda0/ty-0.0.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c20423b8744b484f93e7bf2ef8a9724bca2657873593f9f41d08bd9f83444c9", size = 10013116, upload-time = "2026-02-13T13:26:34.543Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/ef/22f3ed401520afac90dbdf1f9b8b7755d85b0d5c35c1cb35cf5bd11b59c2/ty-0.0.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6f5b1aba97db9af86517b911674b02f5bc310750485dc47603a105bd0e83ddd", size = 10533623, upload-time = "2026-02-13T13:26:31.449Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/ce/744b15279a11ac7138832e3a55595706b4a8a209c9f878e3ab8e571d9032/ty-0.0.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:488bce1a9bea80b851a97cd34c4d2ffcd69593d6c3f54a72ae02e5c6e47f3d0c", size = 11069750, upload-time = "2026-02-13T13:26:48.638Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/be/1133c91f15a0e00d466c24f80df486d630d95d1b2af63296941f7473812f/ty-0.0.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8df66b91ec84239420985ec215e7f7549bfda2ac036a3b3c065f119d1c06825a", size = 10870862, upload-time = "2026-02-13T13:26:54.715Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/4a/a2ed209ef215b62b2d3246e07e833081e07d913adf7e0448fc204be443d6/ty-0.0.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:002139e807c53002790dfefe6e2f45ab0e04012e76db3d7c8286f96ec121af8f", size = 10628118, upload-time = "2026-02-13T13:26:45.439Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/0c/87476004cb5228e9719b98afffad82c3ef1f84334bde8527bcacba7b18cb/ty-0.0.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6c4e01f05ce82e5d489ab3900ca0899a56c4ccb52659453780c83e5b19e2b64c", size = 10038185, upload-time = "2026-02-13T13:27:02.693Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/4b/98f0b3ba9aef53c1f0305519536967a4aa793a69ed72677b0a625c5313ac/ty-0.0.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2b226dd1e99c0d2152d218c7e440150d1a47ce3c431871f0efa073bbf899e881", size = 10047644, upload-time = "2026-02-13T13:27:05.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/e0/06737bb80aa1a9103b8651d2eb691a7e53f1ed54111152be25f4a02745db/ty-0.0.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8b11f1da7859e0ad69e84b3c5ef9a7b055ceed376a432fad44231bdfc48061c2", size = 10231140, upload-time = "2026-02-13T13:27:10.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/79/e2a606bd8852383ba9abfdd578f4a227bd18504145381a10a5f886b4e751/ty-0.0.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c04e196809ff570559054d3e011425fd7c04161529eb551b3625654e5f2434cb", size = 10718344, upload-time = "2026-02-13T13:26:51.66Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/2d/2663984ac11de6d78f74432b8b14ba64d170b45194312852b7543cf7fd56/ty-0.0.17-py3-none-win32.whl", hash = "sha256:305b6ed150b2740d00a817b193373d21f0767e10f94ac47abfc3b2e5a5aec809", size = 9672932, upload-time = "2026-02-13T13:27:08.522Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/b5/39be78f30b31ee9f5a585969930c7248354db90494ff5e3d0756560fb731/ty-0.0.17-py3-none-win_amd64.whl", hash = "sha256:531828267527aee7a63e972f54e5eee21d9281b72baf18e5c2850c6b862add83", size = 10542138, upload-time = "2026-02-13T13:27:17.084Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/b7/f875c729c5d0079640c75bad2c7e5d43edc90f16ba242f28a11966df8f65/ty-0.0.17-py3-none-win_arm64.whl", hash = "sha256:de9810234c0c8d75073457e10a84825b9cd72e6629826b7f01c7a0b266ae25b1", size = 10023068, upload-time = "2026-02-13T13:26:39.637Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-html5lib"
|
||||
version = "1.1.11.20251115"
|
||||
version = "1.1.11.20251117"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "types-webencodings" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/09/750cc27de71af3fd9eac061fd23e472730b49d8f06eb7d128a48e41549c7/types_html5lib-1.1.11.20251115.tar.gz", hash = "sha256:a4b666a06e496d7b2a9489dc9206f09a249fab7c62865ac6024cec24628b15d3", size = 17934, upload-time = "2025-11-15T03:00:17.107Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c8/f3/d9a1bbba7b42b5558a3f9fe017d967f5338cf8108d35991d9b15fdea3e0d/types_html5lib-1.1.11.20251117.tar.gz", hash = "sha256:1a6a3ac5394aa12bf547fae5d5eff91dceec46b6d07c4367d9b39a37f42f201a", size = 18100, upload-time = "2025-11-17T03:08:00.78Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/65/db/4d96bd8a069d3c3c3105e4a961a356cbac6aef162d25defb842bf8e50874/types_html5lib-1.1.11.20251115-py3-none-any.whl", hash = "sha256:6cee9173cdf4a3494174b84c8c78adffabb8a1d4f532da4edaad3ec1643fc6e7", size = 24074, upload-time = "2025-11-15T03:00:16.242Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/ab/f5606db367c1f57f7400d3cb3bead6665ee2509621439af1b29c35ef6f9e/types_html5lib-1.1.11.20251117-py3-none-any.whl", hash = "sha256:2a3fc935de788a4d2659f4535002a421e05bea5e172b649d33232e99d4272d08", size = 24302, upload-time = "2025-11-17T03:07:59.996Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-lxml"
|
||||
version = "2025.8.25"
|
||||
version = "2026.2.16"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "beautifulsoup4" },
|
||||
{ name = "cssselect" },
|
||||
{ name = "types-html5lib" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/3e/a545ece610c1bd9699addd887edfe9477a8f647c4336ba75cfb0561d197c/types_lxml-2025.8.25.tar.gz", hash = "sha256:79b9f5b1f236f937f14fe3add9dc687bd8d4111ca5df58eb9f1bde1a3b032fd5", size = 156126, upload-time = "2025-08-26T06:28:56.793Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/dd/ad/c70ac8cbdc28eb58a17301c69b4925af54b614e47f9b2ebc9de5cc10f786/types_lxml-2026.2.16.tar.gz", hash = "sha256:b3a1340cc06db98d541c785732f6f68bea438daff4e2b7809ef748d545d01406", size = 161204, upload-time = "2026-02-17T02:34:50.855Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/29/c45f567b4142288b8184f073af8f659abd134c21de055f971c65f2d755bd/types_lxml-2025.8.25-py3-none-any.whl", hash = "sha256:d61340e5329e102d3f8d64124e90d50c12c0bfeaa9088d65558279ef4e7138ac", size = 95318, upload-time = "2025-08-26T06:28:54.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/5c/03ec9befbf4bb5309bfd576c6a5ac1c75633f78f6b64cf1f594e97cd3d23/types_lxml-2026.2.16-py3-none-any.whl", hash = "sha256:5dd81ffa54830e5f361988737c5f1d6a0ae48b2742790637ec560df790ea0401", size = 97040, upload-time = "2026-02-17T02:34:49.286Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -677,9 +740,9 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.5.0"
|
||||
version = "2.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user