From 713d03f0b070aa8afa70a85bc62c09e1d3201fb6 Mon Sep 17 00:00:00 2001 From: Chris Griffith Date: Mon, 6 Apr 2026 18:45:23 -0500 Subject: [PATCH 1/5] - Adding MSI (Windows Installer) and MPP (Microsoft Project) detection to CFBF scanner - Fixing #146 OOXML detection now uses `[Content_Types].xml` content types as primary method, correctly identifying docx/xlsx/pptx files from LibreOffice, Google Docs, and other non-Microsoft tools (thanks to jonasdeboeck79) - Fixing ZIP deep scan now inspects all ZIP files instead of short-circuiting on .zip extension - Fixing mz5 HDF5 scanner typo in chromatogram dataset name --- CHANGELOG.md | 8 + puremagic/main.py | 2 +- puremagic/scanners/cfbf_scanner.py | 55 ++- puremagic/scanners/hdf5_scanner.py | 2 +- puremagic/scanners/zip_scanner.py | 159 ++++++- test/test_scanners.py | 82 ++++ uv.lock | 639 ++++++++++++++++------------- 7 files changed, 638 insertions(+), 309 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6300553..43971e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Changelog ========= +Version 2.2.0 +------------- + +- Adding MSI (Windows Installer) and MPP (Microsoft Project) detection to CFBF scanner +- Fixing #146 OOXML detection now uses `[Content_Types].xml` content types as primary method, correctly identifying docx/xlsx/pptx files from LibreOffice, Google Docs, and other non-Microsoft tools (thanks to jonasdeboeck79) +- Fixing ZIP deep scan now inspects all ZIP files instead of short-circuiting on .zip extension +- Fixing mz5 HDF5 scanner typo in chromatogram dataset name + Version 2.1.1 ------------- diff --git a/puremagic/main.py b/puremagic/main.py index 56942c6..1e2a20b 100644 --- a/puremagic/main.py +++ b/puremagic/main.py @@ -35,7 +35,7 @@ ) __author__ = "Chris Griffith" -__version__ = "2.1.1" +__version__ = "2.2.0" __all__ = [ "magic_file", "magic_string", diff --git a/puremagic/scanners/cfbf_scanner.py b/puremagic/scanners/cfbf_scanner.py index 5ecaf10..ec62426 100644 --- a/puremagic/scanners/cfbf_scanner.py +++ b/puremagic/scanners/cfbf_scanner.py @@ -24,6 +24,32 @@ ("__substg1.0_", ".msg", "Outlook Message", "application/vnd.ms-outlook"), ] +# Multi-stream detection: all listed streams must be present. +# Each entry: (required_streams, extension, name, mime_type) +_MULTI_STREAM_MATCHES = [ + (("_StringPool", "_StringData"), ".msi", "Windows Installer Package", "application/x-msi"), +] + +# Root directory entry CLSIDs that identify specific formats. +# CLSIDs are stored in mixed-endian format in CFBF files. +# Each entry: (clsid_bytes, extension, name, mime_type) +_CLSID_MATCHES = [ + # Microsoft Project 98/2000/2002/2003: {74b78f3a-c8c8-11d1-be11-00c04fb6faf1} + ( + b"\x3a\x8f\xb7\x74\xc8\xc8\xd1\x11\xbe\x11\x00\xc0\x4f\xb6\xfa\xf1", + ".mpp", + "Microsoft Project", + "application/vnd.ms-project", + ), + # Microsoft Project 4.x: {72fd3320-9a05-11cf-85a4-00a0c904de5f} + ( + b"\x20\x33\xfd\x72\x05\x9a\xcf\x11\x85\xa4\x00\xa0\xc9\x04\xde\x5f", + ".mpp", + "Microsoft Project", + "application/vnd.ms-project", + ), +] + def _extract_stream_names(dir_data: bytes) -> set[str]: """Parse CFBF directory entries and return the set of stream/storage names.""" @@ -45,8 +71,19 @@ def _extract_stream_names(dir_data: bytes) -> set[str]: return names -def _identify_format(stream_names: set[str]) -> Match | None: - """Match stream names against known CFBF format signatures.""" +def _extract_root_clsid(dir_data: bytes) -> bytes | None: + """Extract the CLSID from the root directory entry (obj_type 5).""" + for i in range(0, len(dir_data), 128): + entry = dir_data[i : i + 128] + if len(entry) < 96: + break + if entry[66] == 5: # Root storage + return entry[80:96] + return None + + +def _identify_format(stream_names: set[str], dir_data: bytes) -> Match | None: + """Match stream names and CLSIDs against known CFBF format signatures.""" # Check prefix matches first (e.g. __substg1.0_ for MSG) for name in stream_names: for prefix, ext, fmt_name, mime in _PREFIX_MATCHES: @@ -58,6 +95,18 @@ def _identify_format(stream_names: set[str]) -> Match | None: if stream_name in stream_names: return Match(ext, fmt_name, mime) + # Check multi-stream matches (all required streams must be present) + for required_streams, ext, fmt_name, mime in _MULTI_STREAM_MATCHES: + if all(s in stream_names for s in required_streams): + return Match(ext, fmt_name, mime) + + # Check root CLSID + root_clsid = _extract_root_clsid(dir_data) + if root_clsid: + for clsid, ext, fmt_name, mime in _CLSID_MATCHES: + if root_clsid == clsid: + return Match(ext, fmt_name, mime) + return None @@ -94,4 +143,4 @@ def main(file_path: os.PathLike, head: bytes, foot: bytes) -> Match | None: return None stream_names = _extract_stream_names(dir_data) - return _identify_format(stream_names) + return _identify_format(stream_names, dir_data) diff --git a/puremagic/scanners/hdf5_scanner.py b/puremagic/scanners/hdf5_scanner.py index 1ca102a..77a702e 100644 --- a/puremagic/scanners/hdf5_scanner.py +++ b/puremagic/scanners/hdf5_scanner.py @@ -32,7 +32,7 @@ "application/x-biom2", ), # mz5 - mass spectrometry - ([], [b"/SpectrumMetaData", b"/ChomatogramMetaData"], 1, ".mz5", "mz5 mass spectrometry data", "application/x-mz5"), + ([], [b"/SpectrumMetaData", b"/ChromatogramList"], 1, ".mz5", "mz5 mass spectrometry data", "application/x-mz5"), # h5mlm - ML model ([], [b"model_type", b"h5mlm"], 1, ".h5mlm", "HDF5 ML model", "application/x-h5mlm"), ] diff --git a/puremagic/scanners/zip_scanner.py b/puremagic/scanners/zip_scanner.py index f8c30d3..1fa1ff0 100644 --- a/puremagic/scanners/zip_scanner.py +++ b/puremagic/scanners/zip_scanner.py @@ -8,6 +8,120 @@ office_macro_enable_match = b"macroEnabled" application_re = re.compile(b"(.*)") +_content_type_re = re.compile(rb'ContentType="([^"]*main[^"]*)"') + +# Maps OOXML main content type fragments (from [Content_Types].xml) to +# (extension, name, mime_type). Based on ECMA-376 Part 2. +_OOXML_CONTENT_TYPE_MAP: dict[str, tuple[str, str, str]] = { + # Word + "wordprocessingml.document.main+xml": ( + ".docx", + "Word Document", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ), + "wordprocessingml.template.main+xml": ( + ".dotx", + "Word Template", + "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ), + "ms-word.document.macroEnabled.main+xml": ( + ".docm", + "Word Document (Macro-Enabled)", + "application/vnd.ms-word.document.macroEnabled.12", + ), + "ms-word.template.macroEnabledTemplate.main+xml": ( + ".dotm", + "Word Template (Macro-Enabled)", + "application/vnd.ms-word.template.macroEnabled.12", + ), + # Excel + "spreadsheetml.sheet.main+xml": ( + ".xlsx", + "Excel Spreadsheet", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ), + "spreadsheetml.template.main+xml": ( + ".xltx", + "Excel Template", + "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ), + "ms-excel.sheet.macroEnabled.main+xml": ( + ".xlsm", + "Excel Spreadsheet (Macro-Enabled)", + "application/vnd.ms-excel.sheet.macroEnabled.12", + ), + "ms-excel.template.macroEnabled.main+xml": ( + ".xltm", + "Excel Template (Macro-Enabled)", + "application/vnd.ms-excel.template.macroEnabled.12", + ), + "ms-excel.sheet.binary.macroEnabled.main": ( + ".xlsb", + "Excel Binary Workbook", + "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ), + "ms-excel.addin.macroEnabled.main+xml": ( + ".xlam", + "Excel Add-In (Macro-Enabled)", + "application/vnd.ms-excel.addin.macroEnabled.12", + ), + # PowerPoint + "presentationml.presentation.main+xml": ( + ".pptx", + "PowerPoint Presentation", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ), + "presentationml.template.main+xml": ( + ".potx", + "PowerPoint Template", + "application/vnd.openxmlformats-officedocument.presentationml.template", + ), + "ms-powerpoint.presentation.macroEnabled.main+xml": ( + ".pptm", + "PowerPoint Presentation (Macro-Enabled)", + "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + ), + "ms-powerpoint.template.macroEnabled.main+xml": ( + ".potm", + "PowerPoint Template (Macro-Enabled)", + "application/vnd.ms-powerpoint.template.macroEnabled.12", + ), + "presentationml.slideshow.main+xml": ( + ".ppsx", + "PowerPoint Slideshow", + "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ), + "ms-powerpoint.slideshow.macroEnabled.main+xml": ( + ".ppsm", + "PowerPoint Slideshow (Macro-Enabled)", + "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + ), + "ms-powerpoint.addin.macroEnabled.main+xml": ( + ".ppam", + "PowerPoint Add-In (Macro-Enabled)", + "application/vnd.ms-powerpoint.addin.macroEnabled", + ), +} + + +def _detect_from_content_types(zip_file: ZipFile) -> Match | None: + """Detect OOXML format from [Content_Types].xml main content types. + + This is the ECMA-376 standard approach, working with all compliant + implementations (Microsoft Office, LibreOffice, Google Docs, etc.). + """ + try: + ct_data = zip_file.read("[Content_Types].xml") + except KeyError: + return None + + for match in _content_type_re.finditer(ct_data): + content_type = match.group(1).decode("utf-8") + for key, (ext, name, mime) in _OOXML_CONTENT_TYPE_MAP.items(): + if key in content_type: + return Match(ext, name, mime) + + return None def open_office_check(internal_files: list[str], zip_file: ZipFile, extension: str | None = None) -> Match | None: @@ -32,9 +146,10 @@ def open_office_check(internal_files: list[str], zip_file: ZipFile, extension: s return None -def office_check(internal_files: list[str], zip_file: ZipFile, extension: str | None = None) -> Match | None: - if "[Content_Types].xml" not in internal_files: - return None +def _detect_from_application( + internal_files: list[str], zip_file: ZipFile, extension: str | None = None +) -> Match | None: + """Fallback detection using docProps/app.xml Application tag.""" if "docProps/app.xml" not in internal_files: return None app_type_matches = application_re.search(zip_file.read("docProps/app.xml")) @@ -44,22 +159,30 @@ def office_check(internal_files: list[str], zip_file: ZipFile, extension: str | if "PowerPoint" in application_type: if extension: + if extension == "pptm": + return Match(".pptm", application_type, "application/vnd.ms-powerpoint.presentation.macroEnabled.12") if extension == "ppsm": return Match(".ppsm", application_type, "application/vnd.ms-powerpoint.slideshow.macroEnabled.12") + if extension == "ppsx": + return Match( + ".ppsx", + application_type, + "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ) if extension == "potm": return Match(".potm", application_type, "application/vnd.ms-powerpoint.template.macroEnabled.12") if extension == "potx": return Match( - "potx", + ".potx", application_type, "application/vnd.openxmlformats-officedocument.presentationml.template", ) if extension == "ppam": return Match(".ppam", application_type, "application/vnd.ms-powerpoint.addin.macroEnabled") if office_macro_enable_match in zip_file.read("[Content_Types].xml"): - return Match(".ppsm", application_type, "application/vnd.ms-powerpoint.slideshow.macroEnabled.12") + return Match(".pptm", application_type, "application/vnd.ms-powerpoint.presentation.macroEnabled.12") return Match( - "pptx", + ".pptx", application_type, "application/vnd.openxmlformats-officedocument.presentationml.presentation", ) @@ -75,7 +198,7 @@ def office_check(internal_files: list[str], zip_file: ZipFile, extension: str | return Match(".xltm", application_type, "application/vnd.ms-excel.template.macroEnabled.12") if extension == "xltx": return Match( - "xltx", + ".xltx", application_type, "application/vnd.openxmlformats-officedocument.spreadsheetml.template", ) @@ -91,19 +214,32 @@ def office_check(internal_files: list[str], zip_file: ZipFile, extension: str | return Match(".dotm", application_type, "application/vnd.ms-word.template.macroEnabled.12") if extension == "dotx": return Match( - "dotx", + ".dotx", application_type, "application/vnd.openxmlformats-officedocument.wordprocessingml.template", ) if office_macro_enable_match in zip_file.read("[Content_Types].xml"): return Match(".docm", application_type, "application/vnd.ms-word.document.macroEnabled.12") return Match( - "docx", application_type, "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ".docx", application_type, "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) return None +def office_check(internal_files: list[str], zip_file: ZipFile, extension: str | None = None) -> Match | None: + if "[Content_Types].xml" not in internal_files: + return None + + # Primary: content-type-based detection (works with all OOXML creators) + result = _detect_from_content_types(zip_file) + if result: + return result + + # Fallback: application-based detection for non-standard OOXML packages + return _detect_from_application(internal_files, zip_file, extension) + + def jar_check(internal_files: list[str], zip_file: ZipFile) -> Match | None: if "META-INF/MANIFEST.MF" not in internal_files: return None @@ -156,8 +292,6 @@ def cbz_check(internal_files: list[str], extension: str) -> Match | None: def main(file_path: os.PathLike, _, __) -> Match | None: extension = str(file_path).split(".")[-1].lower() - if extension == "zip" and not str(file_path).endswith(".fb2.zip"): - return Match(".zip", "ZIP archive", "application/zip") with ZipFile(file_path) as myzip: internal_files = myzip.namelist() @@ -189,4 +323,5 @@ def main(file_path: os.PathLike, _, __) -> Match | None: if cbz_result: return cbz_result - return None + # No specific format detected — return generic ZIP (same confidence as other matches) + return Match(".zip", "ZIP archive", "application/zip") diff --git a/test/test_scanners.py b/test/test_scanners.py index 4d4a0cc..0222a4f 100644 --- a/test/test_scanners.py +++ b/test/test_scanners.py @@ -1,3 +1,7 @@ +import os +import tempfile +from zipfile import ZipFile + import puremagic from test.common import IMAGE_DIR, OFFICE_DIR, SYSTEM_DIR, AUDIO_DIR from puremagic.scanners import python_scanner, json_scanner, sndhdr_scanner @@ -135,3 +139,81 @@ def test_sndhdr_scanner(): assert result.name.startswith("Macintosh SNDR Resource") assert result.mime_type == "audio/x-sndr" assert result.confidence == 0.1 + + +def test_ooxml_content_type_detection(): + # GH #146: All OOXML files should be detected with correct extension and MIME type + expected = { + "test.docx": (".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"), + "test.docm": (".docm", "application/vnd.ms-word.document.macroEnabled.12"), + "test.dotx": (".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"), + "test.dotm": (".dotm", "application/vnd.ms-word.template.macroEnabled.12"), + "test.xlsx": (".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), + "test.xlsm": (".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"), + "test.xlsb": (".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"), + "test.xltx": (".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"), + "test.xltm": (".xltm", "application/vnd.ms-excel.template.macroEnabled.12"), + "test.pptx": (".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"), + "test.pptm": (".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"), + "test.potx": (".potx", "application/vnd.openxmlformats-officedocument.presentationml.template"), + "test.potm": (".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"), + } + for filename, (exp_ext, exp_mime) in expected.items(): + filepath = os.path.join(OFFICE_DIR, filename) + ext = puremagic.from_file(filepath) + mime = puremagic.from_file(filepath, mime=True) + assert ext == exp_ext, f"{filename}: expected ext {exp_ext}, got {ext}" + assert mime == exp_mime, f"{filename}: expected mime {exp_mime}, got {mime}" + + +def test_ooxml_without_app_xml(): + # GH #146: OOXML files without docProps/app.xml should still be detected + # (e.g., Google Docs exports) + content_types = b""" + + +""" + + with tempfile.NamedTemporaryFile(suffix=".docx", delete=False) as f: + with ZipFile(f, "w") as zf: + zf.writestr("[Content_Types].xml", content_types) + zf.writestr("word/document.xml", "") + tmppath = f.name + + try: + ext = puremagic.from_file(tmppath) + assert ext == ".docx" + mime = puremagic.from_file(tmppath, mime=True) + assert mime == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + finally: + os.unlink(tmppath) + + +def test_ooxml_libreoffice_application(): + # GH #146: OOXML files with non-Microsoft Application tag should still be detected + content_types = b""" + + +""" + + app_xml = b""" + +LibreOffice/24.8.5.2 +""" + + with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as f: + with ZipFile(f, "w") as zf: + zf.writestr("[Content_Types].xml", content_types) + zf.writestr("docProps/app.xml", app_xml) + zf.writestr("xl/workbook.xml", "") + tmppath = f.name + + try: + ext = puremagic.from_file(tmppath) + assert ext == ".xlsx" + mime = puremagic.from_file(tmppath, mime=True) + assert mime == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + finally: + os.unlink(tmppath) diff --git a/uv.lock b/uv.lock index 52c02d2..bb7e864 100644 --- a/uv.lock +++ b/uv.lock @@ -4,11 +4,11 @@ requires-python = ">=3.12" [[package]] name = "certifi" -version = "2025.6.15" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -50,46 +50,84 @@ wheels = [ [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] [[package]] @@ -112,196 +150,196 @@ wheels = [ [[package]] name = "coverage" -version = "7.13.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" }, - { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" }, - { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" }, - { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" }, - { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" }, - { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" }, - { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" }, - { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" }, - { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" }, - { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" }, - { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" }, - { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" }, - { url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" }, - { url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" }, - { url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" }, - { url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" }, - { url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" }, - { url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" }, - { url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" }, - { url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" }, - { url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" }, - { url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" }, - { url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" }, - { url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" }, - { url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" }, - { url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" }, - { url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" }, - { url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" }, - { url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" }, - { url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" }, - { url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" }, - { url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" }, - { url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" }, - { url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" }, - { url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" }, - { url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" }, - { url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" }, - { url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" }, - { url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" }, - { url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" }, - { url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" }, - { url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" }, - { url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" }, - { url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" }, - { url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" }, - { url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" }, - { url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" }, - { url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" }, - { url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" }, - { url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" }, - { url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" }, - { url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" }, - { url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" }, - { url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" }, - { url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" }, - { url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" }, - { url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" }, - { url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" }, - { url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" }, - { url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" }, - { url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" }, - { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" }, +version = "7.13.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" }, + { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" }, + { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" }, + { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159, upload-time = "2026-03-17T10:30:47.204Z" }, + { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270, upload-time = "2026-03-17T10:30:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538, upload-time = "2026-03-17T10:30:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821, upload-time = "2026-03-17T10:30:52.5Z" }, + { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191, upload-time = "2026-03-17T10:30:54.543Z" }, + { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337, upload-time = "2026-03-17T10:30:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404, upload-time = "2026-03-17T10:30:58.427Z" }, + { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903, upload-time = "2026-03-17T10:31:00.093Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780, upload-time = "2026-03-17T10:31:01.916Z" }, + { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093, upload-time = "2026-03-17T10:31:03.642Z" }, + { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900, upload-time = "2026-03-17T10:31:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515, upload-time = "2026-03-17T10:31:07.293Z" }, + { url = "https://files.pythonhosted.org/packages/74/8c/74fedc9663dcf168b0a059d4ea756ecae4da77a489048f94b5f512a8d0b3/coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1", size = 219576, upload-time = "2026-03-17T10:31:09.045Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c9/44fb661c55062f0818a6ffd2685c67aa30816200d5f2817543717d4b92eb/coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3", size = 219942, upload-time = "2026-03-17T10:31:10.708Z" }, + { url = "https://files.pythonhosted.org/packages/5f/13/93419671cee82b780bab7ea96b67c8ef448f5f295f36bf5031154ec9a790/coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26", size = 250935, upload-time = "2026-03-17T10:31:12.392Z" }, + { url = "https://files.pythonhosted.org/packages/ac/68/1666e3a4462f8202d836920114fa7a5ee9275d1fa45366d336c551a162dd/coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3", size = 253541, upload-time = "2026-03-17T10:31:14.247Z" }, + { url = "https://files.pythonhosted.org/packages/4e/5e/3ee3b835647be646dcf3c65a7c6c18f87c27326a858f72ab22c12730773d/coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b", size = 254780, upload-time = "2026-03-17T10:31:16.193Z" }, + { url = "https://files.pythonhosted.org/packages/44/b3/cb5bd1a04cfcc49ede6cd8409d80bee17661167686741e041abc7ee1b9a9/coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a", size = 256912, upload-time = "2026-03-17T10:31:17.89Z" }, + { url = "https://files.pythonhosted.org/packages/1b/66/c1dceb7b9714473800b075f5c8a84f4588f887a90eb8645282031676e242/coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969", size = 251165, upload-time = "2026-03-17T10:31:19.605Z" }, + { url = "https://files.pythonhosted.org/packages/b7/62/5502b73b97aa2e53ea22a39cf8649ff44827bef76d90bf638777daa27a9d/coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161", size = 252908, upload-time = "2026-03-17T10:31:21.312Z" }, + { url = "https://files.pythonhosted.org/packages/7d/37/7792c2d69854397ca77a55c4646e5897c467928b0e27f2d235d83b5d08c6/coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15", size = 250873, upload-time = "2026-03-17T10:31:23.565Z" }, + { url = "https://files.pythonhosted.org/packages/a3/23/bc866fb6163be52a8a9e5d708ba0d3b1283c12158cefca0a8bbb6e247a43/coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1", size = 255030, upload-time = "2026-03-17T10:31:25.58Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8b/ef67e1c222ef49860701d346b8bbb70881bef283bd5f6cbba68a39a086c7/coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6", size = 250694, upload-time = "2026-03-17T10:31:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/46/0d/866d1f74f0acddbb906db212e096dee77a8e2158ca5e6bb44729f9d93298/coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17", size = 252469, upload-time = "2026-03-17T10:31:29.472Z" }, + { url = "https://files.pythonhosted.org/packages/7a/f5/be742fec31118f02ce42b21c6af187ad6a344fed546b56ca60caacc6a9a0/coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85", size = 222112, upload-time = "2026-03-17T10:31:31.526Z" }, + { url = "https://files.pythonhosted.org/packages/66/40/7732d648ab9d069a46e686043241f01206348e2bbf128daea85be4d6414b/coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b", size = 222923, upload-time = "2026-03-17T10:31:33.633Z" }, + { url = "https://files.pythonhosted.org/packages/48/af/fea819c12a095781f6ccd504890aaddaf88b8fab263c4940e82c7b770124/coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664", size = 221540, upload-time = "2026-03-17T10:31:35.445Z" }, + { url = "https://files.pythonhosted.org/packages/23/d2/17879af479df7fbbd44bd528a31692a48f6b25055d16482fdf5cdb633805/coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d", size = 220262, upload-time = "2026-03-17T10:31:37.184Z" }, + { url = "https://files.pythonhosted.org/packages/5b/4c/d20e554f988c8f91d6a02c5118f9abbbf73a8768a3048cb4962230d5743f/coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0", size = 220617, upload-time = "2026-03-17T10:31:39.245Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/f9f5277b95184f764b24e7231e166dfdb5780a46d408a2ac665969416d61/coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806", size = 261912, upload-time = "2026-03-17T10:31:41.324Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f6/7f1ab39393eeb50cfe4747ae8ef0e4fc564b989225aa1152e13a180d74f8/coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3", size = 263987, upload-time = "2026-03-17T10:31:43.724Z" }, + { url = "https://files.pythonhosted.org/packages/a0/d7/62c084fb489ed9c6fbdf57e006752e7c516ea46fd690e5ed8b8617c7d52e/coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9", size = 266416, upload-time = "2026-03-17T10:31:45.769Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f6/df63d8660e1a0bff6125947afda112a0502736f470d62ca68b288ea762d8/coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd", size = 267558, upload-time = "2026-03-17T10:31:48.293Z" }, + { url = "https://files.pythonhosted.org/packages/5b/02/353ca81d36779bd108f6d384425f7139ac3c58c750dcfaafe5d0bee6436b/coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606", size = 261163, upload-time = "2026-03-17T10:31:50.125Z" }, + { url = "https://files.pythonhosted.org/packages/2c/16/2e79106d5749bcaf3aee6d309123548e3276517cd7851faa8da213bc61bf/coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e", size = 263981, upload-time = "2026-03-17T10:31:51.961Z" }, + { url = "https://files.pythonhosted.org/packages/29/c7/c29e0c59ffa6942030ae6f50b88ae49988e7e8da06de7ecdbf49c6d4feae/coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0", size = 261604, upload-time = "2026-03-17T10:31:53.872Z" }, + { url = "https://files.pythonhosted.org/packages/40/48/097cdc3db342f34006a308ab41c3a7c11c3f0d84750d340f45d88a782e00/coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87", size = 265321, upload-time = "2026-03-17T10:31:55.997Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/4994af354689e14fd03a75f8ec85a9a68d94e0188bbdab3fc1516b55e512/coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479", size = 260502, upload-time = "2026-03-17T10:31:58.308Z" }, + { url = "https://files.pythonhosted.org/packages/22/c6/9bb9ef55903e628033560885f5c31aa227e46878118b63ab15dc7ba87797/coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2", size = 262688, upload-time = "2026-03-17T10:32:00.141Z" }, + { url = "https://files.pythonhosted.org/packages/14/4f/f5df9007e50b15e53e01edea486814783a7f019893733d9e4d6caad75557/coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a", size = 222788, upload-time = "2026-03-17T10:32:02.246Z" }, + { url = "https://files.pythonhosted.org/packages/e1/98/aa7fccaa97d0f3192bec013c4e6fd6d294a6ed44b640e6bb61f479e00ed5/coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819", size = 223851, upload-time = "2026-03-17T10:32:04.416Z" }, + { url = "https://files.pythonhosted.org/packages/3d/8b/e5c469f7352651e5f013198e9e21f97510b23de957dd06a84071683b4b60/coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911", size = 222104, upload-time = "2026-03-17T10:32:06.65Z" }, + { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621, upload-time = "2026-03-17T10:32:08.589Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953, upload-time = "2026-03-17T10:32:10.507Z" }, + { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992, upload-time = "2026-03-17T10:32:12.41Z" }, + { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503, upload-time = "2026-03-17T10:32:14.449Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852, upload-time = "2026-03-17T10:32:16.56Z" }, + { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161, upload-time = "2026-03-17T10:32:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021, upload-time = "2026-03-17T10:32:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858, upload-time = "2026-03-17T10:32:23.506Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823, upload-time = "2026-03-17T10:32:25.516Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099, upload-time = "2026-03-17T10:32:27.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638, upload-time = "2026-03-17T10:32:29.914Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295, upload-time = "2026-03-17T10:32:31.981Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360, upload-time = "2026-03-17T10:32:34.233Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174, upload-time = "2026-03-17T10:32:36.369Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739, upload-time = "2026-03-17T10:32:38.736Z" }, + { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351, upload-time = "2026-03-17T10:32:41.196Z" }, + { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612, upload-time = "2026-03-17T10:32:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985, upload-time = "2026-03-17T10:32:45.514Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107, upload-time = "2026-03-17T10:32:47.971Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513, upload-time = "2026-03-17T10:32:50.1Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650, upload-time = "2026-03-17T10:32:52.391Z" }, + { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089, upload-time = "2026-03-17T10:32:54.544Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982, upload-time = "2026-03-17T10:32:56.803Z" }, + { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579, upload-time = "2026-03-17T10:32:59.466Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316, upload-time = "2026-03-17T10:33:01.847Z" }, + { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427, upload-time = "2026-03-17T10:33:03.945Z" }, + { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745, upload-time = "2026-03-17T10:33:06.285Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146, upload-time = "2026-03-17T10:33:08.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254, upload-time = "2026-03-17T10:33:11.174Z" }, + { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276, upload-time = "2026-03-17T10:33:13.466Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] [[package]] name = "cryptography" -version = "46.0.5" +version = "46.0.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, - { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, - { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, - { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, - { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, - { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, - { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, - { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" }, - { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" }, - { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" }, - { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" }, - { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, - { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, - { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, - { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, - { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, - { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, - { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, - { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/a4/ba/04b1bd4218cbc58dc90ce967106d51582371b898690f3ae0402876cc4f34/cryptography-46.0.6.tar.gz", hash = "sha256:27550628a518c5c6c903d84f637fbecf287f6cb9ced3804838a1295dc1fd0759", size = 750542, upload-time = "2026-03-25T23:34:53.396Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/f8/e61f8f13950ab6195b31913b42d39f0f9afc7d93f76710f299b5ec286ae6/cryptography-46.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:26031f1e5ca62fcb9d1fcb34b2b60b390d1aacaa15dc8b895a9ed00968b97b30", size = 4275275, upload-time = "2026-03-25T23:33:23.844Z" }, + { url = "https://files.pythonhosted.org/packages/19/69/732a736d12c2631e140be2348b4ad3d226302df63ef64d30dfdb8db7ad1c/cryptography-46.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9a693028b9cbe51b5a1136232ee8f2bc242e4e19d456ded3fa7c86e43c713b4a", size = 4425320, upload-time = "2026-03-25T23:33:25.703Z" }, + { url = "https://files.pythonhosted.org/packages/d4/12/123be7292674abf76b21ac1fc0e1af50661f0e5b8f0ec8285faac18eb99e/cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175", size = 4278082, upload-time = "2026-03-25T23:33:27.423Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ba/d5e27f8d68c24951b0a484924a84c7cdaed7502bac9f18601cd357f8b1d2/cryptography-46.0.6-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d9528b535a6c4f8ff37847144b8986a9a143585f0540fbcb1a98115b543aa463", size = 4926514, upload-time = "2026-03-25T23:33:29.206Z" }, + { url = "https://files.pythonhosted.org/packages/34/71/1ea5a7352ae516d5512d17babe7e1b87d9db5150b21f794b1377eac1edc0/cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97", size = 4457766, upload-time = "2026-03-25T23:33:30.834Z" }, + { url = "https://files.pythonhosted.org/packages/01/59/562be1e653accee4fdad92c7a2e88fced26b3fdfce144047519bbebc299e/cryptography-46.0.6-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:760997a4b950ff00d418398ad73fbc91aa2894b5c1db7ccb45b4f68b42a63b3c", size = 3986535, upload-time = "2026-03-25T23:33:33.02Z" }, + { url = "https://files.pythonhosted.org/packages/d6/8b/b1ebfeb788bf4624d36e45ed2662b8bd43a05ff62157093c1539c1288a18/cryptography-46.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3dfa6567f2e9e4c5dceb8ccb5a708158a2a871052fa75c8b78cb0977063f1507", size = 4277618, upload-time = "2026-03-25T23:33:34.567Z" }, + { url = "https://files.pythonhosted.org/packages/dd/52/a005f8eabdb28df57c20f84c44d397a755782d6ff6d455f05baa2785bd91/cryptography-46.0.6-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:cdcd3edcbc5d55757e5f5f3d330dd00007ae463a7e7aa5bf132d1f22a4b62b19", size = 4890802, upload-time = "2026-03-25T23:33:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4d/8e7d7245c79c617d08724e2efa397737715ca0ec830ecb3c91e547302555/cryptography-46.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:d4e4aadb7fc1f88687f47ca20bb7227981b03afaae69287029da08096853b738", size = 4457425, upload-time = "2026-03-25T23:33:38.904Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5c/f6c3596a1430cec6f949085f0e1a970638d76f81c3ea56d93d564d04c340/cryptography-46.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2b417edbe8877cda9022dde3a008e2deb50be9c407eef034aeeb3a8b11d9db3c", size = 4405530, upload-time = "2026-03-25T23:33:40.842Z" }, + { url = "https://files.pythonhosted.org/packages/7e/c9/9f9cea13ee2dbde070424e0c4f621c091a91ffcc504ffea5e74f0e1daeff/cryptography-46.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:380343e0653b1c9d7e1f55b52aaa2dbb2fdf2730088d48c43ca1c7c0abb7cc2f", size = 4667896, upload-time = "2026-03-25T23:33:42.781Z" }, + { url = "https://files.pythonhosted.org/packages/fa/87/887f35a6fca9dde90cad08e0de0c89263a8e59b2d2ff904fd9fcd8025b6f/cryptography-46.0.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7f417f034f91dcec1cb6c5c35b07cdbb2ef262557f701b4ecd803ee8cefed4f4", size = 4266221, upload-time = "2026-03-25T23:33:49.874Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a8/0a90c4f0b0871e0e3d1ed126aed101328a8a57fd9fd17f00fb67e82a51ca/cryptography-46.0.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d24c13369e856b94892a89ddf70b332e0b70ad4a5c43cf3e9cb71d6d7ffa1f7b", size = 4408952, upload-time = "2026-03-25T23:33:52.128Z" }, + { url = "https://files.pythonhosted.org/packages/16/0b/b239701eb946523e4e9f329336e4ff32b1247e109cbab32d1a7b61da8ed7/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:aad75154a7ac9039936d50cf431719a2f8d4ed3d3c277ac03f3339ded1a5e707", size = 4270141, upload-time = "2026-03-25T23:33:54.11Z" }, + { url = "https://files.pythonhosted.org/packages/0f/a8/976acdd4f0f30df7b25605f4b9d3d89295351665c2091d18224f7ad5cdbf/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:3c21d92ed15e9cfc6eb64c1f5a0326db22ca9c2566ca46d845119b45b4400361", size = 4904178, upload-time = "2026-03-25T23:33:55.725Z" }, + { url = "https://files.pythonhosted.org/packages/b1/1b/bf0e01a88efd0e59679b69f42d4afd5bced8700bb5e80617b2d63a3741af/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:4668298aef7cddeaf5c6ecc244c2302a2b8e40f384255505c22875eebb47888b", size = 4441812, upload-time = "2026-03-25T23:33:57.364Z" }, + { url = "https://files.pythonhosted.org/packages/bb/8b/11df86de2ea389c65aa1806f331cae145f2ed18011f30234cc10ca253de8/cryptography-46.0.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:8ce35b77aaf02f3b59c90b2c8a05c73bac12cea5b4e8f3fbece1f5fddea5f0ca", size = 3963923, upload-time = "2026-03-25T23:33:59.361Z" }, + { url = "https://files.pythonhosted.org/packages/91/e0/207fb177c3a9ef6a8108f234208c3e9e76a6aa8cf20d51932916bd43bda0/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c89eb37fae9216985d8734c1afd172ba4927f5a05cfd9bf0e4863c6d5465b013", size = 4269695, upload-time = "2026-03-25T23:34:00.909Z" }, + { url = "https://files.pythonhosted.org/packages/21/5e/19f3260ed1e95bced52ace7501fabcd266df67077eeb382b79c81729d2d3/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:ed418c37d095aeddf5336898a132fba01091f0ac5844e3e8018506f014b6d2c4", size = 4869785, upload-time = "2026-03-25T23:34:02.796Z" }, + { url = "https://files.pythonhosted.org/packages/10/38/cd7864d79aa1d92ef6f1a584281433419b955ad5a5ba8d1eb6c872165bcb/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:69cf0056d6947edc6e6760e5f17afe4bea06b56a9ac8a06de9d2bd6b532d4f3a", size = 4441404, upload-time = "2026-03-25T23:34:04.35Z" }, + { url = "https://files.pythonhosted.org/packages/09/0a/4fe7a8d25fed74419f91835cf5829ade6408fd1963c9eae9c4bce390ecbb/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e7304c4f4e9490e11efe56af6713983460ee0780f16c63f219984dab3af9d2d", size = 4397549, upload-time = "2026-03-25T23:34:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a0/7d738944eac6513cd60a8da98b65951f4a3b279b93479a7e8926d9cd730b/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b928a3ca837c77a10e81a814a693f2295200adb3352395fad024559b7be7a736", size = 4651874, upload-time = "2026-03-25T23:34:07.916Z" }, + { url = "https://files.pythonhosted.org/packages/49/b3/dc27efd8dcc4bff583b3f01d4a3943cd8b5821777a58b3a6a5f054d61b79/cryptography-46.0.6-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:639301950939d844a9e1c4464d7e07f902fe9a7f6b215bb0d4f28584729935d8", size = 4270529, upload-time = "2026-03-25T23:34:15.019Z" }, + { url = "https://files.pythonhosted.org/packages/e6/05/e8d0e6eb4f0d83365b3cb0e00eb3c484f7348db0266652ccd84632a3d58d/cryptography-46.0.6-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ed3775295fb91f70b4027aeba878d79b3e55c0b3e97eaa4de71f8f23a9f2eb77", size = 4414827, upload-time = "2026-03-25T23:34:16.604Z" }, + { url = "https://files.pythonhosted.org/packages/2f/97/daba0f5d2dc6d855e2dcb70733c812558a7977a55dd4a6722756628c44d1/cryptography-46.0.6-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8927ccfbe967c7df312ade694f987e7e9e22b2425976ddbf28271d7e58845290", size = 4271265, upload-time = "2026-03-25T23:34:18.586Z" }, + { url = "https://files.pythonhosted.org/packages/89/06/fe1fce39a37ac452e58d04b43b0855261dac320a2ebf8f5260dd55b201a9/cryptography-46.0.6-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b12c6b1e1651e42ab5de8b1e00dc3b6354fdfd778e7fa60541ddacc27cd21410", size = 4916800, upload-time = "2026-03-25T23:34:20.561Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8a/b14f3101fe9c3592603339eb5d94046c3ce5f7fc76d6512a2d40efd9724e/cryptography-46.0.6-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:063b67749f338ca9c5a0b7fe438a52c25f9526b851e24e6c9310e7195aad3b4d", size = 4448771, upload-time = "2026-03-25T23:34:22.406Z" }, + { url = "https://files.pythonhosted.org/packages/01/b3/0796998056a66d1973fd52ee89dc1bb3b6581960a91ad4ac705f182d398f/cryptography-46.0.6-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:02fad249cb0e090b574e30b276a3da6a149e04ee2f049725b1f69e7b8351ec70", size = 3978333, upload-time = "2026-03-25T23:34:24.281Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3d/db200af5a4ffd08918cd55c08399dc6c9c50b0bc72c00a3246e099d3a849/cryptography-46.0.6-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e6142674f2a9291463e5e150090b95a8519b2fb6e6aaec8917dd8d094ce750d", size = 4271069, upload-time = "2026-03-25T23:34:25.895Z" }, + { url = "https://files.pythonhosted.org/packages/d7/18/61acfd5b414309d74ee838be321c636fe71815436f53c9f0334bf19064fa/cryptography-46.0.6-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:456b3215172aeefb9284550b162801d62f5f264a081049a3e94307fe20792cfa", size = 4878358, upload-time = "2026-03-25T23:34:27.67Z" }, + { url = "https://files.pythonhosted.org/packages/8b/65/5bf43286d566f8171917cae23ac6add941654ccf085d739195a4eacf1674/cryptography-46.0.6-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:341359d6c9e68834e204ceaf25936dffeafea3829ab80e9503860dcc4f4dac58", size = 4448061, upload-time = "2026-03-25T23:34:29.375Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/7e49c0fa7205cf3597e525d156a6bce5b5c9de1fd7e8cb01120e459f205a/cryptography-46.0.6-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9a9c42a2723999a710445bc0d974e345c32adfd8d2fac6d8a251fa829ad31cfb", size = 4399103, upload-time = "2026-03-25T23:34:32.036Z" }, + { url = "https://files.pythonhosted.org/packages/44/46/466269e833f1c4718d6cd496ffe20c56c9c8d013486ff66b4f69c302a68d/cryptography-46.0.6-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6617f67b1606dfd9fe4dbfa354a9508d4a6d37afe30306fe6c101b7ce3274b72", size = 4659255, upload-time = "2026-03-25T23:34:33.679Z" }, ] [[package]] name = "distlib" -version = "0.3.9" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "docutils" -version = "0.21.2" +version = "0.22.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, + { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, ] [[package]] name = "filelock" -version = "3.24.3" +version = "3.25.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" }, ] [[package]] name = "id" -version = "1.5.0" +version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "requests" }, + { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/11/102da08f88412d875fa2f1a9a469ff7ad4c874b0ca6fed0048fe385bdb3d/id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d", size = 15237, upload-time = "2024-12-04T19:53:05.575Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/04/c2156091427636080787aac190019dc64096e56a23b7364d3c1764ee3a06/id-1.6.1.tar.gz", hash = "sha256:d0732d624fb46fd4e7bc4e5152f00214450953b9e772c182c1c22964def1a069", size = 18088, upload-time = "2026-02-04T16:19:41.26Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/cb/18326d2d89ad3b0dd143da971e77afd1e6ca6674f1b1c3df4b6bec6279fc/id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658", size = 13611, upload-time = "2024-12-04T19:53:03.02Z" }, + { url = "https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl", hash = "sha256:f5ec41ed2629a508f5d0988eda142e190c9c6da971100612c4de9ad9f9b237ca", size = 14689, upload-time = "2026-02-04T16:19:40.051Z" }, ] [[package]] name = "identify" -version = "2.6.12" +version = "2.6.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/c4/7fb4db12296cdb11893d61c92048fe617ee853f8523b9b296ac03b43757e/identify-2.6.18.tar.gz", hash = "sha256:873ac56a5e3fd63e7438a7ecbc4d91aca692eb3fefa4534db2b7913f3fc352fd", size = 99580, upload-time = "2026-03-15T18:39:50.319Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, + { url = "https://files.pythonhosted.org/packages/46/33/92ef41c6fad0233e41d3d84ba8e8ad18d1780f1e5d99b3c683e6d7f98b63/identify-2.6.18-py2.py3-none-any.whl", hash = "sha256:8db9d3c8ea9079db92cafb0ebf97abdc09d52e97f4dcf773a2e694048b7cd737", size = 99394, upload-time = "2026-03-15T18:39:48.915Z" }, ] [[package]] name = "idna" -version = "3.10" +version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] name = "iniconfig" -version = "2.1.0" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] @@ -318,23 +356,23 @@ wheels = [ [[package]] name = "jaraco-context" -version = "6.0.1" +version = "6.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912, upload-time = "2024-08-20T03:39:27.358Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/50/4763cd07e722bb6285316d390a164bc7e479db9d90daa769f22578f698b4/jaraco_context-6.1.2.tar.gz", hash = "sha256:f1a6c9d391e661cc5b8d39861ff077a7dc24dc23833ccee564b234b81c82dfe3", size = 16801, upload-time = "2026-03-20T22:13:33.922Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825, upload-time = "2024-08-20T03:39:25.966Z" }, + { url = "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl", hash = "sha256:bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535", size = 7871, upload-time = "2026-03-20T22:13:32.808Z" }, ] [[package]] name = "jaraco-functools" -version = "4.2.1" +version = "4.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "more-itertools" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/1c/831faaaa0f090b711c355c6d8b2abf277c72133aab472b6932b03322294c/jaraco_functools-4.2.1.tar.gz", hash = "sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353", size = 19661, upload-time = "2025-06-21T19:22:03.201Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/fd/179a20f832824514df39a90bb0e5372b314fea99f217f5ab942b10a8a4e8/jaraco_functools-4.2.1-py3-none-any.whl", hash = "sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e", size = 10349, upload-time = "2025-06-21T19:22:02.039Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl", hash = "sha256:9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176", size = 10481, upload-time = "2025-12-21T09:29:42.27Z" }, ] [[package]] @@ -348,7 +386,7 @@ wheels = [ [[package]] name = "keyring" -version = "25.6.0" +version = "25.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jaraco-classes" }, @@ -358,21 +396,21 @@ dependencies = [ { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, { name = "secretstorage", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750, upload-time = "2024-12-25T15:26:45.782Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085, upload-time = "2024-12-25T15:26:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" }, ] [[package]] name = "markdown-it-py" -version = "3.0.0" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] [[package]] @@ -386,60 +424,63 @@ wheels = [ [[package]] name = "more-itertools" -version = "10.7.0" +version = "11.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/a0/834b0cebabbfc7e311f30b46c8188790a37f89fc8d756660346fe5abfd09/more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", size = 127671, upload-time = "2025-04-22T14:17:41.838Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/24/e0acc4bf54cba50c1d432c70a72a3df96db4a321b2c4c68432a60759044f/more_itertools-11.0.1.tar.gz", hash = "sha256:fefaf25b7ab08f0b45fa9f1892cae93b9fc0089ef034d39213bce15f1cc9e199", size = 144739, upload-time = "2026-04-02T16:17:45.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e", size = 65278, upload-time = "2025-04-22T14:17:40.49Z" }, + { url = "https://files.pythonhosted.org/packages/d8/f4/5e52c7319b8087acef603ed6e50dc325c02eaa999355414830468611f13c/more_itertools-11.0.1-py3-none-any.whl", hash = "sha256:eaf287826069452a8f61026c597eae2428b2d1ba2859083abbf240b46842ce6d", size = 72182, upload-time = "2026-04-02T16:17:43.724Z" }, ] [[package]] name = "nh3" -version = "0.2.21" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/30/2f81466f250eb7f591d4d193930df661c8c23e9056bdc78e365b646054d8/nh3-0.2.21.tar.gz", hash = "sha256:4990e7ee6a55490dbf00d61a6f476c9a3258e31e711e13713b2ea7d6616f670e", size = 16581, upload-time = "2025-02-25T13:38:44.619Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/81/b83775687fcf00e08ade6d4605f0be9c4584cb44c4973d9f27b7456a31c9/nh3-0.2.21-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:fcff321bd60c6c5c9cb4ddf2554e22772bb41ebd93ad88171bbbb6f271255286", size = 1297678, upload-time = "2025-02-25T13:37:56.063Z" }, - { url = "https://files.pythonhosted.org/packages/22/ee/d0ad8fb4b5769f073b2df6807f69a5e57ca9cea504b78809921aef460d20/nh3-0.2.21-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31eedcd7d08b0eae28ba47f43fd33a653b4cdb271d64f1aeda47001618348fde", size = 733774, upload-time = "2025-02-25T13:37:58.419Z" }, - { url = "https://files.pythonhosted.org/packages/ea/76/b450141e2d384ede43fe53953552f1c6741a499a8c20955ad049555cabc8/nh3-0.2.21-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d426d7be1a2f3d896950fe263332ed1662f6c78525b4520c8e9861f8d7f0d243", size = 760012, upload-time = "2025-02-25T13:38:01.017Z" }, - { url = "https://files.pythonhosted.org/packages/97/90/1182275db76cd8fbb1f6bf84c770107fafee0cb7da3e66e416bcb9633da2/nh3-0.2.21-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9d67709bc0d7d1f5797b21db26e7a8b3d15d21c9c5f58ccfe48b5328483b685b", size = 923619, upload-time = "2025-02-25T13:38:02.617Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/269a7cfbec9693fad8d767c34a755c25ccb8d048fc1dfc7a7d86bc99375c/nh3-0.2.21-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:55823c5ea1f6b267a4fad5de39bc0524d49a47783e1fe094bcf9c537a37df251", size = 1000384, upload-time = "2025-02-25T13:38:04.402Z" }, - { url = "https://files.pythonhosted.org/packages/68/a9/48479dbf5f49ad93f0badd73fbb48b3d769189f04c6c69b0df261978b009/nh3-0.2.21-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:818f2b6df3763e058efa9e69677b5a92f9bc0acff3295af5ed013da544250d5b", size = 918908, upload-time = "2025-02-25T13:38:06.693Z" }, - { url = "https://files.pythonhosted.org/packages/d7/da/0279c118f8be2dc306e56819880b19a1cf2379472e3b79fc8eab44e267e3/nh3-0.2.21-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b3b5c58161e08549904ac4abd450dacd94ff648916f7c376ae4b2c0652b98ff9", size = 909180, upload-time = "2025-02-25T13:38:10.941Z" }, - { url = "https://files.pythonhosted.org/packages/26/16/93309693f8abcb1088ae143a9c8dbcece9c8f7fb297d492d3918340c41f1/nh3-0.2.21-cp313-cp313t-win32.whl", hash = "sha256:637d4a10c834e1b7d9548592c7aad760611415fcd5bd346f77fd8a064309ae6d", size = 532747, upload-time = "2025-02-25T13:38:12.548Z" }, - { url = "https://files.pythonhosted.org/packages/a2/3a/96eb26c56cbb733c0b4a6a907fab8408ddf3ead5d1b065830a8f6a9c3557/nh3-0.2.21-cp313-cp313t-win_amd64.whl", hash = "sha256:713d16686596e556b65e7f8c58328c2df63f1a7abe1277d87625dcbbc012ef82", size = 528908, upload-time = "2025-02-25T13:38:14.059Z" }, - { url = "https://files.pythonhosted.org/packages/ba/1d/b1ef74121fe325a69601270f276021908392081f4953d50b03cbb38b395f/nh3-0.2.21-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a772dec5b7b7325780922dd904709f0f5f3a79fbf756de5291c01370f6df0967", size = 1316133, upload-time = "2025-02-25T13:38:16.601Z" }, - { url = "https://files.pythonhosted.org/packages/b8/f2/2c7f79ce6de55b41e7715f7f59b159fd59f6cdb66223c05b42adaee2b645/nh3-0.2.21-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d002b648592bf3033adfd875a48f09b8ecc000abd7f6a8769ed86b6ccc70c759", size = 758328, upload-time = "2025-02-25T13:38:18.972Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ad/07bd706fcf2b7979c51b83d8b8def28f413b090cf0cb0035ee6b425e9de5/nh3-0.2.21-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2a5174551f95f2836f2ad6a8074560f261cf9740a48437d6151fd2d4d7d617ab", size = 747020, upload-time = "2025-02-25T13:38:20.571Z" }, - { url = "https://files.pythonhosted.org/packages/75/99/06a6ba0b8a0d79c3d35496f19accc58199a1fb2dce5e711a31be7e2c1426/nh3-0.2.21-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b8d55ea1fc7ae3633d758a92aafa3505cd3cc5a6e40470c9164d54dff6f96d42", size = 944878, upload-time = "2025-02-25T13:38:22.204Z" }, - { url = "https://files.pythonhosted.org/packages/79/d4/dc76f5dc50018cdaf161d436449181557373869aacf38a826885192fc587/nh3-0.2.21-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ae319f17cd8960d0612f0f0ddff5a90700fa71926ca800e9028e7851ce44a6f", size = 903460, upload-time = "2025-02-25T13:38:25.951Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c3/d4f8037b2ab02ebf5a2e8637bd54736ed3d0e6a2869e10341f8d9085f00e/nh3-0.2.21-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ca02ac6f27fc80f9894409eb61de2cb20ef0a23740c7e29f9ec827139fa578", size = 839369, upload-time = "2025-02-25T13:38:28.174Z" }, - { url = "https://files.pythonhosted.org/packages/11/a9/1cd3c6964ec51daed7b01ca4686a5c793581bf4492cbd7274b3f544c9abe/nh3-0.2.21-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5f77e62aed5c4acad635239ac1290404c7e940c81abe561fd2af011ff59f585", size = 739036, upload-time = "2025-02-25T13:38:30.539Z" }, - { url = "https://files.pythonhosted.org/packages/fd/04/bfb3ff08d17a8a96325010ae6c53ba41de6248e63cdb1b88ef6369a6cdfc/nh3-0.2.21-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:087ffadfdcd497658c3adc797258ce0f06be8a537786a7217649fc1c0c60c293", size = 768712, upload-time = "2025-02-25T13:38:32.992Z" }, - { url = "https://files.pythonhosted.org/packages/9e/aa/cfc0bf545d668b97d9adea4f8b4598667d2b21b725d83396c343ad12bba7/nh3-0.2.21-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ac7006c3abd097790e611fe4646ecb19a8d7f2184b882f6093293b8d9b887431", size = 930559, upload-time = "2025-02-25T13:38:35.204Z" }, - { url = "https://files.pythonhosted.org/packages/78/9d/6f5369a801d3a1b02e6a9a097d56bcc2f6ef98cffebf03c4bb3850d8e0f0/nh3-0.2.21-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:6141caabe00bbddc869665b35fc56a478eb774a8c1dfd6fba9fe1dfdf29e6efa", size = 1008591, upload-time = "2025-02-25T13:38:37.099Z" }, - { url = "https://files.pythonhosted.org/packages/a6/df/01b05299f68c69e480edff608248313cbb5dbd7595c5e048abe8972a57f9/nh3-0.2.21-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:20979783526641c81d2f5bfa6ca5ccca3d1e4472474b162c6256745fbfe31cd1", size = 925670, upload-time = "2025-02-25T13:38:38.696Z" }, - { url = "https://files.pythonhosted.org/packages/3d/79/bdba276f58d15386a3387fe8d54e980fb47557c915f5448d8c6ac6f7ea9b/nh3-0.2.21-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a7ea28cd49293749d67e4fcf326c554c83ec912cd09cd94aa7ec3ab1921c8283", size = 917093, upload-time = "2025-02-25T13:38:40.249Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d8/c6f977a5cd4011c914fb58f5ae573b071d736187ccab31bfb1d539f4af9f/nh3-0.2.21-cp38-abi3-win32.whl", hash = "sha256:6c9c30b8b0d291a7c5ab0967ab200598ba33208f754f2f4920e9343bdd88f79a", size = 537623, upload-time = "2025-02-25T13:38:41.893Z" }, - { url = "https://files.pythonhosted.org/packages/23/fc/8ce756c032c70ae3dd1d48a3552577a325475af2a2f629604b44f571165c/nh3-0.2.21-cp38-abi3-win_amd64.whl", hash = "sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629", size = 535283, upload-time = "2025-02-25T13:38:43.355Z" }, +version = "0.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/86/f8d3a7c9bd1bbaa181f6312c757e0b74d25f71ecf84ea3c0dc5e0f01840d/nh3-0.3.4.tar.gz", hash = "sha256:96709a379997c1b28c8974146ca660b0dcd3794f4f6d50c1ea549bab39ac6ade", size = 19520, upload-time = "2026-03-25T10:57:30.789Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/5e/c400663d14be2216bc084ed2befc871b7b12563f85d40904f2a4bf0dd2b7/nh3-0.3.4-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8b61058f34c2105d44d2a4d4241bacf603a1ef5c143b08766bbd0cf23830118f", size = 1417991, upload-time = "2026-03-25T10:56:59.13Z" }, + { url = "https://files.pythonhosted.org/packages/36/f5/109526f5002ec41322ac8cafd50f0f154bae0c26b9607c0fcb708bdca8ec/nh3-0.3.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:554cc2bab281758e94d770c3fb0bf2d8be5fb403ef6b2e8841dd7c1615df7a0f", size = 790566, upload-time = "2026-03-25T10:57:00.445Z" }, + { url = "https://files.pythonhosted.org/packages/7b/66/38950f2b4b316ffd82ee51ed8f9143d1f56fdd620312cacc91613b77b3e7/nh3-0.3.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dbe76feaa44e2ef9436f345016012a591550e77818876a8de5c8bc2a248e08df", size = 837538, upload-time = "2026-03-25T10:57:01.848Z" }, + { url = "https://files.pythonhosted.org/packages/d8/9f/9d6da970e9524fe360ea02a2082856390c2c8ba540409d1be6e5851887b3/nh3-0.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:87dac8d611b4a478400e0821a13b35770e88c266582f065e7249d6a37b0f86e8", size = 1012154, upload-time = "2026-03-25T10:57:03.592Z" }, + { url = "https://files.pythonhosted.org/packages/54/92/7c85c33c241e9dd51dda115bd3f765e940446588cdaaca62ef8edffe675f/nh3-0.3.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8d697e19f2995b337f648204848ac3a528eaafffc39e7ce4ac6b7a2fbe6c84af", size = 1092516, upload-time = "2026-03-25T10:57:04.726Z" }, + { url = "https://files.pythonhosted.org/packages/16/0f/597842bdb2890999a3faa2f3fcb02db8aa6ad09320d3d843ff6d0a1f737b/nh3-0.3.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:7cae217f031809321db962cd7e092bda8d4e95a87f78c0226628fa6c2ea8ebc5", size = 1053793, upload-time = "2026-03-25T10:57:06.171Z" }, + { url = "https://files.pythonhosted.org/packages/7d/32/669da65147bc10746d2e1d7a8a3dbfbffe0315f419e74b559e2ee3471a01/nh3-0.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:07999b998bf89692738f15c0eac76a416382932f855709e0b7488b595c30ec89", size = 1035975, upload-time = "2026-03-25T10:57:07.292Z" }, + { url = "https://files.pythonhosted.org/packages/a1/7e/9e97a8b3c5161c79b4bf21cc54e9334860a52cc54ede15bf2239ef494b73/nh3-0.3.4-cp314-cp314t-win32.whl", hash = "sha256:ca90397c8d36c1535bf1988b2bed006597337843a164c7ec269dc8813f37536b", size = 600419, upload-time = "2026-03-25T10:57:08.342Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c7/6849d8d4295d3997d148eacb2d4b1c9faada4895ee3c1b1e12e72f4611e2/nh3-0.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:41e46b3499918ab6128b6421677b316e79869d0c140da24069d220a94f4e72d1", size = 613342, upload-time = "2026-03-25T10:57:09.593Z" }, + { url = "https://files.pythonhosted.org/packages/8b/0e/14a3f510f36c20b922c123a2730f071f938d006fb513aacfd46d6cbc03a7/nh3-0.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:80b955d802bf365bd42e09f6c3d64567dce777d20e97968d94b3e9d9e99b265e", size = 607025, upload-time = "2026-03-25T10:57:10.959Z" }, + { url = "https://files.pythonhosted.org/packages/4a/57/a97955bc95960cfb1f0517043d60a121f4ba93fde252d4d9ffd3c2a9eead/nh3-0.3.4-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d8bebcb20ab4b91858385cd98fe58046ec4a624275b45ef9b976475604f45b49", size = 1439519, upload-time = "2026-03-25T10:57:12.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/60/c9a33361da8cde7c7760f091cd10467bc470634e4eea31c8bb70935b00a4/nh3-0.3.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d825722a1e8cbc87d7ca1e47ffb1d2a6cf343ad4c1b8465becf7cadcabcdfd0", size = 833798, upload-time = "2026-03-25T10:57:13.264Z" }, + { url = "https://files.pythonhosted.org/packages/6b/19/9487790780b8c94eacca37866c1270b747a4af8e244d43b3b550fddbbf62/nh3-0.3.4-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4aa8b43e68c26b68069a3b6cef09de166d1d7fa140cf8d77e409a46cbf742e44", size = 820414, upload-time = "2026-03-25T10:57:14.236Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b4/c6a340dd321d20b1e4a663307032741da045685c87403926c43656f6f5ec/nh3-0.3.4-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f5f214618ad5eff4f2a6b13a8d4da4d9e7f37c569d90a13fb9f0caaf7d04fe21", size = 1061531, upload-time = "2026-03-25T10:57:15.384Z" }, + { url = "https://files.pythonhosted.org/packages/c4/49/f6b4b474e0032e4bcbb7174b44e4cf6915670e09c62421deb06ccfcb88b8/nh3-0.3.4-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3390e4333883673a684ce16c1716b481e91782d6f56dec5c85fed9feedb23382", size = 1021889, upload-time = "2026-03-25T10:57:16.454Z" }, + { url = "https://files.pythonhosted.org/packages/43/da/e52a6941746d1f974752af3fc8591f1dbcdcf7fd8c726c7d99f444ba820e/nh3-0.3.4-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a2e44ccb29cbb45071b8f3f2dab9ebfb41a6516f328f91f1f1fd18196239a4", size = 912965, upload-time = "2026-03-25T10:57:17.624Z" }, + { url = "https://files.pythonhosted.org/packages/d6/b7/ec1cbc6b297a808c513f59f501656389623fc09ad6a58c640851289c7854/nh3-0.3.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0961a27dc2057c38d0364cb05880e1997ae1c80220cbc847db63213720b8f304", size = 804975, upload-time = "2026-03-25T10:57:18.994Z" }, + { url = "https://files.pythonhosted.org/packages/a9/56/b1275aa2c6510191eed76178da4626b0900402439cb9f27d6b9bf7c6d5e9/nh3-0.3.4-cp38-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:9337517edb7c10228252cce2898e20fb3d77e32ffaccbb3c66897927d74215a0", size = 833400, upload-time = "2026-03-25T10:57:20.086Z" }, + { url = "https://files.pythonhosted.org/packages/7c/a5/5d574ffa3c6e49a5364d1b25ebad165501c055340056671493beb467a15e/nh3-0.3.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d866701affe67a5171b916b5c076e767a74c6a9efb7fb2006eb8d3c5f9a293d5", size = 854277, upload-time = "2026-03-25T10:57:21.433Z" }, + { url = "https://files.pythonhosted.org/packages/79/36/8aeb2ab21517cefa212db109e41024e02650716cb42bf293d0a88437a92d/nh3-0.3.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:47d749d99ae005ab19517224140b280dd56e77b33afb82f9b600e106d0458003", size = 1022021, upload-time = "2026-03-25T10:57:22.433Z" }, + { url = "https://files.pythonhosted.org/packages/9c/95/9fd860997685e64abe2d5a995ca2eb5004c0fb6d6585429612a7871548b9/nh3-0.3.4-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f987cb56458323405e8e5ea827e1befcf141ffa0c0ac797d6d02e6b646056d9a", size = 1103526, upload-time = "2026-03-25T10:57:23.487Z" }, + { url = "https://files.pythonhosted.org/packages/7d/0d/df545070614c1007f0109bb004230226c9000e7857c9785583ec25cda9d7/nh3-0.3.4-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:883d5a6d6ee8078c4afc8e96e022fe579c4c265775ff6ee21e39b8c542cabab3", size = 1068050, upload-time = "2026-03-25T10:57:24.624Z" }, + { url = "https://files.pythonhosted.org/packages/94/d5/17b016df52df052f714c53be71df26a1943551d9931e9383b92c998b88f8/nh3-0.3.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:75643c22f5092d8e209f766ee8108c400bc1e44760fc94d2d638eb138d18f853", size = 1046037, upload-time = "2026-03-25T10:57:25.799Z" }, + { url = "https://files.pythonhosted.org/packages/51/39/49f737907e6ab2b4ca71855d3bd63dd7958862e9c8b94fb4e5b18ccf6988/nh3-0.3.4-cp38-abi3-win32.whl", hash = "sha256:72e4e9ca1c4bd41b4a28b0190edc2e21e3f71496acd36a0162858e1a28db3d7e", size = 609542, upload-time = "2026-03-25T10:57:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/73/4f/af8e9071d7464575a7316831938237ffc9d92d27f163dbdd964b1309cd9b/nh3-0.3.4-cp38-abi3-win_amd64.whl", hash = "sha256:c10b1f0c741e257a5cb2978d6bac86e7c784ab20572724b20c6402c2e24bce75", size = 624244, upload-time = "2026-03-25T10:57:28.302Z" }, + { url = "https://files.pythonhosted.org/packages/44/0c/37695d6b0168f6714b5c492331636a9e6123d6ec22d25876c68d06eab1b8/nh3-0.3.4-cp38-abi3-win_arm64.whl", hash = "sha256:43ad4eedee7e049b9069bc015b7b095d320ed6d167ecec111f877de1540656e9", size = 616649, upload-time = "2026-03-25T10:57:29.623Z" }, ] [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +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/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, + { 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 = "25.0" +version = "26.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/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/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/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] [[package]] @@ -453,11 +494,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.9.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" }, ] [[package]] @@ -471,15 +512,15 @@ wheels = [ [[package]] name = "poethepoet" -version = "0.42.1" +version = "0.43.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/9b/e717572686bbf23e17483389c1bf3a381ca2427c84c7e0af0cdc0f23fccc/poethepoet-0.42.1.tar.gz", hash = "sha256:205747e276062c2aaba8afd8a98838f8a3a0237b7ab94715fab8d82718aac14f", size = 93209, upload-time = "2026-02-26T22:57:50.883Z" } +sdist = { url = "https://files.pythonhosted.org/packages/91/4a/3cdfd054e4e81913028d8c399d04e51a8c2431110d5797e302206d350ffa/poethepoet-0.43.0.tar.gz", hash = "sha256:62b058ef92ca76fc758dd6362918f5054b9f519fa5328e2eeaa00c72bdc90e85", size = 95454, upload-time = "2026-04-03T10:56:26.299Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/68/75fa0a5ef39718ea6ba7ab6a3d031fa93640e57585580cec85539540bb65/poethepoet-0.42.1-py3-none-any.whl", hash = "sha256:d8d1345a5ca521be9255e7c13bc2c4c8698ed5e5ac5e9e94890d239fcd423d0a", size = 119967, upload-time = "2026-02-26T22:57:49.467Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6f/23f86e5abfb3308ef1fa749571ba06d86e437d355862356ff8e3dfd66b05/poethepoet-0.43.0-py3-none-any.whl", hash = "sha256:c12f8be41dbecee8abac4266bda4b04060b7129d2868edf50823e6509c249431", size = 122290, upload-time = "2026-04-03T10:56:24.645Z" }, ] [[package]] @@ -536,20 +577,20 @@ dev = [ [[package]] name = "pycparser" -version = "2.22" +version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +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/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, + { 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]] name = "pygments" -version = "2.19.2" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] @@ -570,16 +611,29 @@ wheels = [ [[package]] name = "pytest-cov" -version = "7.0.0" +version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/88/815e53084c5079a59df912825a279f41dd2e0df82281770eadc732f5352c/python_discovery-1.2.1.tar.gz", hash = "sha256:180c4d114bff1c32462537eac5d6a332b768242b76b69c0259c7d14b1b680c9e", size = 58457, upload-time = "2026-03-26T22:30:44.496Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, + { url = "https://files.pythonhosted.org/packages/67/0f/019d3949a40280f6193b62bc010177d4ce702d0fce424322286488569cd3/python_discovery-1.2.1-py3-none-any.whl", hash = "sha256:b6a957b24c1cd79252484d3566d1b49527581d46e789aaf43181005e56201502", size = 31674, upload-time = "2026-03-26T22:30:43.396Z" }, ] [[package]] @@ -653,7 +707,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.33.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -661,9 +715,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, ] [[package]] @@ -689,62 +743,62 @@ wheels = [ [[package]] name = "rich" -version = "14.0.0" +version = "14.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, ] [[package]] name = "ruff" -version = "0.15.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" }, - { url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" }, - { url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" }, - { url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" }, - { url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" }, - { url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" }, - { url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" }, - { url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" }, - { url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" }, - { url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" }, - { url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" }, - { url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, +version = "0.15.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/97/e9f1ca355108ef7194e38c812ef40ba98c7208f47b13ad78d023caa583da/ruff-0.15.9.tar.gz", hash = "sha256:29cbb1255a9797903f6dde5ba0188c707907ff44a9006eb273b5a17bfa0739a2", size = 4617361, upload-time = "2026-04-02T18:17:20.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/1f/9cdfd0ac4b9d1e5a6cf09bedabdf0b56306ab5e333c85c87281273e7b041/ruff-0.15.9-py3-none-linux_armv6l.whl", hash = "sha256:6efbe303983441c51975c243e26dff328aca11f94b70992f35b093c2e71801e1", size = 10511206, upload-time = "2026-04-02T18:16:41.574Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f6/32bfe3e9c136b35f02e489778d94384118bb80fd92c6d92e7ccd97db12ce/ruff-0.15.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4965bac6ac9ea86772f4e23587746f0b7a395eccabb823eb8bfacc3fa06069f7", size = 10923307, upload-time = "2026-04-02T18:17:08.645Z" }, + { url = "https://files.pythonhosted.org/packages/ca/25/de55f52ab5535d12e7aaba1de37a84be6179fb20bddcbe71ec091b4a3243/ruff-0.15.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf05aad70ca5b5a0a4b0e080df3a6b699803916d88f006efd1f5b46302daab8", size = 10316722, upload-time = "2026-04-02T18:16:44.206Z" }, + { url = "https://files.pythonhosted.org/packages/48/11/690d75f3fd6278fe55fff7c9eb429c92d207e14b25d1cae4064a32677029/ruff-0.15.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9439a342adb8725f32f92732e2bafb6d5246bd7a5021101166b223d312e8fc59", size = 10623674, upload-time = "2026-04-02T18:16:50.951Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ec/176f6987be248fc5404199255522f57af1b4a5a1b57727e942479fec98ad/ruff-0.15.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5e6faf9d97c8edc43877c3f406f47446fc48c40e1442d58cfcdaba2acea745", size = 10351516, upload-time = "2026-04-02T18:16:57.206Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fc/51cffbd2b3f240accc380171d51446a32aa2ea43a40d4a45ada67368fbd2/ruff-0.15.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b34a9766aeec27a222373d0b055722900fbc0582b24f39661aa96f3fe6ad901", size = 11150202, upload-time = "2026-04-02T18:17:06.452Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d4/25292a6dfc125f6b6528fe6af31f5e996e19bf73ca8e3ce6eb7fa5b95885/ruff-0.15.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89dd695bc72ae76ff484ae54b7e8b0f6b50f49046e198355e44ea656e521fef9", size = 11988891, upload-time = "2026-04-02T18:17:18.575Z" }, + { url = "https://files.pythonhosted.org/packages/13/e1/1eebcb885c10e19f969dcb93d8413dfee8172578709d7ee933640f5e7147/ruff-0.15.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce187224ef1de1bd225bc9a152ac7102a6171107f026e81f317e4257052916d5", size = 11480576, upload-time = "2026-04-02T18:16:52.986Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/a1548ac378a78332a4c3dcf4a134c2475a36d2a22ddfa272acd574140b50/ruff-0.15.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b0c7c341f68adb01c488c3b7d4b49aa8ea97409eae6462d860a79cf55f431b6", size = 11254525, upload-time = "2026-04-02T18:17:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/42/aa/4bb3af8e61acd9b1281db2ab77e8b2c3c5e5599bf2a29d4a942f1c62b8d6/ruff-0.15.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:55cc15eee27dc0eebdfcb0d185a6153420efbedc15eb1d38fe5e685657b0f840", size = 11204072, upload-time = "2026-04-02T18:17:13.581Z" }, + { url = "https://files.pythonhosted.org/packages/69/48/d550dc2aa6e423ea0bcc1d0ff0699325ffe8a811e2dba156bd80750b86dc/ruff-0.15.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6537f6eed5cda688c81073d46ffdfb962a5f29ecb6f7e770b2dc920598997ed", size = 10594998, upload-time = "2026-04-02T18:16:46.369Z" }, + { url = "https://files.pythonhosted.org/packages/63/47/321167e17f5344ed5ec6b0aa2cff64efef5f9e985af8f5622cfa6536043f/ruff-0.15.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6d3fcbca7388b066139c523bda744c822258ebdcfbba7d24410c3f454cc9af71", size = 10359769, upload-time = "2026-04-02T18:17:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/67/5e/074f00b9785d1d2c6f8c22a21e023d0c2c1817838cfca4c8243200a1fa87/ruff-0.15.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:058d8e99e1bfe79d8a0def0b481c56059ee6716214f7e425d8e737e412d69677", size = 10850236, upload-time = "2026-04-02T18:16:48.749Z" }, + { url = "https://files.pythonhosted.org/packages/76/37/804c4135a2a2caf042925d30d5f68181bdbd4461fd0d7739da28305df593/ruff-0.15.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8e1ddb11dbd61d5983fa2d7d6370ef3eb210951e443cace19594c01c72abab4c", size = 11358343, upload-time = "2026-04-02T18:16:55.068Z" }, + { url = "https://files.pythonhosted.org/packages/88/3d/1364fcde8656962782aa9ea93c92d98682b1ecec2f184e625a965ad3b4a6/ruff-0.15.9-py3-none-win32.whl", hash = "sha256:bde6ff36eaf72b700f32b7196088970bf8fdb2b917b7accd8c371bfc0fd573ec", size = 10583382, upload-time = "2026-04-02T18:17:04.261Z" }, + { url = "https://files.pythonhosted.org/packages/4c/56/5c7084299bd2cacaa07ae63a91c6f4ba66edc08bf28f356b24f6b717c799/ruff-0.15.9-py3-none-win_amd64.whl", hash = "sha256:45a70921b80e1c10cf0b734ef09421f71b5aa11d27404edc89d7e8a69505e43d", size = 11744969, upload-time = "2026-04-02T18:16:59.611Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/76704c4f312257d6dbaae3c959add2a622f63fcca9d864659ce6d8d97d3d/ruff-0.15.9-py3-none-win_arm64.whl", hash = "sha256:0694e601c028fd97dc5c6ee244675bc241aeefced7ef80cd9c6935a871078f53", size = 11005870, upload-time = "2026-04-02T18:17:15.773Z" }, ] [[package]] name = "secretstorage" -version = "3.3.3" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "jeepney" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739, upload-time = "2022-08-13T16:22:46.976Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221, upload-time = "2022-08-13T16:22:44.457Z" }, + { url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" }, ] [[package]] name = "setuptools" -version = "82.0.0" +version = "82.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893, upload-time = "2026-02-08T15:08:40.206Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468, upload-time = "2026-02-08T15:08:38.723Z" }, + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, ] [[package]] @@ -769,26 +823,26 @@ wheels = [ [[package]] name = "ty" -version = "0.0.21" +version = "0.0.29" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/20/2ba8fd9493c89c41dfe9dbb73bc70a28b28028463bc0d2897ba8be36230a/ty-0.0.21.tar.gz", hash = "sha256:a4c2ba5d67d64df8fcdefd8b280ac1149d24a73dbda82fa953a0dff9d21400ed", size = 5297967, upload-time = "2026-03-06T01:57:13.809Z" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d5/853561de49fae38c519e905b2d8da9c531219608f1fccc47a0fc2c896980/ty-0.0.29.tar.gz", hash = "sha256:e7936cca2f691eeda631876c92809688dbbab68687c3473f526cd83b6a9228d8", size = 5469221, upload-time = "2026-04-05T15:01:21.328Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/70/edf38bb37517531681d1c37f5df64744e5ad02673c02eb48447eae4bea08/ty-0.0.21-py3-none-linux_armv6l.whl", hash = "sha256:7bdf2f572378de78e1f388d24691c89db51b7caf07cf90f2bfcc1d6b18b70a76", size = 10299222, upload-time = "2026-03-06T01:57:16.64Z" }, - { url = "https://files.pythonhosted.org/packages/72/62/0047b0bd19afeefbc7286f20a5f78a2aa39f92b4d89853f0d7185ab89edc/ty-0.0.21-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7e9613994610431ab8625025bd2880dbcb77c5c9fabdd21134cda12d840a529d", size = 10130513, upload-time = "2026-03-06T01:57:29.93Z" }, - { url = "https://files.pythonhosted.org/packages/a2/20/0b93a9e91aaed23155780258cdfdb4726ef68b6985378ac069bc427291a0/ty-0.0.21-py3-none-macosx_11_0_arm64.whl", hash = "sha256:56d3b198b64dd0a19b2b66e257deaed2ecea568e722ae5352f3c6fb62027f89d", size = 9605425, upload-time = "2026-03-06T01:57:27.115Z" }, - { url = "https://files.pythonhosted.org/packages/ea/fd/9945e2fa2996a1287b1e1d7ce050e97e1f420233b271e770934bfa0880a0/ty-0.0.21-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d23d2c34f7a77d974bb08f0860ef700addc8a683d81a0319f71c08f87506cfd0", size = 10108298, upload-time = "2026-03-06T01:57:35.429Z" }, - { url = "https://files.pythonhosted.org/packages/52/e7/4ec52fcb15f3200826c9f048472c062549a05b0d1ef0b51f32d527b513c4/ty-0.0.21-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56b01fd2519637a4ca88344f61c96225f540c98ff18bca321d4eaa7bb0f7aa2f", size = 10121556, upload-time = "2026-03-06T01:57:03.242Z" }, - { url = "https://files.pythonhosted.org/packages/ee/c0/ad457be2a8abea0f25549598bd098554540ced66229488daa0d558dad3c8/ty-0.0.21-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9de7e11c63c6afc40f3e9ba716374add171aee7fabc70b5146a510705c6d41b", size = 10603264, upload-time = "2026-03-06T01:56:52.134Z" }, - { url = "https://files.pythonhosted.org/packages/f8/5b/2ecc7a2175243a4bcb72f5298ae41feabbb93b764bb0dc45722f3752c2c2/ty-0.0.21-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62f7f5b235c4f7876db305c36997aea07b7af29b1a068f373d0e2547e25f32ff", size = 11196428, upload-time = "2026-03-06T01:57:32.94Z" }, - { url = "https://files.pythonhosted.org/packages/37/f5/aff507d6a901f328ef96a298032b0c11aaaf950a146ed7dd3b5bf2cd3acf/ty-0.0.21-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee8399f7c453a425291e6688efe430cfae7ab0ac4ffd50eba9f872bf878b54f6", size = 10866355, upload-time = "2026-03-06T01:56:57.831Z" }, - { url = "https://files.pythonhosted.org/packages/be/30/822bbcb92d55b65989aa7ed06d9585f28ade9c9447369194ed4b0fb3b5b9/ty-0.0.21-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210e7568c9f886c4d01308d751949ee714ad7ad9d7d928d2ba90d329dd880367", size = 10738177, upload-time = "2026-03-06T01:57:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/57/cc/46e7991b6469e93ac2c7e533a028983e402485580150ac864c56352a3a82/ty-0.0.21-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:53508e345b11569f78b21ba8e2b4e61df38a9754947fb3cd9f2ef574367338fb", size = 10079158, upload-time = "2026-03-06T01:57:00.516Z" }, - { url = "https://files.pythonhosted.org/packages/15/c2/0bbdadfbd008240f8f1a87dc877433cb3884436097926107ccf06e618199/ty-0.0.21-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:553e43571f4a35604c36cfd07d8b61a5eb7a714e3c67f8c4ff2cf674fefbaef9", size = 10150535, upload-time = "2026-03-06T01:57:08.815Z" }, - { url = "https://files.pythonhosted.org/packages/c5/b5/2dbdb7b57b5362200ef0a39738ebd31331726328336def0143ac097ee59d/ty-0.0.21-py3-none-musllinux_1_2_i686.whl", hash = "sha256:666f6822e3b9200abfa7e95eb0ddd576460adb8d66b550c0ad2c70abc84a2048", size = 10319803, upload-time = "2026-03-06T01:57:19.106Z" }, - { url = "https://files.pythonhosted.org/packages/72/84/70e52c0b7abc7c2086f9876ef454a73b161d3125315536d8d7e911c94ca4/ty-0.0.21-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0854d008347ce4a5fb351af132f660a390ab2a1163444d075251d43e6f74b9b", size = 10826239, upload-time = "2026-03-06T01:57:21.727Z" }, - { url = "https://files.pythonhosted.org/packages/a1/8a/1f72480fd013bbc6cd1929002abbbcde9a0b08ead6a15154de9d7f7fa37e/ty-0.0.21-py3-none-win32.whl", hash = "sha256:bef3ab4c7b966bcc276a8ac6c11b63ba222d21355b48d471ea782c4104eee4e0", size = 9693196, upload-time = "2026-03-06T01:57:24.126Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f8/1104808b875c26c640e536945753a78562d606bef4e241d9dbf3d92477f6/ty-0.0.21-py3-none-win_amd64.whl", hash = "sha256:a709d576e5bea84b745d43058d8b9cd4f27f74a0b24acb4b0cbb7d3d41e0d050", size = 10668660, upload-time = "2026-03-06T01:56:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b8/25e0adc404bbf986977657b25318991f93097b49f8aea640d93c0b0db68e/ty-0.0.21-py3-none-win_arm64.whl", hash = "sha256:f72047996598ac20553fb7e21ba5741e3c82dee4e9eadf10d954551a5fe09391", size = 10104161, upload-time = "2026-03-06T01:57:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/03/b7/911f9962115acfa24e3b2ec9d4992dd994c38e8769e1b1d7680bb4d28a51/ty-0.0.29-py3-none-linux_armv6l.whl", hash = "sha256:b8a40955f7660d3eaceb0d964affc81b790c0765e7052921a5f861ff8a471c30", size = 10568206, upload-time = "2026-04-05T15:01:19.165Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/fcae2167d4c77a97269f92f11d1b43b03617f81de1283d5d05b43432110c/ty-0.0.29-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6b6849adae15b00bbe2d3c5b078967dcb62eba37d38936b8eeb4c81a82d2e3b8", size = 10442530, upload-time = "2026-04-05T15:01:28.471Z" }, + { url = "https://files.pythonhosted.org/packages/97/33/5a6bfa240cfcb9c36046ae2459fa9ea23238d20130d8656ff5ac4d6c012a/ty-0.0.29-py3-none-macosx_11_0_arm64.whl", hash = "sha256:dcdd9b17209788152f7b7ea815eda07989152325052fe690013537cc7904ce49", size = 9915735, upload-time = "2026-04-05T15:01:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1e/318f45fae232118e81a6306c30f50de42c509c412128d5bd231eab699ffb/ty-0.0.29-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d8ed4789bae78ffaf94462c0d25589a734cab0366b86f2bbcb1bb90e1a7a169", size = 10419748, upload-time = "2026-04-05T15:01:32.375Z" }, + { url = "https://files.pythonhosted.org/packages/a9/a8/5687872e2ab5a0f7dd4fd8456eac31e9381ad4dc74961f6f29965ad4dd91/ty-0.0.29-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91ec374b8565e0ad0900011c24641ebbef2da51adbd4fb69ff3280c8a7eceb02", size = 10394738, upload-time = "2026-04-05T15:01:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/de/68/015d118097eeb95e6a44c4abce4c0a28b7b9dfb3085b7f0ee48e4f099633/ty-0.0.29-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:298a8d5faa2502d3810bbbb47a030b9455495b9921594206043c785dd61548cf", size = 10910613, upload-time = "2026-04-05T15:01:17.17Z" }, + { url = "https://files.pythonhosted.org/packages/1c/01/47ce3c6c53e0670eadbe80756b167bf80ed6681d1ba57cfde2e8065a13d1/ty-0.0.29-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c8fba1a3524c6109d1e020d92301c79d41bf442fa8d335b9fa366239339cb70", size = 11475750, upload-time = "2026-04-05T15:01:30.461Z" }, + { url = "https://files.pythonhosted.org/packages/c4/cf/e361845b1081c9264ad5b7c963231bab03f2666865a9f2a115c4233f2137/ty-0.0.29-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c48adf88a70d264128c39ee922ed14a947817fced1e93c08c1a89c9244edcde", size = 11190055, upload-time = "2026-04-05T15:01:12.369Z" }, + { url = "https://files.pythonhosted.org/packages/79/12/0fb0857e9a62cb11586e9a712103877bbf717f5fb570d16634408cfdefee/ty-0.0.29-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ce0a7a0e96bc7b42518cd3a1a6a6298ef64ff40ca4614355c1aa807059b5c6f", size = 11020539, upload-time = "2026-04-05T15:01:37.022Z" }, + { url = "https://files.pythonhosted.org/packages/20/36/5a26753802083f80cd125db6c4348ad42b3c982ec36e718e0bf4c18f75e5/ty-0.0.29-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6ac86a05b4a3731d45365ab97780acc7b8146fa62fccb3cbe94fe6546c67a97", size = 10396399, upload-time = "2026-04-05T15:01:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/00/e6/b4e75b5752239ab3ab400f19faef4dbef81d05aab5d3419fda0c062a3765/ty-0.0.29-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6bbbf53141af0f3150bf288d716263f1a3550054e4b3551ca866d38192ba9891", size = 10421461, upload-time = "2026-04-05T15:01:08.367Z" }, + { url = "https://files.pythonhosted.org/packages/c0/21/1084b5b609f9abed62070ec0b31c283a403832a6310c8bbc208bd45ee1e6/ty-0.0.29-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1c9e06b770c1d0ff5efc51e34312390db31d53fcf3088163f413030b42b74f84", size = 10599187, upload-time = "2026-04-05T15:01:23.52Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a1/ce19a2ca717bbcc1ee11378aba52ef70b6ce5b87245162a729d9fdc2360f/ty-0.0.29-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0307fe37e3f000ef1a4ae230bbaf511508a78d24a5e51b40902a21b09d5e6037", size = 11121198, upload-time = "2026-04-05T15:01:15.22Z" }, + { url = "https://files.pythonhosted.org/packages/6b/6b/f1430b279af704321566ce7ec2725d3d8258c2f815ebd93e474c64cd4543/ty-0.0.29-py3-none-win32.whl", hash = "sha256:7a2a898217960a825f8bc0087e1fdbaf379606175e98f9807187221d53a4a8ed", size = 9995331, upload-time = "2026-04-05T15:01:01.32Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ef/3ef01c17785ff9a69378465c7d0faccd48a07b163554db0995e5d65a5a23/ty-0.0.29-py3-none-win_amd64.whl", hash = "sha256:fc1294200226b91615acbf34e0a9ad81caf98c081e9c6a912a31b0a7b603bc3f", size = 11023644, upload-time = "2026-04-05T15:01:04.432Z" }, + { url = "https://files.pythonhosted.org/packages/2c/55/87280a994d6a2d2647c65e12abbc997ed49835794366153c04c4d9304d76/ty-0.0.29-py3-none-win_arm64.whl", hash = "sha256:f9794bbd1bb3ce13f78c191d0c89ae4c63f52c12b6daa0c6fe220b90d019d12c", size = 10428165, upload-time = "2026-04-05T15:01:34.665Z" }, ] [[package]] @@ -802,16 +856,17 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.36.1" +version = "21.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, + { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, + { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" }, ] [[package]] From a493f0982d7aa996b2955fd65820059a2b2fec84 Mon Sep 17 00:00:00 2001 From: Chris Griffith Date: Tue, 7 Apr 2026 07:40:01 -0500 Subject: [PATCH 2/5] - Adding Ogg scanner to distinguish Vorbis, Opus, Theora, FLAC, Speex, and OGM codecs - Adding ASF scanner to distinguish WMV (video) from WMA (audio) files - Adding EBML scanner to distinguish Matroska (.mkv) from WebM (.webm) files --- CHANGELOG.md | 3 ++ puremagic/main.py | 11 ++++++ puremagic/scanners/asf_scanner.py | 59 ++++++++++++++++++++++++++++++ puremagic/scanners/ebml_scanner.py | 21 +++++++++++ puremagic/scanners/ogg_scanner.py | 39 ++++++++++++++++++++ test/test_scanners.py | 23 +++++++++++- 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 puremagic/scanners/asf_scanner.py create mode 100644 puremagic/scanners/ebml_scanner.py create mode 100644 puremagic/scanners/ogg_scanner.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 43971e1..c238f45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ Changelog Version 2.2.0 ------------- +- Adding Ogg scanner to distinguish Vorbis, Opus, Theora, FLAC, Speex, and OGM codecs +- Adding ASF scanner to distinguish WMV (video) from WMA (audio) files +- Adding EBML scanner to distinguish Matroska (.mkv) from WebM (.webm) files - Adding MSI (Windows Installer) and MPP (Microsoft Project) detection to CFBF scanner - Fixing #146 OOXML detection now uses `[Content_Types].xml` content types as primary method, correctly identifying docx/xlsx/pptx files from LibreOffice, Google Docs, and other non-Microsoft tools (thanks to jonasdeboeck79) - Fixing ZIP deep scan now inspects all ZIP files instead of short-circuiting on .zip extension diff --git a/puremagic/main.py b/puremagic/main.py index 1e2a20b..a674358 100644 --- a/puremagic/main.py +++ b/puremagic/main.py @@ -32,6 +32,9 @@ mpeg_audio_scanner, hdf5_scanner, cfbf_scanner, + ogg_scanner, + asf_scanner, + ebml_scanner, ) __author__ = "Chris Griffith" @@ -466,6 +469,14 @@ def single_deep_scan( return result case cfbf_scanner.match_bytes | cfbf_scanner.match_bytes_short: return cfbf_scanner.main(filename, head, foot) + case ogg_scanner.match_bytes: + result = ogg_scanner.main(filename, head, foot) + if result and result.confidence > confidence: + return result + case asf_scanner.match_bytes: + return asf_scanner.main(filename, head, foot) + case ebml_scanner.match_bytes: + return ebml_scanner.main(filename, head, foot) if eml_result := text_scanner.eml_check(head): return eml_result diff --git a/puremagic/scanners/asf_scanner.py b/puremagic/scanners/asf_scanner.py new file mode 100644 index 0000000..a85848f --- /dev/null +++ b/puremagic/scanners/asf_scanner.py @@ -0,0 +1,59 @@ +import os +import struct + +from puremagic.scanners.helpers import Match + +# ASF Header Object GUID +match_bytes = b"\x30\x26\xb2\x75\x8e\x66\xcf\x11\xa6\xd9\x00\xaa\x00\x62\xce\x6c" + +_STREAM_PROPS_GUID = b"\x91\x07\xdc\xb7\xb7\xa9\xcf\x11\x8e\xe6\x00\xc0\x0c\x20\x53\x65" +_AUDIO_MEDIA_GUID = b"\x40\x9e\x69\xf8\x4d\x5b\xcf\x11\xa8\xfd\x00\x80\x5f\x5c\x44\x2b" +_VIDEO_MEDIA_GUID = b"\xc0\xef\x19\xbc\x4d\x5b\xcf\x11\xa8\xfd\x00\x80\x5f\x5c\x44\x2b" + + +def main(file_path: os.PathLike, head: bytes, foot: bytes) -> Match | None: + if not head or len(head) < 30: + return None + if head[:16] != match_bytes: + return None + + header_size = struct.unpack_from(" len(head): + try: + with open(file_path, "rb") as f: + data = f.read(min(int(header_size), 65536)) + except (OSError, ValueError): + return None + else: + data = head + + has_audio = False + has_video = False + offset = 30 # Past header GUID(16) + size(8) + count(4) + reserved(2) + + for _ in range(min(obj_count, 50)): + if offset + 24 > len(data): + break + obj_guid = data[offset : offset + 16] + obj_size = struct.unpack_from(" Match | None: + if not head or len(head) < 8: + return None + if head[:4] != match_bytes: + return None + + # Search for DocType string in the EBML header (first 64 bytes) + search_area = head[:64] + if b"webm" in search_area: + return Match(".webm", "WebM Video", "video/webm") + if b"matroska" in search_area: + return Match(".mkv", "Matroska Video", "video/x-matroska") + + return None diff --git a/puremagic/scanners/ogg_scanner.py b/puremagic/scanners/ogg_scanner.py new file mode 100644 index 0000000..e642f5b --- /dev/null +++ b/puremagic/scanners/ogg_scanner.py @@ -0,0 +1,39 @@ +import os + +from puremagic.scanners.helpers import Match + +match_bytes = b"OggS" + +# Ogg codec identification signatures found at the start of the first page payload. +# Each entry: (codec_id_bytes, extension, name, mime_type) +_OGG_CODEC_MAP = [ + (b"\x01vorbis", ".ogg", "Ogg Vorbis Audio", "audio/ogg"), + (b"OpusHead", ".opus", "Ogg Opus Audio", "audio/ogg"), + (b"\x80theora", ".ogv", "Ogg Theora Video", "video/ogg"), + (b"\x7fFLAC", ".oga", "Ogg FLAC Audio", "audio/ogg"), + (b"Speex ", ".spx", "Ogg Speex Audio", "audio/ogg"), + (b"fishead\x00", ".ogv", "Ogg Annodex", "video/ogg"), + (b"\x01video", ".ogm", "OGM Video", "video/x-ogm+ogg"), +] + + +def main(file_path: os.PathLike, head: bytes, foot: bytes) -> Match | None: + if not head or len(head) < 28: + return None + + # Verify OggS capture pattern, version 0, and beginning-of-stream flag + if head[:4] != match_bytes or head[4] != 0 or not (head[5] & 0x02): + return None + + seg_count = head[26] + payload_start = 27 + seg_count + + if payload_start >= len(head): + return None + + payload = head[payload_start:] + for codec_id, ext, name, mime in _OGG_CODEC_MAP: + if payload.startswith(codec_id): + return Match(ext, name, mime, confidence=0.9) + + return None diff --git a/test/test_scanners.py b/test/test_scanners.py index 0222a4f..980dfd1 100644 --- a/test/test_scanners.py +++ b/test/test_scanners.py @@ -3,7 +3,7 @@ from zipfile import ZipFile import puremagic -from test.common import IMAGE_DIR, OFFICE_DIR, SYSTEM_DIR, AUDIO_DIR +from test.common import IMAGE_DIR, OFFICE_DIR, SYSTEM_DIR, AUDIO_DIR, VIDEO_DIR from puremagic.scanners import python_scanner, json_scanner, sndhdr_scanner sample_text = b"""Lorem ipsum dolor sit amet, consectetur adipiscing elit,{ending} @@ -217,3 +217,24 @@ def test_ooxml_libreoffice_application(): assert mime == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" finally: os.unlink(tmppath) + + +def test_ogg_opus_scanner(): + opus_file = AUDIO_DIR / "test.opus" + results = puremagic.magic_file(opus_file) + assert results[0].extension == ".opus" + assert results[0].mime_type == "audio/ogg" + + +def test_matroska_scanner(): + mkv_file = VIDEO_DIR / "test.mkv" + results = puremagic.magic_file(mkv_file) + assert results[0].extension == ".mkv" + assert results[0].mime_type == "video/x-matroska" + + +def test_asf_wmv_scanner(): + wmv_file = VIDEO_DIR / "test.wmv" + results = puremagic.magic_file(wmv_file) + assert results[0].extension == ".wmv" + assert results[0].mime_type == "video/x-ms-wmv" From 90bacb70fc5a40b7888637da9780b3522e40eeae Mon Sep 17 00:00:00 2001 From: Chris Griffith Date: Tue, 7 Apr 2026 08:08:59 -0500 Subject: [PATCH 3/5] - Fixing text scanner now treats files containing NUL bytes as binary data instead of misidentifying them as text --- CHANGELOG.md | 1 + puremagic/scanners/text_scanner.py | 4 + test/resources/audio/test.oga | Bin 0 -> 26892 bytes test/resources/audio/test.ogg | Bin 0 -> 8212 bytes test/resources/audio/test.wma | Bin 0 -> 10370 bytes test/resources/video/test.ogv | Bin 0 -> 6198 bytes test/resources/video/test.webm | Bin 0 -> 4704 bytes test/test_scanners.py | 651 ++++++++++++++++++++++++++++- 8 files changed, 651 insertions(+), 5 deletions(-) create mode 100644 test/resources/audio/test.oga create mode 100644 test/resources/audio/test.ogg create mode 100644 test/resources/audio/test.wma create mode 100644 test/resources/video/test.ogv create mode 100644 test/resources/video/test.webm diff --git a/CHANGELOG.md b/CHANGELOG.md index c238f45..5cd6451 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Version 2.2.0 - Adding MSI (Windows Installer) and MPP (Microsoft Project) detection to CFBF scanner - Fixing #146 OOXML detection now uses `[Content_Types].xml` content types as primary method, correctly identifying docx/xlsx/pptx files from LibreOffice, Google Docs, and other non-Microsoft tools (thanks to jonasdeboeck79) - Fixing ZIP deep scan now inspects all ZIP files instead of short-circuiting on .zip extension +- Fixing text scanner now treats files containing NUL bytes as binary data instead of misidentifying them as text - Fixing mz5 HDF5 scanner typo in chromatogram dataset name Version 2.1.1 diff --git a/puremagic/scanners/text_scanner.py b/puremagic/scanners/text_scanner.py index 9136bec..5e55b15 100644 --- a/puremagic/scanners/text_scanner.py +++ b/puremagic/scanners/text_scanner.py @@ -200,6 +200,10 @@ def main(file_path: os.PathLike | str, _, __) -> Match | None: if len(head) < 8: return Match("", "very short file", "application/octet-stream", confidence=0.5) + # NUL bytes indicate binary data, but skip this check for UTF-16 (which has NUL bytes naturally) + if b"\x00" in head and head[:2] not in (b"\xff\xfe", b"\xfe\xff"): + return Match("", "data", "application/octet-stream", confidence=0.5) + try: text, encoding = decode_any(head) except TypeError: diff --git a/test/resources/audio/test.oga b/test/resources/audio/test.oga new file mode 100644 index 0000000000000000000000000000000000000000..597e32db8d1a24a00756618f45d007e5e6652969 GIT binary patch literal 26892 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 Y2=ISDC=yoq`!k%G0;u+XSLVk39}Mi8=Kufz literal 0 HcmV?d00001 diff --git a/test/resources/audio/test.ogg b/test/resources/audio/test.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c0ef97e3f678852ccb0914d447019f44916bde20 GIT binary patch literal 8212 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 literal 0 HcmV?d00001 diff --git a/test/resources/audio/test.wma b/test/resources/audio/test.wma new file mode 100644 index 0000000000000000000000000000000000000000..9a374a9e409464c601c8abceb903399372b06222 GIT binary patch literal 10370 zcmeHLd011&7N460*&&c1hzKEuB~;l2v{WGppd>8PfKfzDz^Fh$M6@ndNiir?K?o5o zUYgM;V`BhK_qA$eDF+eGkV2WUhuT}3^aJbtjYY52nNTDlZRE6)PsrI8P zf!CG(+Jgvo^p#ear1U4qJD}89=&1@&r2yv98z=xcfo0DkJVveYcG=Lr~kA-(U zv_(bdjatTFF$e-qU;!*!1J;dN5Z`#`0%zp~fEn;rMq2^xV!>La*F;zg6?@^>1LSiUJY)F7|m)M7L4p z2oP|W`F;}8^;6T{sBWX(b#R0nA0#PV!^8sKTJTl@8iinhuN2m{0w5W|Lo`uQl_AOS zf>|2-;?8LFHTy&j=)?qybhkFGek*99f!>lAXn!IOa@Fvn+-Z!u^DA+ z4Ui$Q!UO2s-Ph9T{&;|7q;DtXH`aE|w%kn8ub9%4s+oJi`dQ=MC5@Yw4FxCJeD|zz z<*5tSCq4R-P4RsRCp!XG^;uJ-!BF5xf}-SrrR3o8YYsGj24;>;h0#a7GZG&^4&J~1 z*fam`e#{GbXj|gB$*-2BRQ%1(rw-O1Njf9FO?(*Y=aeU})%J5Lk~646({6cA8av-u zD6z$S&LX(5s3wGxR2{t*Mx0RKYonnDvdxeJ(Xe*8G}(CE?RE zS<90g7smW4L-ZWJDl1R)eSfLe`q{38<83a;c} zlZu0sv3a2R0$3!b_G2R=wifks9#K?gn3p3S$nBCQbe4Ka zC^L9c+x(S%I1!*T9Ci)XiCETJ_8M9n=9fzf*GG_Q-z;pvchh)=;oX! zTf6Pz95?=}*|xj-mrp+XY5^4(#DDm{eykA@&9Qmls^Z|)>+gXWSSCEhMy&r~KDMH3 zxU58Ynop6?N^;Xe!kGDZVUKNz3^B$yV0h$mW4!iE?F0_J$^*%~PN&@3;ow7asG5DC zveWVBqsP|V-@o>->5T7VhGfW^|L3Lue+~l#-EFJ(MN#j}gKNOd;9A<=sV4*O60B`p zg{E>_A>Q8JE{Jm7xin0J$c~keau|9(?852pEQ-DcB?AO^;&$NgoZ7$bcznD2J@3uB ztY0tGUq6>tVR-0wxDfH4W-S5ulXmJ^@CF+w0~0K&^9Oq3K+hlAsCVUBw^zyWqt|<1 zjT^uc>jo^ITM6=H*yhTG0+B$Ybr~V7v+nUz5(Z_I8GqrK>{lQap1}`Q)O~ zlC(_wt;Qo-#ct)h+J<%KizS#B7a821;^=&PsyjkuIFypB7)WWchK&}nlzdpgq*ZZD z{AtumhwO|XU!oK#M{F^nAq0#R1Y&pr2noZRg7G)z1(;9cxqVF`LuH`0bvaH}jSmbk zr{x-lJKJP_?QA1jB-k+HV1P|zU~tWv>s3bs={t`lIrmL#I}opNKj7-^b+H*e{hzvv ze&+ZcI8mc$`;ucd7l-kxy3u&(8=2+;a{+QNCUREebkCvi`-P8ei@46P@z9tz_o?Vq3oKbRce{8Lr z=Ea@&6|za&0z`Uq3hzXHk2`f|@y!pH=MMGN+;I)W2VnPaeN(_3foWP6zk5 z$lMT zO%!LpJ=j4VI^8-u^P#Wiv6g)u6_2(w{I0{k?UUsB-0g>4!q&vJxn>6ne0+R55?oyL zp|H%}V0@TOv=uUW ajDtIB4kjAi@%cj;P>UJ?H3Acjz<&TKN=#}1 literal 0 HcmV?d00001 diff --git a/test/resources/video/test.ogv b/test/resources/video/test.ogv new file mode 100644 index 0000000000000000000000000000000000000000..7d8af806c92eabe348cd212a94a6f97e7a5edf77 GIT binary patch literal 6198 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 STe6seWYspeWzwE-bpHaNol;H! literal 0 HcmV?d00001 diff --git a/test/resources/video/test.webm b/test/resources/video/test.webm new file mode 100644 index 0000000000000000000000000000000000000000..015d7016d68b884bea761dd4da53e8e84f72dbf8 GIT binary patch literal 4704 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 literal 0 HcmV?d00001 diff --git a/test/test_scanners.py b/test/test_scanners.py index 980dfd1..4088568 100644 --- a/test/test_scanners.py +++ b/test/test_scanners.py @@ -219,18 +219,98 @@ def test_ooxml_libreoffice_application(): os.unlink(tmppath) +def _make_ogg_bos_page(codec_id: bytes) -> bytes: + """Build a minimal Ogg beginning-of-stream page with the given codec ID payload.""" + # OggS capture pattern + version 0 + BOS header type + header = b"OggS\x00\x02" + # granule(8) + serial(4) + page_seq(4) + crc(4) = 20 bytes + header += b"\x00" * 20 + # 1 segment, segment size = len(codec_id) + header += bytes([1, len(codec_id)]) + return header + codec_id + + def test_ogg_opus_scanner(): opus_file = AUDIO_DIR / "test.opus" results = puremagic.magic_file(opus_file) assert results[0].extension == ".opus" assert results[0].mime_type == "audio/ogg" + assert results[0].name == "Ogg Opus Audio" -def test_matroska_scanner(): - mkv_file = VIDEO_DIR / "test.mkv" - results = puremagic.magic_file(mkv_file) - assert results[0].extension == ".mkv" - assert results[0].mime_type == "video/x-matroska" +def test_ogg_vorbis_scanner(): + ogg_file = AUDIO_DIR / "test.ogg" + results = puremagic.magic_file(ogg_file) + assert results[0].extension == ".ogg" + assert results[0].mime_type == "audio/ogg" + assert results[0].name == "Ogg Vorbis Audio" + + +def test_ogg_theora_scanner(): + ogv_file = VIDEO_DIR / "test.ogv" + results = puremagic.magic_file(ogv_file) + assert results[0].extension == ".ogv" + assert results[0].mime_type == "video/ogg" + assert results[0].name == "Ogg Theora Video" + + +def test_ogg_flac_scanner(): + oga_file = AUDIO_DIR / "test.oga" + results = puremagic.magic_file(oga_file) + assert results[0].extension == ".oga" + assert results[0].mime_type == "audio/ogg" + assert results[0].name == "Ogg FLAC Audio" + + +def test_ogg_scanner_direct(): + from puremagic.scanners import ogg_scanner + + # Test all codecs via real files + for path, expected_ext in [ + (AUDIO_DIR / "test.opus", ".opus"), + (AUDIO_DIR / "test.ogg", ".ogg"), + (VIDEO_DIR / "test.ogv", ".ogv"), + (AUDIO_DIR / "test.oga", ".oga"), + ]: + with open(path, "rb") as f: + head = f.read(256) + result = ogg_scanner.main(path, head, b"") + assert result is not None, f"{path}: expected {expected_ext}, got None" + assert result.extension == expected_ext, f"{path}: expected {expected_ext}, got {result.extension}" + assert result.confidence == 0.9 + + +def test_ogg_scanner_synthetic_codecs(): + """Test codec detection for formats without real test files (Speex, Annodex, OGM).""" + from puremagic.scanners import ogg_scanner + + cases = [ + (b"Speex ", ".spx", "Ogg Speex Audio", "audio/ogg"), + (b"fishead\x00", ".ogv", "Ogg Annodex", "video/ogg"), + (b"\x01video\x00\x00\x00", ".ogm", "OGM Video", "video/x-ogm+ogg"), + ] + for codec_id, expected_ext, expected_name, expected_mime in cases: + head = _make_ogg_bos_page(codec_id) + result = ogg_scanner.main("fake.ogg", head, b"") + assert result is not None, f"codec {codec_id!r}: expected {expected_ext}, got None" + assert result.extension == expected_ext + assert result.name == expected_name + assert result.mime_type == expected_mime + assert result.confidence == 0.9 + + +def test_ogg_scanner_rejects_non_ogg(): + from puremagic.scanners import ogg_scanner + + assert ogg_scanner.main("fake.ogg", b"not ogg data at all", b"") is None + assert ogg_scanner.main("fake.ogg", b"", b"") is None + # Valid OggS but wrong version + assert ogg_scanner.main("fake.ogg", b"OggS\x01\x02" + b"\x00" * 50, b"") is None + # Valid OggS but not BOS page + assert ogg_scanner.main("fake.ogg", b"OggS\x00\x00" + b"\x00" * 50, b"") is None + # Valid BOS page but unknown codec + head = _make_ogg_bos_page(b"UnknownCodecXYZ") + assert ogg_scanner.main("fake.ogg", head, b"") is None def test_asf_wmv_scanner(): @@ -238,3 +318,564 @@ def test_asf_wmv_scanner(): results = puremagic.magic_file(wmv_file) assert results[0].extension == ".wmv" assert results[0].mime_type == "video/x-ms-wmv" + assert results[0].name == "Windows Media Video" + + +def test_asf_wma_scanner(): + wma_file = AUDIO_DIR / "test.wma" + results = puremagic.magic_file(wma_file) + assert results[0].extension == ".wma" + assert results[0].mime_type == "audio/x-ms-wma" + assert results[0].name == "Windows Media Audio" + + +def test_asf_scanner_direct(): + from puremagic.scanners import asf_scanner + + # WMV (has video) + wmv_file = VIDEO_DIR / "test.wmv" + with open(wmv_file, "rb") as f: + head = f.read(256) + result = asf_scanner.main(wmv_file, head, b"") + assert result is not None + assert result.extension == ".wmv" + assert result.mime_type == "video/x-ms-wmv" + + # WMA (audio only) + wma_file = AUDIO_DIR / "test.wma" + with open(wma_file, "rb") as f: + head = f.read(256) + result = asf_scanner.main(wma_file, head, b"") + assert result is not None + assert result.extension == ".wma" + assert result.mime_type == "audio/x-ms-wma" + + +def test_asf_scanner_generic_fallback(): + """ASF with no recognized stream types should return .asf.""" + import struct + from puremagic.scanners import asf_scanner + + # Build minimal ASF header: GUID(16) + size(8) + count(4) + reserved(2) = 30 bytes + # With 0 sub-objects so no streams are found + header_guid = asf_scanner.match_bytes + header_size = struct.pack("= len(head).""" + from puremagic.scanners import ogg_scanner + + # Valid OggS BOS header with seg_count=200 → payload_start=227, but head is only 50 bytes + head = bytearray(50) + head[0:4] = b"OggS" + head[4] = 0 # version + head[5] = 0x02 # BOS flag + head[26] = 200 # seg_count → payload at offset 227 + assert ogg_scanner.main("fake.ogg", bytes(head), b"") is None + + +def test_json_scanner_array(): + """json_scanner: valid JSON array file.""" + json_file = SYSTEM_DIR / "test_array.json" + json_file.write_bytes(b"[1, 2, 3]") + try: + result = json_scanner.main(json_file, b"[1, 2, 3]", b"[1, 2, 3]") + assert result is not None + assert result.extension == ".json" + finally: + json_file.unlink() + + +def test_json_scanner_malformed(): + """json_scanner lines 17-18: passes structural check but fails json.load().""" + json_file = SYSTEM_DIR / "test_bad.json" + json_file.write_bytes(b"{invalid json content}") + try: + result = json_scanner.main(json_file, b"{invalid json content}", b"{invalid json content}") + assert result is None + finally: + json_file.unlink() + + +def test_sndhdr_hcom_detection(): + """sndhdr_scanner line 25: HCOM format detected via FSSD+HCOM markers.""" + from puremagic.scanners import sndhdr_scanner + + head = bytearray(133) + head[65:69] = b"FSSD" + head[128:132] = b"HCOM" + result = sndhdr_scanner.main(None, bytes(head), None) + assert result is not None + assert result.extension == ".hcom" + assert result.mime_type == "audio/x-hcom" + assert result.confidence == 1.0 + + +def test_sndhdr_short_head(): + """sndhdr_scanner lines 44-45: head too short for struct.unpack.""" + from puremagic.scanners import sndhdr_scanner + + # 2 bytes is too short for get_short_le(head[2:4]) + result = sndhdr_scanner.main(None, b"\x00\x00", None) + # Should not crash — except catches IndexError, then test_hcom also fails (head too short) + # test_hcom will raise IndexError on head[65:69] check but that returns None since slicing doesn't raise + assert result is None + + +def test_asf_scanner_wrong_magic_30_bytes(): + """asf_scanner line 18: 30+ bytes but wrong magic.""" + from puremagic.scanners import asf_scanner + + assert asf_scanner.main("fake.asf", b"\x00" * 30, b"") is None + + +def test_asf_scanner_file_io_error(): + """asf_scanner lines 28-29: OSError when header_size > len(head) and file doesn't exist.""" + import struct + from puremagic.scanners import asf_scanner + + # Valid ASF magic + header_size=99999 (much larger than head) + obj_count=0 + head = asf_scanner.match_bytes + head += struct.pack(" len(data).""" + import struct + from puremagic.scanners import asf_scanner + + # Valid header with obj_count=1 but no actual object data after the header + head = asf_scanner.match_bytes # 16 bytes + head += struct.pack(" 30 → break + result = asf_scanner.main("fake.asf", head, b"") + assert result is not None + assert result.extension == ".asf" # Falls through to generic ASF + + +def test_asf_scanner_bad_object_size(): + """asf_scanner line 43: break when obj_size < 24.""" + import struct + from puremagic.scanners import asf_scanner + + header_body = struct.pack(" 1MB return None.""" + large_file = SYSTEM_DIR / "test_large.py" + large_file.write_bytes(b"import os\n" * 200_000) # ~2MB + try: + result = python_scanner.main(large_file, None, None) + assert result is None + finally: + large_file.unlink() + + +def test_python_scanner_no_constructs(): + """python_scanner lines 31-37, 54-55: non-.py file that parses as Python but lacks constructs.""" + # This file parses as valid Python (just assignments) but has no imports/defs/control flow + no_constructs = SYSTEM_DIR / "test_noconstructs.txt" + no_constructs.write_bytes(b"a = 1\nb = 2\nc = 3\nd = 4\ne = 5\nf = 6\ng = 7\n" * 20) + try: + result = python_scanner.main(no_constructs, None, None) + assert result is None + finally: + no_constructs.unlink() + + +def test_python_scanner_few_constructs(): + """python_scanner lines 34-37: non-.py with some constructs but below threshold of 4.""" + few_file = SYSTEM_DIR / "test_few.txt" + # Only 2 imports + padding to exceed 100 byte minimum — below threshold of 4 constructs + few_file.write_bytes(b"import os\nimport sys\nx = 1\ny = 2\n" + b"z = 0\n" * 30) + try: + result = python_scanner.main(few_file, None, None) + assert result is None + finally: + few_file.unlink() + + +# ── Medium tier: main.py coverage ───────────────────────────────────── + + +def test_deepscan_disabled_magic_file(monkeypatch): + """main.py line 351: magic_file returns without deep scan when PUREMAGIC_DEEPSCAN=0.""" + monkeypatch.setenv("PUREMAGIC_DEEPSCAN", "0") + # Force reimport so the env var takes effect at module level + # But scanners are imported at module load time; the env check is in run_deep_scan/single_deep_scan + results = puremagic.magic_file(OFFICE_DIR / "test.docx") + # Without deep scan, all OOXML formats share the same PK magic bytes + assert len(results) > 1 # Multiple matches, not narrowed by scanner + + +def test_deepscan_disabled_magic_stream(monkeypatch): + """main.py line 395: magic_stream returns without deep scan when PUREMAGIC_DEEPSCAN=0.""" + monkeypatch.setenv("PUREMAGIC_DEEPSCAN", "0") + with open(OFFICE_DIR / "test.docx", "rb") as f: + results = puremagic.magic_stream(f, filename=OFFICE_DIR / "test.docx") + assert len(results) > 1 + + +def test_single_deep_scan_disabled(monkeypatch): + """main.py line 451: single_deep_scan returns None when PUREMAGIC_DEEPSCAN=0.""" + monkeypatch.setenv("PUREMAGIC_DEEPSCAN", "0") + result = puremagic.main.single_deep_scan(b"PK\x03\x04", "fake.zip", head=b"\x00", foot=b"\x00") + assert result is None + + +def test_single_deep_scan_none_head(): + """main.py line 453: single_deep_scan returns None when head is None.""" + result = puremagic.main.single_deep_scan(b"PK\x03\x04", "fake.zip", head=None, foot=b"\x00") + assert result is None + result = puremagic.main.single_deep_scan(b"PK\x03\x04", "fake.zip", head=b"\x00", foot=None) + assert result is None + + +def test_catch_all_deep_scan_disabled(monkeypatch): + """main.py line 498: catch_all_deep_scan returns None when PUREMAGIC_DEEPSCAN=0.""" + monkeypatch.setenv("PUREMAGIC_DEEPSCAN", "0") + result = puremagic.main.catch_all_deep_scan("fake.txt", head=b"\x00", foot=b"\x00") + assert result is None + + +def test_catch_all_deep_scan_none_head(): + """main.py line 500: catch_all_deep_scan returns None when head is None.""" + result = puremagic.main.catch_all_deep_scan("fake.txt", head=None, foot=b"\x00") + assert result is None + + +def test_file_details_non_regular_file(): + """main.py line 235: file_details raises PureError for directories.""" + import pytest + + with pytest.raises(puremagic.main.PureError, match="Not a regular file"): + puremagic.main.file_details(SYSTEM_DIR) + + +def test_magic_file_no_matches(): + """main.py lines 346-347: identify_all raises PureError, caught and info set to [].""" + # File with random bytes that don't match any magic signature + random_file = SYSTEM_DIR / "test_random.bin" + random_file.write_bytes(bytes(range(256)) * 4) + try: + results = puremagic.magic_file(random_file) + # Should not raise — either returns results from deep scan or empty-ish list + assert isinstance(results, list) + finally: + random_file.unlink() + + +def test_run_deep_scan_no_matches_raises(monkeypatch): + """main.py lines 546-547: run_deep_scan raises PureError when no matches and raise_on_none=True.""" + import pytest + from puremagic.scanners import text_scanner + + random_file = SYSTEM_DIR / "test_unrecognizable.bin" + random_file.write_bytes(b"\x00" * 100) + # Patch catch-all text scanner to return None so we reach the raise + monkeypatch.setattr(text_scanner, "main", lambda *a, **kw: None) + try: + with pytest.raises(puremagic.main.PureError, match="Could not identify file"): + puremagic.main.run_deep_scan([], random_file, b"\x00" * 40, b"\x00" * 40, raise_on_none=True) + finally: + random_file.unlink() + + +# ── Medium tier: hdf5_scanner coverage ──────────────────────────────── + + +def test_hdf5_scanner_no_subtype(): + """hdf5_scanner lines 46-61: valid HDF5 magic but no matching subtype → None.""" + from puremagic.scanners import hdf5_scanner + + hdf5_file = SYSTEM_DIR / "test_generic.hdf5" + hdf5_file.write_bytes(b"\x89HDF\r\n\x1a\n" + b"\x00" * 1024) + try: + result = hdf5_scanner.main(hdf5_file, b"\x89HDF\r\n\x1a\n" + b"\x00" * 100, b"") + assert result is None + finally: + hdf5_file.unlink() + + +def test_hdf5_scanner_anndata_match(): + """hdf5_scanner lines 53-58: HDF5 with AnnData signatures → .h5ad.""" + from puremagic.scanners import hdf5_scanner + + # Create file with HDF5 magic + group paths that look like AnnData + content = b"\x89HDF\r\n\x1a\n" + b"\x00" * 100 + b"/obs" + b"\x00" * 100 + b"/var" + b"\x00" * 100 + hdf5_file = SYSTEM_DIR / "test_anndata.h5ad" + hdf5_file.write_bytes(content) + try: + result = hdf5_scanner.main(hdf5_file, content[:20], b"") + assert result is not None + assert result.extension == ".h5ad" + assert result.name == "AnnData" + assert result.confidence == 0.9 + finally: + hdf5_file.unlink() + + +# ── Medium tier: cfbf_scanner coverage ──────────────────────────────── + + +def test_cfbf_extract_stream_names_incomplete_entry(): + """cfbf_scanner line 60: break on incomplete trailing entry.""" + from puremagic.scanners.cfbf_scanner import _extract_stream_names + + # One valid 128-byte entry + 50 bytes of trailing garbage + entry = bytearray(128) + name = "TestStream".encode("utf-16-le") + b"\x00\x00" + entry[: len(name)] = name + import struct + + struct.pack_into(" Date: Tue, 7 Apr 2026 13:38:28 -0500 Subject: [PATCH 4/5] type check fixes --- test/test_scanners.py | 55 ++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/test/test_scanners.py b/test/test_scanners.py index 4088568..918b2b8 100644 --- a/test/test_scanners.py +++ b/test/test_scanners.py @@ -1,5 +1,6 @@ import os import tempfile +from pathlib import Path from zipfile import ZipFile import puremagic @@ -291,7 +292,7 @@ def test_ogg_scanner_synthetic_codecs(): ] for codec_id, expected_ext, expected_name, expected_mime in cases: head = _make_ogg_bos_page(codec_id) - result = ogg_scanner.main("fake.ogg", head, b"") + result = ogg_scanner.main(Path("fake.ogg"), head, b"") assert result is not None, f"codec {codec_id!r}: expected {expected_ext}, got None" assert result.extension == expected_ext assert result.name == expected_name @@ -302,15 +303,15 @@ def test_ogg_scanner_synthetic_codecs(): def test_ogg_scanner_rejects_non_ogg(): from puremagic.scanners import ogg_scanner - assert ogg_scanner.main("fake.ogg", b"not ogg data at all", b"") is None - assert ogg_scanner.main("fake.ogg", b"", b"") is None + assert ogg_scanner.main(Path("fake.ogg"), b"not ogg data at all", b"") is None + assert ogg_scanner.main(Path("fake.ogg"), b"", b"") is None # Valid OggS but wrong version - assert ogg_scanner.main("fake.ogg", b"OggS\x01\x02" + b"\x00" * 50, b"") is None + assert ogg_scanner.main(Path("fake.ogg"), b"OggS\x01\x02" + b"\x00" * 50, b"") is None # Valid OggS but not BOS page - assert ogg_scanner.main("fake.ogg", b"OggS\x00\x00" + b"\x00" * 50, b"") is None + assert ogg_scanner.main(Path("fake.ogg"), b"OggS\x00\x00" + b"\x00" * 50, b"") is None # Valid BOS page but unknown codec head = _make_ogg_bos_page(b"UnknownCodecXYZ") - assert ogg_scanner.main("fake.ogg", head, b"") is None + assert ogg_scanner.main(Path("fake.ogg"), head, b"") is None def test_asf_wmv_scanner(): @@ -363,7 +364,7 @@ def test_asf_scanner_generic_fallback(): obj_count = struct.pack(" 30 → break - result = asf_scanner.main("fake.asf", head, b"") + result = asf_scanner.main(Path("fake.asf"), head, b"") assert result is not None assert result.extension == ".asf" # Falls through to generic ASF @@ -546,7 +547,7 @@ def test_asf_scanner_bad_object_size(): # Object with GUID(16 bytes of 0xFF) + size=0 (invalid) obj = b"\xff" * 16 + struct.pack(" Date: Tue, 7 Apr 2026 13:40:19 -0500 Subject: [PATCH 5/5] Safety fixes --- puremagic/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/puremagic/main.py b/puremagic/main.py index a674358..e2f6419 100644 --- a/puremagic/main.py +++ b/puremagic/main.py @@ -209,10 +209,12 @@ def identify_all(header: bytes, footer: bytes, ext=None) -> list[PureMagicWithCo return determine_confidence(matches, ext) -def perform_magic(header: bytes, footer: bytes, mime: bool, ext=None, filename=None) -> str: +def perform_magic(header: bytes | None, footer: bytes | None, mime: bool | None, ext=None, filename=None) -> str: """Discover what type of file it is based on the incoming string""" if not header: raise PureValueError("Input was empty") + if not footer: + footer = b"" infos = identify_all(header, footer, ext) if filename and os.path.isfile(filename) and os.getenv("PUREMAGIC_DEEPSCAN") != "0": results = run_deep_scan(infos, filename, header, footer, raise_on_none=not infos)