From 8141e36c76acd24dad83b3ff2422680ab4a70b51 Mon Sep 17 00:00:00 2001 From: DirtyRacer Date: Sat, 10 May 2025 08:41:14 +0700 Subject: [PATCH 1/6] reduce test logs --- namer/__main__.py | 2 +- namer/watchdog.py | 11 ++++++++--- test/namer_configparser_test.py | 13 ++++++++++--- test/namer_ffmpeg_test.py | 8 ++++++++ test/namer_file_parser_test.py | 9 +++++++++ test/namer_fileutils_test.py | 9 +++++++++ test/namer_metadataapi_test.py | 9 +++++++++ test/namer_moviexml_test.py | 10 +++++++++- test/namer_mutagen_test.py | 8 ++++++++ test/namer_test.py | 8 ++++++++ test/namer_types_test.py | 11 +++++++++-- test/namer_videophash_test.py | 11 +++++++++-- test/namer_watchdog_test.py | 31 ++++++++----------------------- test/namer_webhook_test.py | 11 +++++++++-- test/utils.py | 3 +-- test/web/namer_web_test.py | 9 ++++++++- 16 files changed, 123 insertions(+), 40 deletions(-) diff --git a/namer/__main__.py b/namer/__main__.py index e9637e65..2d133ad1 100644 --- a/namer/__main__.py +++ b/namer/__main__.py @@ -74,7 +74,7 @@ def main(): arg1 = None if len(arg_list) == 0 else arg_list[0] if arg1 == 'watchdog': - namer.watchdog.create_watcher(config).run() + namer.watchdog.main(config) elif arg1 == 'rename': namer.namer.main(arg_list[1:]) elif arg1 == 'suggest': diff --git a/namer/watchdog.py b/namer/watchdog.py index 24a2ae40..3d7829d4 100644 --- a/namer/watchdog.py +++ b/namer/watchdog.py @@ -302,9 +302,6 @@ def create_watcher(namer_watchdog_config: NamerConfig) -> MovieWatcher: """ Configure and start a watchdog looking for new Movies. """ - level = 'DEBUG' if namer_watchdog_config.debug else 'INFO' - logger.add(sys.stdout, format=namer_watchdog_config.console_format, level=level, diagnose=namer_watchdog_config.diagnose_errors) - logger.info(namer_watchdog_config) if not verify_configuration(namer_watchdog_config, PartialFormatter()): @@ -322,3 +319,11 @@ def create_watcher(namer_watchdog_config: NamerConfig) -> MovieWatcher: movie_watcher = MovieWatcher(namer_watchdog_config) return movie_watcher + + +def main(config: NamerConfig): + level = 'DEBUG' if config.debug else 'INFO' + logger.add(sys.stdout, format=config.console_format, level=level, diagnose=config.diagnose_errors) + + create_watcher(config).run() + diff --git a/test/namer_configparser_test.py b/test/namer_configparser_test.py index be458a89..3bfdf0b3 100644 --- a/test/namer_configparser_test.py +++ b/test/namer_configparser_test.py @@ -5,8 +5,12 @@ from configupdater import ConfigUpdater import unittest from importlib import resources + +from loguru import logger + from namer.configuration import NamerConfig from namer.configuration_utils import from_config, to_ini +from test import utils class UnitTestAsTheDefaultExecution(unittest.TestCase): @@ -14,6 +18,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_configuration(self) -> None: updater = ConfigUpdater(allow_no_value=True) config_str = '' @@ -44,6 +54,3 @@ def test_configuration(self) -> None: updated.read_string(files_no_sites_with_no_date_info) double_read = from_config(updated, double_read) self.assertIn('badsite', double_read.sites_with_no_date_info) - - print(namer_config) - print(to_ini(namer_config)) diff --git a/test/namer_ffmpeg_test.py b/test/namer_ffmpeg_test.py index 0e28ac13..244a87b4 100644 --- a/test/namer_ffmpeg_test.py +++ b/test/namer_ffmpeg_test.py @@ -7,13 +7,21 @@ import unittest from pathlib import Path +from loguru import logger + from namer.ffmpeg import FFMpeg +from test import utils class UnitTestAsTheDefaultExecution(unittest.TestCase): """ Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() def test_get_resolution(self): """ diff --git a/test/namer_file_parser_test.py b/test/namer_file_parser_test.py index 82047fd4..9bd325d4 100644 --- a/test/namer_file_parser_test.py +++ b/test/namer_file_parser_test.py @@ -8,8 +8,11 @@ from pathlib import Path from unittest.mock import patch +from loguru import logger + from namer.fileinfo import parse_file_name from namer.command import make_command +from test import utils from test.utils import environment, sample_config REGEX_TOKEN = '{_site}{_sep}{_optional_date}{_ts}{_name}{_dot}{_ext}' @@ -20,6 +23,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_parse_file_name(self): """ Test standard name parsing. diff --git a/test/namer_fileutils_test.py b/test/namer_fileutils_test.py index db0d0f39..de3d4669 100644 --- a/test/namer_fileutils_test.py +++ b/test/namer_fileutils_test.py @@ -10,7 +10,10 @@ from platform import system from unittest.mock import patch +from loguru import logger + from namer.command import main, set_permissions +from test import utils from test.utils import environment, sample_config REGEX_TOKEN = '{_site}{_sep}{_optional_date}{_ts}{_name}{_dot}{_ext}' @@ -21,6 +24,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + @patch('sys.stdout', new_callable=io.StringIO) def test_main_method(self, mock_stdout): """ diff --git a/test/namer_metadataapi_test.py b/test/namer_metadataapi_test.py index 464ecb3b..e35bd1b8 100644 --- a/test/namer_metadataapi_test.py +++ b/test/namer_metadataapi_test.py @@ -6,10 +6,13 @@ import unittest from unittest import mock +from loguru import logger + from namer.comparison_results import SceneType from namer.fileinfo import parse_file_name from namer.command import make_command from namer.metadataapi import main, match +from test import utils from test.utils import environment, sample_config @@ -18,6 +21,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_parse_response_metadataapi_net_dorcel(self): """ Test parsing a stored response as a LookedUpFileInfo diff --git a/test/namer_moviexml_test.py b/test/namer_moviexml_test.py index 5ce9fb3a..56eeaee8 100644 --- a/test/namer_moviexml_test.py +++ b/test/namer_moviexml_test.py @@ -8,10 +8,13 @@ from pathlib import Path from shutil import copytree +from loguru import logger + from namer.fileinfo import parse_file_name from namer.metadataapi import match from namer.moviexml import parse_movie_xml_file, write_movie_xml_file from namer.comparison_results import Performer +from test import utils from test.utils import environment @@ -20,6 +23,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_parsing_xml_metadata(self): """ verify tag in place functions. @@ -137,7 +146,6 @@ def test_writing_xml_metadata(self): self.assertEqual(len(results.results), 1) result = results.results[0] output = write_movie_xml_file(result.looked_up, config) - print(output) expected = f""" Cute brunette Carmela Clutch positions her big, juicy ass for famed director/cocksman Mark Wood's camera to ogle. The well-endowed babe teases, flaunting her voluptuous jugs and derriere. Mark's sexy MILF partner, Francesca Le, finds a 'nice warm place' for her tongue and serves Carmela a lesbian rim job. Francesca takes a labia-licking face ride from the busty babe. Francesca takes over the camera as Mark takes over Carmela's hairy snatch, his big cock ram-fucking her twat. Carmela sucks Mark's meat in a lewd blowjob. Carmela jerks her clit as Mark delivers a vigorous anal pounding! With Mark's prick shoved up her ass, off-screen Francesca orders, 'Keep that pussy busy!' Carmela's huge boobs jiggle as she takes a rectal reaming and buzzes a vibrator on her clit at the same time. Francesca jumps in to make it a threesome, trading ass-to-mouth flavor with the young tramp. This ribald romp reaches its climax as Mark drops a messy, open-mouth cum facial onto Carmela. She lets the jizz drip from her lips, licking the mess from her fingers and rubbing it onto her robust melons. diff --git a/test/namer_mutagen_test.py b/test/namer_mutagen_test.py index f7c0400e..a849ecf4 100644 --- a/test/namer_mutagen_test.py +++ b/test/namer_mutagen_test.py @@ -8,6 +8,7 @@ from pathlib import Path import hashlib +from loguru import logger from mutagen.mp4 import MP4 from namer.configuration import NamerConfig @@ -16,6 +17,7 @@ from namer.metadataapi import match from namer.mutagen import resolution_to_hdv_setting, update_mp4_file from namer.comparison_results import LookedUpFileInfo +from test import utils from test.utils import validate_mp4_tags from test.namer_metadataapi_test import environment @@ -25,6 +27,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_video_size(self): """ Test resolution. diff --git a/test/namer_test.py b/test/namer_test.py index 17daf28f..219bc610 100644 --- a/test/namer_test.py +++ b/test/namer_test.py @@ -8,11 +8,13 @@ import unittest from pathlib import Path +from loguru import logger from mutagen.mp4 import MP4 from namer.configuration import NamerConfig from namer.configuration_utils import to_ini from namer.namer import check_arguments, main, set_permissions +from test import utils from test.utils import new_ea, sample_config, validate_mp4_tags, environment, FakeTPDB @@ -21,6 +23,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_check_arguments(self): """ verify file system checks diff --git a/test/namer_types_test.py b/test/namer_types_test.py index ed0e7de0..b6814dfe 100644 --- a/test/namer_types_test.py +++ b/test/namer_types_test.py @@ -2,16 +2,18 @@ Test namer_types.py """ -import logging import os import sys import unittest from pathlib import Path +from loguru import logger + from namer.configuration import NamerConfig from namer.configuration_utils import verify_configuration from namer.name_formatter import PartialFormatter from namer.comparison_results import Performer +from test import utils class UnitTestAsTheDefaultExecution(unittest.TestCase): @@ -19,6 +21,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_performer(self): """ Test performer __str__ @@ -97,7 +105,6 @@ def test_config_verification(self): """ Verify config verification. """ - logging.basicConfig(level=logging.INFO) config = NamerConfig() success = verify_configuration(config, PartialFormatter()) self.assertEqual(success, True) diff --git a/test/namer_videophash_test.py b/test/namer_videophash_test.py index 6d7f8141..13dfb982 100644 --- a/test/namer_videophash_test.py +++ b/test/namer_videophash_test.py @@ -2,15 +2,17 @@ Test namer_videophash.py """ -import logging import shutil import tempfile import unittest from pathlib import Path +from loguru import logger + from namer.videophash import imagehash from namer.videophash.videophashstash import StashVideoPerceptualHash from namer.videophash.videophash import VideoPerceptualHash +from test import utils from test.utils import sample_config @@ -19,6 +21,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + config = sample_config() __generator = VideoPerceptualHash(config.ffmpeg) __stash_generator = StashVideoPerceptualHash() @@ -65,5 +73,4 @@ def test_get_stash_phash(self): if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) unittest.main() diff --git a/test/namer_watchdog_test.py b/test/namer_watchdog_test.py index e4dc49d7..0f3a0e25 100644 --- a/test/namer_watchdog_test.py +++ b/test/namer_watchdog_test.py @@ -3,18 +3,18 @@ """ import contextlib -import logging import time -import os from typing import Any import unittest from pathlib import Path +from loguru import logger from mutagen.mp4 import MP4 from namer.ffmpeg import FFMpeg from namer.configuration import NamerConfig from namer.watchdog import create_watcher, done_copying, retry_failed, MovieWatcher +from test import utils from test.utils import Wait, new_ea, new_dorcel, validate_mp4_tags, validate_permissions, environment, sample_config, ProcessingTarget @@ -23,11 +23,8 @@ def wait_until_processed(watcher: MovieWatcher, durration: int = 60): Waits until all files have been moved out of watch/working dirs. """ config = watcher.get_config() - logging.info('waiting for files to be processes') Wait().seconds(durration).checking(1).until(lambda: len(list(config.watch_dir.iterdir())) > 0 or len(list(config.work_dir.iterdir())) > 0).isFalse() - logging.info('past waiting for files') watcher.stop() - logging.info('past stopping') @contextlib.contextmanager @@ -48,6 +45,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_done_copying_non_existent_file(self): """ Test negatives. @@ -78,7 +81,6 @@ def test_handler_collisions_success(self): self.assertEqual(output2.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_collisions_success_choose_best(self): """ @@ -111,7 +113,6 @@ def test_handler_collisions_success_choose_best(self): self.assertEqual(stream.codec_name, 'hevc') output_file2 = config.dest_dir / 'Evil Angel' / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-720p](1).mp4' self.assertFalse(output_file2.exists()) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_event_listener_success(self): """ @@ -132,7 +133,6 @@ def test_event_listener_success(self): self.assertEqual(output.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_event_listener_success_conversion(self): """ @@ -151,7 +151,6 @@ def test_event_listener_success_conversion(self): self.assertEqual(len(list(config.work_dir.iterdir())), 0) output_file = config.dest_dir / 'Evil Angel' / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-240].mkv' self.assertTrue(output_file.exists()) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_deeply_nested_success_no_dirname(self): """ @@ -178,7 +177,6 @@ def test_handler_deeply_nested_success_no_dirname(self): validate_permissions(self, output_file2, 664) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_deeply_nested_success_no_dirname_extra_files(self): """ @@ -208,7 +206,6 @@ def test_handler_deeply_nested_success_no_dirname_extra_files(self): self.assertEqual(output_test_file.read_text(), contents) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_deeply_nested_success(self): """ @@ -235,7 +232,6 @@ def test_handler_deeply_nested_success(self): validate_permissions(self, output_file, 600) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_deeply_nested_success_missing_network(self): """ @@ -261,7 +257,6 @@ def test_handler_deeply_nested_success_missing_network(self): validate_permissions(self, output_file, 600) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_deeply_nested_success_custom_location(self): """ @@ -287,7 +282,6 @@ def test_handler_deeply_nested_success_custom_location(self): validate_permissions(self, output_file, 600) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_deeply_nested_success_bracked(self): """ @@ -313,7 +307,6 @@ def test_handler_deeply_nested_success_bracked(self): validate_permissions(self, output_file, 600) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_ignore(self): """ @@ -326,7 +319,6 @@ def test_handler_ignore(self): time.sleep(2) watcher.stop() self.assertTrue(targets[0].get_file().exists()) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_handler_failure(self): """ @@ -350,7 +342,6 @@ def test_handler_failure(self): retry_failed(config) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertGreater(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_name_parser_success(self): """ @@ -373,7 +364,6 @@ def test_name_parser_success(self): self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) self.assertEqual(len(list(config.work_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def remove_performer_genders(self, data: Any): single_scene = data['data'] @@ -404,7 +394,6 @@ def test_missing_performers_gender_success(self): self.assertEqual(output.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def remove_performers(self, data: Any): single_scene = data['data'] @@ -432,7 +421,6 @@ def test_missing_performers_success(self): self.assertEqual(output.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_name_parser_failure_with_startup_processing(self): """ @@ -456,7 +444,6 @@ def test_name_parser_failure_with_startup_processing(self): self.assertEqual(len(list(config.watch_dir.iterdir())), 0) self.assertEqual(len(list(config.work_dir.iterdir())), 0) self.assertEqual(len(list(config.dest_dir.iterdir())), 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) def test_fetch_trailer_write_nfo_success(self): """ @@ -482,9 +469,7 @@ def test_fetch_trailer_write_nfo_success(self): self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) self.assertTrue(nfo_file.exists() and nfo_file.is_file() and nfo_file.stat().st_size != 0) - logging.info(os.environ.get('PYTEST_CURRENT_TEST')) if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) unittest.main() diff --git a/test/namer_webhook_test.py b/test/namer_webhook_test.py index d66102ae..cd453775 100644 --- a/test/namer_webhook_test.py +++ b/test/namer_webhook_test.py @@ -3,12 +3,14 @@ """ import json -import logging import unittest from pathlib import Path from unittest.mock import patch, MagicMock +from loguru import logger + from namer.namer import send_webhook_notification +from test import utils from test.utils import sample_config, environment, new_ea @@ -17,6 +19,12 @@ class WebhookTest(unittest.TestCase): Test the webhook notification functionality. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_webhook_disabled(self): """ Test that no webhook is sent when the feature is disabled. @@ -100,5 +108,4 @@ def test_integration_with_file_processing(self): if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) unittest.main() diff --git a/test/utils.py b/test/utils.py index c6f5866c..9c5a0c6f 100644 --- a/test/utils.py +++ b/test/utils.py @@ -205,7 +205,7 @@ def default_additions(self): @contextlib.contextmanager -def environment(config: NamerConfig = None): # type: ignore +def environment(config: NamerConfig = None): # ty if config is None: config = sample_config() @@ -240,7 +240,6 @@ def validate_permissions(test_self, file: Path, perm: int): if hasattr(os, 'chmod') and platform.system() != 'Windows': found = oct(file.stat().st_mode)[-3:] expected = str(perm)[-3:] - print('Found {found}, Expected {expected}') # test_self.assertEqual(found, "664") test_self.assertEqual(found, expected) diff --git a/test/web/namer_web_test.py b/test/web/namer_web_test.py index 63dd8c2f..5b0cdf6c 100644 --- a/test/web/namer_web_test.py +++ b/test/web/namer_web_test.py @@ -5,12 +5,14 @@ from platform import system import requests +from loguru import logger from selenium.webdriver import Chrome, ChromeOptions, Edge, EdgeOptions, Safari from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.safari.service import Service as SafariService from namer.configuration import NamerConfig from namer.watchdog import create_watcher +from test import utils from test.namer_metadataapi_test import environment from test.namer_watchdog_test import new_ea from test.utils import is_debugging, sample_config @@ -73,6 +75,12 @@ class UnitTestAsTheDefaultExecution(unittest.TestCase): Always test first. """ + def __init__(self, method_name='runTest'): + super().__init__(method_name) + + if not utils.is_debugging(): + logger.remove() + def test_webdriver_flow(self: unittest.TestCase): """ Test we can start the app, install, run and control a browser and shut it all down safely. @@ -128,7 +136,6 @@ def test_webdriver_flow(self: unittest.TestCase): .select() # returns to failed page .assert_has_no_files() ) - print('done') def test_parrot(self): with ParrotWebServer() as parrot: From 3f681819caa1c9061e01bffc1fa1b859989e78fe Mon Sep 17 00:00:00 2001 From: DirtyRacer Date: Sat, 10 May 2025 08:41:43 +0700 Subject: [PATCH 2/6] refactor --- namer/configuration.py | 9 +++++++++ namer/metadataapi.py | 2 +- namer/watchdog.py | 18 +++++++++++++----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/namer/configuration.py b/namer/configuration.py index b55c0a7a..b50701c0 100644 --- a/namer/configuration.py +++ b/namer/configuration.py @@ -510,6 +510,15 @@ def __init__(self): self.re_cleanup = [re.compile(rf'\b{regex}\b', re.IGNORECASE) for regex in database.re_cleanup] + if hasattr(self, 'watch_dir'): + self.watch_dir = self.watch_dir.resolve() + if hasattr(self, 'work_dir'): + self.work_dir = self.work_dir.resolve() + if hasattr(self, 'dest_dir'): + self.dest_dir = self.dest_dir.resolve() + if hasattr(self, 'failed_dir'): + self.failed_dir = self.failed_dir.resolve() + def __str__(self): config = self.to_dict() diff --git a/namer/metadataapi.py b/namer/metadataapi.py index 01979265..09008c64 100644 --- a/namer/metadataapi.py +++ b/namer/metadataapi.py @@ -472,7 +472,7 @@ def __get_metadataapi_net_info(url: str, name_parts: Optional[FileInfo], namer_c if json_response and json_response.strip() != '': # logger.debug("json_response: \n{}", json_response) json_obj = orjson.loads(json_response) - formatted = orjson.dumps(orjson.loads(json_response), option=orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS).decode('UTF-8') + formatted = orjson.dumps(json_obj, option=orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS).decode('UTF-8') file_infos = __metadataapi_response_to_data(json_obj, url, formatted, name_parts, namer_config) return file_infos diff --git a/namer/watchdog.py b/namer/watchdog.py index 3d7829d4..3292231f 100644 --- a/namer/watchdog.py +++ b/namer/watchdog.py @@ -103,7 +103,11 @@ def on_any_event(self, event: FileSystemEvent): file_path = event.src_path if file_path: - path = Path(file_path) + path = Path(file_path).resolve() + if not path.is_relative_to(self.__namer_config.watch_dir): + logger.error('file should be in watch dir {}', path) + return + relative_path = str(path.relative_to(self.__namer_config.watch_dir)) if not self.__namer_config.ignored_dir_regex.search(relative_path) and done_copying(path) and is_interesting_movie(path, self.__namer_config): logger.info('watchdog process called for {}', relative_path) @@ -249,10 +253,14 @@ def start(self): # touch all existing movie files. with suppress(FileNotFoundError): for file in self.__namer_config.watch_dir.rglob('**/*.*'): - if file.is_file() and file.suffix.lower()[1:] in self.__namer_config.target_extensions: - relative_path = str(file.relative_to(self.__namer_config.watch_dir)) - if not config.ignored_dir_regex.search(relative_path) and done_copying(file) and is_interesting_movie(file, self.__namer_config): - self.__event_handler.prepare_file_for_processing(file) + file = file.resolve() + if not file.is_relative_to(self.__namer_config.watch_dir): + logger.error('file should be in watch dir {}', file) + return + + relative_path = str(file.relative_to(self.__namer_config.watch_dir)) + if not self.__namer_config.ignored_dir_regex.search(relative_path) and done_copying(file) and is_interesting_movie(file, self.__namer_config): + self.__event_handler.prepare_file_for_processing(file) def stop(self): """ From 21eb6562cc0be729d987d0c660586ec00fdbdafd Mon Sep 17 00:00:00 2001 From: DirtyRacer Date: Sat, 10 May 2025 08:41:56 +0700 Subject: [PATCH 3/6] update dependences --- package.json | 16 +- pnpm-lock.yaml | 664 ++++++++++++++++++++++++------------------------- poetry.lock | 142 +++++------ 3 files changed, 407 insertions(+), 415 deletions(-) diff --git a/package.json b/package.json index ad5c627e..dece2eca 100644 --- a/package.json +++ b/package.json @@ -13,14 +13,14 @@ }, "dependencies": { "@popperjs/core": "^2.11.8", - "bootstrap": "^5.3.5", - "bootstrap-icons": "^1.11.3", + "bootstrap": "^5.3.6", + "bootstrap-icons": "^1.13.1", "datatables.net": "^2.3.0", "datatables.net-bs5": "^2.3.0", "datatables.net-buttons": "^3.2.3", "datatables.net-buttons-bs5": "^3.2.3", - "datatables.net-colreorder": "^2.0.4", - "datatables.net-colreorder-bs5": "^2.0.4", + "datatables.net-colreorder": "^2.1.0", + "datatables.net-colreorder-bs5": "^2.1.0", "datatables.net-fixedheader": "^4.0.1", "datatables.net-fixedheader-bs5": "^4.0.1", "datatables.net-responsive": "^3.0.4", @@ -30,7 +30,7 @@ }, "devDependencies": { "@babel/core": "^7.27.1", - "@babel/preset-env": "^7.27.1", + "@babel/preset-env": "^7.27.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.26.0", "babel-loader": "^10.0.0", @@ -40,10 +40,10 @@ "eslint": "^9.26.0", "eslint-config-standard": "^17.1.0", "file-loader": "^6.2.0", - "globals": "^16.0.0", + "globals": "^16.1.0", "html-minimizer-webpack-plugin": "^5.0.2", "husky": "^9.1.7", - "lint-staged": "^15.5.1", + "lint-staged": "^15.5.2", "mini-css-extract-plugin": "^2.9.2", "postcss": "^8.5.3", "postcss-loader": "^8.1.1", @@ -51,7 +51,7 @@ "sass": "^1.87.0", "sass-loader": "^16.0.5", "terser-webpack-plugin": "^5.3.14", - "webpack": "^5.99.7", + "webpack": "^5.99.8", "webpack-cli": "^6.0.1" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13604524..6101031e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,11 +12,11 @@ importers: specifier: ^2.11.8 version: 2.11.8 bootstrap: - specifier: ^5.3.5 - version: 5.3.5(@popperjs/core@2.11.8) + specifier: ^5.3.6 + version: 5.3.6(@popperjs/core@2.11.8) bootstrap-icons: - specifier: ^1.11.3 - version: 1.11.3 + specifier: ^1.13.1 + version: 1.13.1 datatables.net: specifier: ^2.3.0 version: 2.3.0 @@ -30,11 +30,11 @@ importers: specifier: ^3.2.3 version: 3.2.3 datatables.net-colreorder: - specifier: ^2.0.4 - version: 2.0.4 + specifier: ^2.1.0 + version: 2.1.0 datatables.net-colreorder-bs5: - specifier: ^2.0.4 - version: 2.0.4 + specifier: ^2.1.0 + version: 2.1.0 datatables.net-fixedheader: specifier: ^4.0.1 version: 4.0.1 @@ -58,8 +58,8 @@ importers: specifier: ^7.27.1 version: 7.27.1 '@babel/preset-env': - specifier: ^7.27.1 - version: 7.27.1(@babel/core@7.27.1) + specifier: ^7.27.2 + version: 7.27.2(@babel/core@7.27.1) '@eslint/eslintrc': specifier: ^3.3.1 version: 3.3.1 @@ -68,16 +68,16 @@ importers: version: 9.26.0 babel-loader: specifier: ^10.0.0 - version: 10.0.0(@babel/core@7.27.1)(webpack@5.99.7) + version: 10.0.0(@babel/core@7.27.1)(webpack@5.99.8) copy-webpack-plugin: specifier: ^13.0.0 - version: 13.0.0(webpack@5.99.7) + version: 13.0.0(webpack@5.99.8) css-loader: specifier: ^7.1.2 - version: 7.1.2(webpack@5.99.7) + version: 7.1.2(webpack@5.99.8) css-minimizer-webpack-plugin: specifier: ^7.0.2 - version: 7.0.2(webpack@5.99.7) + version: 7.0.2(webpack@5.99.8) eslint: specifier: ^9.26.0 version: 9.26.0(jiti@1.21.7) @@ -86,28 +86,28 @@ importers: version: 17.1.0(eslint-plugin-import@2.31.0(eslint@9.26.0(jiti@1.21.7)))(eslint-plugin-n@16.6.2(eslint@9.26.0(jiti@1.21.7)))(eslint-plugin-promise@6.6.0(eslint@9.26.0(jiti@1.21.7)))(eslint@9.26.0(jiti@1.21.7)) file-loader: specifier: ^6.2.0 - version: 6.2.0(webpack@5.99.7) + version: 6.2.0(webpack@5.99.8) globals: - specifier: ^16.0.0 - version: 16.0.0 + specifier: ^16.1.0 + version: 16.1.0 html-minimizer-webpack-plugin: specifier: ^5.0.2 - version: 5.0.2(webpack@5.99.7) + version: 5.0.2(webpack@5.99.8) husky: specifier: ^9.1.7 version: 9.1.7 lint-staged: - specifier: ^15.5.1 - version: 15.5.1 + specifier: ^15.5.2 + version: 15.5.2 mini-css-extract-plugin: specifier: ^2.9.2 - version: 2.9.2(webpack@5.99.7) + version: 2.9.2(webpack@5.99.8) postcss: specifier: ^8.5.3 version: 8.5.3 postcss-loader: specifier: ^8.1.1 - version: 8.1.1(postcss@8.5.3)(typescript@5.6.2)(webpack@5.99.7) + version: 8.1.1(postcss@8.5.3)(typescript@5.6.2)(webpack@5.99.8) postcss-preset-env: specifier: ^10.1.6 version: 10.1.6(postcss@8.5.3) @@ -116,16 +116,16 @@ importers: version: 1.87.0 sass-loader: specifier: ^16.0.5 - version: 16.0.5(sass@1.87.0)(webpack@5.99.7) + version: 16.0.5(sass@1.87.0)(webpack@5.99.8) terser-webpack-plugin: specifier: ^5.3.14 - version: 5.3.14(webpack@5.99.7) + version: 5.3.14(webpack@5.99.8) webpack: - specifier: ^5.99.7 - version: 5.99.7(webpack-cli@6.0.1) + specifier: ^5.99.8 + version: 5.99.8(webpack-cli@6.0.1) webpack-cli: specifier: ^6.0.1 - version: 6.0.1(webpack@5.99.7) + version: 6.0.1(webpack@5.99.8) packages: @@ -137,8 +137,8 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.27.1': - resolution: {integrity: sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==} + '@babel/compat-data@7.27.2': + resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} engines: {node: '>=6.9.0'} '@babel/core@7.27.1': @@ -153,8 +153,8 @@ packages: resolution: {integrity: sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.1': - resolution: {integrity: sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==} + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} '@babel/helper-create-class-features-plugin@7.27.1': @@ -232,8 +232,8 @@ packages: resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.1': - resolution: {integrity: sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==} + '@babel/parser@7.27.2': + resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} engines: {node: '>=6.0.0'} hasBin: true @@ -471,8 +471,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.27.1': - resolution: {integrity: sha512-/sSliVc9gHE20/7D5qsdGlq7RG5NCDTWsAhyqzGuq174EtWJoGzIu1BQ7G56eDsTcy1jseBZwv50olSdXOlGuA==} + '@babel/plugin-transform-object-rest-spread@7.27.2': + resolution: {integrity: sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -591,8 +591,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.27.1': - resolution: {integrity: sha512-TZ5USxFpLgKDpdEt8YWBR7p6g+bZo6sHaXLqP2BY/U0acaoI8FTVflcYCr/v94twM1C5IWFdZ/hscq9WjUeLXA==} + '@babel/preset-env@7.27.2': + resolution: {integrity: sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -602,8 +602,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/template@7.27.1': - resolution: {integrity: sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} '@babel/traverse@7.27.1': @@ -924,8 +924,8 @@ packages: resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} - '@humanwhocodes/retry@0.4.2': - resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} '@jest/schemas@29.6.3': @@ -957,8 +957,8 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@modelcontextprotocol/sdk@1.11.0': - resolution: {integrity: sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==} + '@modelcontextprotocol/sdk@1.11.1': + resolution: {integrity: sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==} engines: {node: '>=18'} '@parcel/watcher-android-arm64@2.5.1': @@ -1083,8 +1083,8 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/node@22.15.3': - resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} + '@types/node@22.15.17': + resolution: {integrity: sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==} '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -1299,11 +1299,11 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - bootstrap-icons@1.11.3: - resolution: {integrity: sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==} + bootstrap-icons@1.13.1: + resolution: {integrity: sha512-ijombt4v6bv5CLeXvRWKy7CuM3TRTuPEuGaGKvTV5cz65rQSY8RQ2JcHt6b90cBBAC7s8fsf2EkQDldzCoXUjw==} - bootstrap@5.3.5: - resolution: {integrity: sha512-ct1CHKtiobRimyGzmsSldEtM03E8fcEX4Tb3dGXz1V8faRwM50+vfHwTzOxB3IlKO7m+9vTH3s/3C6T2EAPeTA==} + bootstrap@5.3.6: + resolution: {integrity: sha512-jX0GAcRzvdwISuvArXn3m7KZscWWFAf1MKBcnzaN02qWMb3jpMoUX4/qgeiGzqyIb4ojulRzs89UCUmGcFSzTA==} peerDependencies: '@popperjs/core': ^2.11.8 @@ -1355,8 +1355,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001716: - resolution: {integrity: sha512-49/c1+x3Kwz7ZIWt+4DvK3aMJy9oYXXG6/97JKsnjdCk/6n9vVyWL8NAwVt95Lwt9eigI10Hl782kDfZUUlRXw==} + caniuse-lite@1.0.30001717: + resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1558,23 +1558,23 @@ packages: engines: {node: '>=4'} hasBin: true - cssnano-preset-default@7.0.6: - resolution: {integrity: sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==} + cssnano-preset-default@7.0.7: + resolution: {integrity: sha512-jW6CG/7PNB6MufOrlovs1TvBTEVmhY45yz+bd0h6nw3h6d+1e+/TX+0fflZ+LzvZombbT5f+KC063w9VoHeHow==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - cssnano-utils@5.0.0: - resolution: {integrity: sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==} + cssnano-utils@5.0.1: + resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - cssnano@7.0.6: - resolution: {integrity: sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==} + cssnano@7.0.7: + resolution: {integrity: sha512-evKu7yiDIF7oS+EIpwFlMF730ijRyLFaM2o5cTxRGJR9OKHKkc+qP443ZEVR9kZG0syaAJJCPJyfv5pbrxlSng==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} @@ -1601,11 +1601,11 @@ packages: datatables.net-buttons@3.2.3: resolution: {integrity: sha512-K+WeQWUYVGe5c3Gwb8Gfi7YpUXbJEerik3B2vynnVKpBlYBF5AHTGbrK1Psek2q/mjxeIVNHafQ9eX2otLhJVw==} - datatables.net-colreorder-bs5@2.0.4: - resolution: {integrity: sha512-FRMADJ3FU8W5d5KiYV2eJIqi3+JDKBrRDpn45JRt6584M2Z+UBftxFGQ0EtbY+tPsCxLr7Y3j7f43d2xcUKTYQ==} + datatables.net-colreorder-bs5@2.1.0: + resolution: {integrity: sha512-s7ekoFwsj/NqyxnWQoGTQh8QbDvejM7dDSqLoAjfQDOgKpv3t0eZvzXIvufsZZhKPEJEw3Yof/tpN8+CHwDVxA==} - datatables.net-colreorder@2.0.4: - resolution: {integrity: sha512-j2d2uObivMaMLX+VTsIu9XEfucMPuS+OYurezQtPNHo0LgdXdgKvouEAUghVtlkTxW+jX7tjiSbagH2YWIS5Jg==} + datatables.net-colreorder@2.1.0: + resolution: {integrity: sha512-VMZkrR6cPzaCdlXnFmkM/oZS/TFY6NMusE7km3M3pYFVcmTyooQL/zDhEbhcCJrvNvuQkskruFYxwPK8+MzFPA==} datatables.net-fixedheader-bs5@4.0.1: resolution: {integrity: sha512-rA02QKEDvzj9dtwoUDl8hdSFDi4THpZeqCpCne0sVul1AM4OBy0O4zcx2WMSiEc5yEjFVZwKHmkvcDyhioV5IQ==} @@ -1686,8 +1686,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.149: - resolution: {integrity: sha512-UyiO82eb9dVOx8YO3ajDf9jz2kKyt98DEITRdeLPstOEuTlLzDA4Gyq5K9he71TQziU5jUVu2OAu5N48HmQiyQ==} + electron-to-chromium@1.5.151: + resolution: {integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==} emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -1898,8 +1898,8 @@ packages: resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} engines: {node: '>=18.0.0'} - eventsource@3.0.6: - resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} execa@8.0.1: @@ -2048,8 +2048,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@16.0.0: - resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==} + globals@16.1.0: + resolution: {integrity: sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==} engines: {node: '>=18'} globalthis@1.0.4: @@ -2132,8 +2132,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - immutable@5.1.1: - resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==} + immutable@5.1.2: + resolution: {integrity: sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -2373,13 +2373,13 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lint-staged@15.5.1: - resolution: {integrity: sha512-6m7u8mue4Xn6wK6gZvSCQwBvMBR36xfY24nF5bMTf2MHDYG6S3yhJuOgdYVw99hsjyDt2d4z168b3naI8+NWtQ==} + lint-staged@15.5.2: + resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==} engines: {node: '>=18.12.0'} hasBin: true - listr2@8.3.2: - resolution: {integrity: sha512-vsBzcU4oE+v0lj4FhVLzr9dBTv4/fHIa57l+GCwovP8MoFNZJTOhGU8PXd4v2VJCbECAaijBiHntiekFMLvo0g==} + listr2@8.3.3: + resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} loader-runner@4.3.0: @@ -2698,17 +2698,17 @@ packages: peerDependencies: postcss: ^8.4 - postcss-colormin@7.0.2: - resolution: {integrity: sha512-YntRXNngcvEvDbEjTdRWGU606eZvB5prmHG4BF0yLmVpamXbpsRJzevyy6MZVyuecgzI2AWAlvFi8DAeCqwpvA==} + postcss-colormin@7.0.3: + resolution: {integrity: sha512-xZxQcSyIVZbSsl1vjoqZAcMYYdnJsIyG8OvqShuuqf12S88qQboxxEy0ohNCOLwVPXTU+hFHvJPACRL2B5ohTA==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-convert-values@7.0.4: - resolution: {integrity: sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==} + postcss-convert-values@7.0.5: + resolution: {integrity: sha512-0VFhH8nElpIs3uXKnVtotDJJNX0OGYSZmdt4XfSfvOMrFw1jKfpwpZxfC4iN73CTM/MWakDEmsHQXkISYj4BXw==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-custom-media@11.0.5: resolution: {integrity: sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==} @@ -2734,29 +2734,29 @@ packages: peerDependencies: postcss: ^8.4 - postcss-discard-comments@7.0.3: - resolution: {integrity: sha512-q6fjd4WU4afNhWOA2WltHgCbkRhZPgQe7cXF74fuVB/ge4QbM9HEaOIzGSiMvM+g/cOsNAUGdf2JDzqA2F8iLA==} + postcss-discard-comments@7.0.4: + resolution: {integrity: sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-discard-duplicates@7.0.1: - resolution: {integrity: sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==} + postcss-discard-duplicates@7.0.2: + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-discard-empty@7.0.0: - resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==} + postcss-discard-empty@7.0.1: + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-discard-overridden@7.0.0: - resolution: {integrity: sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==} + postcss-discard-overridden@7.0.1: + resolution: {integrity: sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-double-position-gradients@6.0.1: resolution: {integrity: sha512-ZitCwmvOR4JzXmKw6sZblTgwV1dcfLvClcyjADuqZ5hU0Uk4SVNpvSN9w8NcJ7XuxhRYxVA8m8AB3gy+HNBQOA==} @@ -2818,41 +2818,41 @@ packages: peerDependencies: postcss: ^8.4 - postcss-merge-longhand@7.0.4: - resolution: {integrity: sha512-zer1KoZA54Q8RVHKOY5vMke0cCdNxMP3KBfDerjH/BYHh4nCIh+1Yy0t1pAEQF18ac/4z3OFclO+ZVH8azjR4A==} + postcss-merge-longhand@7.0.5: + resolution: {integrity: sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-merge-rules@7.0.4: - resolution: {integrity: sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==} + postcss-merge-rules@7.0.5: + resolution: {integrity: sha512-ZonhuSwEaWA3+xYbOdJoEReKIBs5eDiBVLAGpYZpNFPzXZcEE5VKR7/qBEQvTZpiwjqhhqEQ+ax5O3VShBj9Wg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-minify-font-values@7.0.0: - resolution: {integrity: sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==} + postcss-minify-font-values@7.0.1: + resolution: {integrity: sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-minify-gradients@7.0.0: - resolution: {integrity: sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==} + postcss-minify-gradients@7.0.1: + resolution: {integrity: sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-minify-params@7.0.2: - resolution: {integrity: sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==} + postcss-minify-params@7.0.3: + resolution: {integrity: sha512-vUKV2+f5mtjewYieanLX0xemxIp1t0W0H/D11u+kQV/MWdygOO7xPMkbK+r9P6Lhms8MgzKARF/g5OPXhb8tgg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-minify-selectors@7.0.4: - resolution: {integrity: sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==} + postcss-minify-selectors@7.0.5: + resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-modules-extract-imports@3.1.0: resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} @@ -2884,59 +2884,59 @@ packages: peerDependencies: postcss: ^8.4 - postcss-normalize-charset@7.0.0: - resolution: {integrity: sha512-ABisNUXMeZeDNzCQxPxBCkXexvBrUHV+p7/BXOY+ulxkcjUZO0cp8ekGBwvIh2LbCwnWbyMPNJVtBSdyhM2zYQ==} + postcss-normalize-charset@7.0.1: + resolution: {integrity: sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-display-values@7.0.0: - resolution: {integrity: sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==} + postcss-normalize-display-values@7.0.1: + resolution: {integrity: sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-positions@7.0.0: - resolution: {integrity: sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==} + postcss-normalize-positions@7.0.1: + resolution: {integrity: sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-repeat-style@7.0.0: - resolution: {integrity: sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==} + postcss-normalize-repeat-style@7.0.1: + resolution: {integrity: sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-string@7.0.0: - resolution: {integrity: sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==} + postcss-normalize-string@7.0.1: + resolution: {integrity: sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-timing-functions@7.0.0: - resolution: {integrity: sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==} + postcss-normalize-timing-functions@7.0.1: + resolution: {integrity: sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-unicode@7.0.2: - resolution: {integrity: sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==} + postcss-normalize-unicode@7.0.3: + resolution: {integrity: sha512-EcoA29LvG3F+EpOh03iqu+tJY3uYYKzArqKJHxDhUYLa2u58aqGq16K6/AOsXD9yqLN8O6y9mmePKN5cx6krOw==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-url@7.0.0: - resolution: {integrity: sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==} + postcss-normalize-url@7.0.1: + resolution: {integrity: sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-normalize-whitespace@7.0.0: - resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==} + postcss-normalize-whitespace@7.0.1: + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-opacity-percentage@3.0.0: resolution: {integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==} @@ -2944,11 +2944,11 @@ packages: peerDependencies: postcss: ^8.4 - postcss-ordered-values@7.0.1: - resolution: {integrity: sha512-irWScWRL6nRzYmBOXReIKch75RRhNS86UPUAxXdmW/l0FcAsg0lvAXQCby/1lymxn/o0gVa6Rv/0f03eJOwHxw==} + postcss-ordered-values@7.0.2: + resolution: {integrity: sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-overflow-shorthand@6.0.0: resolution: {integrity: sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==} @@ -2979,17 +2979,17 @@ packages: peerDependencies: postcss: ^8.4 - postcss-reduce-initial@7.0.2: - resolution: {integrity: sha512-pOnu9zqQww7dEKf62Nuju6JgsW2V0KRNBHxeKohU+JkHd/GAH5uvoObqFLqkeB2n20mr6yrlWDvo5UBU5GnkfA==} + postcss-reduce-initial@7.0.3: + resolution: {integrity: sha512-RFvkZaqiWtGMlVjlUHpaxGqEL27lgt+Q2Ixjf83CRAzqdo+TsDyGPtJUbPx2MuYIJ+sCQc2TrOvRnhcXQfgIVA==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-reduce-transforms@7.0.0: - resolution: {integrity: sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==} + postcss-reduce-transforms@7.0.1: + resolution: {integrity: sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-replace-overflow-wrap@4.0.0: resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==} @@ -3002,25 +3002,21 @@ packages: peerDependencies: postcss: ^8.4 - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} - postcss-selector-parser@7.1.0: resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} engines: {node: '>=4'} - postcss-svgo@7.0.1: - resolution: {integrity: sha512-0WBUlSL4lhD9rA5k1e5D8EN5wCEyZD6HJk0jIvRxl+FDVOMlJ7DePHYWGGVc5QRqrJ3/06FTXM0bxjmJpmTPSA==} + postcss-svgo@7.0.2: + resolution: {integrity: sha512-5Dzy66JlnRM6pkdOTF8+cGsB1fnERTE8Nc+Eed++fOWo1hdsBptCsbG8UuJkgtZt75bRtMJIrPeZmtfANixdFA==} engines: {node: ^18.12.0 || ^20.9.0 || >= 18} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 - postcss-unique-selectors@7.0.3: - resolution: {integrity: sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==} + postcss-unique-selectors@7.0.4: + resolution: {integrity: sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -3307,11 +3303,11 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - stylehacks@7.0.4: - resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==} + stylehacks@7.0.5: + resolution: {integrity: sha512-5kNb7V37BNf0Q3w+1pxfa+oiNPS++/b4Jil9e/kPDgrk1zjEd6uR7SZeJiYaLYH6RRSC1XX2/37OTeU/4FvuIA==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.4.32 supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -3475,8 +3471,8 @@ packages: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} - webpack@5.99.7: - resolution: {integrity: sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w==} + webpack@5.99.8: + resolution: {integrity: sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -3537,8 +3533,8 @@ packages: peerDependencies: zod: ^3.24.1 - zod@3.24.3: - resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} + zod@3.24.4: + resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} snapshots: @@ -3553,18 +3549,18 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.27.1': {} + '@babel/compat-data@7.27.2': {} '@babel/core@7.27.1': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.27.1 '@babel/generator': 7.27.1 - '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) '@babel/helpers': 7.27.1 - '@babel/parser': 7.27.1 - '@babel/template': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/template': 7.27.2 '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 2.0.0 @@ -3577,7 +3573,7 @@ snapshots: '@babel/generator@7.27.1': dependencies: - '@babel/parser': 7.27.1 + '@babel/parser': 7.27.2 '@babel/types': 7.27.1 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 @@ -3587,9 +3583,9 @@ snapshots: dependencies: '@babel/types': 7.27.1 - '@babel/helper-compilation-targets@7.27.1': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.27.1 + '@babel/compat-data': 7.27.2 '@babel/helper-validator-option': 7.27.1 browserslist: 4.24.5 lru-cache: 5.1.1 @@ -3618,7 +3614,7 @@ snapshots: '@babel/helper-define-polyfill-provider@0.6.4(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 - '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.0 lodash.debounce: 4.0.8 @@ -3688,7 +3684,7 @@ snapshots: '@babel/helper-wrap-function@7.27.1': dependencies: - '@babel/template': 7.27.1 + '@babel/template': 7.27.2 '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 transitivePeerDependencies: @@ -3696,10 +3692,10 @@ snapshots: '@babel/helpers@7.27.1': dependencies: - '@babel/template': 7.27.1 + '@babel/template': 7.27.2 '@babel/types': 7.27.1 - '@babel/parser@7.27.1': + '@babel/parser@7.27.2': dependencies: '@babel/types': 7.27.1 @@ -3811,7 +3807,7 @@ snapshots: dependencies: '@babel/core': 7.27.1 '@babel/helper-annotate-as-pure': 7.27.1 - '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.1) '@babel/traverse': 7.27.1 @@ -3823,7 +3819,7 @@ snapshots: dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.1 + '@babel/template': 7.27.2 '@babel/plugin-transform-destructuring@7.27.1(@babel/core@7.27.1)': dependencies: @@ -3873,7 +3869,7 @@ snapshots: '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 - '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/traverse': 7.27.1 transitivePeerDependencies: @@ -3954,11 +3950,12 @@ snapshots: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-object-rest-spread@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-transform-object-rest-spread@7.27.2(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 - '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-parameters': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.27.1)': @@ -4076,11 +4073,11 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.27.1) '@babel/helper-plugin-utils': 7.27.1 - '@babel/preset-env@7.27.1(@babel/core@7.27.1)': + '@babel/preset-env@7.27.2(@babel/core@7.27.1)': dependencies: - '@babel/compat-data': 7.27.1 + '@babel/compat-data': 7.27.2 '@babel/core': 7.27.1 - '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.27.1) @@ -4122,7 +4119,7 @@ snapshots: '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.27.1) - '@babel/plugin-transform-object-rest-spread': 7.27.1(@babel/core@7.27.1) + '@babel/plugin-transform-object-rest-spread': 7.27.2(@babel/core@7.27.1) '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.27.1) @@ -4158,18 +4155,18 @@ snapshots: '@babel/types': 7.27.1 esutils: 2.0.3 - '@babel/template@7.27.1': + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.27.1 + '@babel/parser': 7.27.2 '@babel/types': 7.27.1 '@babel/traverse@7.27.1': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.27.1 - '@babel/parser': 7.27.1 - '@babel/template': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/template': 7.27.2 '@babel/types': 7.27.1 debug: 4.4.0 globals: 11.12.0 @@ -4490,7 +4487,7 @@ snapshots: '@humanwhocodes/retry@0.3.1': {} - '@humanwhocodes/retry@0.4.2': {} + '@humanwhocodes/retry@0.4.3': {} '@jest/schemas@29.6.3': dependencies: @@ -4501,7 +4498,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.15.3 + '@types/node': 22.15.17 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -4527,18 +4524,18 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@modelcontextprotocol/sdk@1.11.0': + '@modelcontextprotocol/sdk@1.11.1': dependencies: content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 - eventsource: 3.0.6 + eventsource: 3.0.7 express: 5.1.0 express-rate-limit: 7.5.0(express@5.1.0) pkce-challenge: 5.0.0 raw-body: 3.0.0 - zod: 3.24.3 - zod-to-json-schema: 3.24.5(zod@3.24.3) + zod: 3.24.4 + zod-to-json-schema: 3.24.5(zod@3.24.4) transitivePeerDependencies: - supports-color @@ -4639,7 +4636,7 @@ snapshots: '@types/json5@0.0.29': {} - '@types/node@22.15.3': + '@types/node@22.15.17': dependencies: undici-types: 6.21.0 @@ -4725,20 +4722,20 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.99.7)': + '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.99.8)': dependencies: - webpack: 5.99.7(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.99.7) + webpack: 5.99.8(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.99.8) - '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.99.7)': + '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.99.8)': dependencies: - webpack: 5.99.7(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.99.7) + webpack: 5.99.8(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.99.8) - '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.99.7)': + '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.99.8)': dependencies: - webpack: 5.99.7(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.99.7) + webpack: 5.99.8(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.99.8) '@xtuc/ieee754@1.2.0': {} @@ -4849,7 +4846,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.3): dependencies: browserslist: 4.24.5 - caniuse-lite: 1.0.30001716 + caniuse-lite: 1.0.30001717 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -4860,15 +4857,15 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - babel-loader@10.0.0(@babel/core@7.27.1)(webpack@5.99.7): + babel-loader@10.0.0(@babel/core@7.27.1)(webpack@5.99.8): dependencies: '@babel/core': 7.27.1 find-up: 5.0.0 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) babel-plugin-polyfill-corejs2@0.4.13(@babel/core@7.27.1): dependencies: - '@babel/compat-data': 7.27.1 + '@babel/compat-data': 7.27.2 '@babel/core': 7.27.1 '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.27.1) semver: 6.3.1 @@ -4910,9 +4907,9 @@ snapshots: boolbase@1.0.0: {} - bootstrap-icons@1.11.3: {} + bootstrap-icons@1.13.1: {} - bootstrap@5.3.5(@popperjs/core@2.11.8): + bootstrap@5.3.6(@popperjs/core@2.11.8): dependencies: '@popperjs/core': 2.11.8 @@ -4927,8 +4924,8 @@ snapshots: browserslist@4.24.5: dependencies: - caniuse-lite: 1.0.30001716 - electron-to-chromium: 1.5.149 + caniuse-lite: 1.0.30001717 + electron-to-chromium: 1.5.151 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.5) @@ -4969,11 +4966,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.24.5 - caniuse-lite: 1.0.30001716 + caniuse-lite: 1.0.30001717 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001716: {} + caniuse-lite@1.0.30001717: {} chalk@4.1.2: dependencies: @@ -5043,14 +5040,14 @@ snapshots: cookie@0.7.2: {} - copy-webpack-plugin@13.0.0(webpack@5.99.7): + copy-webpack-plugin@13.0.0(webpack@5.99.8): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.2 serialize-javascript: 6.0.2 tinyglobby: 0.2.13 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) core-js-compat@3.42.0: dependencies: @@ -5092,7 +5089,7 @@ snapshots: postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 - css-loader@7.1.2(webpack@5.99.7): + css-loader@7.1.2(webpack@5.99.8): dependencies: icss-utils: 5.1.0(postcss@8.5.3) postcss: 8.5.3 @@ -5103,17 +5100,17 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.1 optionalDependencies: - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) - css-minimizer-webpack-plugin@7.0.2(webpack@5.99.7): + css-minimizer-webpack-plugin@7.0.2(webpack@5.99.8): dependencies: '@jridgewell/trace-mapping': 0.3.25 - cssnano: 7.0.6(postcss@8.5.3) + cssnano: 7.0.7(postcss@8.5.3) jest-worker: 29.7.0 postcss: 8.5.3 schema-utils: 4.3.2 serialize-javascript: 6.0.2 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) css-prefers-color-scheme@10.0.0(postcss@8.5.3): dependencies: @@ -5143,47 +5140,47 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@7.0.6(postcss@8.5.3): + cssnano-preset-default@7.0.7(postcss@8.5.3): dependencies: browserslist: 4.24.5 css-declaration-sorter: 7.2.0(postcss@8.5.3) - cssnano-utils: 5.0.0(postcss@8.5.3) + cssnano-utils: 5.0.1(postcss@8.5.3) postcss: 8.5.3 postcss-calc: 10.1.1(postcss@8.5.3) - postcss-colormin: 7.0.2(postcss@8.5.3) - postcss-convert-values: 7.0.4(postcss@8.5.3) - postcss-discard-comments: 7.0.3(postcss@8.5.3) - postcss-discard-duplicates: 7.0.1(postcss@8.5.3) - postcss-discard-empty: 7.0.0(postcss@8.5.3) - postcss-discard-overridden: 7.0.0(postcss@8.5.3) - postcss-merge-longhand: 7.0.4(postcss@8.5.3) - postcss-merge-rules: 7.0.4(postcss@8.5.3) - postcss-minify-font-values: 7.0.0(postcss@8.5.3) - postcss-minify-gradients: 7.0.0(postcss@8.5.3) - postcss-minify-params: 7.0.2(postcss@8.5.3) - postcss-minify-selectors: 7.0.4(postcss@8.5.3) - postcss-normalize-charset: 7.0.0(postcss@8.5.3) - postcss-normalize-display-values: 7.0.0(postcss@8.5.3) - postcss-normalize-positions: 7.0.0(postcss@8.5.3) - postcss-normalize-repeat-style: 7.0.0(postcss@8.5.3) - postcss-normalize-string: 7.0.0(postcss@8.5.3) - postcss-normalize-timing-functions: 7.0.0(postcss@8.5.3) - postcss-normalize-unicode: 7.0.2(postcss@8.5.3) - postcss-normalize-url: 7.0.0(postcss@8.5.3) - postcss-normalize-whitespace: 7.0.0(postcss@8.5.3) - postcss-ordered-values: 7.0.1(postcss@8.5.3) - postcss-reduce-initial: 7.0.2(postcss@8.5.3) - postcss-reduce-transforms: 7.0.0(postcss@8.5.3) - postcss-svgo: 7.0.1(postcss@8.5.3) - postcss-unique-selectors: 7.0.3(postcss@8.5.3) - - cssnano-utils@5.0.0(postcss@8.5.3): + postcss-colormin: 7.0.3(postcss@8.5.3) + postcss-convert-values: 7.0.5(postcss@8.5.3) + postcss-discard-comments: 7.0.4(postcss@8.5.3) + postcss-discard-duplicates: 7.0.2(postcss@8.5.3) + postcss-discard-empty: 7.0.1(postcss@8.5.3) + postcss-discard-overridden: 7.0.1(postcss@8.5.3) + postcss-merge-longhand: 7.0.5(postcss@8.5.3) + postcss-merge-rules: 7.0.5(postcss@8.5.3) + postcss-minify-font-values: 7.0.1(postcss@8.5.3) + postcss-minify-gradients: 7.0.1(postcss@8.5.3) + postcss-minify-params: 7.0.3(postcss@8.5.3) + postcss-minify-selectors: 7.0.5(postcss@8.5.3) + postcss-normalize-charset: 7.0.1(postcss@8.5.3) + postcss-normalize-display-values: 7.0.1(postcss@8.5.3) + postcss-normalize-positions: 7.0.1(postcss@8.5.3) + postcss-normalize-repeat-style: 7.0.1(postcss@8.5.3) + postcss-normalize-string: 7.0.1(postcss@8.5.3) + postcss-normalize-timing-functions: 7.0.1(postcss@8.5.3) + postcss-normalize-unicode: 7.0.3(postcss@8.5.3) + postcss-normalize-url: 7.0.1(postcss@8.5.3) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.3) + postcss-ordered-values: 7.0.2(postcss@8.5.3) + postcss-reduce-initial: 7.0.3(postcss@8.5.3) + postcss-reduce-transforms: 7.0.1(postcss@8.5.3) + postcss-svgo: 7.0.2(postcss@8.5.3) + postcss-unique-selectors: 7.0.4(postcss@8.5.3) + + cssnano-utils@5.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 - cssnano@7.0.6(postcss@8.5.3): + cssnano@7.0.7(postcss@8.5.3): dependencies: - cssnano-preset-default: 7.0.6(postcss@8.5.3) + cssnano-preset-default: 7.0.7(postcss@8.5.3) lilconfig: 3.1.3 postcss: 8.5.3 @@ -5225,13 +5222,13 @@ snapshots: datatables.net: 2.3.0 jquery: 3.7.1 - datatables.net-colreorder-bs5@2.0.4: + datatables.net-colreorder-bs5@2.1.0: dependencies: datatables.net-bs5: 2.3.0 - datatables.net-colreorder: 2.0.4 + datatables.net-colreorder: 2.1.0 jquery: 3.7.1 - datatables.net-colreorder@2.0.4: + datatables.net-colreorder@2.1.0: dependencies: datatables.net: 2.3.0 jquery: 3.7.1 @@ -5324,7 +5321,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.149: {} + electron-to-chromium@1.5.151: {} emoji-regex@10.4.0: {} @@ -5544,8 +5541,8 @@ snapshots: '@eslint/plugin-kit': 0.2.8 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.2 - '@modelcontextprotocol/sdk': 1.11.0 + '@humanwhocodes/retry': 0.4.3 + '@modelcontextprotocol/sdk': 1.11.1 '@types/estree': 1.0.7 '@types/json-schema': 7.0.15 ajv: 6.12.6 @@ -5570,7 +5567,7 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - zod: 3.24.3 + zod: 3.24.4 optionalDependencies: jiti: 1.21.7 transitivePeerDependencies: @@ -5604,7 +5601,7 @@ snapshots: eventsource-parser@3.0.1: {} - eventsource@3.0.6: + eventsource@3.0.7: dependencies: eventsource-parser: 3.0.1 @@ -5674,11 +5671,11 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-loader@6.2.0(webpack@5.99.7): + file-loader@6.2.0(webpack@5.99.8): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) fill-range@7.1.1: dependencies: @@ -5785,7 +5782,7 @@ snapshots: globals@14.0.0: {} - globals@16.0.0: {} + globals@16.1.0: {} globalthis@1.0.4: dependencies: @@ -5828,14 +5825,14 @@ snapshots: relateurl: 0.2.7 terser: 5.39.0 - html-minimizer-webpack-plugin@5.0.2(webpack@5.99.7): + html-minimizer-webpack-plugin@5.0.2(webpack@5.99.8): dependencies: '@types/html-minifier-terser': 7.0.2 html-minifier-terser: 7.2.0 jest-worker: 29.7.0 schema-utils: 4.3.2 serialize-javascript: 6.0.2 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) http-errors@2.0.0: dependencies: @@ -5859,7 +5856,7 @@ snapshots: ignore@5.3.2: {} - immutable@5.1.1: {} + immutable@5.1.2: {} import-fresh@3.3.1: dependencies: @@ -6019,7 +6016,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.15.3 + '@types/node': 22.15.17 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -6027,13 +6024,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.15.3 + '@types/node': 22.15.17 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 22.15.3 + '@types/node': 22.15.17 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -6083,14 +6080,14 @@ snapshots: lines-and-columns@1.2.4: {} - lint-staged@15.5.1: + lint-staged@15.5.2: dependencies: chalk: 5.4.1 commander: 13.1.0 debug: 4.4.0 execa: 8.0.1 lilconfig: 3.1.3 - listr2: 8.3.2 + listr2: 8.3.3 micromatch: 4.0.8 pidtree: 0.6.0 string-argv: 0.3.2 @@ -6098,7 +6095,7 @@ snapshots: transitivePeerDependencies: - supports-color - listr2@8.3.2: + listr2@8.3.3: dependencies: cli-truncate: 4.0.0 colorette: 2.0.20 @@ -6182,11 +6179,11 @@ snapshots: mimic-function@5.0.1: {} - mini-css-extract-plugin@2.9.2(webpack@5.99.7): + mini-css-extract-plugin@2.9.2(webpack@5.99.8): dependencies: schema-utils: 4.3.2 tapable: 2.2.1 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) minimatch@3.1.2: dependencies: @@ -6396,7 +6393,7 @@ snapshots: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-colormin@7.0.2(postcss@8.5.3): + postcss-colormin@7.0.3(postcss@8.5.3): dependencies: browserslist: 4.24.5 caniuse-api: 3.0.0 @@ -6404,7 +6401,7 @@ snapshots: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-convert-values@7.0.4(postcss@8.5.3): + postcss-convert-values@7.0.5(postcss@8.5.3): dependencies: browserslist: 4.24.5 postcss: 8.5.3 @@ -6440,20 +6437,20 @@ snapshots: postcss: 8.5.3 postcss-selector-parser: 7.1.0 - postcss-discard-comments@7.0.3(postcss@8.5.3): + postcss-discard-comments@7.0.4(postcss@8.5.3): dependencies: postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.0 - postcss-discard-duplicates@7.0.1(postcss@8.5.3): + postcss-discard-duplicates@7.0.2(postcss@8.5.3): dependencies: postcss: 8.5.3 - postcss-discard-empty@7.0.0(postcss@8.5.3): + postcss-discard-empty@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 - postcss-discard-overridden@7.0.0(postcss@8.5.3): + postcss-discard-overridden@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 @@ -6497,14 +6494,14 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.5.3) postcss: 8.5.3 - postcss-loader@8.1.1(postcss@8.5.3)(typescript@5.6.2)(webpack@5.99.7): + postcss-loader@8.1.1(postcss@8.5.3)(typescript@5.6.2)(webpack@5.99.8): dependencies: cosmiconfig: 9.0.0(typescript@5.6.2) jiti: 1.21.7 postcss: 8.5.3 semver: 7.7.1 optionalDependencies: - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) transitivePeerDependencies: - typescript @@ -6513,44 +6510,44 @@ snapshots: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-merge-longhand@7.0.4(postcss@8.5.3): + postcss-merge-longhand@7.0.5(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - stylehacks: 7.0.4(postcss@8.5.3) + stylehacks: 7.0.5(postcss@8.5.3) - postcss-merge-rules@7.0.4(postcss@8.5.3): + postcss-merge-rules@7.0.5(postcss@8.5.3): dependencies: browserslist: 4.24.5 caniuse-api: 3.0.0 - cssnano-utils: 5.0.0(postcss@8.5.3) + cssnano-utils: 5.0.1(postcss@8.5.3) postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.0 - postcss-minify-font-values@7.0.0(postcss@8.5.3): + postcss-minify-font-values@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-minify-gradients@7.0.0(postcss@8.5.3): + postcss-minify-gradients@7.0.1(postcss@8.5.3): dependencies: colord: 2.9.3 - cssnano-utils: 5.0.0(postcss@8.5.3) + cssnano-utils: 5.0.1(postcss@8.5.3) postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-minify-params@7.0.2(postcss@8.5.3): + postcss-minify-params@7.0.3(postcss@8.5.3): dependencies: browserslist: 4.24.5 - cssnano-utils: 5.0.0(postcss@8.5.3) + cssnano-utils: 5.0.1(postcss@8.5.3) postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-minify-selectors@7.0.4(postcss@8.5.3): + postcss-minify-selectors@7.0.5(postcss@8.5.3): dependencies: cssesc: 3.0.0 postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.0 postcss-modules-extract-imports@3.1.0(postcss@8.5.3): dependencies: @@ -6580,47 +6577,47 @@ snapshots: postcss: 8.5.3 postcss-selector-parser: 7.1.0 - postcss-normalize-charset@7.0.0(postcss@8.5.3): + postcss-normalize-charset@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 - postcss-normalize-display-values@7.0.0(postcss@8.5.3): + postcss-normalize-display-values@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-positions@7.0.0(postcss@8.5.3): + postcss-normalize-positions@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@7.0.0(postcss@8.5.3): + postcss-normalize-repeat-style@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-string@7.0.0(postcss@8.5.3): + postcss-normalize-string@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@7.0.0(postcss@8.5.3): + postcss-normalize-timing-functions@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@7.0.2(postcss@8.5.3): + postcss-normalize-unicode@7.0.3(postcss@8.5.3): dependencies: browserslist: 4.24.5 postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-url@7.0.0(postcss@8.5.3): + postcss-normalize-url@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@7.0.0(postcss@8.5.3): + postcss-normalize-whitespace@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 @@ -6629,9 +6626,9 @@ snapshots: dependencies: postcss: 8.5.3 - postcss-ordered-values@7.0.1(postcss@8.5.3): + postcss-ordered-values@7.0.2(postcss@8.5.3): dependencies: - cssnano-utils: 5.0.0(postcss@8.5.3) + cssnano-utils: 5.0.1(postcss@8.5.3) postcss: 8.5.3 postcss-value-parser: 4.2.0 @@ -6721,13 +6718,13 @@ snapshots: postcss: 8.5.3 postcss-selector-parser: 7.1.0 - postcss-reduce-initial@7.0.2(postcss@8.5.3): + postcss-reduce-initial@7.0.3(postcss@8.5.3): dependencies: browserslist: 4.24.5 caniuse-api: 3.0.0 postcss: 8.5.3 - postcss-reduce-transforms@7.0.0(postcss@8.5.3): + postcss-reduce-transforms@7.0.1(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 @@ -6741,26 +6738,21 @@ snapshots: postcss: 8.5.3 postcss-selector-parser: 7.1.0 - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - postcss-selector-parser@7.1.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@7.0.1(postcss@8.5.3): + postcss-svgo@7.0.2(postcss@8.5.3): dependencies: postcss: 8.5.3 postcss-value-parser: 4.2.0 svgo: 3.3.2 - postcss-unique-selectors@7.0.3(postcss@8.5.3): + postcss-unique-selectors@7.0.4(postcss@8.5.3): dependencies: postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.0 postcss-value-parser@4.2.0: {} @@ -6903,17 +6895,17 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@16.0.5(sass@1.87.0)(webpack@5.99.7): + sass-loader@16.0.5(sass@1.87.0)(webpack@5.99.8): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.87.0 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) sass@1.87.0: dependencies: chokidar: 4.0.3 - immutable: 5.1.1 + immutable: 5.1.2 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 @@ -7090,11 +7082,11 @@ snapshots: strip-json-comments@3.1.1: {} - stylehacks@7.0.4(postcss@8.5.3): + stylehacks@7.0.5(postcss@8.5.3): dependencies: browserslist: 4.24.5 postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.0 supports-color@7.2.0: dependencies: @@ -7118,14 +7110,14 @@ snapshots: tapable@2.2.1: {} - terser-webpack-plugin@5.3.14(webpack@5.99.7): + terser-webpack-plugin@5.3.14(webpack@5.99.8): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.2 serialize-javascript: 6.0.2 terser: 5.39.0 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) terser@5.39.0: dependencies: @@ -7243,12 +7235,12 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - webpack-cli@6.0.1(webpack@5.99.7): + webpack-cli@6.0.1(webpack@5.99.8): dependencies: '@discoveryjs/json-ext': 0.6.3 - '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.7) - '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.7) - '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.7) + '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.8) + '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.8) + '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.99.8) colorette: 2.0.20 commander: 12.1.0 cross-spawn: 7.0.6 @@ -7257,7 +7249,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.99.7(webpack-cli@6.0.1) + webpack: 5.99.8(webpack-cli@6.0.1) webpack-merge: 6.0.1 webpack-merge@6.0.1: @@ -7268,7 +7260,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack@5.99.7(webpack-cli@6.0.1): + webpack@5.99.8(webpack-cli@6.0.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.7 @@ -7291,11 +7283,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.2 tapable: 2.2.1 - terser-webpack-plugin: 5.3.14(webpack@5.99.7) + terser-webpack-plugin: 5.3.14(webpack@5.99.8) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: - webpack-cli: 6.0.1(webpack@5.99.7) + webpack-cli: 6.0.1(webpack@5.99.8) transitivePeerDependencies: - '@swc/core' - esbuild @@ -7364,8 +7356,8 @@ snapshots: yocto-queue@0.1.0: {} - zod-to-json-schema@3.24.5(zod@3.24.3): + zod-to-json-schema@3.24.5(zod@3.24.4): dependencies: - zod: 3.24.3 + zod: 3.24.4 - zod@3.24.3: {} + zod@3.24.4: {} diff --git a/poetry.lock b/poetry.lock index 47dbebce..e82df588 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "assertpy" @@ -1160,14 +1160,14 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.3.7" +version = "4.3.8" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, - {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, + {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, + {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, ] [package.extras] @@ -1528,30 +1528,30 @@ yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "ruff" -version = "0.11.8" +version = "0.11.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.11.8-py3-none-linux_armv6l.whl", hash = "sha256:896a37516c594805e34020c4a7546c8f8a234b679a7716a3f08197f38913e1a3"}, - {file = "ruff-0.11.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab86d22d3d721a40dd3ecbb5e86ab03b2e053bc93c700dc68d1c3346b36ce835"}, - {file = "ruff-0.11.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:258f3585057508d317610e8a412788cf726efeefa2fec4dba4001d9e6f90d46c"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:727d01702f7c30baed3fc3a34901a640001a2828c793525043c29f7614994a8c"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3dca977cc4fc8f66e89900fa415ffe4dbc2e969da9d7a54bfca81a128c5ac219"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c657fa987d60b104d2be8b052d66da0a2a88f9bd1d66b2254333e84ea2720c7f"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f2e74b021d0de5eceb8bd32919f6ff8a9b40ee62ed97becd44993ae5b9949474"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9b5ef39820abc0f2c62111f7045009e46b275f5b99d5e59dda113c39b7f4f38"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1dba3135ca503727aa4648152c0fa67c3b1385d3dc81c75cd8a229c4b2a1458"}, - {file = "ruff-0.11.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f024d32e62faad0f76b2d6afd141b8c171515e4fb91ce9fd6464335c81244e5"}, - {file = "ruff-0.11.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d365618d3ad747432e1ae50d61775b78c055fee5936d77fb4d92c6f559741948"}, - {file = "ruff-0.11.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4d9aaa91035bdf612c8ee7266153bcf16005c7c7e2f5878406911c92a31633cb"}, - {file = "ruff-0.11.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0eba551324733efc76116d9f3a0d52946bc2751f0cd30661564117d6fd60897c"}, - {file = "ruff-0.11.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:161eb4cff5cfefdb6c9b8b3671d09f7def2f960cee33481dd898caf2bcd02304"}, - {file = "ruff-0.11.8-py3-none-win32.whl", hash = "sha256:5b18caa297a786465cc511d7f8be19226acf9c0a1127e06e736cd4e1878c3ea2"}, - {file = "ruff-0.11.8-py3-none-win_amd64.whl", hash = "sha256:6e70d11043bef637c5617297bdedec9632af15d53ac1e1ba29c448da9341b0c4"}, - {file = "ruff-0.11.8-py3-none-win_arm64.whl", hash = "sha256:304432e4c4a792e3da85b7699feb3426a0908ab98bf29df22a31b0cdd098fac2"}, - {file = "ruff-0.11.8.tar.gz", hash = "sha256:6d742d10626f9004b781f4558154bb226620a7242080e11caeffab1a40e99df8"}, + {file = "ruff-0.11.9-py3-none-linux_armv6l.whl", hash = "sha256:a31a1d143a5e6f499d1fb480f8e1e780b4dfdd580f86e05e87b835d22c5c6f8c"}, + {file = "ruff-0.11.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:66bc18ca783b97186a1f3100e91e492615767ae0a3be584e1266aa9051990722"}, + {file = "ruff-0.11.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bd576cd06962825de8aece49f28707662ada6a1ff2db848d1348e12c580acbf1"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b1d18b4be8182cc6fddf859ce432cc9631556e9f371ada52f3eaefc10d878de"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0f3f46f759ac623e94824b1e5a687a0df5cd7f5b00718ff9c24f0a894a683be7"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f34847eea11932d97b521450cf3e1d17863cfa5a94f21a056b93fb86f3f3dba2"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f33b15e00435773df97cddcd263578aa83af996b913721d86f47f4e0ee0ff271"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b27613a683b086f2aca8996f63cb3dd7bc49e6eccf590563221f7b43ded3f65"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e0d88756e63e8302e630cee3ce2ffb77859797cc84a830a24473939e6da3ca6"}, + {file = "ruff-0.11.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:537c82c9829d7811e3aa680205f94c81a2958a122ac391c0eb60336ace741a70"}, + {file = "ruff-0.11.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:440ac6a7029f3dee7d46ab7de6f54b19e34c2b090bb4f2480d0a2d635228f381"}, + {file = "ruff-0.11.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:71c539bac63d0788a30227ed4d43b81353c89437d355fdc52e0cda4ce5651787"}, + {file = "ruff-0.11.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c67117bc82457e4501473c5f5217d49d9222a360794bfb63968e09e70f340abd"}, + {file = "ruff-0.11.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e4b78454f97aa454586e8a5557facb40d683e74246c97372af3c2d76901d697b"}, + {file = "ruff-0.11.9-py3-none-win32.whl", hash = "sha256:7fe1bc950e7d7b42caaee2a8a3bc27410547cc032c9558ee2e0f6d3b209e845a"}, + {file = "ruff-0.11.9-py3-none-win_amd64.whl", hash = "sha256:52edaa4a6d70f8180343a5b7f030c7edd36ad180c9f4d224959c2d689962d964"}, + {file = "ruff-0.11.9-py3-none-win_arm64.whl", hash = "sha256:bcf42689c22f2e240f496d0c183ef2c6f7b35e809f12c1db58f75d9aa8d630ca"}, + {file = "ruff-0.11.9.tar.gz", hash = "sha256:ebd58d4f67a00afb3a30bf7d383e52d0e036e6195143c6db7019604a05335517"}, ] [[package]] @@ -1571,58 +1571,58 @@ timezone = ["pytz"] [[package]] name = "scipy" -version = "1.15.2" +version = "1.15.3" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "scipy-1.15.2-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a2ec871edaa863e8213ea5df811cd600734f6400b4af272e1c011e69401218e9"}, - {file = "scipy-1.15.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:6f223753c6ea76983af380787611ae1291e3ceb23917393079dcc746ba60cfb5"}, - {file = "scipy-1.15.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:ecf797d2d798cf7c838c6d98321061eb3e72a74710e6c40540f0e8087e3b499e"}, - {file = "scipy-1.15.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:9b18aa747da280664642997e65aab1dd19d0c3d17068a04b3fe34e2559196cb9"}, - {file = "scipy-1.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87994da02e73549dfecaed9e09a4f9d58a045a053865679aeb8d6d43747d4df3"}, - {file = "scipy-1.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69ea6e56d00977f355c0f84eba69877b6df084516c602d93a33812aa04d90a3d"}, - {file = "scipy-1.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:888307125ea0c4466287191e5606a2c910963405ce9671448ff9c81c53f85f58"}, - {file = "scipy-1.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9412f5e408b397ff5641080ed1e798623dbe1ec0d78e72c9eca8992976fa65aa"}, - {file = "scipy-1.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:b5e025e903b4f166ea03b109bb241355b9c42c279ea694d8864d033727205e65"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:92233b2df6938147be6fa8824b8136f29a18f016ecde986666be5f4d686a91a4"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:62ca1ff3eb513e09ed17a5736929429189adf16d2d740f44e53270cc800ecff1"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4c6676490ad76d1c2894d77f976144b41bd1a4052107902238047fb6a473e971"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8bf5cb4a25046ac61d38f8d3c3426ec11ebc350246a4642f2f315fe95bda655"}, - {file = "scipy-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a8e34cf4c188b6dd004654f88586d78f95639e48a25dfae9c5e34a6dc34547e"}, - {file = "scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28a0d2c2075946346e4408b211240764759e0fabaeb08d871639b5f3b1aca8a0"}, - {file = "scipy-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:42dabaaa798e987c425ed76062794e93a243be8f0f20fff6e7a89f4d61cb3d40"}, - {file = "scipy-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f5e296ec63c5da6ba6fa0343ea73fd51b8b3e1a300b0a8cae3ed4b1122c7462"}, - {file = "scipy-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:597a0c7008b21c035831c39927406c6181bcf8f60a73f36219b69d010aa04737"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c4697a10da8f8765bb7c83e24a470da5797e37041edfd77fd95ba3811a47c4fd"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:869269b767d5ee7ea6991ed7e22b3ca1f22de73ab9a49c44bad338b725603301"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bad78d580270a4d32470563ea86c6590b465cb98f83d760ff5b0990cb5518a93"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b09ae80010f52efddb15551025f9016c910296cf70adbf03ce2a8704f3a5ad20"}, - {file = "scipy-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a6fd6eac1ce74a9f77a7fc724080d507c5812d61e72bd5e4c489b042455865e"}, - {file = "scipy-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b871df1fe1a3ba85d90e22742b93584f8d2b8e6124f8372ab15c71b73e428b8"}, - {file = "scipy-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:03205d57a28e18dfd39f0377d5002725bf1f19a46f444108c29bdb246b6c8a11"}, - {file = "scipy-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:601881dfb761311045b03114c5fe718a12634e5608c3b403737ae463c9885d53"}, - {file = "scipy-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:e7c68b6a43259ba0aab737237876e5c2c549a031ddb7abc28c7b47f22e202ded"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01edfac9f0798ad6b46d9c4c9ca0e0ad23dbf0b1eb70e96adb9fa7f525eff0bf"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:08b57a9336b8e79b305a143c3655cc5bdbe6d5ece3378578888d2afbb51c4e37"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:54c462098484e7466362a9f1672d20888f724911a74c22ae35b61f9c5919183d"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:cf72ff559a53a6a6d77bd8eefd12a17995ffa44ad86c77a5df96f533d4e6c6bb"}, - {file = "scipy-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de9d1416b3d9e7df9923ab23cd2fe714244af10b763975bea9e4f2e81cebd27"}, - {file = "scipy-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb530e4794fc8ea76a4a21ccb67dea33e5e0e60f07fc38a49e821e1eae3b71a0"}, - {file = "scipy-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5ea7ed46d437fc52350b028b1d44e002646e28f3e8ddc714011aaf87330f2f32"}, - {file = "scipy-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11e7ad32cf184b74380f43d3c0a706f49358b904fa7d5345f16ddf993609184d"}, - {file = "scipy-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:a5080a79dfb9b78b768cebf3c9dcbc7b665c5875793569f48bf0e2b1d7f68f6f"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:447ce30cee6a9d5d1379087c9e474628dab3db4a67484be1b7dc3196bfb2fac9"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:c90ebe8aaa4397eaefa8455a8182b164a6cc1d59ad53f79943f266d99f68687f"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:def751dd08243934c884a3221156d63e15234a3155cf25978b0a668409d45eb6"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:302093e7dfb120e55515936cb55618ee0b895f8bcaf18ff81eca086c17bd80af"}, - {file = "scipy-1.15.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd5b77413e1855351cdde594eca99c1f4a588c2d63711388b6a1f1c01f62274"}, - {file = "scipy-1.15.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d0194c37037707b2afa7a2f2a924cf7bac3dc292d51b6a925e5fcb89bc5c776"}, - {file = "scipy-1.15.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:bae43364d600fdc3ac327db99659dcb79e6e7ecd279a75fe1266669d9a652828"}, - {file = "scipy-1.15.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f031846580d9acccd0044efd1a90e6f4df3a6e12b4b6bd694a7bc03a89892b28"}, - {file = "scipy-1.15.2-cp313-cp313t-win_amd64.whl", hash = "sha256:fe8a9eb875d430d81755472c5ba75e84acc980e4a8f6204d402849234d3017db"}, - {file = "scipy-1.15.2.tar.gz", hash = "sha256:cd58a314d92838f7e6f755c8a2167ead4f27e1fd5c1251fd54289569ef3495ec"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, ] [package.dependencies] @@ -1630,7 +1630,7 @@ numpy = ">=1.23.5,<2.5" [package.extras] dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] -doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.16.5)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] From 334d288d68110950203e23ccc5f1c3b18ba357b8 Mon Sep 17 00:00:00 2001 From: DirtyRacer Date: Sat, 10 May 2025 09:26:55 +0700 Subject: [PATCH 4/6] increase wait time --- test/namer_watchdog_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/namer_watchdog_test.py b/test/namer_watchdog_test.py index 0f3a0e25..da17d23d 100644 --- a/test/namer_watchdog_test.py +++ b/test/namer_watchdog_test.py @@ -18,12 +18,12 @@ from test.utils import Wait, new_ea, new_dorcel, validate_mp4_tags, validate_permissions, environment, sample_config, ProcessingTarget -def wait_until_processed(watcher: MovieWatcher, durration: int = 60): +def wait_until_processed(watcher: MovieWatcher, duration: int = 120): """ Waits until all files have been moved out of watch/working dirs. """ config = watcher.get_config() - Wait().seconds(durration).checking(1).until(lambda: len(list(config.watch_dir.iterdir())) > 0 or len(list(config.work_dir.iterdir())) > 0).isFalse() + Wait().seconds(duration).checking(1).until(lambda: len(list(config.watch_dir.iterdir())) > 0 or len(list(config.work_dir.iterdir())) > 0).isFalse() watcher.stop() @@ -98,7 +98,7 @@ def test_handler_collisions_success_choose_best(self): config.desired_codec = ['hevc', 'h264'] with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): targets: list[ProcessingTarget] = [new_ea(config.watch_dir, mp4_file_name=okay), new_ea(config.watch_dir, use_dir=False, post_stem='2', mp4_file_name=better), new_ea(config.watch_dir, use_dir=False, post_stem='1', mp4_file_name=best)] - wait_until_processed(watcher, 120) + wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) self.assertEqual(len(list(config.work_dir.iterdir())), 0) output_file = config.dest_dir / 'Evil Angel' / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-720p].mp4' From 2103d6c445e1e7dc35837ab8d375d0f40b2bd7a1 Mon Sep 17 00:00:00 2001 From: DirtyRacer Date: Sat, 10 May 2025 09:56:16 +0700 Subject: [PATCH 5/6] refactor --- test/namer_watchdog_test.py | 4 ++-- test/utils.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/namer_watchdog_test.py b/test/namer_watchdog_test.py index da17d23d..2463c8cb 100644 --- a/test/namer_watchdog_test.py +++ b/test/namer_watchdog_test.py @@ -18,7 +18,7 @@ from test.utils import Wait, new_ea, new_dorcel, validate_mp4_tags, validate_permissions, environment, sample_config, ProcessingTarget -def wait_until_processed(watcher: MovieWatcher, duration: int = 120): +def wait_until_processed(watcher: MovieWatcher, duration: int = 60): """ Waits until all files have been moved out of watch/working dirs. """ @@ -98,7 +98,7 @@ def test_handler_collisions_success_choose_best(self): config.desired_codec = ['hevc', 'h264'] with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): targets: list[ProcessingTarget] = [new_ea(config.watch_dir, mp4_file_name=okay), new_ea(config.watch_dir, use_dir=False, post_stem='2', mp4_file_name=better), new_ea(config.watch_dir, use_dir=False, post_stem='1', mp4_file_name=best)] - wait_until_processed(watcher) + wait_until_processed(watcher, 120) self.assertFalse(targets[0].get_file().exists()) self.assertEqual(len(list(config.work_dir.iterdir())), 0) output_file = config.dest_dir / 'Evil Angel' / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-720p].mp4' diff --git a/test/utils.py b/test/utils.py index 9c5a0c6f..f4ace524 100644 --- a/test/utils.py +++ b/test/utils.py @@ -205,12 +205,12 @@ def default_additions(self): @contextlib.contextmanager -def environment(config: NamerConfig = None): # ty +def environment(config: NamerConfig = None): # type: ignore if config is None: config = sample_config() with tempfile.TemporaryDirectory(prefix='test') as tmpdir, FakeTPDB() as fakeTpdb: - tempdir = Path(tmpdir) + tempdir = Path(tmpdir).resolve() config.enabled_tagging = True config.enabled_poster = True From 8535bc23cbada68931d4e8b932bc7971b4e27421 Mon Sep 17 00:00:00 2001 From: DirtyRacer Date: Sat, 10 May 2025 10:12:44 +0700 Subject: [PATCH 6/6] fix: refactor --- namer/configuration.py | 2 +- test/namer_ffmpeg_test.py | 24 ++++++------ test/namer_file_parser_test.py | 12 +++--- test/namer_fileutils_test.py | 8 ++-- test/namer_metadataapi_test.py | 16 ++++---- test/namer_moviexml_test.py | 32 ++++++++-------- test/namer_mutagen_test.py | 36 +++++++++--------- test/namer_test.py | 44 +++++++++++----------- test/namer_videophash_test.py | 12 +++--- test/namer_watchdog_test.py | 69 ++++++++++++++++++---------------- test/namer_webhook_test.py | 4 +- test/utils.py | 22 +++++------ test/web/namer_web_test.py | 6 +-- 13 files changed, 145 insertions(+), 142 deletions(-) diff --git a/namer/configuration.py b/namer/configuration.py index b50701c0..66d10a5d 100644 --- a/namer/configuration.py +++ b/namer/configuration.py @@ -245,7 +245,7 @@ class NamerConfig: a set of tags that indicates an individual video is vr. """ - database_path: Path = Path(tempfile.gettempdir()) / 'namer' + database_path: Path = Path(tempfile.gettemp_dir()) / 'namer' """ Path where stores namer system data. """ diff --git a/test/namer_ffmpeg_test.py b/test/namer_ffmpeg_test.py index 244a87b4..fc562c26 100644 --- a/test/namer_ffmpeg_test.py +++ b/test/namer_ffmpeg_test.py @@ -28,9 +28,9 @@ def test_get_resolution(self): Verifies we can resolutions from mp4 files. """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - shutil.copytree(Path(__file__).resolve().parent, tempdir / 'test') - file = tempdir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' + temp_dir = Path(tmpdir) + shutil.copytree(Path(__file__).resolve().parent, temp_dir / 'test') + file = temp_dir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' results = FFMpeg().ffprobe(file) self.assertIsNotNone(results) if results: @@ -42,9 +42,9 @@ def test_get_audio_stream(self): Verifies we can get audio stream language names from files. """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - shutil.copytree(Path(__file__).resolve().parent, tempdir / 'test') - file = tempdir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' + temp_dir = Path(tmpdir) + shutil.copytree(Path(__file__).resolve().parent, temp_dir / 'test') + file = temp_dir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' stream_number = FFMpeg().get_audio_stream_for_lang(file, 'und') self.assertEqual(stream_number, -1) stream_number = FFMpeg().get_audio_stream_for_lang(file, 'eng') @@ -55,9 +55,9 @@ def test_ffprobe(self) -> None: read stream info. """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - shutil.copytree(Path(__file__).resolve().parent, tempdir / 'test') - file = tempdir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost_wrong.mp4' + temp_dir = Path(tmpdir) + shutil.copytree(Path(__file__).resolve().parent, temp_dir / 'test') + file = temp_dir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost_wrong.mp4' results = FFMpeg().ffprobe(file) self.assertIsNotNone(results) if results: @@ -84,9 +84,9 @@ def test_update_audio_stream(self): Verifies we can change default audio stream languages for mp4's. """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - shutil.copytree(Path(__file__).resolve().parent, tempdir / 'test') - file = tempdir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost_wrong.mp4' + temp_dir = Path(tmpdir) + shutil.copytree(Path(__file__).resolve().parent, temp_dir / 'test') + file = temp_dir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost_wrong.mp4' stream_number = FFMpeg().get_audio_stream_for_lang(file, 'und') self.assertEqual(stream_number, -1) stream_number = FFMpeg().get_audio_stream_for_lang(file, 'eng') diff --git a/test/namer_file_parser_test.py b/test/namer_file_parser_test.py index 9bd325d4..60e74892 100644 --- a/test/namer_file_parser_test.py +++ b/test/namer_file_parser_test.py @@ -133,10 +133,10 @@ def test_parse_file(self, mock_stdout): """ Test the main method. """ - with environment() as (tmpdir, _parrot, config): - tempdir = Path(tmpdir) + with environment() as (tmp_dir, _parrot, config): + temp_dir = Path(tmp_dir) test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) config.min_file_size = 0 command = make_command(target_file, config) @@ -155,10 +155,10 @@ def test_parse_dir_name(self, mock_stdout): """ Test the main method. """ - with environment() as (tmpdir, _parrot, config): - tempdir = Path(tmpdir) + with environment() as (tmp_dir, _parrot, config): + temp_dir = Path(tmp_dir) test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.1080p.HEVC.x265.PRT[XvX]-xpost' / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.1080p.HEVC.x265.PRT[XvX]-xpost' / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' target_file.parent.mkdir() shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) config.min_file_size = 0 diff --git a/test/namer_fileutils_test.py b/test/namer_fileutils_test.py index de3d4669..e1c3fffb 100644 --- a/test/namer_fileutils_test.py +++ b/test/namer_fileutils_test.py @@ -37,9 +37,9 @@ def test_main_method(self, mock_stdout): """ config = sample_config() config.min_file_size = 0 - with environment(config) as (tempdir, _parrot, config): + with environment(config) as (temp_dir, _parrot, config): test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) main(arg_list=['-f', str(target_file), '-c', str(config.config_file)]) self.assertIn('site: EvilAngel', mock_stdout.getvalue()) @@ -50,8 +50,8 @@ def test_set_permission(self): """ if system() != 'Windows': with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - target_dir = tempdir / 'target_dir' + temp_dir = Path(tmpdir) + target_dir = temp_dir / 'target_dir' target_dir.mkdir() testfile = target_dir / 'test_file.txt' with open(testfile, 'w', encoding='utf-8') as file: diff --git a/test/namer_metadataapi_test.py b/test/namer_metadataapi_test.py index e35bd1b8..b1690509 100644 --- a/test/namer_metadataapi_test.py +++ b/test/namer_metadataapi_test.py @@ -172,11 +172,11 @@ def test_call_metadataapi_net_no_data(self): """ verify an empty response from porndb is properly handled. """ - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): filename: str = 'GoodAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' - with open((tempdir / filename), 'w'): + with open((temp_dir / filename), 'w'): pass - command = make_command((tempdir / filename), config) + command = make_command((temp_dir / filename), config) self.assertIsNotNone(command) if command is not None: results = match(command.parsed_file, config) @@ -188,11 +188,11 @@ def test_call_metadataapi_net_no_message(self): """ config = sample_config() config.min_file_size = 0 - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): filename: str = 'OkAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' - with open((tempdir / filename), 'w'): + with open((temp_dir / filename), 'w'): pass - command = make_command((tempdir / filename), config) + command = make_command((temp_dir / filename), config) self.assertIsNotNone(command) if command is not None: results = match(command.parsed_file, config) @@ -203,9 +203,9 @@ def test_main_metadataapi_net(self, mock_stdout): """ Test parsing a full stored response (with tags) as a LookedUpFileInfo """ - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): filename: str = 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' - tmp_file = tempdir / filename + tmp_file = temp_dir / filename with open(tmp_file, 'w'): pass main(['-f', str(tmp_file), '-c', str(config.config_file)]) diff --git a/test/namer_moviexml_test.py b/test/namer_moviexml_test.py index 56eeaee8..2ae7c5f4 100644 --- a/test/namer_moviexml_test.py +++ b/test/namer_moviexml_test.py @@ -35,10 +35,10 @@ def test_parsing_xml_metadata(self): """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - copytree(Path(__file__).resolve().parent, tempdir / 'test') - xmlfile = tempdir / 'test' / 'ea.nfo' - info = parse_movie_xml_file(xmlfile) + temp_dir = Path(tmpdir) + copytree(Path(__file__).resolve().parent, temp_dir / 'test') + xml_file = temp_dir / 'test' / 'ea.nfo' + info = parse_movie_xml_file(xml_file) self.assertEqual(info.site, 'Evil Angel') self.assertEqual(info.date, '2022-01-03') self.assertIsNotNone(info.description) @@ -56,7 +56,7 @@ def test_writing_xml_metadata_genre_flag(self): Test parsing a stored response as a LookedUpFileInfo """ - with environment() as (_path, fakeTPDB, config): + with environment() as (_path, fake_tpdb, config): name = parse_file_name('EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4', config) config.enable_metadataapi_genres = True results = match(name, config) @@ -75,8 +75,8 @@ def test_writing_xml_metadata_genre_flag(self): 2022-01-03 XXX - {fakeTPDB.get_url()}qWAUIAUpBsoqKUwozc4NOTR1tPI=/1000x1500/smart/filters:sharpen():upscale():watermark(https%3A%2F%2Fcdn.metadataapi.net%2Fsites%2F3f%2F9f%2F51%2Fcf3828d65425bca2890d53ef242d8cf%2Flogo%2Fevil-angel_dark%5B1%5D.png,-10,-10,25,50)/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp - {fakeTPDB.get_url()}gAu-1j1ZP4f6gNMPibgAyGKoa_c=/fit-in/3000x3000/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp + {fake_tpdb.get_url()}qWAUIAUpBsoqKUwozc4NOTR1tPI=/1000x1500/smart/filters:sharpen():upscale():watermark(https%3A%2F%2Fcdn.metadataapi.net%2Fsites%2F3f%2F9f%2F51%2Fcf3828d65425bca2890d53ef242d8cf%2Flogo%2Fevil-angel_dark%5B1%5D.png,-10,-10,25,50)/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp + {fake_tpdb.get_url()}gAu-1j1ZP4f6gNMPibgAyGKoa_c=/fit-in/3000x3000/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp Anal Ass @@ -112,7 +112,7 @@ def test_writing_xml_metadata_genre_flag(self): Carmela Clutch Carmela Clutch Female - {fakeTPDB.get_url()}flLf1pecTlKcpJCki30l5iWXNdQ=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fd3%2F47%2Fcd%2Fde8cbe2fd9f73dec8c985d2d69b67ac%2Fposter%2Fcarmela-clutch.webp + {fake_tpdb.get_url()}flLf1pecTlKcpJCki30l5iWXNdQ=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fd3%2F47%2Fcd%2Fde8cbe2fd9f73dec8c985d2d69b67ac%2Fposter%2Fcarmela-clutch.webp @@ -120,7 +120,7 @@ def test_writing_xml_metadata_genre_flag(self): Francesca Le Francesca Le Female - {fakeTPDB.get_url()}r8g92zymZ6SduikMTwcXMojRxik=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2F71%2F51%2Fdc%2F4b09a05007ba30c041e474c2b398a51%2Fposter%2Ffrancesca-le.png + {fake_tpdb.get_url()}r8g92zymZ6SduikMTwcXMojRxik=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2F71%2F51%2Fdc%2F4b09a05007ba30c041e474c2b398a51%2Fposter%2Ffrancesca-le.png @@ -128,7 +128,7 @@ def test_writing_xml_metadata_genre_flag(self): Mark Wood Mark Wood Male - {fakeTPDB.get_url()}V7F3bvj0YDEr3_qrKqyaJ5fKxd0=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fa3%2F48%2Fcd%2Ffcd5cd6cecf1f7ae3af587286e9fccf%2Fposter%2Fmark-wood.webp + {fake_tpdb.get_url()}V7F3bvj0YDEr3_qrKqyaJ5fKxd0=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fa3%2F48%2Fcd%2Ffcd5cd6cecf1f7ae3af587286e9fccf%2Fposter%2Fmark-wood.webp @@ -140,7 +140,7 @@ def test_writing_xml_metadata(self): """ Test parsing a stored response as a LookedUpFileInfo """ - with environment() as (_path, fakeTPDB, config): + with environment() as (_path, fake_tpdb, config): name = parse_file_name('EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4', config) results = match(name, config) self.assertEqual(len(results.results), 1) @@ -158,8 +158,8 @@ def test_writing_xml_metadata(self): 2022-01-03 XXX - {fakeTPDB.get_url()}qWAUIAUpBsoqKUwozc4NOTR1tPI=/1000x1500/smart/filters:sharpen():upscale():watermark(https%3A%2F%2Fcdn.metadataapi.net%2Fsites%2F3f%2F9f%2F51%2Fcf3828d65425bca2890d53ef242d8cf%2Flogo%2Fevil-angel_dark%5B1%5D.png,-10,-10,25,50)/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp - {fakeTPDB.get_url()}gAu-1j1ZP4f6gNMPibgAyGKoa_c=/fit-in/3000x3000/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp + {fake_tpdb.get_url()}qWAUIAUpBsoqKUwozc4NOTR1tPI=/1000x1500/smart/filters:sharpen():upscale():watermark(https%3A%2F%2Fcdn.metadataapi.net%2Fsites%2F3f%2F9f%2F51%2Fcf3828d65425bca2890d53ef242d8cf%2Flogo%2Fevil-angel_dark%5B1%5D.png,-10,-10,25,50)/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp + {fake_tpdb.get_url()}gAu-1j1ZP4f6gNMPibgAyGKoa_c=/fit-in/3000x3000/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fscene%2Ff4%2Fab%2F3e%2Fa91d31d6dee223f4f30a57bfd83b151%2Fbackground%2Fbg-evil-angel-carmela-clutch-fabulous-anal-3-way.webp Anal Ass @@ -196,7 +196,7 @@ def test_writing_xml_metadata(self): Carmela Clutch Carmela Clutch Female - {fakeTPDB.get_url()}flLf1pecTlKcpJCki30l5iWXNdQ=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fd3%2F47%2Fcd%2Fde8cbe2fd9f73dec8c985d2d69b67ac%2Fposter%2Fcarmela-clutch.webp + {fake_tpdb.get_url()}flLf1pecTlKcpJCki30l5iWXNdQ=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fd3%2F47%2Fcd%2Fde8cbe2fd9f73dec8c985d2d69b67ac%2Fposter%2Fcarmela-clutch.webp @@ -204,7 +204,7 @@ def test_writing_xml_metadata(self): Francesca Le Francesca Le Female - {fakeTPDB.get_url()}r8g92zymZ6SduikMTwcXMojRxik=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2F71%2F51%2Fdc%2F4b09a05007ba30c041e474c2b398a51%2Fposter%2Ffrancesca-le.png + {fake_tpdb.get_url()}r8g92zymZ6SduikMTwcXMojRxik=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2F71%2F51%2Fdc%2F4b09a05007ba30c041e474c2b398a51%2Fposter%2Ffrancesca-le.png @@ -212,7 +212,7 @@ def test_writing_xml_metadata(self): Mark Wood Mark Wood Male - {fakeTPDB.get_url()}V7F3bvj0YDEr3_qrKqyaJ5fKxd0=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fa3%2F48%2Fcd%2Ffcd5cd6cecf1f7ae3af587286e9fccf%2Fposter%2Fmark-wood.webp + {fake_tpdb.get_url()}V7F3bvj0YDEr3_qrKqyaJ5fKxd0=/1000x1500/smart/filters:sharpen():upscale()/https%3A%2F%2Fcdn.metadataapi.net%2Fperformer%2Fa3%2F48%2Fcd%2Ffcd5cd6cecf1f7ae3af587286e9fccf%2Fposter%2Fmark-wood.webp diff --git a/test/namer_mutagen_test.py b/test/namer_mutagen_test.py index a849ecf4..f4152844 100644 --- a/test/namer_mutagen_test.py +++ b/test/namer_mutagen_test.py @@ -48,11 +48,11 @@ def test_writing_metadata(self): """ verify tag in place functions. """ - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): test_dir = Path(__file__).resolve().parent - poster = tempdir / 'poster.png' + poster = temp_dir / 'poster.png' shutil.copy(test_dir / 'poster.png', poster) - target_file = tempdir / 'DorcelClub - 2021-12-23 - Aya.Benetti.Megane.Lopez.And.Bella.Tina.XXX.1080p.mp4' + target_file = temp_dir / 'DorcelClub - 2021-12-23 - Aya.Benetti.Megane.Lopez.And.Bella.Tina.XXX.1080p.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) name_parts = parse_file_name(target_file.name, config) info = match(name_parts, config) @@ -66,11 +66,11 @@ def test_writing_full_metadata(self): Test writing metadata to a mp4, including tag information, which is only available on scene requests to the porndb using uuid to request scene information. """ - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) - poster = tempdir / 'poster.png' + poster = temp_dir / 'poster.png' shutil.copy(test_dir / 'poster.png', poster) name_parts = parse_file_name(target_file.name, config) info = match(name_parts, config) @@ -88,11 +88,11 @@ def test_sha_sum_two_identical_transformations(self): sha_1 = None sha_2 = None - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) - poster = tempdir / 'poster.png' + poster = temp_dir / 'poster.png' shutil.copy(test_dir / 'poster.png', poster) name_parts = parse_file_name(target_file.name, config) info = match(name_parts, config) @@ -100,11 +100,11 @@ def test_sha_sum_two_identical_transformations(self): update_mp4_file(target_file, info.results[0].looked_up, poster, ffprobe_results, NamerConfig()) validate_mp4_tags(self, target_file) sha_1 = hashlib.sha256(target_file.read_bytes()).digest().hex() - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) - poster = tempdir / 'poster.png' + poster = temp_dir / 'poster.png' shutil.copy(test_dir / 'poster.png', poster) name_parts = parse_file_name(target_file.name, config) info = match(name_parts, config) @@ -120,9 +120,9 @@ def test_non_existent_poster(self): Test writing metadata to an mp4, including tag information, which is only available on scene requests to the porndb using uuid to request scene information. """ - with environment() as (tempdir, _parrot, config): + with environment() as (temp_dir, _parrot, config): test_dir = Path(__file__).resolve().parent - target_file = tempdir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + target_file = temp_dir / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) poster = None name_parts = parse_file_name(target_file.name, config) @@ -136,8 +136,8 @@ def test_non_existent_file(self): Test writing metadata to an mp4, including tag information, which is only available on scene requests to the porndb using uuid to request scene information. """ - with environment() as (tempdir, _parrot, config): - targetfile = tempdir / 'test' / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + with environment() as (temp_dir, _parrot, config): + targetfile = temp_dir / 'test' / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' poster = None name_parts = parse_file_name(targetfile.name, config) info = match(name_parts, config) @@ -151,8 +151,8 @@ def test_empty_infos(self): available on scene requests to the porndb using uuid to request scene information. """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - target_file = tempdir / 'test' / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' + temp_dir = Path(tmpdir) + target_file = temp_dir / 'test' / 'EvilAngel.22.01.03.Carmela.Clutch.Fabulous.Anal.3-Way.XXX.mp4' target_file.parent.mkdir(parents=True, exist_ok=True) test_dir = Path(__file__).resolve().parent shutil.copy(test_dir / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4', target_file) diff --git a/test/namer_test.py b/test/namer_test.py index 219bc610..98afe5c0 100644 --- a/test/namer_test.py +++ b/test/namer_test.py @@ -34,10 +34,10 @@ def test_check_arguments(self): verify file system checks """ with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - target_dir = tempdir / 'path/' - file = tempdir / 'file' - config = tempdir / 'config' + temp_dir = Path(tmpdir) + target_dir = temp_dir / 'path/' + file = temp_dir / 'file' + config = temp_dir / 'config' error = check_arguments(dir_to_process=target_dir, file_to_process=file, config_override=config) self.assertTrue(error) target_dir.mkdir() @@ -50,8 +50,8 @@ def test_writing_metadata_file(self: unittest.TestCase): """ test namer main method renames and tags in place when -f (video file) is passed """ - with environment() as (tempdir, _fakeTPDB, config): - targets = [new_ea(tempdir, use_dir=False)] + with environment() as (temp_dir, fake_tpdb, config): + targets = [new_ea(temp_dir, use_dir=False)] main(['-f', str(targets[0].file), '-c', str(config.config_file)]) output = MP4(targets[0].get_file().parent / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-240].mp4') self.assertEqual(output.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) @@ -60,8 +60,8 @@ def test_writing_metadata_dir(self: unittest.TestCase): """ test namer main method renames and tags in place when -d (directory) is passed """ - with environment() as (tempdir, _fakeTPDB, config): - targets = [new_ea(tempdir, use_dir=True)] + with environment() as (temp_dir, fake_tpdb, config): + targets = [new_ea(temp_dir, use_dir=True)] main(['-d', str(targets[0].get_file().parent), '-c', str(config.config_file)]) output = MP4(targets[0].get_file().parent.parent / 'Evil Angel' / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-240].mp4') self.assertEqual(output.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) @@ -71,13 +71,13 @@ def test_writing_metadata_all_dirs(self: unittest.TestCase): Test multiple directories are processed when -d (directory) and -m are passed. Process all subdirs of -d. """ - with environment() as (tempdir, _fakeTPDB, config): - tempdir: Path - _fakeTPDB: FakeTPDB + with environment() as (temp_dir, fake_tpdb, config): + temp_dir: Path + fake_tpdb: FakeTPDB config: NamerConfig targets = [ - new_ea(tempdir, use_dir=True, post_stem='1'), - new_ea(tempdir, use_dir=True, post_stem='2'), + new_ea(temp_dir, use_dir=True, post_stem='1'), + new_ea(temp_dir, use_dir=True, post_stem='2'), ] main(['-d', str(targets[0].get_file().parent.parent), '-m', '-c', str(config.config_file)]) output = MP4(targets[0].get_file().parent.parent / 'Evil Angel' / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-240].mp4') @@ -96,23 +96,23 @@ def test_writing_metadata_from_nfo(self): config.min_file_size = 0 with tempfile.TemporaryDirectory(prefix='test') as tmpdir: current = Path(__file__).resolve().parent - tempdir = Path(tmpdir) + temp_dir = Path(tmpdir) nfo_file = current / 'ea.nfo' mp4_file = current / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' poster_file = current / 'poster.png' - target_nfo_file = tempdir / 'ea.nfo' - target_mp4_file = tempdir / 'ea.mp4' - target_poster_file = tempdir / 'poster.png' + target_nfo_file = temp_dir / 'ea.nfo' + target_mp4_file = temp_dir / 'ea.mp4' + target_poster_file = temp_dir / 'poster.png' shutil.copy(mp4_file, target_mp4_file) shutil.copy(nfo_file, target_nfo_file) shutil.copy(poster_file, target_poster_file) - cfgfile = tempdir / 'test_namer.cfg' - with open(cfgfile, 'w') as file: + cfg_file = temp_dir / 'test_namer.cfg' + with open(cfg_file, 'w') as file: content = to_ini(config) file.write(content) - main(['-f', str(target_mp4_file), '-i', '-c', str(cfgfile)]) + main(['-f', str(target_mp4_file), '-i', '-c', str(cfg_file)]) output = MP4(target_mp4_file.parent / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-240].mp4') self.assertEqual(output.get('\xa9nam'), ['Carmela Clutch: Fabulous Anal 3-Way!']) @@ -122,8 +122,8 @@ def test_writing_metadata_all_dirs_files(self): Process all sub-dirs of -d. """ config = sample_config() - with environment(config) as (tempdir, _fakeTPDB, config): - targets = [new_ea(tempdir, use_dir=False, post_stem='1'), new_ea(tempdir, use_dir=False, post_stem='2')] + with environment(config) as (temp_dir, fake_tpdb, config): + targets = [new_ea(temp_dir, use_dir=False, post_stem='1'), new_ea(temp_dir, use_dir=False, post_stem='2')] main(['-d', str(targets[0].get_file().parent), '-m', '-c', str(config.config_file)]) output1 = targets[0].get_file().parent / 'Evil Angel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! [WEBDL-240].mp4' validate_mp4_tags(self, output1) diff --git a/test/namer_videophash_test.py b/test/namer_videophash_test.py index 13dfb982..6a2487f0 100644 --- a/test/namer_videophash_test.py +++ b/test/namer_videophash_test.py @@ -40,9 +40,9 @@ def test_get_phash(self): expected_duration = 30 with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - shutil.copytree(Path(__file__).resolve().parent, tempdir / 'test') - file = tempdir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' + temp_dir = Path(tmpdir) + shutil.copytree(Path(__file__).resolve().parent, temp_dir / 'test') + file = temp_dir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' res = self.__generator.get_hashes(file) self.assertIsNotNone(res) @@ -60,9 +60,9 @@ def test_get_stash_phash(self): expected_duration = 30 with tempfile.TemporaryDirectory(prefix='test') as tmpdir: - tempdir = Path(tmpdir) - shutil.copytree(Path(__file__).resolve().parent, tempdir / 'test') - file = tempdir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' + temp_dir = Path(tmpdir) + shutil.copytree(Path(__file__).resolve().parent, temp_dir / 'test') + file = temp_dir / 'test' / 'Site.22.01.01.painful.pun.XXX.720p.xpost.mp4' res = self.__stash_generator.get_hashes(file) self.assertIsNotNone(res) diff --git a/test/namer_watchdog_test.py b/test/namer_watchdog_test.py index 2463c8cb..3eaf1f97 100644 --- a/test/namer_watchdog_test.py +++ b/test/namer_watchdog_test.py @@ -23,7 +23,7 @@ def wait_until_processed(watcher: MovieWatcher, duration: int = 60): Waits until all files have been moved out of watch/working dirs. """ config = watcher.get_config() - Wait().seconds(duration).checking(1).until(lambda: len(list(config.watch_dir.iterdir())) > 0 or len(list(config.work_dir.iterdir())) > 0).isFalse() + Wait().seconds(duration).checking(1).until(lambda: len(list(config.watch_dir.iterdir())) > 0 or len(list(config.work_dir.iterdir())) > 0).is_false() watcher.stop() @@ -32,12 +32,25 @@ def make_watchdog_context(config: NamerConfig, targets=None): if targets is None: targets = [] - with environment(config) as (tempdir, mock_tpdb, config): + with environment(config) as (temp_dir, mock_tpdb, config): for target in targets: if target.file is None: target.setup(config.watch_dir) with create_watcher(config) as watcher: - yield tempdir, watcher, mock_tpdb + yield temp_dir, watcher, mock_tpdb + + +def remove_performer_genders(data: Any): + single_scene = data['data'] + for json_performer in single_scene['performers']: + if not json_performer['extra']: + continue + json_performer['extra']['gender'] = None + + +def remove_performers(data: Any): + single_scene = data['data'] + single_scene['performers'] = [] class UnitTestAsTheDefaultExecution(unittest.TestCase): @@ -68,7 +81,7 @@ def test_handler_collisions_success(self): config.write_namer_log = True config.min_file_size = 0 targets: list[ProcessingTarget] = [new_ea(), new_ea(use_dir=False)] - with make_watchdog_context(config, targets) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config, targets) as (temp_dir, watcher, fake_tpdb): wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) self.assertEqual(len(list(config.work_dir.iterdir())), 0) @@ -96,7 +109,7 @@ def test_handler_collisions_success_choose_best(self): config.preserve_duplicates = False config.max_desired_resolutions = -1 config.desired_codec = ['hevc', 'h264'] - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets: list[ProcessingTarget] = [new_ea(config.watch_dir, mp4_file_name=okay), new_ea(config.watch_dir, use_dir=False, post_stem='2', mp4_file_name=better), new_ea(config.watch_dir, use_dir=False, post_stem='1', mp4_file_name=best)] wait_until_processed(watcher, 120) self.assertFalse(targets[0].get_file().exists()) @@ -123,7 +136,7 @@ def test_event_listener_success(self): config.min_file_size = 0 config.write_namer_log = True config.min_file_size = 0 - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [new_ea(config.watch_dir)] wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) @@ -144,7 +157,7 @@ def test_event_listener_success_conversion(self): config.write_namer_log = True config.min_file_size = 0 config.convert_container_to = 'mkv' - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [new_ea(config.watch_dir)] wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) @@ -161,7 +174,7 @@ def test_handler_deeply_nested_success_no_dirname(self): config.write_namer_log = True config.min_file_size = 0 config.preserve_duplicates = True - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(config.watch_dir / 'deeper' / 'and_deeper', use_dir=False), new_ea(config.watch_dir, post_stem='number2', use_dir=False), @@ -188,7 +201,7 @@ def test_handler_deeply_nested_success_no_dirname_extra_files(self): config.min_file_size = 0 config.del_other_files = False config.new_relative_path_name = '{site}/{site} - {date} - {name}/{site} - {date} - {name}.{ext}' - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(config.watch_dir / 'deeper' / 'and_deeper', use_dir=False), ] @@ -219,7 +232,7 @@ def test_handler_deeply_nested_success(self): config.set_dir_permissions = None config.set_file_permissions = None config.new_relative_path_name = './{network}/' + config.new_relative_path_name - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(config.watch_dir / 'EvilAngel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way', use_dir=True), ] @@ -245,7 +258,7 @@ def test_handler_deeply_nested_success_missing_network(self): config.set_dir_permissions = None config.set_file_permissions = None config.new_relative_path_name = './{network}/' + config.new_relative_path_name - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_dorcel(config.watch_dir, use_dir=True), ] @@ -270,7 +283,7 @@ def test_handler_deeply_nested_success_custom_location(self): config.set_dir_permissions = None config.set_file_permissions = None config.new_relative_path_name = '{site} - {date} - {name}/{site} - {date} - {name} - {uuid} - {external_id} - ({resolution}).{ext}' - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(config.watch_dir / 'EvilAngel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way', use_dir=True), ] @@ -286,6 +299,7 @@ def test_handler_deeply_nested_success_custom_location(self): def test_handler_deeply_nested_success_bracked(self): """ Test the handle function works for a directory. + """ config = sample_config() config.prefer_dir_name_if_available = True @@ -295,7 +309,7 @@ def test_handler_deeply_nested_success_bracked(self): config.set_dir_permissions = None config.set_file_permissions = None config.new_relative_path_name = '{site} - {date} - {name}/{site} - {date} - {name} - {uuid} - {external_id} - ({resolution}).{ext}' - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(config.watch_dir / 'EvilAngel - 2022-01-03 - Carmela Clutch Fabulous Anal 3-Way! XXX [XvX]', post_stem='XXX [XvX]'), ] @@ -312,7 +326,7 @@ def test_handler_ignore(self): """ Test the handle function works for a directory. """ - with make_watchdog_context(sample_config()) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(sample_config()) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(watcher.get_config().watch_dir / '_UNPACK_stuff' / 'EvilAngel - Carmela Clutch Fabulous Anal 3-Way', use_dir=True), ] @@ -328,7 +342,7 @@ def test_handler_failure(self): config.write_namer_log = True config.del_other_files = False config.min_file_size = 0 - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [new_ea(config.watch_dir, use_dir=False, match=False)] wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) @@ -353,7 +367,7 @@ def test_name_parser_success(self): config.min_file_size = 0 config.name_parser = '{_site} - {_ts}{_name}.{_ext}' config.sites_with_no_date_info = ['evilangel'] - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): targets = [ new_ea(config.watch_dir / 'EvilAngel - Carmela Clutch Fabulous Anal 3-Way', use_dir=True), ] @@ -365,13 +379,6 @@ def test_name_parser_success(self): self.assertEqual(len(list(config.watch_dir.iterdir())), 0) self.assertEqual(len(list(config.work_dir.iterdir())), 0) - def remove_performer_genders(self, data: Any): - single_scene = data['data'] - for json_performer in single_scene['performers']: - if not json_performer['extra']: - continue - json_performer['extra']['gender'] = None - def test_missing_performers_gender_success(self): """ Test files aren't lost when fields are missing. @@ -382,8 +389,8 @@ def test_missing_performers_gender_success(self): config.write_namer_log = True config.min_file_size = 0 config.new_relative_path_name = '{performers}/{site} - {date} - {name}.{ext}' - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): - self.remove_performer_genders(fakeTPDB._scenes['ea.full.json']) + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): + remove_performer_genders(fake_tpdb._scenes['ea.full.json']) targets = [new_ea(config.watch_dir)] wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) @@ -395,10 +402,6 @@ def test_missing_performers_gender_success(self): self.assertEqual(len(list(config.failed_dir.iterdir())), 0) self.assertEqual(len(list(config.watch_dir.iterdir())), 0) - def remove_performers(self, data: Any): - single_scene = data['data'] - single_scene['performers'] = [] - def test_missing_performers_success(self): """ Test files aren't lost when fields are missing. @@ -409,8 +412,8 @@ def test_missing_performers_success(self): config.write_namer_log = True config.min_file_size = 0 config.new_relative_path_name = '{performers}/{site} - {date} - {name}.{ext}' - with make_watchdog_context(config) as (tempdir, watcher, fakeTPDB): - self.remove_performers(fakeTPDB._scenes['ea.full.json']) + with make_watchdog_context(config) as (temp_dir, watcher, fake_tpdb): + remove_performers(fake_tpdb._scenes['ea.full.json']) targets = [new_ea(config.watch_dir)] wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) @@ -434,7 +437,7 @@ def test_name_parser_failure_with_startup_processing(self): targets = [ new_ea(relative='EvilAngel - Carmela Clutch Fabulous Anal 3-Way/', use_dir=True), ] - with make_watchdog_context(config, targets) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config, targets) as (temp_dir, watcher, fake_tpdb): wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) output_file = config.failed_dir / 'EvilAngel - Carmela Clutch Fabulous Anal 3-Way' @@ -458,7 +461,7 @@ def test_fetch_trailer_write_nfo_success(self): config.min_file_size = 0 config.write_nfo = True targets = [new_ea()] - with make_watchdog_context(config, targets) as (tempdir, watcher, fakeTPDB): + with make_watchdog_context(config, targets) as (temp_dir, watcher, fake_tpdb): wait_until_processed(watcher) self.assertFalse(targets[0].get_file().exists()) self.assertEqual(len(list(config.work_dir.iterdir())), 0) diff --git a/test/namer_webhook_test.py b/test/namer_webhook_test.py index cd453775..2a3b7bee 100644 --- a/test/namer_webhook_test.py +++ b/test/namer_webhook_test.py @@ -91,12 +91,12 @@ def test_integration_with_file_processing(self): """ Test that webhook is triggered when a file is successfully processed. """ - with environment() as (tempdir, _fakeTPDB, config): + with environment() as (temp_dir, fake_tpdb, config): config.webhook_enabled = True config.webhook_url = 'http://example.com/webhook' with patch('namer.namer.send_webhook_notification') as mock_webhook: - targets = [new_ea(tempdir, use_dir=False)] + targets = [new_ea(temp_dir, use_dir=False)] # Process the file from namer.namer import main diff --git a/test/utils.py b/test/utils.py index f4ace524..d425c7e7 100644 --- a/test/utils.py +++ b/test/utils.py @@ -59,10 +59,10 @@ def __wait(self, state: bool): sleep(self._checking) raise RuntimeError(f'Timed out waiting for predicate {self._predicate} to return {state}') - def isTrue(self): + def is_true(self): self.__wait(True) - def isFalse(self): + def is_false(self): self.__wait(False) @@ -209,28 +209,28 @@ def environment(config: NamerConfig = None): # type: ignore if config is None: config = sample_config() - with tempfile.TemporaryDirectory(prefix='test') as tmpdir, FakeTPDB() as fakeTpdb: - tempdir = Path(tmpdir).resolve() + with tempfile.TemporaryDirectory(prefix='test') as tmp_dir, FakeTPDB() as fake_tpdb: + temp_dir = Path(tmp_dir).resolve() config.enabled_tagging = True config.enabled_poster = True - config.override_tpdb_address = fakeTpdb.get_url() - config.watch_dir = tempdir / 'watch' + config.override_tpdb_address = fake_tpdb.get_url() + config.watch_dir = temp_dir / 'watch' config.watch_dir.mkdir(parents=True, exist_ok=True) - config.dest_dir = tempdir / 'dest' + config.dest_dir = temp_dir / 'dest' config.dest_dir.mkdir(parents=True, exist_ok=True) - config.work_dir = tempdir / 'work' + config.work_dir = temp_dir / 'work' config.work_dir.mkdir(parents=True, exist_ok=True) - config.failed_dir = tempdir / 'failed' + config.failed_dir = temp_dir / 'failed' config.failed_dir.mkdir(parents=True, exist_ok=True) config.porndb_token = 'notarealtoken' - cfgfile = tempdir / 'test_namer.cfg' + cfgfile = temp_dir / 'test_namer.cfg' config.min_file_size = 0 with open(cfgfile, 'w') as file: content = to_ini(config) file.write(content) config.config_file = cfgfile - yield tempdir, fakeTpdb, config + yield temp_dir, fake_tpdb, config def validate_permissions(test_self, file: Path, perm: int): diff --git a/test/web/namer_web_test.py b/test/web/namer_web_test.py index 5b0cdf6c..b195d388 100644 --- a/test/web/namer_web_test.py +++ b/test/web/namer_web_test.py @@ -64,10 +64,10 @@ def default_os_browser(debug: bool) -> WebDriver: @contextlib.contextmanager # type: ignore def make_test_context(config: NamerConfig): - with environment(config) as (tempdir, mock_tpdb, config), create_watcher(config) as watcher, default_os_browser(is_debugging()) as browser: + with environment(config) as (temp_dir, mock_tpdb, config), create_watcher(config) as watcher, default_os_browser(is_debugging()) as browser: url = f'http://{config.host}:{watcher.get_web_port()}{config.web_root}/failed' browser.get(url) - yield tempdir, watcher, browser, mock_tpdb + yield temp_dir, watcher, browser, mock_tpdb class UnitTestAsTheDefaultExecution(unittest.TestCase): @@ -96,7 +96,7 @@ def test_webdriver_flow(self: unittest.TestCase): config.write_namer_failed_log = True config.del_other_files = True config.extra_sleep_time = 1 - with make_test_context(config) as (_tempdir, _watcher, browser, _mock_tpdb): + with make_test_context(config) as (temp_dir, watcher, browser, mock_tpdb): new_ea(config.failed_dir, use_dir=False) ( FailedPage(browser)