From 6f243148f6290f53b4392dc465a2c03d73470e68 Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 11:48:50 +0100 Subject: [PATCH 01/26] Restructure modules --- recoverpy/lib/env_check.py | 2 +- recoverpy/lib/search/{scanner.py => binary_scanner.py} | 0 recoverpy/lib/search/search_engine.py | 8 ++++---- recoverpy/lib/storage/__init__.py | 0 .../block_device_inventory.py} | 0 .../{device_io.py => storage/block_device_metadata.py} | 0 .../byte_range_reader.py} | 0 recoverpy/lib/text/__init__.py | 0 recoverpy/lib/{helper.py => text/text_processing.py} | 2 +- recoverpy/models/search_params.py | 2 +- recoverpy/models/search_result.py | 2 +- recoverpy/ui/screens/screen_result.py | 4 ++-- recoverpy/ui/screens/screen_search.py | 2 +- recoverpy/ui/widgets/partition_list.py | 2 +- tests/conftest.py | 10 +++++----- tests/fixtures/mock_scan_hits.py | 2 +- tests/integration/test_block_extractor_integration.py | 2 +- tests/integration/test_full_workflow.py | 2 +- tests/integration/test_search_ui_responsiveness.py | 4 ++-- tests/unit/test_block_extractor.py | 2 +- tests/unit/test_device_discovery.py | 4 ++-- tests/unit/test_device_io.py | 2 +- tests/unit/test_partition_list.py | 2 +- tests/unit/test_result_screen.py | 2 +- tests/unit/test_scanner.py | 2 +- tests/unit/test_search_engine.py | 2 +- tests/unit/test_search_screen.py | 2 +- 27 files changed, 31 insertions(+), 31 deletions(-) rename recoverpy/lib/search/{scanner.py => binary_scanner.py} (100%) create mode 100644 recoverpy/lib/storage/__init__.py rename recoverpy/lib/{device_discovery.py => storage/block_device_inventory.py} (100%) rename recoverpy/lib/{device_io.py => storage/block_device_metadata.py} (100%) rename recoverpy/lib/{block_extractor.py => storage/byte_range_reader.py} (100%) create mode 100644 recoverpy/lib/text/__init__.py rename recoverpy/lib/{helper.py => text/text_processing.py} (84%) diff --git a/recoverpy/lib/env_check.py b/recoverpy/lib/env_check.py index 4692664a..c3557864 100644 --- a/recoverpy/lib/env_check.py +++ b/recoverpy/lib/env_check.py @@ -35,7 +35,7 @@ def _is_user_root() -> bool: def _is_version_supported() -> bool: - return version_info >= (3, 8) + return version_info >= (3, 9) def _is_linux() -> bool: diff --git a/recoverpy/lib/search/scanner.py b/recoverpy/lib/search/binary_scanner.py similarity index 100% rename from recoverpy/lib/search/scanner.py rename to recoverpy/lib/search/binary_scanner.py diff --git a/recoverpy/lib/search/search_engine.py b/recoverpy/lib/search/search_engine.py index 7bdd0a91..57fd5e78 100644 --- a/recoverpy/lib/search/search_engine.py +++ b/recoverpy/lib/search/search_engine.py @@ -13,10 +13,10 @@ from time import monotonic, sleep from typing import Iterable, Optional -from recoverpy.lib.block_extractor import BlockExtractionError, read_block -from recoverpy.lib.device_io import get_device_info -from recoverpy.lib.helper import decode_result, get_printable -from recoverpy.lib.search.scanner import ScanError, ScanHit, iter_scan_hits +from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, read_block +from recoverpy.lib.storage.block_device_metadata import get_device_info +from recoverpy.lib.text.text_processing import decode_result, get_printable +from recoverpy.lib.search.binary_scanner import ScanError, ScanHit, iter_scan_hits from recoverpy.log.logger import log from recoverpy.models.search_result import SearchResult from recoverpy.models.search_params import SearchParams diff --git a/recoverpy/lib/storage/__init__.py b/recoverpy/lib/storage/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/recoverpy/lib/device_discovery.py b/recoverpy/lib/storage/block_device_inventory.py similarity index 100% rename from recoverpy/lib/device_discovery.py rename to recoverpy/lib/storage/block_device_inventory.py diff --git a/recoverpy/lib/device_io.py b/recoverpy/lib/storage/block_device_metadata.py similarity index 100% rename from recoverpy/lib/device_io.py rename to recoverpy/lib/storage/block_device_metadata.py diff --git a/recoverpy/lib/block_extractor.py b/recoverpy/lib/storage/byte_range_reader.py similarity index 100% rename from recoverpy/lib/block_extractor.py rename to recoverpy/lib/storage/byte_range_reader.py diff --git a/recoverpy/lib/text/__init__.py b/recoverpy/lib/text/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/recoverpy/lib/helper.py b/recoverpy/lib/text/text_processing.py similarity index 84% rename from recoverpy/lib/helper.py rename to recoverpy/lib/text/text_processing.py index cc08eac7..f36a9e9c 100755 --- a/recoverpy/lib/helper.py +++ b/recoverpy/lib/text/text_processing.py @@ -1,6 +1,6 @@ from re import findall -from recoverpy.lib.device_io import get_logical_block_size +from recoverpy.lib.storage.block_device_metadata import get_logical_block_size def decode_result(result: bytes) -> str: return result.decode("utf-8", errors="ignore") diff --git a/recoverpy/models/search_params.py b/recoverpy/models/search_params.py index 9e85263d..955f1c5e 100755 --- a/recoverpy/models/search_params.py +++ b/recoverpy/models/search_params.py @@ -1,4 +1,4 @@ -from recoverpy.lib.helper import get_block_size +from recoverpy.lib.text.text_processing import get_block_size class SearchParams: diff --git a/recoverpy/models/search_result.py b/recoverpy/models/search_result.py index f12565ba..91954c46 100755 --- a/recoverpy/models/search_result.py +++ b/recoverpy/models/search_result.py @@ -2,7 +2,7 @@ from textual.widgets import Label, ListItem -from recoverpy.lib.helper import get_inode, get_printable +from recoverpy.lib.text.text_processing import get_inode, get_printable from recoverpy.log.logger import log diff --git a/recoverpy/ui/screens/screen_result.py b/recoverpy/ui/screens/screen_result.py index e0d9b0f1..62ced4f2 100755 --- a/recoverpy/ui/screens/screen_result.py +++ b/recoverpy/ui/screens/screen_result.py @@ -8,8 +8,8 @@ from textual.screen import Screen from textual.widgets import Button, Label, RichLog -from recoverpy.lib.block_extractor import BlockExtractionError, read_block -from recoverpy.lib.helper import decode_result, get_printable +from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, read_block +from recoverpy.lib.text.text_processing import decode_result, get_printable from recoverpy.lib.saver import Saver from recoverpy.log.logger import log from recoverpy.ui.screens.screen_save import SaveScreen diff --git a/recoverpy/ui/screens/screen_search.py b/recoverpy/ui/screens/screen_search.py index cf5ef360..1f626d8f 100755 --- a/recoverpy/ui/screens/screen_search.py +++ b/recoverpy/ui/screens/screen_search.py @@ -11,7 +11,7 @@ from textual.timer import Timer from textual.widgets import Button, Label -from recoverpy.lib.device_io import DeviceIOError +from recoverpy.lib.storage.block_device_metadata import DeviceIOError from recoverpy.lib.search.search_engine import SearchEngine from recoverpy.log.logger import log from recoverpy.models.search_result import SearchResult diff --git a/recoverpy/ui/widgets/partition_list.py b/recoverpy/ui/widgets/partition_list.py index 7b2e913b..bfbd855f 100755 --- a/recoverpy/ui/widgets/partition_list.py +++ b/recoverpy/ui/widgets/partition_list.py @@ -4,7 +4,7 @@ from textual.widgets import Label, ListItem, ListView -from recoverpy.lib.device_discovery import DeviceDiscoveryError, get_partitions +from recoverpy.lib.storage.block_device_inventory import DeviceDiscoveryError, get_partitions from recoverpy.log.logger import log from recoverpy.models.partition import Partition diff --git a/tests/conftest.py b/tests/conftest.py index 13639303..475c6ba7 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ import pytest import pytest_asyncio -from recoverpy.lib.device_io import DeviceInfo +from recoverpy.lib.storage.block_device_metadata import DeviceInfo from recoverpy.lib.search.search_engine import SearchEngine from .fixtures import ( @@ -40,19 +40,19 @@ def system_calls_mock(session_mocker): side_effect=mock_block_reader.mock_read_block_output, ) session_mocker.patch( - "recoverpy.lib.device_discovery._read_proc_mounts", + "recoverpy.lib.storage.block_device_inventory._read_proc_mounts", return_value=mock_device_discovery.MOCK_PROC_MOUNTS, ) session_mocker.patch( - "recoverpy.lib.device_discovery._read_proc_partition_sizes", + "recoverpy.lib.storage.block_device_inventory._read_proc_partition_sizes", return_value=mock_device_discovery.MOCK_PROC_PARTITION_SIZES, ) session_mocker.patch( - "recoverpy.lib.device_discovery._list_block_devices", + "recoverpy.lib.storage.block_device_inventory._list_block_devices", return_value=mock_device_discovery.MOCK_BLOCK_DEVICES, ) session_mocker.patch( - "recoverpy.lib.device_discovery._read_device_type", + "recoverpy.lib.storage.block_device_inventory._read_device_type", side_effect=mock_device_discovery.mock_read_device_type, ) session_mocker.patch( diff --git a/tests/fixtures/mock_scan_hits.py b/tests/fixtures/mock_scan_hits.py index 7ab0ab2c..d10ac051 100644 --- a/tests/fixtures/mock_scan_hits.py +++ b/tests/fixtures/mock_scan_hits.py @@ -1,4 +1,4 @@ -from recoverpy.lib.search.scanner import ScanHit +from recoverpy.lib.search.binary_scanner import ScanHit SCAN_HIT_COUNT = 3 diff --git a/tests/integration/test_block_extractor_integration.py b/tests/integration/test_block_extractor_integration.py index ead1aafe..8f463dcc 100644 --- a/tests/integration/test_block_extractor_integration.py +++ b/tests/integration/test_block_extractor_integration.py @@ -1,4 +1,4 @@ -from recoverpy.lib.block_extractor import extract_range, read_range +from recoverpy.lib.storage.byte_range_reader import extract_range, read_range def test_extract_range_from_fake_disk_image(tmp_path): diff --git a/tests/integration/test_full_workflow.py b/tests/integration/test_full_workflow.py index cce99d98..3e3b09dd 100644 --- a/tests/integration/test_full_workflow.py +++ b/tests/integration/test_full_workflow.py @@ -5,7 +5,7 @@ from textual.widgets import DirectoryTree from recoverpy import RecoverpyApp -from recoverpy.lib.device_io import DeviceInfo +from recoverpy.lib.storage.block_device_metadata import DeviceInfo from tests.conftest import TEST_BLOCK_SIZE from tests.fixtures.mock_scan_hits import SCAN_HIT_COUNT from tests.fixtures.mock_device_discovery import ( diff --git a/tests/integration/test_search_ui_responsiveness.py b/tests/integration/test_search_ui_responsiveness.py index 984d4bde..5f39c0ff 100644 --- a/tests/integration/test_search_ui_responsiveness.py +++ b/tests/integration/test_search_ui_responsiveness.py @@ -5,8 +5,8 @@ import pytest from recoverpy import RecoverpyApp -from recoverpy.lib.device_io import DeviceInfo -from recoverpy.lib.search.scanner import ScanHit +from recoverpy.lib.storage.block_device_metadata import DeviceInfo +from recoverpy.lib.search.binary_scanner import ScanHit from recoverpy.ui.screens.screen_params import ParamsScreen from tests.conftest import TEST_BLOCK_SIZE diff --git a/tests/unit/test_block_extractor.py b/tests/unit/test_block_extractor.py index a869585c..047f9678 100644 --- a/tests/unit/test_block_extractor.py +++ b/tests/unit/test_block_extractor.py @@ -2,7 +2,7 @@ import pytest -from recoverpy.lib.block_extractor import BlockExtractionError, extract_range, read_block +from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, extract_range, read_block def test_extract_range_success(tmp_path): diff --git a/tests/unit/test_device_discovery.py b/tests/unit/test_device_discovery.py index e8838521..82fe6a52 100755 --- a/tests/unit/test_device_discovery.py +++ b/tests/unit/test_device_discovery.py @@ -1,6 +1,6 @@ import pytest -from recoverpy.lib.device_discovery import ( +from recoverpy.lib.storage.block_device_inventory import ( DeviceDiscoveryError, _IGNORED_PARTITION_TYPES, get_partitions, @@ -27,7 +27,7 @@ def test_get_partitions_unfiltered(): def test_get_partitions_permission_error(mocker): mocker.patch( - "recoverpy.lib.device_discovery._read_proc_mounts", + "recoverpy.lib.storage.block_device_inventory._read_proc_mounts", side_effect=PermissionError("permission denied"), ) diff --git a/tests/unit/test_device_io.py b/tests/unit/test_device_io.py index beb08917..3d78255e 100644 --- a/tests/unit/test_device_io.py +++ b/tests/unit/test_device_io.py @@ -4,7 +4,7 @@ import pytest -from recoverpy.lib.device_io import ( +from recoverpy.lib.storage.block_device_metadata import ( BLKGETSIZE64, BLKPBSZGET, BLKROGET, diff --git a/tests/unit/test_partition_list.py b/tests/unit/test_partition_list.py index 4745b919..0133ca9f 100644 --- a/tests/unit/test_partition_list.py +++ b/tests/unit/test_partition_list.py @@ -1,7 +1,7 @@ import pytest from textual.app import App, ComposeResult -from recoverpy.lib.device_discovery import DeviceDiscoveryError +from recoverpy.lib.storage.block_device_inventory import DeviceDiscoveryError from recoverpy.ui.widgets.partition_list import PartitionList diff --git a/tests/unit/test_result_screen.py b/tests/unit/test_result_screen.py index 41c5cbcb..51f080fc 100644 --- a/tests/unit/test_result_screen.py +++ b/tests/unit/test_result_screen.py @@ -1,4 +1,4 @@ -from recoverpy.lib.block_extractor import BlockExtractionError +from recoverpy.lib.storage.byte_range_reader import BlockExtractionError from recoverpy.ui.screens.screen_result import ResultScreen diff --git a/tests/unit/test_scanner.py b/tests/unit/test_scanner.py index eaa98708..2e2a444d 100644 --- a/tests/unit/test_scanner.py +++ b/tests/unit/test_scanner.py @@ -1,6 +1,6 @@ from threading import Event -from recoverpy.lib.search.scanner import iter_scan_hits +from recoverpy.lib.search.binary_scanner import iter_scan_hits def test_scan_offsets_are_exact(tmp_path): diff --git a/tests/unit/test_search_engine.py b/tests/unit/test_search_engine.py index c64166ec..113045b1 100755 --- a/tests/unit/test_search_engine.py +++ b/tests/unit/test_search_engine.py @@ -4,7 +4,7 @@ import pytest import recoverpy.lib.search.search_engine as search_engine_module -from recoverpy.lib.search.scanner import ScanHit +from recoverpy.lib.search.binary_scanner import ScanHit from tests.fixtures.mock_scan_hits import SCAN_HIT_COUNT from tests.integration.helper import assert_with_timeout diff --git a/tests/unit/test_search_screen.py b/tests/unit/test_search_screen.py index 4ade768c..5294fb43 100644 --- a/tests/unit/test_search_screen.py +++ b/tests/unit/test_search_screen.py @@ -3,7 +3,7 @@ import pytest from recoverpy import RecoverpyApp -from recoverpy.lib.device_io import DeviceIOError +from recoverpy.lib.storage.block_device_metadata import DeviceIOError from recoverpy.ui.screens.screen_search import SearchScreen From 420f4813bce06fa8c300f8d5bba3f56c920e790a Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 11:55:19 +0100 Subject: [PATCH 02/26] Add missing docstrings --- recoverpy/__init__.py | 2 ++ recoverpy/__main__.py | 2 ++ recoverpy/lib/env_check.py | 2 ++ recoverpy/lib/saver.py | 2 ++ recoverpy/lib/search/binary_scanner.py | 28 +++++++++++++--- recoverpy/lib/search/search_engine.py | 33 ++++++++++++++----- recoverpy/lib/storage/__init__.py | 1 + .../lib/storage/block_device_inventory.py | 2 ++ .../lib/storage/block_device_metadata.py | 6 ++++ recoverpy/lib/storage/byte_range_reader.py | 5 +++ recoverpy/lib/text/__init__.py | 1 + recoverpy/lib/text/text_processing.py | 2 ++ recoverpy/log/logger.py | 2 ++ recoverpy/models/partition.py | 2 ++ recoverpy/models/search_params.py | 2 ++ recoverpy/models/search_progress.py | 2 ++ recoverpy/models/search_result.py | 2 ++ recoverpy/ui/__init__.py | 1 + recoverpy/ui/css/__init__.py | 2 ++ recoverpy/ui/screens/__init__.py | 1 + recoverpy/ui/screens/modal.py | 2 ++ recoverpy/ui/screens/screen_search.py | 4 +-- .../ui/widgets/folder_only_directory_tree.py | 2 ++ recoverpy/ui/widgets/search_result_list.py | 1 - 24 files changed, 92 insertions(+), 17 deletions(-) diff --git a/recoverpy/__init__.py b/recoverpy/__init__.py index cf0d4766..03230b9f 100755 --- a/recoverpy/__init__.py +++ b/recoverpy/__init__.py @@ -1,3 +1,5 @@ +"""RecoverPy command-line bootstrap and application launcher.""" + import argparse import logging from datetime import datetime diff --git a/recoverpy/__main__.py b/recoverpy/__main__.py index ebc4b340..f4b1d006 100755 --- a/recoverpy/__main__.py +++ b/recoverpy/__main__.py @@ -1,3 +1,5 @@ +"""Executable module entrypoint for `python -m recoverpy`.""" + import recoverpy if __name__ == "__main__": diff --git a/recoverpy/lib/env_check.py b/recoverpy/lib/env_check.py index c3557864..c10fed82 100644 --- a/recoverpy/lib/env_check.py +++ b/recoverpy/lib/env_check.py @@ -1,3 +1,5 @@ +"""Runtime environment checks executed at application startup.""" + from os import geteuid from platform import system from sys import exit, version_info diff --git a/recoverpy/lib/saver.py b/recoverpy/lib/saver.py index 2ae00ce0..4488c6ab 100755 --- a/recoverpy/lib/saver.py +++ b/recoverpy/lib/saver.py @@ -1,3 +1,5 @@ +"""Persistence helper for user-selected recovered blocks.""" + from datetime import datetime from pathlib import Path from typing import Dict, List, Optional diff --git a/recoverpy/lib/search/binary_scanner.py b/recoverpy/lib/search/binary_scanner.py index 0ce1e336..1afdcf69 100644 --- a/recoverpy/lib/search/binary_scanner.py +++ b/recoverpy/lib/search/binary_scanner.py @@ -1,3 +1,11 @@ +""" +Streaming binary scanner for devices and disk images. + +This module performs chunked byte-pattern scanning without loading the full source +in memory. It emits lightweight `ScanHit` records containing the absolute match +offset and a bounded preview window around each match. +""" + from __future__ import annotations import os @@ -6,6 +14,12 @@ from time import sleep from typing import Iterator +DEFAULT_SCAN_CHUNK_SIZE = 8 * 1024 * 1024 +DEFAULT_PREVIEW_BEFORE_BYTES = 256 +DEFAULT_PREVIEW_AFTER_BYTES = 256 +DEFAULT_MAX_PREVIEW_BYTES = 512 +PAUSE_POLL_INTERVAL_SECONDS = 0.25 + @dataclass(frozen=True) class ScanHit: @@ -23,10 +37,10 @@ def iter_scan_hits( source_path: str, needle: bytes, *, - chunk_size: int = 8 * 1024 * 1024, - preview_before: int = 256, - preview_after: int = 256, - max_preview_len: int = 512, + chunk_size: int = DEFAULT_SCAN_CHUNK_SIZE, + preview_before: int = DEFAULT_PREVIEW_BEFORE_BYTES, + preview_after: int = DEFAULT_PREVIEW_AFTER_BYTES, + max_preview_len: int = DEFAULT_MAX_PREVIEW_BYTES, stop_event: Event | None = None, pause_event: Event | None = None, ) -> Iterator[ScanHit]: @@ -39,6 +53,8 @@ def iter_scan_hits( if max_preview_len <= 0: raise ValueError("max_preview_len must be > 0") + # Keep enough trailing bytes from the previous chunk so matches crossing + # chunk boundaries are still detected in the next iteration. overlap = max(0, len(needle) - 1) tail_size = max(overlap, preview_before) preview_window = min(max_preview_len, preview_before + preview_after) @@ -65,7 +81,7 @@ def iter_scan_hits( while pause_event and pause_event.is_set(): if stop_event and stop_event.is_set(): return - sleep(0.25) + sleep(PAUSE_POLL_INTERVAL_SECONDS) try: chunk = os.read(fd, chunk_size) except PermissionError as error: @@ -94,6 +110,8 @@ def iter_scan_hits( absolute_match_offset = buffer_start_offset + match_index search_index = match_index + 1 + # Skip offsets that belong to the previous chunk overlap; + # this prevents duplicate hits while preserving boundary matches. if absolute_match_offset < min_new_match_offset: continue diff --git a/recoverpy/lib/search/search_engine.py b/recoverpy/lib/search/search_engine.py index 57fd5e78..ddaac6f4 100644 --- a/recoverpy/lib/search/search_engine.py +++ b/recoverpy/lib/search/search_engine.py @@ -10,7 +10,7 @@ from collections import OrderedDict from queue import Empty, Full, Queue from threading import Event, Thread -from time import monotonic, sleep +from time import monotonic from typing import Iterable, Optional from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, read_block @@ -26,6 +26,10 @@ _RECENT_BLOCKS_MAXSIZE = 8192 _BATCH_MAX_ITEMS = 100 _BATCH_MAX_WAIT_SECONDS = 0.2 +_QUEUE_PUT_TIMEOUT_SECONDS = 0.1 +_QUEUE_GET_MIN_TIMEOUT_SECONDS = 0.01 +_WORKER_JOIN_TIMEOUT_SECONDS = 1.0 +_MULTILINE_VALIDATION_BLOCK_SPAN = 8 class SearchEngine: @@ -33,6 +37,8 @@ def __init__(self, partition: str, searched_string: str): self.search_params = SearchParams(partition, searched_string) self.search_progress = SearchProgress() self.formatted_results_queue: AsyncQueue[SearchResult] = AsyncQueue() + # Bounded queue enforces backpressure from producer to converter so + # memory usage remains bounded on high-hit scans. self.raw_scan_hits_queue: Queue[Optional[ScanHit]] = Queue( maxsize=_RAW_HITS_QUEUE_MAXSIZE ) @@ -53,9 +59,9 @@ def stop_search(self) -> None: self._pause_event.clear() self._enqueue_sentinel() if self._scan_thread and self._scan_thread.is_alive(): - self._scan_thread.join(timeout=1.0) + self._scan_thread.join(timeout=_WORKER_JOIN_TIMEOUT_SECONDS) if self._convert_thread and self._convert_thread.is_alive(): - self._convert_thread.join(timeout=1.0) + self._convert_thread.join(timeout=_WORKER_JOIN_TIMEOUT_SECONDS) def pause_search(self) -> None: self._pause_event.set() @@ -96,7 +102,9 @@ def _scan_hits_worker(self) -> None: while not self._stop_event.is_set(): try: - self.raw_scan_hits_queue.put(hit, timeout=0.1) + self.raw_scan_hits_queue.put( + hit, timeout=_QUEUE_PUT_TIMEOUT_SECONDS + ) break except Full: continue @@ -128,6 +136,7 @@ def _enqueue_sentinel(self) -> None: return except Full: try: + # Free one slot to guarantee sentinel delivery during shutdown. self.raw_scan_hits_queue.get_nowait() except Empty: continue @@ -148,7 +157,7 @@ def _convert_hits_worker(self) -> None: deadline = monotonic() + _BATCH_MAX_WAIT_SECONDS while len(batch) < _BATCH_MAX_ITEMS and monotonic() < deadline: - timeout = max(0.01, deadline - monotonic()) + timeout = max(_QUEUE_GET_MIN_TIMEOUT_SECONDS, deadline - monotonic()) try: item = self.raw_scan_hits_queue.get(timeout=timeout) except Empty: @@ -173,6 +182,8 @@ def _process_hits_batch( for hit in hits: inode = hit.match_offset // self.search_params.block_size + # Recent-block dedup intentionally stays bounded to avoid unbounded + # memory growth while still reducing noisy near-duplicate hits. if self._is_recent_block(inode): continue @@ -192,18 +203,22 @@ def _process_hits_batch( self._mark_recent_block(inode) def _is_hit_valid_multiline(self, hit: ScanHit) -> bool: - block_factor = self.search_params.block_size * 8 - block_index = hit.match_offset // block_factor + # Multi-line validation reads a wider window than a single logical block + # so patterns split across adjacent blocks are still validated. + multiline_validation_block_size = ( + self.search_params.block_size * _MULTILINE_VALIDATION_BLOCK_SPAN + ) + block_index = hit.match_offset // multiline_validation_block_size try: current_block = read_block( self.search_params.partition, - block_factor, + multiline_validation_block_size, block_index, ) next_block = read_block( self.search_params.partition, - block_factor, + multiline_validation_block_size, block_index + 1, ) except BlockExtractionError as error: diff --git a/recoverpy/lib/storage/__init__.py b/recoverpy/lib/storage/__init__.py index e69de29b..b703916c 100644 --- a/recoverpy/lib/storage/__init__.py +++ b/recoverpy/lib/storage/__init__.py @@ -0,0 +1 @@ +"""Storage-layer modules for block metadata, inventory and byte-range reads.""" diff --git a/recoverpy/lib/storage/block_device_inventory.py b/recoverpy/lib/storage/block_device_inventory.py index b29c41b9..5f5e4a9d 100644 --- a/recoverpy/lib/storage/block_device_inventory.py +++ b/recoverpy/lib/storage/block_device_inventory.py @@ -1,3 +1,5 @@ +"""Linux block device and partition inventory discovery.""" + from pathlib import Path from typing import Dict, List, Optional, Tuple diff --git a/recoverpy/lib/storage/block_device_metadata.py b/recoverpy/lib/storage/block_device_metadata.py index bccf9c4d..7ef2105d 100644 --- a/recoverpy/lib/storage/block_device_metadata.py +++ b/recoverpy/lib/storage/block_device_metadata.py @@ -1,9 +1,13 @@ +"""Low-level block device metadata access via Linux ioctl with safe fallbacks.""" + import fcntl import os import stat import struct from dataclasses import dataclass +# Linux block ioctl request numbers. +# They are stable kernel ABI constants and intentionally kept explicit here. BLKGETSIZE64 = 0x80081272 BLKSSZGET = 0x1268 BLKPBSZGET = 0x127B @@ -77,6 +81,8 @@ def _get_block_device_info(fd: int, path: str) -> DeviceInfo: try: physical_sector_size = _ioctl_get_u32(fd, BLKPBSZGET) except (PermissionError, OSError): + # Some devices/filesystems do not expose physical block size cleanly. + # Falling back to logical size keeps the rest of the pipeline usable. physical_sector_size = logical_sector_size return DeviceInfo( diff --git a/recoverpy/lib/storage/byte_range_reader.py b/recoverpy/lib/storage/byte_range_reader.py index 97091f29..932cbb50 100644 --- a/recoverpy/lib/storage/byte_range_reader.py +++ b/recoverpy/lib/storage/byte_range_reader.py @@ -1,3 +1,5 @@ +"""Bounded byte-range extraction and block reads for devices and disk images.""" + import errno import os from pathlib import Path @@ -47,6 +49,8 @@ def extract_range( os.close(source_fd) if remaining > 0: + # Partial reads at EOF/device end are treated as explicit failures so + # callers never mistake truncated output for a successful extraction. raise BlockExtractionError( "Requested range exceeds available data.", f"Cannot read requested range from {source_path}: reached end of file/device.", @@ -115,6 +119,7 @@ def _open_source(source_path: str) -> int: def _safe_pread(source_fd: int, size: int, offset: int, source_path: str) -> bytes: try: + # pread keeps read position explicit and thread-safe for random access. return os.pread(source_fd, size, offset) except PermissionError as error: raise BlockExtractionError( diff --git a/recoverpy/lib/text/__init__.py b/recoverpy/lib/text/__init__.py index e69de29b..674b61b6 100644 --- a/recoverpy/lib/text/__init__.py +++ b/recoverpy/lib/text/__init__.py @@ -0,0 +1 @@ +"""Text-processing utilities shared across search and UI layers.""" diff --git a/recoverpy/lib/text/text_processing.py b/recoverpy/lib/text/text_processing.py index f36a9e9c..6040dfcd 100755 --- a/recoverpy/lib/text/text_processing.py +++ b/recoverpy/lib/text/text_processing.py @@ -1,3 +1,5 @@ +"""String and byte helpers used by search and rendering layers.""" + from re import findall from recoverpy.lib.storage.block_device_metadata import get_logical_block_size diff --git a/recoverpy/log/logger.py b/recoverpy/log/logger.py index 0148f157..9934e2b5 100644 --- a/recoverpy/log/logger.py +++ b/recoverpy/log/logger.py @@ -1,3 +1,5 @@ +"""Shared application logger instance.""" + import logging log = logging.getLogger() diff --git a/recoverpy/models/partition.py b/recoverpy/models/partition.py index f394a82b..d02571ac 100755 --- a/recoverpy/models/partition.py +++ b/recoverpy/models/partition.py @@ -1,3 +1,5 @@ +"""Domain model describing partitions/devices presented in the UI.""" + from dataclasses import dataclass from typing import Optional diff --git a/recoverpy/models/search_params.py b/recoverpy/models/search_params.py index 955f1c5e..baaeca63 100755 --- a/recoverpy/models/search_params.py +++ b/recoverpy/models/search_params.py @@ -1,3 +1,5 @@ +"""Immutable-ish search request parameters derived from user input.""" + from recoverpy.lib.text.text_processing import get_block_size diff --git a/recoverpy/models/search_progress.py b/recoverpy/models/search_progress.py index c3a0dcba..0e7a51f9 100755 --- a/recoverpy/models/search_progress.py +++ b/recoverpy/models/search_progress.py @@ -1,3 +1,5 @@ +"""Shared mutable search progress state consumed by the UI.""" + class SearchProgress: def __init__(self) -> None: self.result_count = 0 diff --git a/recoverpy/models/search_result.py b/recoverpy/models/search_result.py index 91954c46..e3bf72bd 100755 --- a/recoverpy/models/search_result.py +++ b/recoverpy/models/search_result.py @@ -1,3 +1,5 @@ +"""Search result item model mapped to Textual list rows.""" + from typing import Optional from textual.widgets import Label, ListItem diff --git a/recoverpy/ui/__init__.py b/recoverpy/ui/__init__.py index e69de29b..5a4cdd52 100644 --- a/recoverpy/ui/__init__.py +++ b/recoverpy/ui/__init__.py @@ -0,0 +1 @@ +"""Textual UI package for RecoverPy screens and widgets.""" diff --git a/recoverpy/ui/css/__init__.py b/recoverpy/ui/css/__init__.py index 57e78e3a..7cad3578 100755 --- a/recoverpy/ui/css/__init__.py +++ b/recoverpy/ui/css/__init__.py @@ -1,3 +1,5 @@ +"""CSS asset discovery utilities used by the Textual app.""" + from pathlib import Path from typing import List diff --git a/recoverpy/ui/screens/__init__.py b/recoverpy/ui/screens/__init__.py index e69de29b..c15e07ba 100644 --- a/recoverpy/ui/screens/__init__.py +++ b/recoverpy/ui/screens/__init__.py @@ -0,0 +1 @@ +"""Screen modules composing RecoverPy's Textual interface.""" diff --git a/recoverpy/ui/screens/modal.py b/recoverpy/ui/screens/modal.py index d72010a5..ccc6c3de 100644 --- a/recoverpy/ui/screens/modal.py +++ b/recoverpy/ui/screens/modal.py @@ -1,3 +1,5 @@ +"""Reusable modal screen helpers for user-facing messages and confirmations.""" + from typing import Callable, List, Optional from textual.app import App, ComposeResult diff --git a/recoverpy/ui/screens/screen_search.py b/recoverpy/ui/screens/screen_search.py index 1f626d8f..b423ac66 100755 --- a/recoverpy/ui/screens/screen_search.py +++ b/recoverpy/ui/screens/screen_search.py @@ -1,7 +1,6 @@ """Screen displaying search results.""" from asyncio import Task, create_task -from typing import List from textual.app import ComposeResult from textual.binding import Binding @@ -43,7 +42,6 @@ def __init__(self, *args, **kwargs) -> None: # type: ignore super().__init__(classes="info-container", *args, **kwargs) def __init__(self, *args, **kwargs) -> None: # type: ignore - self.results: List[str] = [] self._progress_timer: Timer | None = None self._consumer_task: Task[None] | None = None self._search_error_notified = False @@ -96,6 +94,8 @@ async def on_search_screen_start(self, message: Start) -> None: async def _start_search_engine(self) -> None: await self.search_engine.start_search() + # UI consumes formatted results asynchronously while scan workers run + # in background threads managed by SearchEngine. self._consumer_task = create_task( self._search_result_list.start_consumer( self.search_engine.formatted_results_queue diff --git a/recoverpy/ui/widgets/folder_only_directory_tree.py b/recoverpy/ui/widgets/folder_only_directory_tree.py index ddf8a98f..64e833bc 100644 --- a/recoverpy/ui/widgets/folder_only_directory_tree.py +++ b/recoverpy/ui/widgets/folder_only_directory_tree.py @@ -1,3 +1,5 @@ +"""DirectoryTree specialization that only exposes folders as selectable nodes.""" + from pathlib import Path from typing import Iterable diff --git a/recoverpy/ui/widgets/search_result_list.py b/recoverpy/ui/widgets/search_result_list.py index 7a36b338..c16dc4f6 100755 --- a/recoverpy/ui/widgets/search_result_list.py +++ b/recoverpy/ui/widgets/search_result_list.py @@ -14,7 +14,6 @@ class SearchResultList(ListView): def __init__(self, *children, **kwargs) -> None: # type: ignore super().__init__(*children, **kwargs) - self.results: List[str] = [] self.lock = Lock() self.search_results: List[SearchResult] = [] self.id = "search-result-list" From e92892517389c242004025528217868a86f05527 Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 12:09:17 +0100 Subject: [PATCH 03/26] Refactor binary scanner --- recoverpy/lib/search/binary_scanner.py | 158 +++++++++++++++-------- recoverpy/ui/screens/screen_path_edit.py | 2 - 2 files changed, 104 insertions(+), 56 deletions(-) diff --git a/recoverpy/lib/search/binary_scanner.py b/recoverpy/lib/search/binary_scanner.py index 1afdcf69..bdd0b9a0 100644 --- a/recoverpy/lib/search/binary_scanner.py +++ b/recoverpy/lib/search/binary_scanner.py @@ -44,14 +44,13 @@ def iter_scan_hits( stop_event: Event | None = None, pause_event: Event | None = None, ) -> Iterator[ScanHit]: - if not needle: - raise ValueError("needle must not be empty") - if chunk_size <= 0: - raise ValueError("chunk_size must be > 0") - if preview_before < 0 or preview_after < 0: - raise ValueError("preview sizes must be >= 0") - if max_preview_len <= 0: - raise ValueError("max_preview_len must be > 0") + _validate_scan_params( + needle=needle, + chunk_size=chunk_size, + preview_before=preview_before, + preview_after=preview_after, + max_preview_len=max_preview_len, + ) # Keep enough trailing bytes from the previous chunk so matches crossing # chunk boundaries are still detected in the next iteration. @@ -59,42 +58,20 @@ def iter_scan_hits( tail_size = max(overlap, preview_before) preview_window = min(max_preview_len, preview_before + preview_after) - try: - fd = os.open(source_path, os.O_RDONLY) - except PermissionError as error: - raise ScanError( - f"Cannot open scan source {source_path}: {error}", - f"Permission denied opening {source_path} (run as root).", - ) from error - except OSError as error: - raise ScanError( - f"Cannot open scan source {source_path}: {error}", - f"Cannot open {source_path}.", - ) from error + fd = _open_scan_source(source_path) offset = 0 tail = b"" try: while True: - if stop_event and stop_event.is_set(): + if _should_stop(stop_event): + return + + _wait_if_paused(stop_event=stop_event, pause_event=pause_event) + if _should_stop(stop_event): return - while pause_event and pause_event.is_set(): - if stop_event and stop_event.is_set(): - return - sleep(PAUSE_POLL_INTERVAL_SECONDS) - try: - chunk = os.read(fd, chunk_size) - except PermissionError as error: - raise ScanError( - f"Permission denied while reading {source_path}: {error}", - f"Permission denied reading {source_path} (run as root).", - ) from error - except OSError as error: - raise ScanError( - f"I/O error while reading {source_path}: {error}", - f"I/O error reading {source_path}.", - ) from error + chunk = _read_chunk(fd=fd, source_path=source_path, chunk_size=chunk_size) if not chunk: return @@ -102,19 +79,12 @@ def iter_scan_hits( buffer_start_offset = offset - len(tail) min_new_match_offset = max(0, offset - overlap) - search_index = 0 - while True: - match_index = buffer.find(needle, search_index) - if match_index < 0: - break - - absolute_match_offset = buffer_start_offset + match_index - search_index = match_index + 1 - # Skip offsets that belong to the previous chunk overlap; - # this prevents duplicate hits while preserving boundary matches. - if absolute_match_offset < min_new_match_offset: - continue - + for absolute_match_offset in _iter_match_offsets( + buffer=buffer, + needle=needle, + buffer_start_offset=buffer_start_offset, + min_new_match_offset=min_new_match_offset, + ): preview = _read_preview( fd=fd, match_offset=absolute_match_offset, @@ -125,14 +95,94 @@ def iter_scan_hits( yield ScanHit(match_offset=absolute_match_offset, preview=preview) offset += len(chunk) - if tail_size > 0: - tail = buffer[-tail_size:] - else: - tail = b"" + tail = buffer[-tail_size:] if tail_size > 0 else b"" finally: os.close(fd) +def _validate_scan_params( + *, + needle: bytes, + chunk_size: int, + preview_before: int, + preview_after: int, + max_preview_len: int, +) -> None: + if not needle: + raise ValueError("needle must not be empty") + if chunk_size <= 0: + raise ValueError("chunk_size must be > 0") + if preview_before < 0 or preview_after < 0: + raise ValueError("preview sizes must be >= 0") + if max_preview_len <= 0: + raise ValueError("max_preview_len must be > 0") + + +def _open_scan_source(source_path: str) -> int: + try: + return os.open(source_path, os.O_RDONLY) + except PermissionError as error: + raise ScanError( + f"Cannot open scan source {source_path}: {error}", + f"Permission denied opening {source_path} (run as root).", + ) from error + except OSError as error: + raise ScanError( + f"Cannot open scan source {source_path}: {error}", + f"Cannot open {source_path}.", + ) from error + + +def _read_chunk(*, fd: int, source_path: str, chunk_size: int) -> bytes: + try: + return os.read(fd, chunk_size) + except PermissionError as error: + raise ScanError( + f"Permission denied while reading {source_path}: {error}", + f"Permission denied reading {source_path} (run as root).", + ) from error + except OSError as error: + raise ScanError( + f"I/O error while reading {source_path}: {error}", + f"I/O error reading {source_path}.", + ) from error + + +def _should_stop(stop_event: Event | None) -> bool: + return bool(stop_event and stop_event.is_set()) + + +def _wait_if_paused(*, stop_event: Event | None, pause_event: Event | None) -> None: + while pause_event and pause_event.is_set(): + if _should_stop(stop_event): + return + sleep(PAUSE_POLL_INTERVAL_SECONDS) + + +def _iter_match_offsets( + *, + buffer: bytes, + needle: bytes, + buffer_start_offset: int, + min_new_match_offset: int, +) -> Iterator[int]: + search_index = 0 + while True: + match_index = buffer.find(needle, search_index) + if match_index < 0: + return + + absolute_match_offset = buffer_start_offset + match_index + search_index = match_index + 1 + + # Skip offsets that belong to the previous chunk overlap; + # this prevents duplicate hits while preserving boundary matches. + if absolute_match_offset < min_new_match_offset: + continue + + yield absolute_match_offset + + def _read_preview( *, fd: int, diff --git a/recoverpy/ui/screens/screen_path_edit.py b/recoverpy/ui/screens/screen_path_edit.py index 5fc239b8..e555499b 100755 --- a/recoverpy/ui/screens/screen_path_edit.py +++ b/recoverpy/ui/screens/screen_path_edit.py @@ -1,7 +1,5 @@ """Screen used to select result save path.""" -from pathlib import Path - from textual.app import ComposeResult from textual.binding import Binding from textual.containers import Horizontal From e11b01e6a86d038849faef36972c1a30b868b531 Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 12:10:54 +0100 Subject: [PATCH 04/26] Run isort --- recoverpy/lib/search/search_engine.py | 8 +++++--- recoverpy/lib/text/text_processing.py | 1 + recoverpy/ui/screens/screen_path_edit.py | 3 ++- recoverpy/ui/screens/screen_result.py | 5 +++-- recoverpy/ui/screens/screen_search.py | 2 +- recoverpy/ui/widgets/partition_list.py | 3 ++- tests/conftest.py | 8 ++------ tests/integration/test_full_workflow.py | 19 ++++++------------- .../test_search_ui_responsiveness.py | 2 +- tests/unit/test_block_extractor.py | 3 ++- tests/unit/test_device_discovery.py | 11 +++-------- tests/unit/test_device_io.py | 10 ++-------- tests/unit/test_folder_only_directory_tree.py | 3 ++- 13 files changed, 32 insertions(+), 46 deletions(-) diff --git a/recoverpy/lib/search/search_engine.py b/recoverpy/lib/search/search_engine.py index ddaac6f4..cb1ccfeb 100644 --- a/recoverpy/lib/search/search_engine.py +++ b/recoverpy/lib/search/search_engine.py @@ -13,14 +13,16 @@ from time import monotonic from typing import Iterable, Optional -from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, read_block +from recoverpy.lib.search.binary_scanner import (ScanError, ScanHit, + iter_scan_hits) from recoverpy.lib.storage.block_device_metadata import get_device_info +from recoverpy.lib.storage.byte_range_reader import (BlockExtractionError, + read_block) from recoverpy.lib.text.text_processing import decode_result, get_printable -from recoverpy.lib.search.binary_scanner import ScanError, ScanHit, iter_scan_hits from recoverpy.log.logger import log -from recoverpy.models.search_result import SearchResult from recoverpy.models.search_params import SearchParams from recoverpy.models.search_progress import SearchProgress +from recoverpy.models.search_result import SearchResult _RAW_HITS_QUEUE_MAXSIZE = 4000 _RECENT_BLOCKS_MAXSIZE = 8192 diff --git a/recoverpy/lib/text/text_processing.py b/recoverpy/lib/text/text_processing.py index 6040dfcd..40b363f7 100755 --- a/recoverpy/lib/text/text_processing.py +++ b/recoverpy/lib/text/text_processing.py @@ -4,6 +4,7 @@ from recoverpy.lib.storage.block_device_metadata import get_logical_block_size + def decode_result(result: bytes) -> str: return result.decode("utf-8", errors="ignore") diff --git a/recoverpy/ui/screens/screen_path_edit.py b/recoverpy/ui/screens/screen_path_edit.py index e555499b..fbdc87bf 100755 --- a/recoverpy/ui/screens/screen_path_edit.py +++ b/recoverpy/ui/screens/screen_path_edit.py @@ -8,7 +8,8 @@ from textual.widgets import Button, DirectoryTree, Label from recoverpy.log.logger import log -from recoverpy.ui.widgets.folder_only_directory_tree import FolderOnlyDirectoryTree +from recoverpy.ui.widgets.folder_only_directory_tree import \ + FolderOnlyDirectoryTree class PathEditScreen(Screen[None]): diff --git a/recoverpy/ui/screens/screen_result.py b/recoverpy/ui/screens/screen_result.py index 62ced4f2..69b817d1 100755 --- a/recoverpy/ui/screens/screen_result.py +++ b/recoverpy/ui/screens/screen_result.py @@ -8,9 +8,10 @@ from textual.screen import Screen from textual.widgets import Button, Label, RichLog -from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, read_block -from recoverpy.lib.text.text_processing import decode_result, get_printable from recoverpy.lib.saver import Saver +from recoverpy.lib.storage.byte_range_reader import (BlockExtractionError, + read_block) +from recoverpy.lib.text.text_processing import decode_result, get_printable from recoverpy.log.logger import log from recoverpy.ui.screens.screen_save import SaveScreen diff --git a/recoverpy/ui/screens/screen_search.py b/recoverpy/ui/screens/screen_search.py index b423ac66..7367b633 100755 --- a/recoverpy/ui/screens/screen_search.py +++ b/recoverpy/ui/screens/screen_search.py @@ -10,8 +10,8 @@ from textual.timer import Timer from textual.widgets import Button, Label -from recoverpy.lib.storage.block_device_metadata import DeviceIOError from recoverpy.lib.search.search_engine import SearchEngine +from recoverpy.lib.storage.block_device_metadata import DeviceIOError from recoverpy.log.logger import log from recoverpy.models.search_result import SearchResult from recoverpy.ui.widgets.search_result_list import SearchResultList diff --git a/recoverpy/ui/widgets/partition_list.py b/recoverpy/ui/widgets/partition_list.py index bfbd855f..c4a31eb2 100755 --- a/recoverpy/ui/widgets/partition_list.py +++ b/recoverpy/ui/widgets/partition_list.py @@ -4,7 +4,8 @@ from textual.widgets import Label, ListItem, ListView -from recoverpy.lib.storage.block_device_inventory import DeviceDiscoveryError, get_partitions +from recoverpy.lib.storage.block_device_inventory import (DeviceDiscoveryError, + get_partitions) from recoverpy.log.logger import log from recoverpy.models.partition import Partition diff --git a/tests/conftest.py b/tests/conftest.py index 475c6ba7..1ac0e9c0 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,14 +3,10 @@ import pytest import pytest_asyncio -from recoverpy.lib.storage.block_device_metadata import DeviceInfo from recoverpy.lib.search.search_engine import SearchEngine +from recoverpy.lib.storage.block_device_metadata import DeviceInfo -from .fixtures import ( - mock_device_discovery, - mock_block_reader, - mock_scan_hits, -) +from .fixtures import mock_block_reader, mock_device_discovery, mock_scan_hits TEST_BLOCK_SIZE = 4096 diff --git a/tests/integration/test_full_workflow.py b/tests/integration/test_full_workflow.py index 3e3b09dd..484c8a3a 100644 --- a/tests/integration/test_full_workflow.py +++ b/tests/integration/test_full_workflow.py @@ -7,21 +7,14 @@ from recoverpy import RecoverpyApp from recoverpy.lib.storage.block_device_metadata import DeviceInfo from tests.conftest import TEST_BLOCK_SIZE +from tests.fixtures.mock_device_discovery import (UNFILTERED_PARTITION_COUNT, + VISIBLE_PARTITION_COUNT) from tests.fixtures.mock_scan_hits import SCAN_HIT_COUNT -from tests.fixtures.mock_device_discovery import ( - UNFILTERED_PARTITION_COUNT, - VISIBLE_PARTITION_COUNT, -) from tests.integration.helper import ( - TEST_FULL_PARTITION, - TEST_PARTITION, - add_expected_save_result, - assert_current_result_is_selected_for_save, - assert_with_timeout, - get_block_content_text, - get_expected_block_content_text, - get_expected_save_result, -) + TEST_FULL_PARTITION, TEST_PARTITION, add_expected_save_result, + assert_current_result_is_selected_for_save, assert_with_timeout, + get_block_content_text, get_expected_block_content_text, + get_expected_save_result) @pytest.mark.asyncio diff --git a/tests/integration/test_search_ui_responsiveness.py b/tests/integration/test_search_ui_responsiveness.py index 5f39c0ff..8459f4e0 100644 --- a/tests/integration/test_search_ui_responsiveness.py +++ b/tests/integration/test_search_ui_responsiveness.py @@ -5,8 +5,8 @@ import pytest from recoverpy import RecoverpyApp -from recoverpy.lib.storage.block_device_metadata import DeviceInfo from recoverpy.lib.search.binary_scanner import ScanHit +from recoverpy.lib.storage.block_device_metadata import DeviceInfo from recoverpy.ui.screens.screen_params import ParamsScreen from tests.conftest import TEST_BLOCK_SIZE diff --git a/tests/unit/test_block_extractor.py b/tests/unit/test_block_extractor.py index 047f9678..420e813e 100644 --- a/tests/unit/test_block_extractor.py +++ b/tests/unit/test_block_extractor.py @@ -2,7 +2,8 @@ import pytest -from recoverpy.lib.storage.byte_range_reader import BlockExtractionError, extract_range, read_block +from recoverpy.lib.storage.byte_range_reader import (BlockExtractionError, + extract_range, read_block) def test_extract_range_success(tmp_path): diff --git a/tests/unit/test_device_discovery.py b/tests/unit/test_device_discovery.py index 82fe6a52..7d6cbaaf 100755 --- a/tests/unit/test_device_discovery.py +++ b/tests/unit/test_device_discovery.py @@ -1,14 +1,9 @@ import pytest from recoverpy.lib.storage.block_device_inventory import ( - DeviceDiscoveryError, - _IGNORED_PARTITION_TYPES, - get_partitions, -) -from tests.fixtures.mock_device_discovery import ( - UNFILTERED_PARTITION_COUNT, - VISIBLE_PARTITION_COUNT, -) + _IGNORED_PARTITION_TYPES, DeviceDiscoveryError, get_partitions) +from tests.fixtures.mock_device_discovery import (UNFILTERED_PARTITION_COUNT, + VISIBLE_PARTITION_COUNT) def test_get_partitions_filtered(): diff --git a/tests/unit/test_device_io.py b/tests/unit/test_device_io.py index 3d78255e..f21dad0c 100644 --- a/tests/unit/test_device_io.py +++ b/tests/unit/test_device_io.py @@ -5,14 +5,8 @@ import pytest from recoverpy.lib.storage.block_device_metadata import ( - BLKGETSIZE64, - BLKPBSZGET, - BLKROGET, - BLKSSZGET, - DeviceIOError, - get_device_info, - get_logical_block_size, -) + BLKGETSIZE64, BLKPBSZGET, BLKROGET, BLKSSZGET, DeviceIOError, + get_device_info, get_logical_block_size) def test_get_device_info_fallback_for_regular_file(tmp_path): diff --git a/tests/unit/test_folder_only_directory_tree.py b/tests/unit/test_folder_only_directory_tree.py index 383b2348..349cb96d 100644 --- a/tests/unit/test_folder_only_directory_tree.py +++ b/tests/unit/test_folder_only_directory_tree.py @@ -1,6 +1,7 @@ from pathlib import Path -from recoverpy.ui.widgets.folder_only_directory_tree import FolderOnlyDirectoryTree +from recoverpy.ui.widgets.folder_only_directory_tree import \ + FolderOnlyDirectoryTree def test_filter_paths_keeps_only_directories(tmp_path: Path) -> None: From 7b9c02102bccbc3f4d0d1d1db4d1c408393e597f Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 14:13:02 +0100 Subject: [PATCH 05/26] Fix types for Python 3.9 --- .github/workflows/pytest.yml | 4 ++-- recoverpy/lib/env_check.py | 2 +- recoverpy/models/search_progress.py | 2 ++ recoverpy/ui/screens/screen_params.py | 2 ++ recoverpy/ui/screens/screen_path_edit.py | 2 ++ recoverpy/ui/screens/screen_result.py | 2 ++ recoverpy/ui/screens/screen_save.py | 2 ++ recoverpy/ui/screens/screen_search.py | 2 ++ 8 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 493ae505..c66f7d8f 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ] fail-fast: false env: IS_GITHUB_RUNNER: "true" @@ -45,4 +45,4 @@ jobs: env: PR_URL: ${{ github.event.pull_request.html_url }} GH_TOKEN: ${{ secrets.DEPENDABOT_TOKEN }} - GITHUB_TOKEN: ${{ secrets.DEPENDABOT_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.DEPENDABOT_TOKEN }} diff --git a/recoverpy/lib/env_check.py b/recoverpy/lib/env_check.py index c10fed82..7ca8c3e0 100644 --- a/recoverpy/lib/env_check.py +++ b/recoverpy/lib/env_check.py @@ -11,7 +11,7 @@ _root_error_message = "The current user is not root, the search is likely to not work. Run this app as root or use sudo." _version_error_message = ( - "The current Python version is not supported. Please use Python 3.8 or higher." + "The current Python version is not supported. Please use Python 3.9 or higher." ) _linux_error_message = ( "Your system may not be Linux-based, the application might not work correctly." diff --git a/recoverpy/models/search_progress.py b/recoverpy/models/search_progress.py index 0e7a51f9..134dde0f 100755 --- a/recoverpy/models/search_progress.py +++ b/recoverpy/models/search_progress.py @@ -1,5 +1,7 @@ """Shared mutable search progress state consumed by the UI.""" +from __future__ import annotations + class SearchProgress: def __init__(self) -> None: self.result_count = 0 diff --git a/recoverpy/ui/screens/screen_params.py b/recoverpy/ui/screens/screen_params.py index d2599b5c..766c50c6 100755 --- a/recoverpy/ui/screens/screen_params.py +++ b/recoverpy/ui/screens/screen_params.py @@ -1,6 +1,8 @@ """First screen displayed to the user. Allows user to enter search string and select partition.""" +from __future__ import annotations + from typing import Generator, Optional from textual.app import ComposeResult diff --git a/recoverpy/ui/screens/screen_path_edit.py b/recoverpy/ui/screens/screen_path_edit.py index fbdc87bf..50eba394 100755 --- a/recoverpy/ui/screens/screen_path_edit.py +++ b/recoverpy/ui/screens/screen_path_edit.py @@ -1,5 +1,7 @@ """Screen used to select result save path.""" +from __future__ import annotations + from textual.app import ComposeResult from textual.binding import Binding from textual.containers import Horizontal diff --git a/recoverpy/ui/screens/screen_result.py b/recoverpy/ui/screens/screen_result.py index 69b817d1..ecfe304d 100755 --- a/recoverpy/ui/screens/screen_result.py +++ b/recoverpy/ui/screens/screen_result.py @@ -1,5 +1,7 @@ """Screen displaying recovered block content.""" +from __future__ import annotations + from typing import Optional, cast from textual.app import ComposeResult diff --git a/recoverpy/ui/screens/screen_save.py b/recoverpy/ui/screens/screen_save.py index 781c9462..6f9f232a 100755 --- a/recoverpy/ui/screens/screen_save.py +++ b/recoverpy/ui/screens/screen_save.py @@ -1,5 +1,7 @@ """Screen used to confirm save.""" +from __future__ import annotations + from typing import Optional, cast from textual.app import ComposeResult diff --git a/recoverpy/ui/screens/screen_search.py b/recoverpy/ui/screens/screen_search.py index 7367b633..d07647ce 100755 --- a/recoverpy/ui/screens/screen_search.py +++ b/recoverpy/ui/screens/screen_search.py @@ -1,5 +1,7 @@ """Screen displaying search results.""" +from __future__ import annotations + from asyncio import Task, create_task from textual.app import ComposeResult From db03a0642ead88ecae84987b6bd045034f38d7f9 Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 14:27:06 +0100 Subject: [PATCH 06/26] Fix highlight styles for mounted partitions --- recoverpy/ui/css/00-theme.tcss | 4 ++-- recoverpy/ui/css/screen-params.css | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/recoverpy/ui/css/00-theme.tcss b/recoverpy/ui/css/00-theme.tcss index 49cdd7e9..bff20962 100644 --- a/recoverpy/ui/css/00-theme.tcss +++ b/recoverpy/ui/css/00-theme.tcss @@ -55,7 +55,7 @@ TextLog:focus { border: solid $rp-primary; } -ListView > ListItem.--highlight { +ListView > ListItem.-highlight { color: $rp-text; } @@ -94,7 +94,7 @@ Checkbox:focus { border: solid $rp-primary; } -SearchResultList > ListItem.--highlight { +SearchResultList > ListItem.-highlight { background: $rp-primary 15%; } diff --git a/recoverpy/ui/css/screen-params.css b/recoverpy/ui/css/screen-params.css index a1cf9427..6fc1be97 100755 --- a/recoverpy/ui/css/screen-params.css +++ b/recoverpy/ui/css/screen-params.css @@ -17,6 +17,15 @@ PartitionList > ListItem { padding: 0 0 0 1; } +PartitionList > ListItem.-highlight { + background: $primary 20%; +} + +PartitionList > ListItem.mounted.-highlight, +PartitionList > ListItem.mounted.-highlight > Label { + color: $block-cursor-foreground; +} + #start-search-button { margin: 0 0 0 10; } From 9958d24b3ebfb64709aff59839cef3941992f42d Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 14:27:15 +0100 Subject: [PATCH 07/26] Edit README --- README.md | 138 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 2521f957..003616c7 100755 --- a/README.md +++ b/README.md @@ -1,112 +1,150 @@
RecoverPy

RecoverPy

- Find and recover deleted or even overwritten files from your Linux partitions, quickly and easily. - -

+ Scan raw partitions and recover data by inspecting disk blocks directly. +

![GitHub release](https://img.shields.io/github/v/release/pablolec/recoverpy?style=flat-square) ![License](https://img.shields.io/github/license/pablolec/recoverpy?style=flat-square) ![Downloads](https://static.pepy.tech/personalized-badge/recoverpy?period=total&units=abbreviation&left_color=grey&right_color=red&left_text=downloads) ![Tests](https://github.com/PabloLec/recoverpy/actions/workflows/pytest.yml/badge.svg?branch=main) -
--- -RecoverPy doesn't just recover deleted files, but also helps you **recover overwritten data** by scanning each disk block. Whether it's a lost snippet of code, accidentally deleted configs, or overwritten text files, RecoverPy gives you a powerful, interactive way to get it back. - -## ✨ Features - -- ✅ Recover **overwritten and deleted files** -- 🔍 Search file contents by string, even in binary files -- 📟 Modern, easy-to-use terminal UI -- 🐧 Linux compatible (all file systems supported) -- ⚡️ Fast, leveraging core Linux utilities (`grep`, `dd`, `lsblk`) - ---- - ## 🎬 Demo

RecoverPy Demo

+## 🔎 Overview + +When a file is deleted, its metadata disappears first. The underlying disk blocks often remain intact until they are reused. + +RecoverPy scans raw partition data directly and searches for byte patterns across the entire device. If the blocks have not been overwritten, fragments of deleted files can still be located by their content. + +It lets you inspect matching blocks, navigate adjacent ones, and extract what remains in a straightforward way. + +If the blocks are gone, recovery is impossible. If they are still there, RecoverPy helps you retrieve them. + --- -## 📦 Installation +## 🧭 What you can do -> **Warning:** You **must** run RecoverPy as root (`sudo`). +* Search a partition or disk image for a specific string. +* Inspect the disk blocks where matches are found. +* Move across adjacent blocks to recover fragmented data. +* Select and save useful content. -RecoverPy is Linux-only. Make sure you have these common tools installed (`grep`, `dd`, `lsblk`). Optionally, install `progress` to monitor scan progress: +RecoverPy does not attempt to interpret filesystem structures or restore filenames. It focuses on exposing what remains on disk and making it accessible. -```bash -# Debian / Ubuntu -sudo apt install grep coreutils util-linux progress +--- -# Arch -sudo pacman -S grep coreutils util-linux progress +## 📦 Installation -# Fedora -sudo dnf install grep coreutils util-linux progress -``` +### Requirements -### Quick Run (no installation) +- Linux +- Python 3.9+ -Using `pipx`: +Accessing raw block devices typically requires `sudo`. + +### Using `uv` ```bash -sudo pipx run recoverpy -``` +sudo uvx recoverpy +```` -Or using `uvx`: +Or install locally: ```bash -sudo uvx recoverpy +uv tool install recoverpy +sudo recoverpy ``` -### Install from PyPI +### Using pip ```bash -python3 -m pip install recoverpy +python -m pip install recoverpy sudo recoverpy ``` --- -## 💻 Usage +## ▶️ Usage -1. **Launch RecoverPy:** +Start RecoverPy: ```bash sudo recoverpy ``` -2. **Select Partition:** - Choose the partition where your lost data resides. If unsure, try scanning your `/home` partition, it might contain editor or IDE backups. +1. Select a partition. +2. Enter a distinctive search string. +3. Start the scan. +4. Open a result. +5. Inspect and navigate blocks. +6. Save useful content. -3. **Search Content:** - Enter a unique string from the lost file content. RecoverPy will scan disk blocks to locate matches. +Using a unique identifier, configuration key, or sentence fragment generally produces better results than common words. -4. **Find & Recover:** - Results appear interactively. Select a result, preview the block, and save it. Explore neighboring blocks if the file spans multiple disk blocks. +--- + +## ⚙️ How it works + +RecoverPy operates directly on the raw byte stream of a block device. + +The selected partition is opened in read-only mode and scanned sequentially using fixed-size chunks. The scanner processes the stream incrementally, keeping a small overlap between chunks to ensure that matches spanning chunk boundaries are not missed. + +Pattern matching is performed at the byte level. For every match, RecoverPy records the exact absolute offset within the device. This offset becomes the reference point for block inspection and navigation. + +Block reads are performed using explicit offsets rather than relying on filesystem abstractions. This allows precise access to adjacent blocks without loading large portions of the device into memory. + +The entire scan is streaming-based and memory-bounded: RecoverPy never loads the full partition into memory. --- -## 💡 Recovery Tips +## ⚠️ Limitations + +RecoverPy works on raw data. It does not reconstruct files automatically or infer file boundaries. + +Results may be partial or fragmented. If the underlying blocks have already been overwritten, recovery is not possible. -- 🛑 **Unmount partition first:** Reduce risk of data overwriting. -- 🎯 **Be specific:** Use unique, simple search strings. -- ⏳ **Act quickly:** The sooner you scan, the higher your recovery chances. -- 📑 **Check adjacent blocks:** Your file might span several blocks, check them all. +Accessing block devices typically requires sudo. To reduce the risk of further overwriting, avoid writing to the target partition during recovery and unmount it when possible. --- ## 🤝 Contributing -Found a bug or have an idea? PRs, issues, and suggestions are warmly welcome. Check out our [contributing guide](CONTRIBUTING.md) for how to get involved! +If you run into a bug or think something could be improved, feel free to open an issue. And if you’d like to work on it yourself, pull requests are always appreciated. --- -If RecoverPy saved your day, consider ⭐️ starring the repo, thanks for your support! +## 🛠 Development + +Project structure: + +* `recoverpy/ui/` — Textual interface +* `recoverpy/lib/search/` — streaming search engine +* `recoverpy/lib/storage/` — block and device access +* `recoverpy/lib/text/` — decoding utilities +* `tests/` — unit and integration tests +### Setup + +```bash +uv sync --dev +``` + +### Run locally + +```bash +sudo uv run recoverpy +``` + +### Run tests + +```bash +uv run pytest -q +``` From 0dbf88e9a4e7b0bfd3c1e3151fb80ac3faebd706 Mon Sep 17 00:00:00 2001 From: PabloLec Date: Sat, 14 Feb 2026 14:27:46 +0100 Subject: [PATCH 08/26] Bump version to 2.3.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3ab28614..1cfa872d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "textual==7.5.0", ] name = "recoverpy" -version = "2.2.1" +version = "2.3.0" description = "A TUI to recover overwritten or deleted data." readme = "README.md" keywords = [ From 812b2908ea303e4f2e0178352a140971769e53d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:42:27 +0000 Subject: [PATCH 09/26] Bump textual from 7.5.0 to 8.0.0 Bumps [textual](https://github.com/Textualize/textual) from 7.5.0 to 8.0.0. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v7.5.0...v8.0.0) --- updated-dependencies: - dependency-name: textual dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1cfa872d..b7c8a184 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==7.5.0", + "textual==8.0.0", ] name = "recoverpy" version = "2.3.0" From 3f0f2fcdc0b8d1193eeeda852d266c69bb2a63ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:30:03 +0000 Subject: [PATCH 10/26] Bump textual from 8.0.0 to 8.0.1 Bumps [textual](https://github.com/Textualize/textual) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.0.0...v8.0.1) --- updated-dependencies: - dependency-name: textual dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b7c8a184..66195eec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.0.0", + "textual==8.0.1", ] name = "recoverpy" version = "2.3.0" From fb5b5bca732121d45b80cfc5c49880b7f7c87c3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:42:38 +0000 Subject: [PATCH 11/26] Bump textual from 8.0.1 to 8.0.2 Bumps [textual](https://github.com/Textualize/textual) from 8.0.1 to 8.0.2. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.0.1...v8.0.2) --- updated-dependencies: - dependency-name: textual dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 66195eec..bd7274f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.0.1", + "textual==8.0.2", ] name = "recoverpy" version = "2.3.0" From 2ade27424cd40fd4cd04def937cf3959475ff629 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 13:43:10 +0000 Subject: [PATCH 12/26] Bump textual from 8.0.2 to 8.1.1 Bumps [textual](https://github.com/Textualize/textual) from 8.0.2 to 8.1.1. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.0.2...v8.1.1) --- updated-dependencies: - dependency-name: textual dependency-version: 8.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bd7274f7..cb79896c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.0.2", + "textual==8.1.1", ] name = "recoverpy" version = "2.3.0" From 9f3bcbc53df1b5089647800b2a8423e1b974172b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2026 13:42:36 +0000 Subject: [PATCH 13/26] Bump textual from 8.1.1 to 8.2.0 Bumps [textual](https://github.com/Textualize/textual) from 8.1.1 to 8.2.0. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.1.1...v8.2.0) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cb79896c..dcede47e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.1.1", + "textual==8.2.0", ] name = "recoverpy" version = "2.3.0" From c2c21eecb7af1d48056f7982706e32cb59e2d567 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:56:08 +0000 Subject: [PATCH 14/26] Bump textual from 8.2.0 to 8.2.1 Bumps [textual](https://github.com/Textualize/textual) from 8.2.0 to 8.2.1. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.0...v8.2.1) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dcede47e..4a31c22e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.0", + "textual==8.2.1", ] name = "recoverpy" version = "2.3.0" From fce73c8fad614315ac15c0e2be2e84d214b08c18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:58:01 +0000 Subject: [PATCH 15/26] Bump pygments from 2.19.2 to 2.20.0 Bumps [pygments](https://github.com/pygments/pygments) from 2.19.2 to 2.20.0. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.19.2...2.20.0) --- updated-dependencies: - dependency-name: pygments dependency-version: 2.20.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- uv.lock | 322 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 161 insertions(+), 161 deletions(-) diff --git a/uv.lock b/uv.lock index a4e3ec30..35a985c4 100644 --- a/uv.lock +++ b/uv.lock @@ -1,83 +1,83 @@ version = 1 -revision = 1 +revision = 3 requires-python = ">=3.9, <4.0.0" [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "coverage" version = "7.6.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 } +sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868, upload-time = "2024-12-26T16:59:18.734Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/12/2a2a923edf4ddabdffed7ad6da50d96a5c126dae7b80a33df7310e329a1e/coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", size = 207982 }, - { url = "https://files.pythonhosted.org/packages/ca/49/6985dbca9c7be3f3cb62a2e6e492a0c88b65bf40579e16c71ae9c33c6b23/coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", size = 208414 }, - { url = "https://files.pythonhosted.org/packages/35/93/287e8f1d1ed2646f4e0b2605d14616c9a8a2697d0d1b453815eb5c6cebdb/coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", size = 236860 }, - { url = "https://files.pythonhosted.org/packages/de/e1/cfdb5627a03567a10031acc629b75d45a4ca1616e54f7133ca1fa366050a/coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", size = 234758 }, - { url = "https://files.pythonhosted.org/packages/6d/85/fc0de2bcda3f97c2ee9fe8568f7d48f7279e91068958e5b2cc19e0e5f600/coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", size = 235920 }, - { url = "https://files.pythonhosted.org/packages/79/73/ef4ea0105531506a6f4cf4ba571a214b14a884630b567ed65b3d9c1975e1/coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", size = 234986 }, - { url = "https://files.pythonhosted.org/packages/c6/4d/75afcfe4432e2ad0405c6f27adeb109ff8976c5e636af8604f94f29fa3fc/coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", size = 233446 }, - { url = "https://files.pythonhosted.org/packages/86/5b/efee56a89c16171288cafff022e8af44f8f94075c2d8da563c3935212871/coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", size = 234566 }, - { url = "https://files.pythonhosted.org/packages/f2/db/67770cceb4a64d3198bf2aa49946f411b85ec6b0a9b489e61c8467a4253b/coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", size = 210675 }, - { url = "https://files.pythonhosted.org/packages/8d/27/e8bfc43f5345ec2c27bc8a1fa77cdc5ce9dcf954445e11f14bb70b889d14/coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", size = 211518 }, - { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088 }, - { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536 }, - { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 }, - { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 }, - { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 }, - { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 }, - { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 }, - { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 }, - { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647 }, - { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508 }, - { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 }, - { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 }, - { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 }, - { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 }, - { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 }, - { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 }, - { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 }, - { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 }, - { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 }, - { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 }, - { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 }, - { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 }, - { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 }, - { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 }, - { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 }, - { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 }, - { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 }, - { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 }, - { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 }, - { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 }, - { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 }, - { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 }, - { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 }, - { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 }, - { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 }, - { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 }, - { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 }, - { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 }, - { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 }, - { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 }, - { url = "https://files.pythonhosted.org/packages/40/41/473617aadf9a1c15bc2d56be65d90d7c29bfa50a957a67ef96462f7ebf8e/coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a", size = 207978 }, - { url = "https://files.pythonhosted.org/packages/10/f6/480586607768b39a30e6910a3c4522139094ac0f1677028e1f4823688957/coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27", size = 208415 }, - { url = "https://files.pythonhosted.org/packages/f1/af/439bb760f817deff6f4d38fe7da08d9dd7874a560241f1945bc3b4446550/coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4", size = 236452 }, - { url = "https://files.pythonhosted.org/packages/d0/13/481f4ceffcabe29ee2332e60efb52e4694f54a402f3ada2bcec10bb32e43/coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f", size = 234374 }, - { url = "https://files.pythonhosted.org/packages/c5/59/4607ea9d6b1b73e905c7656da08d0b00cdf6e59f2293ec259e8914160025/coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25", size = 235505 }, - { url = "https://files.pythonhosted.org/packages/85/60/d66365723b9b7f29464b11d024248ed3523ce5aab958e4ad8c43f3f4148b/coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315", size = 234616 }, - { url = "https://files.pythonhosted.org/packages/74/f8/2cf7a38e7d81b266f47dfcf137fecd8fa66c7bdbd4228d611628d8ca3437/coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90", size = 233099 }, - { url = "https://files.pythonhosted.org/packages/50/2b/bff6c1c6b63c4396ea7ecdbf8db1788b46046c681b8fcc6ec77db9f4ea49/coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d", size = 234089 }, - { url = "https://files.pythonhosted.org/packages/bf/b5/baace1c754d546a67779358341aa8d2f7118baf58cac235db457e1001d1b/coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18", size = 210701 }, - { url = "https://files.pythonhosted.org/packages/b1/bf/9e1e95b8b20817398ecc5a1e8d3e05ff404e1b9fb2185cd71561698fe2a2/coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59", size = 211482 }, - { url = "https://files.pythonhosted.org/packages/a1/70/de81bfec9ed38a64fc44a77c7665e20ca507fc3265597c28b0d989e4082e/coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f", size = 200223 }, + { url = "https://files.pythonhosted.org/packages/c5/12/2a2a923edf4ddabdffed7ad6da50d96a5c126dae7b80a33df7310e329a1e/coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", size = 207982, upload-time = "2024-12-26T16:57:00.767Z" }, + { url = "https://files.pythonhosted.org/packages/ca/49/6985dbca9c7be3f3cb62a2e6e492a0c88b65bf40579e16c71ae9c33c6b23/coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", size = 208414, upload-time = "2024-12-26T16:57:03.826Z" }, + { url = "https://files.pythonhosted.org/packages/35/93/287e8f1d1ed2646f4e0b2605d14616c9a8a2697d0d1b453815eb5c6cebdb/coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", size = 236860, upload-time = "2024-12-26T16:57:06.509Z" }, + { url = "https://files.pythonhosted.org/packages/de/e1/cfdb5627a03567a10031acc629b75d45a4ca1616e54f7133ca1fa366050a/coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", size = 234758, upload-time = "2024-12-26T16:57:09.089Z" }, + { url = "https://files.pythonhosted.org/packages/6d/85/fc0de2bcda3f97c2ee9fe8568f7d48f7279e91068958e5b2cc19e0e5f600/coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", size = 235920, upload-time = "2024-12-26T16:57:10.445Z" }, + { url = "https://files.pythonhosted.org/packages/79/73/ef4ea0105531506a6f4cf4ba571a214b14a884630b567ed65b3d9c1975e1/coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", size = 234986, upload-time = "2024-12-26T16:57:13.298Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4d/75afcfe4432e2ad0405c6f27adeb109ff8976c5e636af8604f94f29fa3fc/coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", size = 233446, upload-time = "2024-12-26T16:57:14.742Z" }, + { url = "https://files.pythonhosted.org/packages/86/5b/efee56a89c16171288cafff022e8af44f8f94075c2d8da563c3935212871/coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", size = 234566, upload-time = "2024-12-26T16:57:17.368Z" }, + { url = "https://files.pythonhosted.org/packages/f2/db/67770cceb4a64d3198bf2aa49946f411b85ec6b0a9b489e61c8467a4253b/coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", size = 210675, upload-time = "2024-12-26T16:57:18.775Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/e8bfc43f5345ec2c27bc8a1fa77cdc5ce9dcf954445e11f14bb70b889d14/coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", size = 211518, upload-time = "2024-12-26T16:57:21.415Z" }, + { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088, upload-time = "2024-12-26T16:57:22.833Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536, upload-time = "2024-12-26T16:57:25.578Z" }, + { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474, upload-time = "2024-12-26T16:57:28.659Z" }, + { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880, upload-time = "2024-12-26T16:57:30.095Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750, upload-time = "2024-12-26T16:57:31.48Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642, upload-time = "2024-12-26T16:57:34.09Z" }, + { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266, upload-time = "2024-12-26T16:57:35.48Z" }, + { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045, upload-time = "2024-12-26T16:57:36.952Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647, upload-time = "2024-12-26T16:57:39.84Z" }, + { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508, upload-time = "2024-12-26T16:57:41.234Z" }, + { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281, upload-time = "2024-12-26T16:57:42.968Z" }, + { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514, upload-time = "2024-12-26T16:57:45.747Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537, upload-time = "2024-12-26T16:57:48.647Z" }, + { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572, upload-time = "2024-12-26T16:57:51.668Z" }, + { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639, upload-time = "2024-12-26T16:57:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072, upload-time = "2024-12-26T16:57:56.087Z" }, + { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386, upload-time = "2024-12-26T16:57:57.572Z" }, + { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054, upload-time = "2024-12-26T16:57:58.967Z" }, + { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904, upload-time = "2024-12-26T16:58:00.688Z" }, + { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692, upload-time = "2024-12-26T16:58:02.35Z" }, + { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308, upload-time = "2024-12-26T16:58:04.487Z" }, + { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565, upload-time = "2024-12-26T16:58:06.774Z" }, + { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083, upload-time = "2024-12-26T16:58:10.27Z" }, + { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235, upload-time = "2024-12-26T16:58:12.497Z" }, + { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220, upload-time = "2024-12-26T16:58:15.619Z" }, + { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847, upload-time = "2024-12-26T16:58:17.126Z" }, + { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922, upload-time = "2024-12-26T16:58:20.198Z" }, + { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783, upload-time = "2024-12-26T16:58:23.614Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965, upload-time = "2024-12-26T16:58:26.765Z" }, + { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719, upload-time = "2024-12-26T16:58:28.781Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050, upload-time = "2024-12-26T16:58:31.616Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321, upload-time = "2024-12-26T16:58:34.509Z" }, + { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039, upload-time = "2024-12-26T16:58:36.072Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758, upload-time = "2024-12-26T16:58:39.458Z" }, + { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119, upload-time = "2024-12-26T16:58:41.018Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597, upload-time = "2024-12-26T16:58:42.827Z" }, + { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473, upload-time = "2024-12-26T16:58:44.486Z" }, + { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737, upload-time = "2024-12-26T16:58:45.919Z" }, + { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611, upload-time = "2024-12-26T16:58:47.883Z" }, + { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781, upload-time = "2024-12-26T16:58:50.822Z" }, + { url = "https://files.pythonhosted.org/packages/40/41/473617aadf9a1c15bc2d56be65d90d7c29bfa50a957a67ef96462f7ebf8e/coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a", size = 207978, upload-time = "2024-12-26T16:58:52.834Z" }, + { url = "https://files.pythonhosted.org/packages/10/f6/480586607768b39a30e6910a3c4522139094ac0f1677028e1f4823688957/coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27", size = 208415, upload-time = "2024-12-26T16:58:56.317Z" }, + { url = "https://files.pythonhosted.org/packages/f1/af/439bb760f817deff6f4d38fe7da08d9dd7874a560241f1945bc3b4446550/coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4", size = 236452, upload-time = "2024-12-26T16:58:59.158Z" }, + { url = "https://files.pythonhosted.org/packages/d0/13/481f4ceffcabe29ee2332e60efb52e4694f54a402f3ada2bcec10bb32e43/coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f", size = 234374, upload-time = "2024-12-26T16:59:00.809Z" }, + { url = "https://files.pythonhosted.org/packages/c5/59/4607ea9d6b1b73e905c7656da08d0b00cdf6e59f2293ec259e8914160025/coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25", size = 235505, upload-time = "2024-12-26T16:59:03.869Z" }, + { url = "https://files.pythonhosted.org/packages/85/60/d66365723b9b7f29464b11d024248ed3523ce5aab958e4ad8c43f3f4148b/coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315", size = 234616, upload-time = "2024-12-26T16:59:05.876Z" }, + { url = "https://files.pythonhosted.org/packages/74/f8/2cf7a38e7d81b266f47dfcf137fecd8fa66c7bdbd4228d611628d8ca3437/coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90", size = 233099, upload-time = "2024-12-26T16:59:08.927Z" }, + { url = "https://files.pythonhosted.org/packages/50/2b/bff6c1c6b63c4396ea7ecdbf8db1788b46046c681b8fcc6ec77db9f4ea49/coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d", size = 234089, upload-time = "2024-12-26T16:59:10.574Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b5/baace1c754d546a67779358341aa8d2f7118baf58cac235db457e1001d1b/coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18", size = 210701, upload-time = "2024-12-26T16:59:12.212Z" }, + { url = "https://files.pythonhosted.org/packages/b1/bf/9e1e95b8b20817398ecc5a1e8d3e05ff404e1b9fb2185cd71561698fe2a2/coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59", size = 211482, upload-time = "2024-12-26T16:59:15.165Z" }, + { url = "https://files.pythonhosted.org/packages/a1/70/de81bfec9ed38a64fc44a77c7665e20ca507fc3265597c28b0d989e4082e/coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f", size = 200223, upload-time = "2024-12-26T16:59:16.968Z" }, ] [package.optional-dependencies] @@ -89,27 +89,27 @@ toml = [ name = "exceptiongroup" version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883, upload-time = "2024-07-12T22:26:00.161Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453, upload-time = "2024-07-12T22:25:58.476Z" }, ] [[package]] name = "iniconfig" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646, upload-time = "2023-01-07T11:08:11.254Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" }, ] [[package]] name = "isort" version = "5.13.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } +sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, + { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, ] [[package]] @@ -119,9 +119,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "uc-micro-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946 } +sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946, upload-time = "2024-02-04T14:48:04.179Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820 }, + { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820, upload-time = "2024-02-04T14:48:02.496Z" }, ] [[package]] @@ -131,9 +131,9 @@ 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 } +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" } 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 }, + { 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" }, ] [package.optional-dependencies] @@ -148,63 +148,63 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 } +sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542, upload-time = "2024-09-09T20:27:49.564Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 }, + { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316, upload-time = "2024-09-09T20:27:48.397Z" }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] name = "nodeenv" version = "1.9.1" 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 } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, + { 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" }, ] [[package]] name = "packaging" version = "24.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, ] [[package]] name = "platformdirs" version = "4.3.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302, upload-time = "2024-09-17T19:06:50.688Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" }, ] [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, ] [[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 } +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 }, + { 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]] @@ -215,9 +215,9 @@ dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/df/3c6f6b08fba7ccf49b114dfc4bb33e25c299883fd763f93fad47ef8bc58d/pyright-1.1.392.post0.tar.gz", hash = "sha256:3b7f88de74a28dcfa90c7d90c782b6569a48c2be5f9d4add38472bdaac247ebd", size = 3789911 } +sdist = { url = "https://files.pythonhosted.org/packages/66/df/3c6f6b08fba7ccf49b114dfc4bb33e25c299883fd763f93fad47ef8bc58d/pyright-1.1.392.post0.tar.gz", hash = "sha256:3b7f88de74a28dcfa90c7d90c782b6569a48c2be5f9d4add38472bdaac247ebd", size = 3789911, upload-time = "2025-01-15T15:01:20.913Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/b1/a18de17f40e4f61ca58856b9ef9b0febf74ff88978c3f7776f910071f567/pyright-1.1.392.post0-py3-none-any.whl", hash = "sha256:252f84458a46fa2f0fd4e2f91fc74f50b9ca52c757062e93f6c250c0d8329eb2", size = 5595487 }, + { url = "https://files.pythonhosted.org/packages/e7/b1/a18de17f40e4f61ca58856b9ef9b0febf74ff88978c3f7776f910071f567/pyright-1.1.392.post0-py3-none-any.whl", hash = "sha256:252f84458a46fa2f0fd4e2f91fc74f50b9ca52c757062e93f6c250c0d8329eb2", size = 5595487, upload-time = "2025-01-15T15:01:17.775Z" }, ] [[package]] @@ -232,9 +232,9 @@ dependencies = [ { name = "pluggy" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919, upload-time = "2024-12-01T12:54:25.98Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083, upload-time = "2024-12-01T12:54:19.735Z" }, ] [[package]] @@ -244,9 +244,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950 } +sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950, upload-time = "2025-01-08T06:20:29.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400 }, + { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400, upload-time = "2025-01-08T06:20:27.862Z" }, ] [[package]] @@ -257,9 +257,9 @@ dependencies = [ { name = "coverage", extra = ["toml"] }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" }, ] [[package]] @@ -269,14 +269,14 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814, upload-time = "2024-03-21T22:14:04.964Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 }, + { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863, upload-time = "2024-03-21T22:14:02.694Z" }, ] [[package]] name = "recoverpy" -version = "2.2.1" +version = "2.3.0" source = { editable = "." } dependencies = [ { name = "textual" }, @@ -294,7 +294,7 @@ dev = [ ] [package.metadata] -requires-dist = [{ name = "textual", specifier = "==7.5.0" }] +requires-dist = [{ name = "textual", specifier = "==8.2.1" }] [package.metadata.requires-dev] dev = [ @@ -315,39 +315,39 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143 } +sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963 }, + { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload-time = "2026-02-01T16:20:46.078Z" }, ] [[package]] name = "ruff" version = "0.9.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/7f/60fda2eec81f23f8aa7cbbfdf6ec2ca11eb11c273827933fb2541c2ce9d8/ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a", size = 3586740 } +sdist = { url = "https://files.pythonhosted.org/packages/1e/7f/60fda2eec81f23f8aa7cbbfdf6ec2ca11eb11c273827933fb2541c2ce9d8/ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a", size = 3586740, upload-time = "2025-01-23T19:29:02.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/77/4fb790596d5d52c87fd55b7160c557c400e90f6116a56d82d76e95d9374a/ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624", size = 11656815 }, - { url = "https://files.pythonhosted.org/packages/a2/a8/3338ecb97573eafe74505f28431df3842c1933c5f8eae615427c1de32858/ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c", size = 11594821 }, - { url = "https://files.pythonhosted.org/packages/8e/89/320223c3421962762531a6b2dd58579b858ca9916fb2674874df5e97d628/ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4", size = 11040475 }, - { url = "https://files.pythonhosted.org/packages/b2/bd/1d775eac5e51409535804a3a888a9623e87a8f4b53e2491580858a083692/ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439", size = 11856207 }, - { url = "https://files.pythonhosted.org/packages/7f/c6/3e14e09be29587393d188454064a4aa85174910d16644051a80444e4fd88/ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5", size = 11420460 }, - { url = "https://files.pythonhosted.org/packages/ef/42/b7ca38ffd568ae9b128a2fa76353e9a9a3c80ef19746408d4ce99217ecc1/ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4", size = 12605472 }, - { url = "https://files.pythonhosted.org/packages/a6/a1/3167023f23e3530fde899497ccfe239e4523854cb874458ac082992d206c/ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1", size = 13243123 }, - { url = "https://files.pythonhosted.org/packages/d0/b4/3c600758e320f5bf7de16858502e849f4216cb0151f819fa0d1154874802/ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5", size = 12744650 }, - { url = "https://files.pythonhosted.org/packages/be/38/266fbcbb3d0088862c9bafa8b1b99486691d2945a90b9a7316336a0d9a1b/ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4", size = 14458585 }, - { url = "https://files.pythonhosted.org/packages/63/a6/47fd0e96990ee9b7a4abda62de26d291bd3f7647218d05b7d6d38af47c30/ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6", size = 12419624 }, - { url = "https://files.pythonhosted.org/packages/84/5d/de0b7652e09f7dda49e1a3825a164a65f4998175b6486603c7601279baad/ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730", size = 11843238 }, - { url = "https://files.pythonhosted.org/packages/9e/be/3f341ceb1c62b565ec1fb6fd2139cc40b60ae6eff4b6fb8f94b1bb37c7a9/ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2", size = 11484012 }, - { url = "https://files.pythonhosted.org/packages/a3/c8/ff8acbd33addc7e797e702cf00bfde352ab469723720c5607b964491d5cf/ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519", size = 12038494 }, - { url = "https://files.pythonhosted.org/packages/73/b1/8d9a2c0efbbabe848b55f877bc10c5001a37ab10aca13c711431673414e5/ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b", size = 12473639 }, - { url = "https://files.pythonhosted.org/packages/cb/44/a673647105b1ba6da9824a928634fe23186ab19f9d526d7bdf278cd27bc3/ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c", size = 9834353 }, - { url = "https://files.pythonhosted.org/packages/c3/01/65cadb59bf8d4fbe33d1a750103e6883d9ef302f60c28b73b773092fbde5/ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4", size = 10821444 }, - { url = "https://files.pythonhosted.org/packages/69/cb/b3fe58a136a27d981911cba2f18e4b29f15010623b79f0f2510fd0d31fd3/ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b", size = 10038168 }, + { url = "https://files.pythonhosted.org/packages/f9/77/4fb790596d5d52c87fd55b7160c557c400e90f6116a56d82d76e95d9374a/ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624", size = 11656815, upload-time = "2025-01-23T19:27:49.457Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a8/3338ecb97573eafe74505f28431df3842c1933c5f8eae615427c1de32858/ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c", size = 11594821, upload-time = "2025-01-23T19:27:53.913Z" }, + { url = "https://files.pythonhosted.org/packages/8e/89/320223c3421962762531a6b2dd58579b858ca9916fb2674874df5e97d628/ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4", size = 11040475, upload-time = "2025-01-23T19:27:58.059Z" }, + { url = "https://files.pythonhosted.org/packages/b2/bd/1d775eac5e51409535804a3a888a9623e87a8f4b53e2491580858a083692/ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439", size = 11856207, upload-time = "2025-01-23T19:28:02.26Z" }, + { url = "https://files.pythonhosted.org/packages/7f/c6/3e14e09be29587393d188454064a4aa85174910d16644051a80444e4fd88/ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5", size = 11420460, upload-time = "2025-01-23T19:28:05.706Z" }, + { url = "https://files.pythonhosted.org/packages/ef/42/b7ca38ffd568ae9b128a2fa76353e9a9a3c80ef19746408d4ce99217ecc1/ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4", size = 12605472, upload-time = "2025-01-23T19:28:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/a6/a1/3167023f23e3530fde899497ccfe239e4523854cb874458ac082992d206c/ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1", size = 13243123, upload-time = "2025-01-23T19:28:14.181Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/3c600758e320f5bf7de16858502e849f4216cb0151f819fa0d1154874802/ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5", size = 12744650, upload-time = "2025-01-23T19:28:19.738Z" }, + { url = "https://files.pythonhosted.org/packages/be/38/266fbcbb3d0088862c9bafa8b1b99486691d2945a90b9a7316336a0d9a1b/ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4", size = 14458585, upload-time = "2025-01-23T19:28:24.255Z" }, + { url = "https://files.pythonhosted.org/packages/63/a6/47fd0e96990ee9b7a4abda62de26d291bd3f7647218d05b7d6d38af47c30/ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6", size = 12419624, upload-time = "2025-01-23T19:28:29.894Z" }, + { url = "https://files.pythonhosted.org/packages/84/5d/de0b7652e09f7dda49e1a3825a164a65f4998175b6486603c7601279baad/ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730", size = 11843238, upload-time = "2025-01-23T19:28:36.111Z" }, + { url = "https://files.pythonhosted.org/packages/9e/be/3f341ceb1c62b565ec1fb6fd2139cc40b60ae6eff4b6fb8f94b1bb37c7a9/ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2", size = 11484012, upload-time = "2025-01-23T19:28:40.919Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c8/ff8acbd33addc7e797e702cf00bfde352ab469723720c5607b964491d5cf/ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519", size = 12038494, upload-time = "2025-01-23T19:28:44.314Z" }, + { url = "https://files.pythonhosted.org/packages/73/b1/8d9a2c0efbbabe848b55f877bc10c5001a37ab10aca13c711431673414e5/ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b", size = 12473639, upload-time = "2025-01-23T19:28:47.686Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/a673647105b1ba6da9824a928634fe23186ab19f9d526d7bdf278cd27bc3/ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c", size = 9834353, upload-time = "2025-01-23T19:28:51.755Z" }, + { url = "https://files.pythonhosted.org/packages/c3/01/65cadb59bf8d4fbe33d1a750103e6883d9ef302f60c28b73b773092fbde5/ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4", size = 10821444, upload-time = "2025-01-23T19:28:56.509Z" }, + { url = "https://files.pythonhosted.org/packages/69/cb/b3fe58a136a27d981911cba2f18e4b29f15010623b79f0f2510fd0d31fd3/ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b", size = 10038168, upload-time = "2025-01-23T19:28:59.81Z" }, ] [[package]] name = "textual" -version = "7.5.0" +version = "8.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py", extra = ["linkify"] }, @@ -357,64 +357,64 @@ dependencies = [ { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/38/7d169a765993efde5095c70a668bf4f5831bb7ac099e932f2783e9b71abf/textual-7.5.0.tar.gz", hash = "sha256:c730cba1e3d704e8f1ca915b6a3af01451e3bca380114baacf6abf87e9dac8b6", size = 1592319 } +sdist = { url = "https://files.pythonhosted.org/packages/4f/07/766ad19cf2b15cae2d79e0db46a1b783b62316e9ff3e058e7424b2a4398b/textual-8.2.1.tar.gz", hash = "sha256:4176890e9cd5c95dcdd206541b2956b0808e74c8c36381c88db53dcb45237451", size = 1848386, upload-time = "2026-03-29T03:57:32.242Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/78/96ddb99933e11d91bc6e05edae23d2687e44213066bcbaca338898c73c47/textual-7.5.0-py3-none-any.whl", hash = "sha256:849dfee9d705eab3b2d07b33152b7bd74fb1f5056e002873cc448bce500c6374", size = 718164 }, + { url = "https://files.pythonhosted.org/packages/25/09/c6f000c2e3702036e593803319af02feee58a662528d0d5728a37e1cf81b/textual-8.2.1-py3-none-any.whl", hash = "sha256:746cbf947a8ca875afc09779ef38cadbc7b9f15ac886a5090f7099fef5ade990", size = 723871, upload-time = "2026-03-29T03:57:34.334Z" }, ] [[package]] name = "tomli" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, - { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, - { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, - { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, - { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, - { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, - { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, - { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, - { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, - { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, - { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, - { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, - { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, - { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, - { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, - { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, - { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, - { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, - { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, - { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, - { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, - { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, - { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, - { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, - { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, - { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, - { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, - { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, - { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, - { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, - { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429, upload-time = "2024-11-27T22:37:56.698Z" }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067, upload-time = "2024-11-27T22:37:57.63Z" }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030, upload-time = "2024-11-27T22:37:59.344Z" }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898, upload-time = "2024-11-27T22:38:00.429Z" }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894, upload-time = "2024-11-27T22:38:02.094Z" }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319, upload-time = "2024-11-27T22:38:03.206Z" }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273, upload-time = "2024-11-27T22:38:04.217Z" }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310, upload-time = "2024-11-27T22:38:05.908Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309, upload-time = "2024-11-27T22:38:06.812Z" }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] [[package]] name = "typing-extensions" version = "4.12.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, ] [[package]] name = "uc-micro-py" version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043 } +sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043, upload-time = "2024-02-09T16:52:01.654Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229 }, + { url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229, upload-time = "2024-02-09T16:52:00.371Z" }, ] From fe4f78a991171a5dab1df61401f7967757c1fa04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 13:42:24 +0000 Subject: [PATCH 16/26] Bump textual from 8.2.1 to 8.2.2 Bumps [textual](https://github.com/Textualize/textual) from 8.2.1 to 8.2.2. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.1...v8.2.2) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4a31c22e..2df1045d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.1", + "textual==8.2.2", ] name = "recoverpy" version = "2.3.0" From 3e63a35b13d3131e422860525cb1349238073f09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:41:52 +0000 Subject: [PATCH 17/26] Bump textual from 8.2.2 to 8.2.3 Bumps [textual](https://github.com/Textualize/textual) from 8.2.2 to 8.2.3. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.2...v8.2.3) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2df1045d..9d53d8f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.2", + "textual==8.2.3", ] name = "recoverpy" version = "2.3.0" From c9591ad95ba92060b2ed937875471f5dd21884b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:41:58 +0000 Subject: [PATCH 18/26] Bump KSXGitHub/github-actions-deploy-aur from 4.1.1 to 4.1.2 Bumps [KSXGitHub/github-actions-deploy-aur](https://github.com/ksxgithub/github-actions-deploy-aur) from 4.1.1 to 4.1.2. - [Release notes](https://github.com/ksxgithub/github-actions-deploy-aur/releases) - [Commits](https://github.com/ksxgithub/github-actions-deploy-aur/compare/v4.1.1...v4.1.2) --- updated-dependencies: - dependency-name: KSXGitHub/github-actions-deploy-aur dependency-version: 4.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/aur-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aur-release.yml b/.github/workflows/aur-release.yml index 417a04a0..3871903d 100644 --- a/.github/workflows/aur-release.yml +++ b/.github/workflows/aur-release.yml @@ -29,7 +29,7 @@ jobs: sed -i "s/license\=$PARTITION_COLUMN.*/license\=(GNU GPLv3)/" PKGBUILD - name: Publish AUR package - uses: KSXGitHub/github-actions-deploy-aur@v4.1.1 + uses: KSXGitHub/github-actions-deploy-aur@v4.1.2 with: pkgname: python-recoverpy pkgbuild: ./PKGBUILD From 16390e6e6ff28a35831ffa2056b7e02c65fa3192 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:01:22 +0000 Subject: [PATCH 19/26] Bump textual from 8.2.3 to 8.2.4 Bumps [textual](https://github.com/Textualize/textual) from 8.2.3 to 8.2.4. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.3...v8.2.4) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9d53d8f1..9f045f4f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.3", + "textual==8.2.4", ] name = "recoverpy" version = "2.3.0" From 930e4a08e555853dfeebe34165285bd0e1d9d447 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:01:42 +0000 Subject: [PATCH 20/26] Bump KSXGitHub/github-actions-deploy-aur from 4.1.2 to 4.1.3 Bumps [KSXGitHub/github-actions-deploy-aur](https://github.com/ksxgithub/github-actions-deploy-aur) from 4.1.2 to 4.1.3. - [Release notes](https://github.com/ksxgithub/github-actions-deploy-aur/releases) - [Commits](https://github.com/ksxgithub/github-actions-deploy-aur/compare/v4.1.2...v4.1.3) --- updated-dependencies: - dependency-name: KSXGitHub/github-actions-deploy-aur dependency-version: 4.1.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/aur-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aur-release.yml b/.github/workflows/aur-release.yml index 3871903d..be7ac28a 100644 --- a/.github/workflows/aur-release.yml +++ b/.github/workflows/aur-release.yml @@ -29,7 +29,7 @@ jobs: sed -i "s/license\=$PARTITION_COLUMN.*/license\=(GNU GPLv3)/" PKGBUILD - name: Publish AUR package - uses: KSXGitHub/github-actions-deploy-aur@v4.1.2 + uses: KSXGitHub/github-actions-deploy-aur@v4.1.3 with: pkgname: python-recoverpy pkgbuild: ./PKGBUILD From 63c8538ea963c114bef17daca81ae318e3dda227 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:42:49 +0000 Subject: [PATCH 21/26] Bump textual from 8.2.4 to 8.2.5 Bumps [textual](https://github.com/Textualize/textual) from 8.2.4 to 8.2.5. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.4...v8.2.5) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9f045f4f..b52c2f61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.4", + "textual==8.2.5", ] name = "recoverpy" version = "2.3.0" From 942c88e0fdde0db6fed724accead5018cc447e80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 13:56:13 +0000 Subject: [PATCH 22/26] Bump textual from 8.2.5 to 8.2.6 Bumps [textual](https://github.com/Textualize/textual) from 8.2.5 to 8.2.6. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.5...v8.2.6) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b52c2f61..0e3e37f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.5", + "textual==8.2.6", ] name = "recoverpy" version = "2.3.0" From 20a155f24d3f41fb2f14fd734a443d8c7e77aa82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 May 2026 00:02:26 +0000 Subject: [PATCH 23/26] Bump textual from 8.2.6 to 8.2.7 Bumps [textual](https://github.com/Textualize/textual) from 8.2.6 to 8.2.7. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.6...v8.2.7) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0e3e37f3..e752b2b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.6", + "textual==8.2.7", ] name = "recoverpy" version = "2.3.0" From fd6f61fc4cb12b0f46c8290f88f11b4566743963 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:42:27 +0000 Subject: [PATCH 24/26] Bump actions/checkout from 6 to 7 Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/aur-release.yml | 2 +- .github/workflows/bandit.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/pypi-release.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/test-pypi-release.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/aur-release.yml b/.github/workflows/aur-release.yml index be7ac28a..9edd5407 100644 --- a/.github/workflows/aur-release.yml +++ b/.github/workflows/aur-release.yml @@ -13,7 +13,7 @@ jobs: aur-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-python@v6 - name: Install and fix pip2pkgbuild diff --git a/.github/workflows/bandit.yml b/.github/workflows/bandit.yml index bb22b9b1..0c6e5a64 100644 --- a/.github/workflows/bandit.yml +++ b/.github/workflows/bandit.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Bandit Scan uses: shundor/python-bandit-scan@9cc5aa4a006482b8a7f91134412df6772dbda22c with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bf16a46a..f524d629 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Initialize CodeQL uses: github/codeql-action/init@v4 diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index f2e592fa..7208c5bd 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index c66f7d8f..279c73e2 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -13,7 +13,7 @@ jobs: IS_GITHUB_RUNNER: "true" steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.github/workflows/test-pypi-release.yml b/.github/workflows/test-pypi-release.yml index e606fb50..d2f63af9 100644 --- a/.github/workflows/test-pypi-release.yml +++ b/.github/workflows/test-pypi-release.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 From e505ebf38d9157632a6a7e41e8518e6751c72e45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:42:30 +0000 Subject: [PATCH 25/26] Bump textual from 8.2.7 to 8.2.8 Bumps [textual](https://github.com/Textualize/textual) from 8.2.7 to 8.2.8. - [Release notes](https://github.com/Textualize/textual/releases) - [Changelog](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) - [Commits](https://github.com/Textualize/textual/compare/v8.2.7...v8.2.8) --- updated-dependencies: - dependency-name: textual dependency-version: 8.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e752b2b5..dc71a385 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ authors = [ license = { text = "GPL-3.0 License" } requires-python = "<4.0.0,>=3.9" dependencies = [ - "textual==8.2.7", + "textual==8.2.8", ] name = "recoverpy" version = "2.3.0" From 5d9026033cad35f3ad88bad14674f147ec475a74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 13:44:21 +0000 Subject: [PATCH 26/26] Bump actions/setup-python from 6 to 7 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/aur-release.yml | 2 +- .github/workflows/pypi-release.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/test-pypi-release.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/aur-release.yml b/.github/workflows/aur-release.yml index 9edd5407..4e66b622 100644 --- a/.github/workflows/aur-release.yml +++ b/.github/workflows/aur-release.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 - name: Install and fix pip2pkgbuild run: | diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 7208c5bd..83f1ffb2 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -17,7 +17,7 @@ jobs: uses: astral-sh/setup-uv@v7 - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 - name: Publish to PyPi env: diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 279c73e2..b57b08db 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -21,7 +21,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} architecture: x64 diff --git a/.github/workflows/test-pypi-release.yml b/.github/workflows/test-pypi-release.yml index d2f63af9..4b93743e 100644 --- a/.github/workflows/test-pypi-release.yml +++ b/.github/workflows/test-pypi-release.yml @@ -14,7 +14,7 @@ jobs: uses: astral-sh/setup-uv@v7 - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 - name: Publish to Test PyPi env: