From 6eeaee688f81f63020683409d7018a831c856ee6 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 18 Nov 2019 15:43:59 +0100 Subject: Add global templates --- patternutils/commands/patterncfg.py | 3 ++- patternutils/config.py | 45 +++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 96e9ac7..062a6a5 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -1,5 +1,6 @@ import os import os.path +import itertools from typing import Optional @@ -28,7 +29,7 @@ def patterncfg() -> None: @patterncfg.command(name='init', help='initialize config folders') def init() -> None: - for dir in CURRENT_SUPPORTED_PROGRAMS: + for dir in itertools.chain(CURRENT_SUPPORTED_PROGRAMS, ('globals',)): os.makedirs(os.path.join(config.CONFIG_PATH, dir), exist_ok=True) diff --git a/patternutils/config.py b/patternutils/config.py index 155789b..ec38ebe 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -1,5 +1,6 @@ import os.path import glob +import re import click @@ -7,6 +8,9 @@ from typing import Tuple, List, Optional CONFIG_PATH = click.get_app_dir('patternutils') +REGEX_PROGRAMS = ('pmatch', ) +TEMPLATE_PROGRAMS = ('tmv', 'targs', 'tln') + def load_template(template_name: str, command_name: Optional[str]) -> Tuple[str, str]: """Load a template from the config directory.""" @@ -28,7 +32,40 @@ def load_template(template_name: str, command_name: Optional[str]) -> Tuple[str, def find_templates(template_name: str, command_name: Optional[str] = None) -> List[str]: - template_glob = '{}.*'.format(template_name) - command_glob = '*' if command_name is None else command_name - command_glob = os.path.join(CONFIG_PATH, command_glob) - return glob.glob(os.path.join(command_glob, template_glob)) + + regex = os.path.join(CONFIG_PATH, '{path_sub_regex}', r'{template_name}\.{extension}') + + if command_name is None: + # CONFIG_PATH/*/TEMPLATE_NAME.* + path_sub_regex = '.*' + extension = '.*' + elif command_name in REGEX_PROGRAMS: + path_sub_regex = '(globals|{command_name})' + extension = 'regex' + elif command_name in TEMPLATE_PROGRAMS: + # CONFIG_PATH/globals/TEMPLATE_NAME.jinja2 + # CONFIG_PATH/globals/TEMPLATE_NAME.python + # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.jinja2 + # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.python + path_sub_regex = '(globals|{command_name})' + extension = '(jinja2|python)' + else: + # Fail over if command name is not know + # This should normally not happen + # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.* + path_sub_regex = '{command_name}' + extension = '.*' + + # We need to format command_name twice, as it can be used in the + # path_sub_regex + regex = regex.format( + path_sub_regex=path_sub_regex.format(command_name=command_name), + command_name=command_name, + template_name=template_name, + extension=extension + ) + compiled_regex = re.compile(regex) + + files = filter(compiled_regex.search, glob.iglob(os.path.join(CONFIG_PATH, '*', '*'))) + + return list(files) -- cgit v1.3.1 From 1e9050e92a8b07b5a99115eb8eaf62a8ddca8fdb Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Sat, 26 Sep 2020 08:45:50 +0200 Subject: Use f-strings in find_templates --- patternutils/config.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/patternutils/config.py b/patternutils/config.py index a124644..5eb44b2 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -32,43 +32,31 @@ def load_template(template_name: str, command_name: Optional[str]) -> Tuple[str, def find_templates(template_name: str, command_name: Optional[str] = None) -> List[str]: - regex = os.path.join( - CONFIG_PATH, "{path_sub_regex}", r"{template_name}\.{extension}" - ) - if command_name is None: # CONFIG_PATH/*/TEMPLATE_NAME.* path_sub_regex = ".*" extension = ".*" elif command_name in REGEX_PROGRAMS: - path_sub_regex = "(globals|{command_name})" + path_sub_regex = f"(globals|{command_name})" extension = "regex" elif command_name in TEMPLATE_PROGRAMS: # CONFIG_PATH/globals/TEMPLATE_NAME.jinja2 # CONFIG_PATH/globals/TEMPLATE_NAME.python # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.jinja2 # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.python - path_sub_regex = "(globals|{command_name})" + path_sub_regex = f"(globals|{command_name})" extension = "(jinja2|python)" else: # Fail over if command name is not know # This should normally not happen # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.* - path_sub_regex = "{command_name}" + path_sub_regex = f"{command_name}" extension = ".*" - # We need to format command_name twice, as it can be used in the - # path_sub_regex - regex = regex.format( - path_sub_regex=path_sub_regex.format(command_name=command_name), - command_name=command_name, - template_name=template_name, - extension=extension, + regex = re.compile( + os.path.join(CONFIG_PATH, f"{path_sub_regex}", f"{template_name}\.{extension}") ) - compiled_regex = re.compile(regex) - files = filter( - compiled_regex.search, glob.iglob(os.path.join(CONFIG_PATH, "*", "*")) - ) + files = filter(regex.search, glob.iglob(os.path.join(CONFIG_PATH, "*", "*"))) return list(files) -- cgit v1.3.1 From 70440dcbcdb4f016c10a0b2afd4c2c1fddd5d494 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Sat, 26 Sep 2020 08:49:50 +0200 Subject: Better comment --- patternutils/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patternutils/config.py b/patternutils/config.py index 5eb44b2..319f035 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -47,7 +47,7 @@ def find_templates(template_name: str, command_name: Optional[str] = None) -> Li path_sub_regex = f"(globals|{command_name})" extension = "(jinja2|python)" else: - # Fail over if command name is not know + # Fail over if command name is not known to have a specific extension # This should normally not happen # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.* path_sub_regex = f"{command_name}" -- cgit v1.3.1 From 478fef8756b45dc1c84adf656d17284c7e27d70b Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Fri, 1 Mar 2024 08:32:43 +0100 Subject: Add proper typing --- patternutils/commands/patterncfg.py | 19 ++++++++++----- patternutils/commands/pjson.py | 2 +- patternutils/commands/pmatch.py | 5 ++-- patternutils/commands/targs.py | 2 +- patternutils/commands/tln.py | 6 ++--- patternutils/commands/tmv.py | 6 ++--- patternutils/config.py | 48 ++++++++++++++++++++++--------------- patternutils/template.py | 13 ++++++---- patternutils/utils.py | 10 ++++---- 9 files changed, 64 insertions(+), 47 deletions(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 6b2f6ec..e84a0db 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -15,9 +15,14 @@ else: has_pygments = True -from .. import config +from .. import config, template -CURRENT_SUPPORTED_PROGRAMS = ("pmatch", "tmv", "targs", "tln") +CURRENT_SUPPORTED_PROGRAMS: tuple[config.CommandNames, ...] = ( + "pmatch", + "tmv", + "targs", + "tln", +) @click.group(context_settings={"help_option_names": ("-h", "--help", "-?")}) @@ -57,7 +62,9 @@ def list() -> None: ) @click.argument("command", required=True, type=click.Choice(CURRENT_SUPPORTED_PROGRAMS)) @click.argument("name") -def add(template_engine: Optional[str], command: str, name: str) -> None: +def add( + template_engine: Optional[template.TemplateEngines], command: str, name: str +) -> None: if command == "pmatch": fileext = "regex" @@ -77,7 +84,7 @@ def add(template_engine: Optional[str], command: str, name: str) -> None: help="select the command from which to remove the file", ) @click.argument("name") -def remove(command: Optional[str], name: str) -> None: +def remove(command: Optional[config.CommandNames], name: str) -> None: files = config.find_templates(name, command) @@ -112,7 +119,7 @@ def remove(command: Optional[str], name: str) -> None: help="Colorize output using pygments", ) @click.argument("name") -def view(name: str, command: str, color: bool) -> None: +def view(name: str, command: config.CommandNames, color: bool) -> None: files = config.find_templates(name, command) if not files: @@ -162,7 +169,7 @@ def view(name: str, command: str, color: bool) -> None: help="select the command from which to edit the file", ) @click.argument("name") -def edit(name: str, command: str) -> None: +def edit(name: str, command: config.CommandNames) -> None: files = config.find_templates(name, command) if not files: diff --git a/patternutils/commands/pjson.py b/patternutils/commands/pjson.py index 8604971..12469ba 100644 --- a/patternutils/commands/pjson.py +++ b/patternutils/commands/pjson.py @@ -1,6 +1,6 @@ import json import re -from typing import Any, Pattern +from typing import Pattern import click diff --git a/patternutils/commands/pmatch.py b/patternutils/commands/pmatch.py index 3884a9d..44e55b4 100644 --- a/patternutils/commands/pmatch.py +++ b/patternutils/commands/pmatch.py @@ -1,8 +1,9 @@ import functools import itertools +import os import os.path import re -from typing import Any, Generator, Iterator, Optional, Pattern +from typing import Generator, Iterator, Optional, Pattern import click @@ -12,7 +13,7 @@ from .. import utils def apply_regex( - walk_function: Iterator[Any], + walk_function: Iterator[os.DirEntry[str]], regex_pattern: Pattern[str], match_full_path: bool, ) -> Generator[Optional[dict[str, str]], None, None]: diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index 34cf018..a88bd71 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -77,7 +77,7 @@ def targs( command: str, read_from: click.File, shell: bool, - template_engine: str, + template_engine: template.TemplateEngines, max_procs: int, redirect_stdout: bool, redirect_stderr: bool, diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index 878f556..ece5b75 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -91,7 +91,7 @@ def tln( editor: bool, force: bool, symbolic: bool, - template_engine: str, + template_engine: template.TemplateEngines, use_predefined_template: bool, read_from: click.File, key: str, @@ -108,9 +108,7 @@ def tln( if use_predefined_template: try: - output_pattern, template_engine = config.load_template( - output_pattern, "tln" - ) + output_pattern, template_engine = config.load_template(output_pattern, "tln") except FileNotFoundError: click.secho(f"Template {output_pattern} not found!", fg="red", err=True) raise SystemExit diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index fa7105e..6ce45ed 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -80,7 +80,7 @@ def tmv( interactive: bool, editor: bool, force: bool, - template_engine: str, + template_engine: template.TemplateEngines, abort_on_path_exist: bool, use_predefined_template: bool, read_from: click.File, @@ -106,9 +106,7 @@ def tmv( if use_predefined_template: try: - output_pattern, template_engine = config.load_template( - output_pattern, "tmv" - ) + output_pattern, template_engine = config.load_template(output_pattern, "tmv") except FileNotFoundError: click.secho(f"Template {output_pattern} not found!", fg="red", err=True) raise SystemExit diff --git a/patternutils/config.py b/patternutils/config.py index f999b2e..b18b72c 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -1,17 +1,29 @@ import glob import os.path import re -from typing import Optional +from typing import Literal, Optional, cast, overload import click +TemplateExtensions = Literal["python", "jinja2", "regex"] +CommandNames = Literal["pmatch", "tmv", "targs", "tln"] + CONFIG_PATH = click.get_app_dir("patternutils") REGEX_PROGRAMS = ("pmatch",) TEMPLATE_PROGRAMS = ("tmv", "targs", "tln") +@overload +def load_template(template_name: str, command_name: Literal["pmatch"]) -> tuple[str, Literal["regex"]]: + ... + +@overload +def load_template(template_name: str, command_name: Literal["tmv", "targs", "tln"]) -> tuple[str, Literal["python", "jinja2"]]: + ... -def load_template(template_name: str, command_name: Optional[str]) -> tuple[str, str]: +def load_template( + template_name: str, command_name: Optional[CommandNames] +) -> tuple[str, TemplateExtensions]: """Load a template from the config directory.""" files = find_templates(template_name, command_name) @@ -25,33 +37,31 @@ def load_template(template_name: str, command_name: Optional[str]) -> tuple[str, raise RuntimeError("Multiple files found!") output_pattern = template_lines.replace("\n", "") - template_engine = os.path.splitext(template_file)[1][1:] + template_engine = cast(TemplateExtensions, os.path.splitext(template_file)[1][1:]) return output_pattern, template_engine -def find_templates(template_name: str, command_name: Optional[str] = None) -> List[str]: +def find_templates( + template_name: str, command_name: Optional[CommandNames] = None +) -> list[str]: if command_name is None: # CONFIG_PATH/*/TEMPLATE_NAME.* path_sub_regex = ".*" extension = ".*" - elif command_name in REGEX_PROGRAMS: - path_sub_regex = f"(globals|{command_name})" - extension = "regex" - elif command_name in TEMPLATE_PROGRAMS: - # CONFIG_PATH/globals/TEMPLATE_NAME.jinja2 - # CONFIG_PATH/globals/TEMPLATE_NAME.python - # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.jinja2 - # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.python - path_sub_regex = f"(globals|{command_name})" - extension = "(jinja2|python)" else: - # Fail over if command name is not known to have a specific extension - # This should normally not happen - # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.* - path_sub_regex = f"{command_name}" - extension = ".*" + path_sub_regex = f"(globals|{command_name})" + if command_name in REGEX_PROGRAMS: + extension = "regex" + elif command_name in TEMPLATE_PROGRAMS: + # CONFIG_PATH/globals/TEMPLATE_NAME.jinja2 + # CONFIG_PATH/globals/TEMPLATE_NAME.python + # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.jinja2 + # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.python + extension = "(jinja2|python)" + else: + raise ValueError(f"{command_name} is not known!") regex = re.compile( os.path.join(CONFIG_PATH, f"{path_sub_regex}", f"{template_name}\.{extension}") diff --git a/patternutils/template.py b/patternutils/template.py index f0b3c43..a05be83 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -1,4 +1,6 @@ -from typing import Callable +from typing import Callable, Literal, cast + +TemplateEngines = Literal["python", "jinja2"] try: import jinja2 @@ -42,13 +44,14 @@ else: jinja_env.filters["splitext"] = splitext -def get_render_function(template: str, *, engine: str = "python") -> Callable[..., str]: +def get_render_function( + template: str, *, engine: TemplateEngines = "python" +) -> Callable[..., str]: if engine == "jinja2": if jinja_feature: env_template = jinja_env.from_string(template) - render_function = env_template.render + return cast(Callable[..., str], env_template.render) else: raise RuntimeError("jinja2 not installed!") else: - render_function = template.format - return render_function + return template.format diff --git a/patternutils/utils.py b/patternutils/utils.py index 0395110..88cad88 100644 --- a/patternutils/utils.py +++ b/patternutils/utils.py @@ -1,6 +1,6 @@ import json import os -from typing import Any, Generator, Optional, Union +from typing import Any, Generator, Optional import click @@ -10,7 +10,7 @@ def max_procs() -> int: return 1 if cpu_count is None else cpu_count * 2 -def edit(data: Union[dict[str, str], list[str]]) -> Optional[dict[str, str]]: +def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str]]: longest = len(max(data, key=len)) @@ -38,11 +38,11 @@ def edit(data: Union[dict[str, str], list[str]]) -> Optional[dict[str, str]]: def json_dumps(data: Any, human_readable: bool = False) -> str: - config = ( + config: dict[str, Any] = ( {"indent": 4, "sort_keys": True} if human_readable else {"separators": (",", ":")} - ) # type: dict[str, Any] + ) return json.dumps(data, **config) @@ -56,7 +56,7 @@ def json_loads(data: Any) -> Any: def walk( directory: str, recursive: bool = False, match_directories: bool = False -) -> Generator[os.DirEntry[Any], None, None]: +) -> Generator[os.DirEntry[str], None, None]: for entry in os.scandir(directory): is_dir = entry.is_dir() if recursive and is_dir: -- cgit v1.3.1 From 74b17048635ab578723dfdc152524bea2828c576 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Fri, 1 Mar 2024 08:33:51 +0100 Subject: Update dependencies --- poetry.lock | 379 +++++++++++++++++++++++++++------------------------------ pyproject.toml | 2 +- 2 files changed, 179 insertions(+), 202 deletions(-) diff --git a/poetry.lock b/poetry.lock index 486a87d..095acbb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,15 @@ +# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. + [[package]] name = "black" version = "21.12b0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.6.2" +files = [ + {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, + {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, +] [package.dependencies] click = ">=7.1.2" @@ -13,8 +18,8 @@ pathspec = ">=0.9.0,<1" platformdirs = ">=2" tomli = ">=0.2.6,<2.0.0" typing-extensions = [ + {version = ">=3.10.0.0,<3.10.0.1 || >3.10.0.1", markers = "python_version >= \"3.10\""}, {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, - {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, ] [package.extras] @@ -26,55 +31,67 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "click" -version = "8.0.3" +version = "8.1.7" description = "Composable command line interface toolkit" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] [[package]] name = "feedparser" -version = "6.0.8" +version = "6.0.11" description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds" -category = "main" optional = true python-versions = ">=3.6" +files = [ + {file = "feedparser-6.0.11-py3-none-any.whl", hash = "sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45"}, + {file = "feedparser-6.0.11.tar.gz", hash = "sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5"}, +] [package.dependencies] sgmllib3k = "*" [[package]] name = "isort" -version = "5.10.1" +version = "5.13.2" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] [package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] -colors = ["colorama (>=0.4.3,<0.5.0)"] -plugins = ["setuptools"] +colors = ["colorama (>=0.4.6)"] [[package]] name = "jinja2" -version = "3.0.3" +version = "3.1.3" description = "A very fast and expressive template engine." -category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -84,19 +101,101 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] [[package]] name = "mypy" version = "0.930" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "mypy-0.930-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871"}, + {file = "mypy-0.930-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31"}, + {file = "mypy-0.930-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b"}, + {file = "mypy-0.930-cp310-cp310-win_amd64.whl", hash = "sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30"}, + {file = "mypy-0.930-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c"}, + {file = "mypy-0.930-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c"}, + {file = "mypy-0.930-cp36-cp36m-win_amd64.whl", hash = "sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f"}, + {file = "mypy-0.930-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2"}, + {file = "mypy-0.930-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29"}, + {file = "mypy-0.930-cp37-cp37m-win_amd64.whl", hash = "sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651"}, + {file = "mypy-0.930-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7"}, + {file = "mypy-0.930-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7"}, + {file = "mypy-0.930-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380"}, + {file = "mypy-0.930-cp38-cp38-win_amd64.whl", hash = "sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01"}, + {file = "mypy-0.930-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae"}, + {file = "mypy-0.930-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f"}, + {file = "mypy-0.930-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95"}, + {file = "mypy-0.930-cp39-cp39-win_amd64.whl", hash = "sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999"}, + {file = "mypy-0.930-py3-none-any.whl", hash = "sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173"}, + {file = "mypy-0.930.tar.gz", hash = "sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2"}, +] [package.dependencies] mypy-extensions = ">=0.4.3" @@ -109,71 +208,98 @@ python2 = ["typed-ast (>=1.4.0,<2)"] [[package]] name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = "*" +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] [[package]] name = "pathspec" -version = "0.9.0" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] [[package]] name = "platformdirs" -version = "2.4.1" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pygments" -version = "2.11.0" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = true -python-versions = ">=3.5" +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "sgmllib3k" version = "1.0.0" description = "Py3k port of sgmllib." -category = "main" optional = true python-versions = "*" +files = [ + {file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"}, +] [[package]] name = "tomli" version = "1.2.3" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, + {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, +] [[package]] name = "typing-extensions" -version = "4.0.1" -description = "Backported and Experimental Type Hints for Python 3.6+" -category = "dev" +version = "4.10.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, +] [[package]] name = "vermin" -version = "1.3.3" +version = "1.6.0" description = "Concurrently detect the minimum Python versions needed to run code" -category = "dev" optional = false -python-versions = ">=2.7" +python-versions = ">=3.0" +files = [ + {file = "vermin-1.6.0-py2.py3-none-any.whl", hash = "sha256:f1fa9ee40f59983dc40e0477eb2b1fa8061a3df4c3b2bcf349add462a5610efb"}, + {file = "vermin-1.6.0.tar.gz", hash = "sha256:6266ca02f55d1c2aa189a610017c132eb2d1934f09e72a955b1eb3820ee6d4ef"}, +] [extras] jinja2 = ["Jinja2"] @@ -181,155 +307,6 @@ prss = ["feedparser"] pygments = ["Pygments"] [metadata] -lock-version = "1.1" -python-versions = ">=3.8,<4" -content-hash = "eedebf0b6e78c4e1fa28738ea11b5cb637b36821c647bdbc53456ab1cf477790" - -[metadata.files] -black = [ - {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, - {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, -] -click = [ - {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, - {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, -] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -feedparser = [ - {file = "feedparser-6.0.8-py3-none-any.whl", hash = "sha256:1b7f57841d9cf85074deb316ed2c795091a238adb79846bc46dccdaf80f9c59a"}, - {file = "feedparser-6.0.8.tar.gz", hash = "sha256:5ce0410a05ab248c8c7cfca3a0ea2203968ee9ff4486067379af4827a59f9661"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, -] -markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, -] -mypy = [ - {file = "mypy-0.930-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871"}, - {file = "mypy-0.930-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31"}, - {file = "mypy-0.930-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b"}, - {file = "mypy-0.930-cp310-cp310-win_amd64.whl", hash = "sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30"}, - {file = "mypy-0.930-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c"}, - {file = "mypy-0.930-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c"}, - {file = "mypy-0.930-cp36-cp36m-win_amd64.whl", hash = "sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f"}, - {file = "mypy-0.930-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2"}, - {file = "mypy-0.930-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29"}, - {file = "mypy-0.930-cp37-cp37m-win_amd64.whl", hash = "sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651"}, - {file = "mypy-0.930-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7"}, - {file = "mypy-0.930-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7"}, - {file = "mypy-0.930-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380"}, - {file = "mypy-0.930-cp38-cp38-win_amd64.whl", hash = "sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01"}, - {file = "mypy-0.930-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae"}, - {file = "mypy-0.930-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f"}, - {file = "mypy-0.930-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95"}, - {file = "mypy-0.930-cp39-cp39-win_amd64.whl", hash = "sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999"}, - {file = "mypy-0.930-py3-none-any.whl", hash = "sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173"}, - {file = "mypy-0.930.tar.gz", hash = "sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, -] -platformdirs = [ - {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, - {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, -] -pygments = [ - {file = "Pygments-2.11.0-py3-none-any.whl", hash = "sha256:ac8098bfc40b8e1091ad7c13490c7f4797e401d0972e8fcfadde90ffb3ed4ea9"}, - {file = "Pygments-2.11.0.tar.gz", hash = "sha256:51130f778a028f2d19c143fce00ced6f8b10f726e17599d7e91b290f6cbcda0c"}, -] -sgmllib3k = [ - {file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"}, -] -tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] -typing-extensions = [ - {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, - {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, -] -vermin = [ - {file = "vermin-1.3.3-py2.py3-none-any.whl", hash = "sha256:c5bd8bf2026d87563332293a0479606954bd973d8cf72ab370e1164a019c0524"}, -] +lock-version = "2.0" +python-versions = ">=3.9,<4" +content-hash = "66d1bf95fe5937b64bb617fcd0effb27288418e4ffc1f5ea782f76b0d02ad088" diff --git a/pyproject.toml b/pyproject.toml index 4a340da..1f1f4c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ prss = "patternutils.commands.prss:prss" pjson = "patternutils.commands.pjson:pjson" [tool.poetry.dependencies] -python = ">=3.8,<4" +python = ">=3.9,<4" click = "^8.0.3" Jinja2 = {version = "^3.0.3", optional = true} Pygments = {version = "^2.10.0", optional = true} -- cgit v1.3.1 From 6f6bc17ab1f62b20628ee7767de10ded7c2dbcef Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Tue, 24 Sep 2024 16:55:38 +0200 Subject: Remove uneeded conditional --- patternutils/commands/patterncfg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index e84a0db..1b37ba4 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -69,7 +69,7 @@ def add( if command == "pmatch": fileext = "regex" else: - fileext = "jinja2" if template_engine == "jinja2" else "python" + fileext = template_engine filename = os.path.join(config.CONFIG_PATH, command, f"{name}.{fileext}") click.edit(filename=filename) -- cgit v1.3.1 From 80d5ce6bd6f7cc8b44a8652cce272cb431741fe2 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Tue, 24 Sep 2024 16:55:46 +0200 Subject: Push pkgrel --- PKGBUILD/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PKGBUILD/PKGBUILD b/PKGBUILD/PKGBUILD index 42ca51b..c4aeba8 100644 --- a/PKGBUILD/PKGBUILD +++ b/PKGBUILD/PKGBUILD @@ -2,7 +2,7 @@ pkgname=patternutils pkgver=0.0.12 -pkgrel=1 +pkgrel=2 pkgdesc="Combine regular expressions with template engines in a powerful matter." arch=('any') url="https://projects.metalgamer.eu/patternutils" -- cgit v1.3.1 From 0d6645ad07f3d271a2d24f8707e0f58d5d756e7a Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Wed, 5 Mar 2025 08:09:19 +0100 Subject: Update hgignore --- .hgignore | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 248 insertions(+), 12 deletions(-) diff --git a/.hgignore b/.hgignore index b22e97c..d96c129 100644 --- a/.hgignore +++ b/.hgignore @@ -1,18 +1,254 @@ syntax: glob -*.pyc -*.json -*.egg-info -*.tar.xz -*.tar.xz.sig -*.tar.zst - -build/* -dist/* PKGBUILD/pkg/* PKGBUILD/src/* -PKGBUILD/*.zip PKGBUILD/.git/* PKGBUILD/.SRCINFO -venv/* -.mypy_cache/* +PKGBUILD/*.zip +PKGBUILD/*.tar.zst +PKGBUILD/*.tar.gz + +.pdm-build/* + +# Created by https://www.toptal.com/developers/gitignore/api/python,linux,windows,macosx,mercurial,git +# Edit at https://www.toptal.com/developers/gitignore?templates=python,linux,windows,macosx,mercurial,git + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +#!! ERROR: macosx is undefined. Use list command to see defined gitignore types !!# + +### Mercurial ### +.hg/ +.hgignore +.hgsigs +.hgsub +.hgsubstate +.hgtags + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/python,linux,windows,macosx,mercurial,git -- cgit v1.3.1 From 71c4d33ebbf709de780da141e78968a92a5aa098 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Wed, 5 Mar 2025 08:12:19 +0100 Subject: Fix some typing --- patternutils/commands/patterncfg.py | 6 ++---- patternutils/config.py | 15 ++++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 1b37ba4..6844efc 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -1,7 +1,7 @@ import itertools import os import os.path -from typing import Optional +from typing import Literal, Optional import click @@ -65,11 +65,9 @@ def list() -> None: def add( template_engine: Optional[template.TemplateEngines], command: str, name: str ) -> None: - + fileext: template.TemplateEngines | Literal["regex"] | None = template_engine if command == "pmatch": fileext = "regex" - else: - fileext = template_engine filename = os.path.join(config.CONFIG_PATH, command, f"{name}.{fileext}") click.edit(filename=filename) diff --git a/patternutils/config.py b/patternutils/config.py index b18b72c..0da5639 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -13,13 +13,18 @@ CONFIG_PATH = click.get_app_dir("patternutils") REGEX_PROGRAMS = ("pmatch",) TEMPLATE_PROGRAMS = ("tmv", "targs", "tln") + @overload -def load_template(template_name: str, command_name: Literal["pmatch"]) -> tuple[str, Literal["regex"]]: - ... +def load_template( + template_name: str, command_name: Literal["pmatch"] +) -> tuple[str, Literal["regex"]]: ... + @overload -def load_template(template_name: str, command_name: Literal["tmv", "targs", "tln"]) -> tuple[str, Literal["python", "jinja2"]]: - ... +def load_template( + template_name: str, command_name: Literal["tmv", "targs", "tln"] +) -> tuple[str, Literal["python", "jinja2"]]: ... + def load_template( template_name: str, command_name: Optional[CommandNames] @@ -64,7 +69,7 @@ def find_templates( raise ValueError(f"{command_name} is not known!") regex = re.compile( - os.path.join(CONFIG_PATH, f"{path_sub_regex}", f"{template_name}\.{extension}") + os.path.join(CONFIG_PATH, f"{path_sub_regex}", f"{template_name}.{extension}") ) files = filter(regex.search, glob.iglob(os.path.join(CONFIG_PATH, "*", "*"))) -- cgit v1.3.1 From 01f53edc8a28b9a447812ea74115ff234d0a3f36 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Wed, 5 Mar 2025 08:13:12 +0100 Subject: Switch to uv --- poetry.lock | 312 ----------------------------------------------- pyproject.toml | 62 ++++++---- uv.lock | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 411 insertions(+), 335 deletions(-) delete mode 100644 poetry.lock create mode 100644 uv.lock diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 095acbb..0000000 --- a/poetry.lock +++ /dev/null @@ -1,312 +0,0 @@ -# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. - -[[package]] -name = "black" -version = "21.12b0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.6.2" -files = [ - {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, - {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, -] - -[package.dependencies] -click = ">=7.1.2" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0,<1" -platformdirs = ">=2" -tomli = ">=0.2.6,<2.0.0" -typing-extensions = [ - {version = ">=3.10.0.0,<3.10.0.1 || >3.10.0.1", markers = "python_version >= \"3.10\""}, - {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, -] - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -python2 = ["typed-ast (>=1.4.3)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "feedparser" -version = "6.0.11" -description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds" -optional = true -python-versions = ">=3.6" -files = [ - {file = "feedparser-6.0.11-py3-none-any.whl", hash = "sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45"}, - {file = "feedparser-6.0.11.tar.gz", hash = "sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5"}, -] - -[package.dependencies] -sgmllib3k = "*" - -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - -[[package]] -name = "jinja2" -version = "3.1.3" -description = "A very fast and expressive template engine." -optional = true -python-versions = ">=3.7" -files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "markupsafe" -version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." -optional = true -python-versions = ">=3.7" -files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, -] - -[[package]] -name = "mypy" -version = "0.930" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mypy-0.930-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871"}, - {file = "mypy-0.930-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31"}, - {file = "mypy-0.930-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b"}, - {file = "mypy-0.930-cp310-cp310-win_amd64.whl", hash = "sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30"}, - {file = "mypy-0.930-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c"}, - {file = "mypy-0.930-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c"}, - {file = "mypy-0.930-cp36-cp36m-win_amd64.whl", hash = "sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f"}, - {file = "mypy-0.930-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2"}, - {file = "mypy-0.930-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29"}, - {file = "mypy-0.930-cp37-cp37m-win_amd64.whl", hash = "sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651"}, - {file = "mypy-0.930-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7"}, - {file = "mypy-0.930-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7"}, - {file = "mypy-0.930-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380"}, - {file = "mypy-0.930-cp38-cp38-win_amd64.whl", hash = "sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01"}, - {file = "mypy-0.930-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae"}, - {file = "mypy-0.930-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f"}, - {file = "mypy-0.930-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95"}, - {file = "mypy-0.930-cp39-cp39-win_amd64.whl", hash = "sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999"}, - {file = "mypy-0.930-py3-none-any.whl", hash = "sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173"}, - {file = "mypy-0.930.tar.gz", hash = "sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2"}, -] - -[package.dependencies] -mypy-extensions = ">=0.4.3" -tomli = ">=1.1.0" -typing-extensions = ">=3.10" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] - -[[package]] -name = "pygments" -version = "2.17.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = true -python-versions = ">=3.7" -files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, -] - -[package.extras] -plugins = ["importlib-metadata"] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "sgmllib3k" -version = "1.0.0" -description = "Py3k port of sgmllib." -optional = true -python-versions = "*" -files = [ - {file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"}, -] - -[[package]] -name = "tomli" -version = "1.2.3" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.6" -files = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] - -[[package]] -name = "typing-extensions" -version = "4.10.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, -] - -[[package]] -name = "vermin" -version = "1.6.0" -description = "Concurrently detect the minimum Python versions needed to run code" -optional = false -python-versions = ">=3.0" -files = [ - {file = "vermin-1.6.0-py2.py3-none-any.whl", hash = "sha256:f1fa9ee40f59983dc40e0477eb2b1fa8061a3df4c3b2bcf349add462a5610efb"}, - {file = "vermin-1.6.0.tar.gz", hash = "sha256:6266ca02f55d1c2aa189a610017c132eb2d1934f09e72a955b1eb3820ee6d4ef"}, -] - -[extras] -jinja2 = ["Jinja2"] -prss = ["feedparser"] -pygments = ["Pygments"] - -[metadata] -lock-version = "2.0" -python-versions = ">=3.9,<4" -content-hash = "66d1bf95fe5937b64bb617fcd0effb27288418e4ffc1f5ea782f76b0d02ad088" diff --git a/pyproject.toml b/pyproject.toml index 1f1f4c0..265aa8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,31 @@ -[tool.poetry] +[project] name = "patternutils" -version = "0.0.12" description = "Combine regular expressions with template engines in a powerful matter." -authors = ["Dennis Fink "] -license = "GPL-3.0-or-later" +version = "0.0.13" +authors = [ + {name = "Dennis Fink", email = "dennis.fink@c3l.lu"}, +] +license = {text = "GPL-3.0-or-later"} +requires-python = ">=3.9, <4" +dependencies = [ + "click >=8.0.3, <9.0.0", +] + +[project.urls] repository = "https://projects.metalgamer.eu/patternutils" -[tool.poetry.scripts] +[project.optional-dependencies] +jinja2 = [ + "Jinja2 >=3.0.3, <4.0.0", +] +pygments = [ + "Pygments >=2.10.0, <3.0.0", +] +prss = [ + "feedparser >=6.0.8, <7.0.0", +] + +[project.scripts] pmatch = "patternutils.commands.pmatch:pmatch" targs = "patternutils.commands.targs:targs" tmv = "patternutils.commands.tmv:tmv" @@ -15,24 +34,21 @@ patterncfg = "patternutils.commands.patterncfg:patterncfg" prss = "patternutils.commands.prss:prss" pjson = "patternutils.commands.pjson:pjson" -[tool.poetry.dependencies] -python = ">=3.9,<4" -click = "^8.0.3" -Jinja2 = {version = "^3.0.3", optional = true} -Pygments = {version = "^2.10.0", optional = true} -feedparser = {version = "^6.0.8", optional = true} +[dependency-groups] +dev = [ + "mypy>=1.11.2,<2.0.0", + "black >=24.8.0, <25.0.0", + "isort >=5.10.1, >=5.10.1", + "vermin >=1.3.2, <2.0.0", +] -[tool.poetry.dev-dependencies] -mypy = "^0.930" -black = "^21.12b0" -isort = "^5.10.1" -vermin = "^1.3.2" +[build-system] +requires = ["pdm-backend"] +build-backend = "pdm.backend" -[tool.poetry.extras] -jinja2 = ["Jinja2"] -pygments = ["Pygments"] -prss = ["feedparser"] -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +[tool.pdm.build] +includes = [] + +[tool.uv] +default-groups = [] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..f0689ba --- /dev/null +++ b/uv.lock @@ -0,0 +1,372 @@ +version = 1 +requires-python = ">=3.9, <4" + +[[package]] +name = "black" +version = "24.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, + { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, + { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, + { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, + { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, + { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, + { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, + { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, + { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, + { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, + { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, + { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, + { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, + { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, + { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, + { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, + { url = "https://files.pythonhosted.org/packages/fe/02/f408c804e0ee78c367dcea0a01aedde4f1712af93b8b6e60df981e0228c7/black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", size = 1622516 }, + { url = "https://files.pythonhosted.org/packages/f8/b9/9b706ed2f55bfb28b436225a9c57da35990c9005b90b8c91f03924454ad7/black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", size = 1456181 }, + { url = "https://files.pythonhosted.org/packages/0a/1c/314d7f17434a5375682ad097f6f4cc0e3f414f3c95a9b1bb4df14a0f11f9/black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", size = 1752801 }, + { url = "https://files.pythonhosted.org/packages/39/a7/20e5cd9237d28ad0b31438de5d9f01c8b99814576f4c0cda1edd62caf4b0/black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", size = 1413626 }, + { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "feedparser" +version = "6.0.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sgmllib3k" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/aa/7af346ebeb42a76bf108027fe7f3328bb4e57a3a96e53e21fd9ef9dd6dd0/feedparser-6.0.11.tar.gz", hash = "sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5", size = 286197 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/d4/8c31aad9cc18f451c49f7f9cfb5799dadffc88177f7917bc90a66459b1d7/feedparser-6.0.11-py3-none-any.whl", hash = "sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45", size = 81343 }, +] + +[[package]] +name = "isort" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/28/b382d1656ac0ee4cef4bf579b13f9c6c813bff8a5cb5996669592c8c75fa/isort-6.0.0.tar.gz", hash = "sha256:75d9d8a1438a9432a7d7b54f2d3b45cad9a4a0fdba43617d9873379704a8bdf1", size = 828356 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c7/d6017f09ae5b1206fbe531f7af3b6dac1f67aedcbd2e79f3b386c27955d6/isort-6.0.0-py3-none-any.whl", hash = "sha256:567954102bb47bb12e0fae62606570faacddd441e45683968c8d1734fb1af892", size = 94053 }, +] + +[[package]] +name = "jinja2" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, + { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, + { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, + { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, + { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, + { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, + { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, + { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, + { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, + { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, + { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 }, + { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 }, + { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 }, + { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 }, + { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826 }, + { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 }, + { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219 }, + { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 }, + { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063 }, + { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506 }, +] + +[[package]] +name = "mypy" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433 }, + { url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472 }, + { url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424 }, + { url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450 }, + { url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765 }, + { url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701 }, + { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338 }, + { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540 }, + { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051 }, + { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751 }, + { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783 }, + { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618 }, + { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981 }, + { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175 }, + { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675 }, + { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020 }, + { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582 }, + { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614 }, + { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592 }, + { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611 }, + { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443 }, + { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541 }, + { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348 }, + { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648 }, + { url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129 }, + { url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335 }, + { url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935 }, + { url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827 }, + { url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924 }, + { url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176 }, + { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + +[[package]] +name = "patternutils" +version = "0.0.13" +source = { editable = "." } +dependencies = [ + { name = "click" }, +] + +[package.optional-dependencies] +jinja2 = [ + { name = "jinja2" }, +] +pmediainfo = [ + { name = "pymediainfo" }, +] +prss = [ + { name = "feedparser" }, +] +pygments = [ + { name = "pygments" }, +] + +[package.dev-dependencies] +dev = [ + { name = "black" }, + { name = "isort" }, + { name = "mypy" }, + { name = "vermin" }, +] + +[package.metadata] +requires-dist = [ + { name = "click", specifier = ">=8.0.3,<9.0.0" }, + { name = "feedparser", marker = "extra == 'prss'", specifier = ">=6.0.8,<7.0.0" }, + { name = "jinja2", marker = "extra == 'jinja2'", specifier = ">=3.0.3,<4.0.0" }, + { name = "pygments", marker = "extra == 'pygments'", specifier = ">=2.10.0,<3.0.0" }, + { name = "pymediainfo", marker = "extra == 'pmediainfo'", specifier = ">=6.1.0,<7.0.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "black", specifier = ">=24.8.0,<25.0.0" }, + { name = "isort", specifier = ">=5.10.1,>=5.10.1" }, + { name = "mypy", specifier = ">=1.11.2,<2.0.0" }, + { name = "vermin", specifier = ">=1.3.2,<2.0.0" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, +] + +[[package]] +name = "pymediainfo" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/ed/a02b18943f9162644f90354fe6445410e942c857dd21ded758f630ba41c0/pymediainfo-6.1.0.tar.gz", hash = "sha256:186a0b41a94524f0984d085ca6b945c79a254465b7097f2560dc0c04e8d1d8a5", size = 446466 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/47/675bac72d4ab5031f69179b1b8e617a57f766ba063b724a82023da06b9c9/pymediainfo-6.1.0-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:69d5d3cac056c24a68a1129216aec82a222e804a35f88567c08585e8ae7ef2b3", size = 6322766 }, + { url = "https://files.pythonhosted.org/packages/62/13/e3938e187a0c48057ffecc031d473b5739d13056d3eefb8b14b7652c27e1/pymediainfo-6.1.0-py3-none-win32.whl", hash = "sha256:19e6baeca3db71f12ed568f056de899fd02f380990fb10f43a26c32b67362dd3", size = 2762429 }, + { url = "https://files.pythonhosted.org/packages/61/36/369234e2f568e11ed3195292cd89c60e7444346eb1dd25bf5d996dc5d78a/pymediainfo-6.1.0-py3-none-win_amd64.whl", hash = "sha256:f3f6bad666c65ac993dd8d64f45a2b26ba2acd50f9875f74cebb624dbf2f8da0", size = 2963468 }, +] + +[[package]] +name = "sgmllib3k" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/bd/3704a8c3e0942d711c1299ebf7b9091930adae6675d7c8f476a7ce48653c/sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9", size = 5750 } + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "vermin" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/26/7b871396c33006c445c25ef7da605ecbd6cef830d577b496d2b73a554f9d/vermin-1.6.0.tar.gz", hash = "sha256:6266ca02f55d1c2aa189a610017c132eb2d1934f09e72a955b1eb3820ee6d4ef", size = 93181 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/98/1a2ca43e6d646421eea16ec19977e2e6d1ea9079bd9d873bfae513d43f1c/vermin-1.6.0-py2.py3-none-any.whl", hash = "sha256:f1fa9ee40f59983dc40e0477eb2b1fa8061a3df4c3b2bcf349add462a5610efb", size = 90845 }, +] -- cgit v1.3.1 From 3b28310412b7d8e38a91c81351e6b2ee61065fda Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Wed, 5 Mar 2025 08:13:23 +0100 Subject: Add pmediainfo --- patternutils/commands/pmediainfo.py | 98 +++++++++++++++++++++++++++++++++++++ pyproject.toml | 4 ++ 2 files changed, 102 insertions(+) create mode 100644 patternutils/commands/pmediainfo.py diff --git a/patternutils/commands/pmediainfo.py b/patternutils/commands/pmediainfo.py new file mode 100644 index 0000000..0fa7b18 --- /dev/null +++ b/patternutils/commands/pmediainfo.py @@ -0,0 +1,98 @@ +import functools +import itertools +import os.path +from typing import Any, Generator, Iterator, Optional + +import click +from pymediainfo import MediaInfo + +from .. import config +from .. import match as mat +from .. import utils + + +def apply_mediainfo( + walk_function: Iterator[os.DirEntry[str]], +) -> Generator[Optional[dict[str, Any]], None, None]: + for f in walk_function: + media_info_raw = MediaInfo.parse(os.path.abspath(f)) + if len(media_info_raw.tracks) <= 1: + click.secho(f"{f.name} cannot be parsed by mediainfo", fg="red", err=True) + yield None + else: + media_info = media_info_raw.to_data() + media_info["_path"] = f.path + media_info["_name"] = f.name + media_info["_abspath"] = os.path.abspath(f.path) + media_info["_realpath"] = os.path.realpath(f.path) + media_info["_relpath"] = os.path.relpath(f.path) + yield media_info + + +@click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) +@click.option("-d", "--directory", multiple=True, default=["./"]) +@click.option( + "-r", + "--recursive", + is_flag=True, + default=False, + help="search directories recursively", +) +@click.option( + "--abort-on-unparseable", + is_flag=True, + default=False, + help="exit if a file cannot be parsed by mediainfo", +) +@click.option( + "--stream", + is_flag=True, + default=False, + help="Output a stream of objects instead a list of objects", +) +@click.option( + "--human-readable", + is_flag=True, + default=False, + help="output the JSON in a human readable format", +) +@click.option( + "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" +) +@click.version_option() +def pmediainfo( + directory: list[str], + recursive: bool, + abort_on_unparseable: bool, + stream: bool, + human_readable: bool, + verbose: bool, +) -> None: + # Monkey patch walk function to include commandline options + walk_function = functools.partial( + utils.walk, recursive=recursive, match_directories=False + ) + new_walk = itertools.chain.from_iterable(map(walk_function, directory)) + + has_unparseable_files = False + parsed_data = [] + + for media_info in apply_mediainfo(new_walk): + if media_info is None: + has_unparseable_files = True + if stream and abort_on_unparseable: + raise SystemExit + else: + if stream: + click.echo(utils.json_dumps(media_info, human_readable)) + else: + parsed_data.append(media_info) + + if not stream: + if has_unparseable_files and abort_on_unparseable: + raise SystemExit + click.echo(utils.json_dumps(parsed_data, human_readable)) + + +if __name__ == "__main__": + pmediainfo() diff --git a/pyproject.toml b/pyproject.toml index 265aa8c..f6942c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,9 @@ pygments = [ prss = [ "feedparser >=6.0.8, <7.0.0", ] +pmediainfo = [ + "pymediainfo >=6.1.0, <7.0.0", +] [project.scripts] pmatch = "patternutils.commands.pmatch:pmatch" @@ -33,6 +36,7 @@ tln = "patternutils.commands.tln:tln" patterncfg = "patternutils.commands.patterncfg:patterncfg" prss = "patternutils.commands.prss:prss" pjson = "patternutils.commands.pjson:pjson" +pmediainfo = "patternutils.commands.pmediainfo:pmediainfo" [dependency-groups] dev = [ -- cgit v1.3.1 From 2f6dddf66e028121c18ac02fe78131982f3e3712 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Wed, 5 Mar 2025 08:23:50 +0100 Subject: Fix some typing --- patternutils/commands/pmediainfo.py | 2 +- patternutils/commands/targs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/patternutils/commands/pmediainfo.py b/patternutils/commands/pmediainfo.py index 0fa7b18..d22bce3 100644 --- a/patternutils/commands/pmediainfo.py +++ b/patternutils/commands/pmediainfo.py @@ -4,7 +4,7 @@ import os.path from typing import Any, Generator, Iterator, Optional import click -from pymediainfo import MediaInfo +from pymediainfo import MediaInfo # type: ignore from .. import config from .. import match as mat diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index a88bd71..2df7968 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -13,7 +13,7 @@ from .. import config, template, utils def run_command( command: str, - run: Callable[..., None], + run: functools.partial[subprocess.CompletedProcess[str]] | Callable[..., None], shell: bool, ) -> None: run(shlex.split(command) if not shell else command) -- cgit v1.3.1 From 571514596481db0f6bff11613ee47cab5290a7d4 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Thu, 6 Mar 2025 09:01:31 +0100 Subject: Update typing --- patternutils/commands/pjson.py | 10 ++++++---- patternutils/commands/targs.py | 11 ++++++----- patternutils/commands/tln.py | 13 +++++++++---- patternutils/commands/tmv.py | 14 +++++++++----- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/patternutils/commands/pjson.py b/patternutils/commands/pjson.py index 12469ba..cbc87c9 100644 --- a/patternutils/commands/pjson.py +++ b/patternutils/commands/pjson.py @@ -1,6 +1,7 @@ import json import re -from typing import Pattern +from collections.abc import Iterable +from typing import Any, Pattern, TextIO import click @@ -67,7 +68,7 @@ def apply_regex( def pjson( key: str, regex_pattern: str, - read_from: click.File, + read_from: TextIO, stream: bool, abort_on_no_key: bool, abort_on_no_match: bool, @@ -84,10 +85,11 @@ def pjson( click.secho(e.msg, fg="red", err=True) raise SystemExit + data: Iterable[dict[str, Any]] if stream: - data = map(utils.json_loads, read_from) # type: ignore + data = map(utils.json_loads, read_from) else: - data = utils.json_loads(read_from.read()) # type: ignore + data = utils.json_loads(read_from.read()) matches = [] diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index 2df7968..a1a159b 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -4,7 +4,8 @@ import multiprocessing import os import shlex import subprocess -from typing import Callable +from collections.abc import Iterable +from typing import Any, Callable, TextIO import click @@ -75,7 +76,7 @@ def run_command( @click.argument("command") def targs( command: str, - read_from: click.File, + read_from: TextIO, shell: bool, template_engine: template.TemplateEngines, max_procs: int, @@ -93,11 +94,11 @@ def targs( --stream option is used), which are then supplied to the templating engine, to generate the command to run. """ - + data: Iterable[dict[str, Any]] if stream: - data = map(utils.json_loads, read_from) # type: ignore + data = map(utils.json_loads, read_from) else: - data = utils.json_loads(read_from.read()) # type: ignore + data = utils.json_loads(read_from.read()) if use_predefined_template: try: diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index ece5b75..8d58342 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -1,6 +1,8 @@ import json import os import os.path +from collections.abc import Iterable +from typing import Any, TextIO import click @@ -93,7 +95,7 @@ def tln( symbolic: bool, template_engine: template.TemplateEngines, use_predefined_template: bool, - read_from: click.File, + read_from: TextIO, key: str, stream: bool, abort_on_path_exist: bool, @@ -101,14 +103,17 @@ def tln( verbose: bool, ) -> None: + data: Iterable[dict[str, Any]] if stream: - data = map(utils.json_loads, read_from) # type: ignore + data = map(utils.json_loads, read_from) else: - data = utils.json_loads(read_from.read()) # type: ignore + data = utils.json_loads(read_from.read()) if use_predefined_template: try: - output_pattern, template_engine = config.load_template(output_pattern, "tln") + output_pattern, template_engine = config.load_template( + output_pattern, "tln" + ) except FileNotFoundError: click.secho(f"Template {output_pattern} not found!", fg="red", err=True) raise SystemExit diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index 6ce45ed..0ddbbd2 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -1,6 +1,8 @@ import json import os.path import shutil +from collections.abc import Iterable +from typing import Any, TextIO import click @@ -83,13 +85,12 @@ def tmv( template_engine: template.TemplateEngines, abort_on_path_exist: bool, use_predefined_template: bool, - read_from: click.File, + read_from: TextIO, key: str, stream: bool, dry_run: bool, verbose: bool, ) -> None: - """Rename files based on the OUTPUT_PATTERN. It reads in a JSON list containing objects or a stream of objects (if the @@ -99,14 +100,17 @@ def tmv( generate the new filename. """ + data: Iterable[dict[str, Any]] if stream: - data = map(utils.json_loads, read_from) # type: ignore + data = map(utils.json_loads, read_from) else: - data = utils.json_loads(read_from.read()) # type: ignore + data = utils.json_loads(read_from.read()) if use_predefined_template: try: - output_pattern, template_engine = config.load_template(output_pattern, "tmv") + output_pattern, template_engine = config.load_template( + output_pattern, "tmv" + ) except FileNotFoundError: click.secho(f"Template {output_pattern} not found!", fg="red", err=True) raise SystemExit -- cgit v1.3.1 From e6f7cc1fc6fae024e2629c27f33b4faf9147b531 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Thu, 6 Mar 2025 09:01:43 +0100 Subject: Update dependencies and typing of pmediainfo --- patternutils/commands/pmediainfo.py | 2 +- pyproject.toml | 20 ++--- uv.lock | 164 ++++++++---------------------------- 3 files changed, 44 insertions(+), 142 deletions(-) diff --git a/patternutils/commands/pmediainfo.py b/patternutils/commands/pmediainfo.py index d22bce3..0fa7b18 100644 --- a/patternutils/commands/pmediainfo.py +++ b/patternutils/commands/pmediainfo.py @@ -4,7 +4,7 @@ import os.path from typing import Any, Generator, Iterator, Optional import click -from pymediainfo import MediaInfo # type: ignore +from pymediainfo import MediaInfo from .. import config from .. import match as mat diff --git a/pyproject.toml b/pyproject.toml index f6942c2..9df713e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,9 +6,9 @@ authors = [ {name = "Dennis Fink", email = "dennis.fink@c3l.lu"}, ] license = {text = "GPL-3.0-or-later"} -requires-python = ">=3.9, <4" +requires-python = ">=3.12, <4" dependencies = [ - "click >=8.0.3, <9.0.0", + "click >=8.1.8, <9.0.0", ] [project.urls] @@ -16,16 +16,16 @@ repository = "https://projects.metalgamer.eu/patternutils" [project.optional-dependencies] jinja2 = [ - "Jinja2 >=3.0.3, <4.0.0", + "Jinja2 >=3.1.5, <4.0.0", ] pygments = [ - "Pygments >=2.10.0, <3.0.0", + "Pygments >=2.19.1, <3.0.0", ] prss = [ - "feedparser >=6.0.8, <7.0.0", + "feedparser >=6.0.11, <7.0.0", ] pmediainfo = [ - "pymediainfo >=6.1.0, <7.0.0", + "pymediainfo >=7.0.1, <8.0.0", ] [project.scripts] @@ -40,10 +40,10 @@ pmediainfo = "patternutils.commands.pmediainfo:pmediainfo" [dependency-groups] dev = [ - "mypy>=1.11.2,<2.0.0", - "black >=24.8.0, <25.0.0", - "isort >=5.10.1, >=5.10.1", - "vermin >=1.3.2, <2.0.0", + "mypy >=1.15.0, <2.0.0", + "black >=25.1.0, <26.0.0", + "isort >=6.0.1, <7.0.0", + "vermin >=1.6.0, <2.0.0", ] [build-system] diff --git a/uv.lock b/uv.lock index f0689ba..b170061 100644 --- a/uv.lock +++ b/uv.lock @@ -1,9 +1,10 @@ version = 1 -requires-python = ">=3.9, <4" +revision = 1 +requires-python = ">=3.12, <4" [[package]] name = "black" -version = "24.10.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -11,32 +12,18 @@ dependencies = [ { name = "packaging" }, { name = "pathspec" }, { name = "platformdirs" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } +sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, - { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, - { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, - { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, - { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, - { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, - { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, - { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, - { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, - { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, - { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, - { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, - { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, - { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, - { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, - { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, - { url = "https://files.pythonhosted.org/packages/fe/02/f408c804e0ee78c367dcea0a01aedde4f1712af93b8b6e60df981e0228c7/black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", size = 1622516 }, - { url = "https://files.pythonhosted.org/packages/f8/b9/9b706ed2f55bfb28b436225a9c57da35990c9005b90b8c91f03924454ad7/black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", size = 1456181 }, - { url = "https://files.pythonhosted.org/packages/0a/1c/314d7f17434a5375682ad097f6f4cc0e3f414f3c95a9b1bb4df14a0f11f9/black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", size = 1752801 }, - { url = "https://files.pythonhosted.org/packages/39/a7/20e5cd9237d28ad0b31438de5d9f01c8b99814576f4c0cda1edd62caf4b0/black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", size = 1413626 }, - { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, + { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988 }, + { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985 }, + { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816 }, + { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860 }, + { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673 }, + { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190 }, + { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926 }, + { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613 }, + { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] [[package]] @@ -74,11 +61,11 @@ wheels = [ [[package]] name = "isort" -version = "6.0.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/28/b382d1656ac0ee4cef4bf579b13f9c6c813bff8a5cb5996669592c8c75fa/isort-6.0.0.tar.gz", hash = "sha256:75d9d8a1438a9432a7d7b54f2d3b45cad9a4a0fdba43617d9873379704a8bdf1", size = 828356 } +sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c7/d6017f09ae5b1206fbe531f7af3b6dac1f67aedcbd2e79f3b386c27955d6/isort-6.0.0-py3-none-any.whl", hash = "sha256:567954102bb47bb12e0fae62606570faacddd441e45683968c8d1734fb1af892", size = 94053 }, + { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186 }, ] [[package]] @@ -99,26 +86,6 @@ version = "3.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, @@ -149,16 +116,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, - { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 }, - { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 }, - { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 }, - { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 }, - { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826 }, - { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 }, - { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219 }, - { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 }, - { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063 }, - { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506 }, ] [[package]] @@ -167,23 +124,10 @@ version = "1.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717 } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433 }, - { url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472 }, - { url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424 }, - { url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450 }, - { url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765 }, - { url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701 }, - { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338 }, - { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540 }, - { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051 }, - { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751 }, - { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783 }, - { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618 }, { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981 }, { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175 }, { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675 }, @@ -196,12 +140,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541 }, { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348 }, { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648 }, - { url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129 }, - { url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335 }, - { url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935 }, - { url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827 }, - { url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924 }, - { url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176 }, { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777 }, ] @@ -264,19 +202,20 @@ dev = [ [package.metadata] requires-dist = [ - { name = "click", specifier = ">=8.0.3,<9.0.0" }, - { name = "feedparser", marker = "extra == 'prss'", specifier = ">=6.0.8,<7.0.0" }, - { name = "jinja2", marker = "extra == 'jinja2'", specifier = ">=3.0.3,<4.0.0" }, - { name = "pygments", marker = "extra == 'pygments'", specifier = ">=2.10.0,<3.0.0" }, - { name = "pymediainfo", marker = "extra == 'pmediainfo'", specifier = ">=6.1.0,<7.0.0" }, + { name = "click", specifier = ">=8.1.8,<9.0.0" }, + { name = "feedparser", marker = "extra == 'prss'", specifier = ">=6.0.11,<7.0.0" }, + { name = "jinja2", marker = "extra == 'jinja2'", specifier = ">=3.1.5,<4.0.0" }, + { name = "pygments", marker = "extra == 'pygments'", specifier = ">=2.19.1,<3.0.0" }, + { name = "pymediainfo", marker = "extra == 'pmediainfo'", specifier = ">=7.0.1,<8.0.0" }, ] +provides-extras = ["jinja2", "pygments", "prss", "pmediainfo"] [package.metadata.requires-dev] dev = [ - { name = "black", specifier = ">=24.8.0,<25.0.0" }, - { name = "isort", specifier = ">=5.10.1,>=5.10.1" }, - { name = "mypy", specifier = ">=1.11.2,<2.0.0" }, - { name = "vermin", specifier = ">=1.3.2,<2.0.0" }, + { name = "black", specifier = ">=25.1.0,<26.0.0" }, + { name = "isort", specifier = ">=6.0.1,<7.0.0" }, + { name = "mypy", specifier = ">=1.15.0,<2.0.0" }, + { name = "vermin", specifier = ">=1.6.0,<2.0.0" }, ] [[package]] @@ -299,13 +238,15 @@ wheels = [ [[package]] name = "pymediainfo" -version = "6.1.0" +version = "7.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/ed/a02b18943f9162644f90354fe6445410e942c857dd21ded758f630ba41c0/pymediainfo-6.1.0.tar.gz", hash = "sha256:186a0b41a94524f0984d085ca6b945c79a254465b7097f2560dc0c04e8d1d8a5", size = 446466 } +sdist = { url = "https://files.pythonhosted.org/packages/4d/80/80a6fb21005b81e30f6193d45cba13857df09f5d483e0551fa6fbb3aaeed/pymediainfo-7.0.1.tar.gz", hash = "sha256:0d5df59ecc615e24c56f303b8f651579c6accab7265715e5d429186d7ba21514", size = 441563 } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/47/675bac72d4ab5031f69179b1b8e617a57f766ba063b724a82023da06b9c9/pymediainfo-6.1.0-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:69d5d3cac056c24a68a1129216aec82a222e804a35f88567c08585e8ae7ef2b3", size = 6322766 }, - { url = "https://files.pythonhosted.org/packages/62/13/e3938e187a0c48057ffecc031d473b5739d13056d3eefb8b14b7652c27e1/pymediainfo-6.1.0-py3-none-win32.whl", hash = "sha256:19e6baeca3db71f12ed568f056de899fd02f380990fb10f43a26c32b67362dd3", size = 2762429 }, - { url = "https://files.pythonhosted.org/packages/61/36/369234e2f568e11ed3195292cd89c60e7444346eb1dd25bf5d996dc5d78a/pymediainfo-6.1.0-py3-none-win_amd64.whl", hash = "sha256:f3f6bad666c65ac993dd8d64f45a2b26ba2acd50f9875f74cebb624dbf2f8da0", size = 2963468 }, + { url = "https://files.pythonhosted.org/packages/a6/4a/d895646df3d3ff617b54d7f06a02ed9d6f5b86673030a543927310e0f7ed/pymediainfo-7.0.1-py3-none-macosx_10_10_universal2.whl", hash = "sha256:286f3bf6299be0997093254e0f371855bc5cf2aaf8641d19455a011e3ee3a84d", size = 6983332 }, + { url = "https://files.pythonhosted.org/packages/77/df/bc6b5a08e908c64a81f6ff169716d408ce7380ceff44e1eceb095f49e0dc/pymediainfo-7.0.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:3648e2379fa67bd02433d1e28c707df3a53834dd480680615a9fefd2266f1182", size = 5768082 }, + { url = "https://files.pythonhosted.org/packages/02/10/a9bc1446a48d3a15940eb1af79a71978f368f27e2cc86f9ec3ec2d206a20/pymediainfo-7.0.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:cde98112f1ce486589b17a12e5da42085faea996224f7c67fa45b8c1dca719c6", size = 6001553 }, + { url = "https://files.pythonhosted.org/packages/ed/7f/c48f8514cb60c9ff9be81b6f383e73e66c7461ef854a1b62628e3c823f13/pymediainfo-7.0.1-py3-none-win32.whl", hash = "sha256:01bcaf82b72cefbf4b96f13b2547e1b2e0e734bab7173d7c33f7f01acc07c98b", size = 3125046 }, + { url = "https://files.pythonhosted.org/packages/e7/26/9d50c2a330541bc36c0ea7ce29eeff5b0c35c2624139660df8bcfa9ae3ce/pymediainfo-7.0.1-py3-none-win_amd64.whl", hash = "sha256:13224fa7590e198763b8baf072e704ea81d334e71aa32a469091460e243893c7", size = 3271232 }, ] [[package]] @@ -314,45 +255,6 @@ version = "1.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9e/bd/3704a8c3e0942d711c1299ebf7b9091930adae6675d7c8f476a7ce48653c/sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9", size = 5750 } -[[package]] -name = "tomli" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, - { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, - { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, - { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, - { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, - { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, - { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, - { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, - { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, - { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, - { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, - { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, - { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, - { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, - { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, - { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, - { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, - { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, - { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, - { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, - { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, - { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, - { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, - { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, - { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, - { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, - { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, - { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, - { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, - { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, - { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, -] - [[package]] name = "typing-extensions" version = "4.12.2" -- cgit v1.3.1 From dbdb615125d2bcd8fe33a67b6851e5a0ee36fbcf Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 14:51:23 +0200 Subject: Better error handling --- patternutils/commands/patterncfg.py | 83 ++++++++++++++++++++----------------- patternutils/commands/pmatch.py | 24 +++++++---- patternutils/commands/targs.py | 18 ++++---- patternutils/commands/tmv.py | 22 ++++++---- patternutils/config.py | 2 +- patternutils/match.py | 2 +- patternutils/template.py | 2 +- patternutils/utils.py | 8 ++-- 8 files changed, 91 insertions(+), 70 deletions(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 6844efc..2d1fd4f 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -49,7 +49,7 @@ def list() -> None: fg="red", err=True, ) - raise SystemExit + raise SystemExit(1) @patterncfg.command(name="add", help="add new template file") @@ -87,19 +87,23 @@ def remove(command: Optional[config.CommandNames], name: str) -> None: files = config.find_templates(name, command) if not files: - click.secho("No files found!", fg="red", err=True) - raise SystemExit - elif len(files) != 1: click.secho( - "Multiple files found! Please specify the command from which to remove the file.", + f"No matching template files found for '{name}'.", fg="red", err=True + ) + + raise SystemExit(1) + + if len(files) > 1: + click.secho( + "Multiple files found! Please specify the command to remove the correct file.", fg="red", err=True, ) for f in files: click.secho(f, fg="red", err=True) - raise SystemExit - else: - os.remove(files[0]) + raise SystemExit(1) + + os.remove(files[0]) @patterncfg.command(name="view", help="view template file") @@ -121,41 +125,43 @@ def view(name: str, command: config.CommandNames, color: bool) -> None: files = config.find_templates(name, command) if not files: - click.secho("No files found!", fg="red", err=True) - raise SystemExit - elif len(files) != 1: click.secho( - "Multiple files found! Please specify the command from which to view the file.", + f"No matching template files found for '{name}'.", fg="red", err=True + ) + raise SystemExit(1) + + if len(files) > 1: + click.secho( + "Multiple files found! Please specify the command to view the correct file.", fg="red", err=True, ) for f in files: click.secho(f, fg="red", err=True) - raise SystemExit - else: - filename = files[0] + raise SystemExit(1) + + filename = files[0] try: with open(filename, encoding="utf-8") as fd: text = fd.read() except FileNotFoundError: - click.secho("File not found!", fg="red", err=True) - raise SystemExit - else: - if color and has_pygments: - if filename.endswith("jinja2"): - lexer = DjangoLexer - else: - lexer = Python3Lexer - text = highlight(text, lexer(), TerminalFormatter()) - elif color and not has_pygments: + click.secho(f"File '{filename}' not found!", fg="red", err=True) + raise SystemExit(1) + + if color: + if not has_pygments: click.secho( - "Pygments is not installed!. Cannot colorize output.", + "Pygments is not installed! Cannot colorize output.", fg="red", err=True, ) - raise SystemExit - click.echo(text[:-1]) + raise SystemExit(1) + + lexer = DjangoLexer if filename.endswith("jinja2") else Python3Lexer + text = highlight(text, lexer(), TerminalFormatter()) + + click.echo(text[:-1]) @patterncfg.command(name="edit", help="edit a template file") @@ -171,18 +177,19 @@ def edit(name: str, command: config.CommandNames) -> None: files = config.find_templates(name, command) if not files: - click.secho("No files found!", fg="red", err=True) - raise SystemExit - elif len(files) != 1: click.secho( - "Multiple files found! Please specify the command from which to edit the file.", + f"No matching template files found for '{name}'.", fg="red", err=True + ) + raise SystemExit(1) + + if len(files) > 1: + click.secho( + "Multiple files found! Please specify the command to edit the correct file.", fg="red", err=True, ) - for f in files: - click.secho(f, fg="red", err=True) - raise SystemExit - else: - filename = files[0] + for file in files: + click.secho(file, fg="red", err=True) + raise SystemExit(1) - click.edit(filename=filename) + click.edit(filename=files[0]) diff --git a/patternutils/commands/pmatch.py b/patternutils/commands/pmatch.py index 44e55b4..166d941 100644 --- a/patternutils/commands/pmatch.py +++ b/patternutils/commands/pmatch.py @@ -23,7 +23,7 @@ def apply_regex( try: match = mat.apply(subject, regex_pattern) except ValueError: - click.secho(f"{subject} did not match", fg="red", err=True) + click.secho(f"'{subject}' did not match!", fg="red", err=True) yield None else: match["_path"] = f.path @@ -103,11 +103,17 @@ def pmatch( try: regex_pattern, _ = config.load_template(regex_pattern, "pmatch") except FileNotFoundError: - click.secho(f"Regex {regex_pattern} not found!", fg="red", err=True) - raise SystemExit + click.secho( + f"Regex pattern '{regex_pattern}' not found!", fg="red", err=True + ) + raise SystemExit(1) except RuntimeError: - click.secho("Multiple files found!", fg="red", err=True) - raise SystemExit + click.secho( + f"Multiple template files found for '{regex_pattern}'!", + fg="red", + err=True, + ) + raise SystemExit(1) try: regex_pattern_c = re.compile(regex_pattern) @@ -115,7 +121,7 @@ def pmatch( if verbose: click.secho("Regular expression could not be compiled!", fg="red", err=True) click.secho(e.msg, fg="red", err=True) - raise SystemExit + raise SystemExit(1) # Monkey patch walk function to include commandline options walk_function = functools.partial( @@ -123,13 +129,13 @@ def pmatch( ) new_walk = itertools.chain.from_iterable(map(walk_function, directory)) - has_invalid_matches = False matches = [] + has_invalid_matches = False for match in apply_regex(new_walk, regex_pattern_c, match_full_path): if match is None: has_invalid_matches = True if stream and abort_on_no_match: - raise SystemExit + raise SystemExit(1) else: if stream: click.echo(utils.json_dumps(match, human_readable)) @@ -138,7 +144,7 @@ def pmatch( if not stream: if has_invalid_matches and abort_on_no_match: - raise SystemExit + raise SystemExit(1) click.echo(utils.json_dumps(matches, human_readable)) diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index a1a159b..c0bfeeb 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -104,17 +104,21 @@ def targs( try: command, template_engine = config.load_template(command, "targs") except FileNotFoundError: - click.secho(f"Command {command} not found!", fg="red", err=True) - raise SystemExit + click.secho(f"Command template '{command}' not found!", fg="red", err=True) + raise SystemExit(1) except RuntimeError: - click.secho("Multiple files found!", fg="red", err=True) - raise SystemExit + click.secho( + f"Multiple template files found for '{command}'!", + fg="red", + err=True, + ) + raise SystemExit(1) try: render = template.get_render_function(command, engine=template_engine) except RuntimeError: - click.secho("jinja2 not installed!", fg="red", err=True) - raise SystemExit + click.secho("Jinja2 not installed!", fg="red", err=True) + raise SystemExit(1) commands = [render(r) for r in data] @@ -125,7 +129,7 @@ def targs( except RuntimeError: click.secho("Your edit is not parseable!", fg="red", err=True) - raise SystemExit + raise SystemExit(1) stdout = subprocess.DEVNULL if redirect_stdout else None stderr = subprocess.DEVNULL if redirect_stderr else None diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index 0ddbbd2..e9c4721 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -112,17 +112,21 @@ def tmv( output_pattern, "tmv" ) except FileNotFoundError: - click.secho(f"Template {output_pattern} not found!", fg="red", err=True) - raise SystemExit + click.secho(f"Template '{output_pattern}' not found!", fg="red", err=True) + raise SystemExit(1) except RuntimeError: - click.secho("Multiple files found!", fg="red", err=True) - raise SystemExit + click.secho( + f"Multiple template files found for '{output_pattern}'!", + fg="red", + err=True, + ) + raise SystemExit(1) try: render = template.get_render_function(output_pattern, engine=template_engine) except RuntimeError: - click.secho("jinja2 not installed!", fg="red", err=True) - raise SystemExit + click.secho("Jinja2 not installed!", fg="red", err=True) + raise SystemExit(1) new_filenames = dict((entry[key], render(**entry)) for entry in data) @@ -132,19 +136,19 @@ def tmv( new_filenames = temporary_filenames except RuntimeError: click.secho("Your edit is not parseable!", fg="red", err=True) - raise SystemExit + raise SystemExit(1) has_existing = False non_existing = {} for old, new in new_filenames.items(): if os.path.exists(new): - click.secho(f"{new} does exist!", fg="red", err=True) + click.secho(f"File '{new}' already exists!", fg="red", err=True) has_existing = True else: non_existing[old] = new if has_existing and abort_on_path_exist: - raise SystemExit + raise SystemExit(1) files_to_move = new_filenames.items() if force else non_existing.items() diff --git a/patternutils/config.py b/patternutils/config.py index 0da5639..2ede863 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -66,7 +66,7 @@ def find_templates( # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.python extension = "(jinja2|python)" else: - raise ValueError(f"{command_name} is not known!") + raise ValueError(f"Unknown command '{command_name}'.") regex = re.compile( os.path.join(CONFIG_PATH, f"{path_sub_regex}", f"{template_name}.{extension}") diff --git a/patternutils/match.py b/patternutils/match.py index fc6a805..6120594 100644 --- a/patternutils/match.py +++ b/patternutils/match.py @@ -7,4 +7,4 @@ def apply(subject: str, regex_pattern: Pattern[str]) -> dict[str, str]: groupdict["_subject"] = subject return groupdict else: - raise ValueError("subject doesn't match regex pattern") + raise ValueError(f"Subject does not match the regex pattern: {subject}") diff --git a/patternutils/template.py b/patternutils/template.py index a05be83..d918e15 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -52,6 +52,6 @@ def get_render_function( env_template = jinja_env.from_string(template) return cast(Callable[..., str], env_template.render) else: - raise RuntimeError("jinja2 not installed!") + raise RuntimeError("Jinja2 is required but not installed!") else: return template.format diff --git a/patternutils/utils.py b/patternutils/utils.py index 88cad88..fed3046 100644 --- a/patternutils/utils.py +++ b/patternutils/utils.py @@ -34,7 +34,7 @@ def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str]]: return None except click.UsageError: click.secho("The editor could not be launced!", fg="red", err=True) - raise SystemExit + raise SystemExit(1) def json_dumps(data: Any, human_readable: bool = False) -> str: @@ -49,9 +49,9 @@ def json_dumps(data: Any, human_readable: bool = False) -> str: def json_loads(data: Any) -> Any: try: return json.loads(data) - except json.JSONDecodeError: - click.secho("JSON not valid!", fg="red", err=True) - raise SystemExit + except json.JSONDecodeError as e: + click.secho(f"Invalid JSON: {e}!", fg="red", err=True) + raise SystemExit(1) def walk( -- cgit v1.3.1 From 7b9bc9a8703fa3fe6687902fe1f3d8ecb74a6b1e Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 14:56:56 +0200 Subject: Better documentation --- patternutils/commands/patterncfg.py | 50 +++++++++++++---------- patternutils/commands/pjson.py | 3 -- patternutils/commands/pmatch.py | 46 +++++++++++++++------ patternutils/commands/pmediainfo.py | 8 ++-- patternutils/commands/prss.py | 10 +++-- patternutils/commands/targs.py | 80 +++++++++++++++++++++++-------------- patternutils/commands/tln.py | 24 ++++++++--- patternutils/commands/tmv.py | 53 +++++++++++++++--------- patternutils/config.py | 48 ++++++++++++++++++---- patternutils/match.py | 12 ++++++ patternutils/template.py | 19 +++++++++ patternutils/utils.py | 71 ++++++++++++++++++++++++++------ 12 files changed, 306 insertions(+), 118 deletions(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 2d1fd4f..3c75711 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -27,44 +27,51 @@ CURRENT_SUPPORTED_PROGRAMS: tuple[config.CommandNames, ...] = ( @click.group(context_settings={"help_option_names": ("-h", "--help", "-?")}) def patterncfg() -> None: + """CLI tool for managing patternutils templates.""" pass -@patterncfg.command(name="init", help="initialize config folders") +@patterncfg.command(name="init", help="Initialize config folders") def init() -> None: - for dir in itertools.chain(CURRENT_SUPPORTED_PROGRAMS, ("globals",)): - os.makedirs(os.path.join(config.CONFIG_PATH, dir), exist_ok=True) + """Creates necessary config directories if they do not exist.""" + for directory in itertools.chain(CURRENT_SUPPORTED_PROGRAMS, ("globals",)): + os.makedirs(os.path.join(config.CONFIG_PATH, directory), exist_ok=True) -@patterncfg.command(name="list", help="list all patternutils template files") +@patterncfg.command(name="list", help="List all patternutils template files") def list() -> None: + """Lists all available template files in the config directory.""" try: - for d in os.listdir(config.CONFIG_PATH): - click.secho(d, fg="blue") - for f in os.listdir(os.path.join(config.CONFIG_PATH, d)): - click.echo(f"└── {f}") + for directory in os.listdir(config.CONFIG_PATH): + click.secho(directory, fg="blue") + for filename in os.listdir(os.path.join(config.CONFIG_PATH, directory)): + click.echo(f"└── {filename}") except FileNotFoundError as e: click.secho( - f"{e.filename} not found! Please run patterncfg init first.", + f"Config directory '{config.CONFIG_PATH}' not found! Run 'patterncfg init' first.", fg="red", err=True, ) raise SystemExit(1) -@patterncfg.command(name="add", help="add new template file") +@patterncfg.command(name="add", help="Add a new template file") @click.option( "-t", "--template-engine", default=None, type=click.Choice(("python", "jinja2")), - help="select the template engine to use. Only applicable for tmv, targs and tln", + help="Select the template engine (only applicable for tmv, targs, tln).", ) @click.argument("command", required=True, type=click.Choice(CURRENT_SUPPORTED_PROGRAMS)) @click.argument("name") def add( - template_engine: Optional[template.TemplateEngines], command: str, name: str + template_engine: Optional[template.TemplateEngines], + command: str, + name: str, ) -> None: + """Creates a new template file for a given command.""" + fileext: template.TemplateEngines | Literal["regex"] | None = template_engine if command == "pmatch": fileext = "regex" @@ -73,17 +80,17 @@ def add( click.edit(filename=filename) -@patterncfg.command(name="remove", help="remove template file") +@patterncfg.command(name="remove", help="Remove a template file") @click.option( "-c", "--command", default=None, type=click.Choice(CURRENT_SUPPORTED_PROGRAMS), - help="select the command from which to remove the file", + help="Specify the command from which to remove the file.", ) @click.argument("name") def remove(command: Optional[config.CommandNames], name: str) -> None: - + """Removes a specified template file.""" files = config.find_templates(name, command) if not files: @@ -106,22 +113,24 @@ def remove(command: Optional[config.CommandNames], name: str) -> None: os.remove(files[0]) -@patterncfg.command(name="view", help="view template file") +@patterncfg.command(name="view", help="View a template file") @click.option( "-c", "--command", default=None, type=click.Choice(CURRENT_SUPPORTED_PROGRAMS), - help="select the command from which to view the file", + help="Specify the command from which to view the file.", ) @click.option( "--color/--no-color", is_flag=True, default=has_pygments, - help="Colorize output using pygments", + help="Colorize output using pygments if available.", ) @click.argument("name") def view(name: str, command: config.CommandNames, color: bool) -> None: + """Displays the contents of a template file.""" + files = config.find_templates(name, command) if not files: @@ -164,16 +173,17 @@ def view(name: str, command: config.CommandNames, color: bool) -> None: click.echo(text[:-1]) -@patterncfg.command(name="edit", help="edit a template file") +@patterncfg.command(name="edit", help="Edit a template file") @click.option( "-c", "--command", default=None, type=click.Choice(CURRENT_SUPPORTED_PROGRAMS), - help="select the command from which to edit the file", + help="Specify the command from which to edit the file.", ) @click.argument("name") def edit(name: str, command: config.CommandNames) -> None: + """Opens a template file in an editor.""" files = config.find_templates(name, command) if not files: diff --git a/patternutils/commands/pjson.py b/patternutils/commands/pjson.py index cbc87c9..de300cb 100644 --- a/patternutils/commands/pjson.py +++ b/patternutils/commands/pjson.py @@ -1,4 +1,3 @@ -import json import re from collections.abc import Iterable from typing import Any, Pattern, TextIO @@ -76,7 +75,6 @@ def pjson( human_readable: bool, verbose: bool, ) -> None: - try: regex_pattern_c = re.compile(regex_pattern) except re.error as e: @@ -97,7 +95,6 @@ def pjson( has_no_match = False has_empty_data = False for line in data: - if not line: has_empty_data = True click.secho(f"{line} has no input.", fg="red", err=True) diff --git a/patternutils/commands/pmatch.py b/patternutils/commands/pmatch.py index 166d941..62fc256 100644 --- a/patternutils/commands/pmatch.py +++ b/patternutils/commands/pmatch.py @@ -7,9 +7,8 @@ from typing import Generator, Iterator, Optional, Pattern import click -from .. import config +from .. import config, utils from .. import match as mat -from .. import utils def apply_regex( @@ -17,9 +16,19 @@ def apply_regex( regex_pattern: Pattern[str], match_full_path: bool, ) -> Generator[Optional[dict[str, str]], None, None]: + """Applies a regex pattern to directory entries and yields matched data. - for f in walk_function: - subject = os.path.abspath(f.path) if match_full_path else f.name + Args: + walk_function: An iterator over directory entries. + regex_pattern: A compiled regex pattern. + match_full_path: Whether to match against full absolute paths. + + Yields: + A dictionary containing match results, or None if no match is found. + """ + + for entry in walk_function: + subject = os.path.abspath(entry.path) if match_full_path else entry.name try: match = mat.apply(subject, regex_pattern) except ValueError: @@ -35,54 +44,64 @@ def apply_regex( @click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) -@click.option("-d", "--directory", multiple=True, default=["./"]) +@click.option( + "-d", + "--directory", + multiple=True, + default=["./"], + help="directories to search. Can be specified multiple times. Default: ./", +) @click.option( "-m", "--match-directories", is_flag=True, default=False, - help="search directory name also for matches", + help="Match on directories as well.", ) @click.option( "-r", "--recursive", is_flag=True, default=False, - help="search directories recursively", + help="Search directories recursively.", ) @click.option( "--abort-on-no-match", is_flag=True, default=False, - help="exit if a name does not match the INPUT_PATTERN", + help="Exit if a name does not match the INPUT_PATTERN.", ) @click.option( "--match-full-path", is_flag=True, default=False, - help="match on full absolute path instead of only the filename", + help="Match on full absolute path instead of only the filename.", ) @click.option( "-p", "--use-predefined-pattern", is_flag=True, default=False, - help="use predefined regex pattern", + help="Use predefined regex pattern.", ) @click.option( "--stream", is_flag=True, default=False, - help="Output a stream of objects instead a list of objects", + help="Output a stream of objects instead a list.", ) @click.option( "--human-readable", is_flag=True, default=False, - help="output the JSON in a human readable format", + help="Output the JSON in a human readable format.", ) @click.option( - "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" + "-v", + "--verbose", + is_flag=True, + default=False, + help="Explain what is being done.", ) @click.version_option() @click.argument("regex-pattern") @@ -98,6 +117,7 @@ def pmatch( human_readable: bool, verbose: bool, ) -> None: + """Match the REGEX_PATTERN against files in specified directories and output JSON.""" if use_predefined_pattern: try: diff --git a/patternutils/commands/pmediainfo.py b/patternutils/commands/pmediainfo.py index 0fa7b18..35f9d4c 100644 --- a/patternutils/commands/pmediainfo.py +++ b/patternutils/commands/pmediainfo.py @@ -6,8 +6,6 @@ from typing import Any, Generator, Iterator, Optional import click from pymediainfo import MediaInfo -from .. import config -from .. import match as mat from .. import utils @@ -57,7 +55,11 @@ def apply_mediainfo( help="output the JSON in a human readable format", ) @click.option( - "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" + "-v", + "--verbose", + is_flag=True, + default=False, + help="explain what is being done", ) @click.version_option() def pmediainfo( diff --git a/patternutils/commands/prss.py b/patternutils/commands/prss.py index 1ec4675..d4232ee 100644 --- a/patternutils/commands/prss.py +++ b/patternutils/commands/prss.py @@ -2,7 +2,7 @@ import functools import itertools import os import os.path -from typing import Any, Generator, Iterator, Optional +from typing import Any, Generator, Optional import click @@ -20,7 +20,6 @@ def match( walk_function: functools.partial[Generator[os.DirEntry[Any], None, None]], directory: list[str], ) -> Generator[Optional[dict[str, str]], None, None]: - direntries = [] filenames = [] @@ -90,7 +89,11 @@ def match( help="output the JSON in a human readable format", ) @click.option( - "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" + "-v", + "--verbose", + is_flag=True, + default=False, + help="explain what is being done", ) @click.version_option() @click.argument("url") @@ -103,7 +106,6 @@ def prss( human_readable: bool, verbose: bool, ) -> None: - try: parsed_feed = feedparser.parse(url) except Exception: diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index c0bfeeb..85acade 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -1,7 +1,5 @@ import functools -import json import multiprocessing -import os import shlex import subprocess from collections.abc import Iterable @@ -17,60 +15,89 @@ def run_command( run: functools.partial[subprocess.CompletedProcess[str]] | Callable[..., None], shell: bool, ) -> None: + """Executes a given command using the provided run function. + + Args: + command: The command string to execute. + run: A callable function for execution (e.g., subprocess.run or print). + shell: Whether to run the command in a shell. + """ run(shlex.split(command) if not shell else command) @click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) -@click.option("--read-from", default="-", type=click.File("r")) @click.option( - "-s", "--shell", is_flag=True, default=False, help="run command in a shell" + "--read-from", + default="-", + type=click.File("r"), + help="Read input from file or stdin.", +) +@click.option( + "-s", + "--shell", + is_flag=True, + default=False, + help="Run command in a shell.", ) @click.option( "-t", "--template-engine", default="python", type=click.Choice(["python", "jinja2"]), - help="select the template engine to use", + help="Select the template engine to use.", +) +@click.option( + "-v", + "--verbose", + is_flag=True, + default=False, + help="Explain what is being done.", ) @click.option( - "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" + "-P", + "--max-procs", + default=1, + type=click.IntRange(min=0, clamp=True), + help="Max parallel processes.", ) -@click.option("-P", "--max-procs", default=1, type=click.IntRange(min=0, clamp=True)) @click.option( "-p", "--use-predefined-template", is_flag=True, default=False, - help="use predefined template", + help="Use a predefined template.", ) @click.option( "--redirect-stdout", is_flag=True, default=False, - help="Redirect stdout to /dev/null", + help="Redirect stdout to /dev/null.", ) @click.option( "--redirect-stderr", is_flag=True, default=False, - help="Redirect stderr to /dev/null", + help="Redirect stderr to /dev/null.", ) @click.option( - "--stream", is_flag=True, default=False, help="Input is a stream of JSON objects" + "--stream", + is_flag=True, + default=False, + help="Input is a stream of JSON objects.", ) @click.option( "-e", "--editor", is_flag=True, default=False, - help="Open an editor before running commands to allow manual changes", + help="Open an editor before running commands to allow manual changes.", ) @click.option( "-n", "--dry-run", is_flag=True, default=False, - help="perform a trial run without actually executing the command", + help="Perform a trial run without executing commands.", ) @click.version_option() @click.argument("command") @@ -126,13 +153,13 @@ def targs( try: if (new_commands := utils.edit(commands)) is not None: commands = list(new_commands.values()) - except RuntimeError: click.secho("Your edit is not parseable!", fg="red", err=True) raise SystemExit(1) stdout = subprocess.DEVNULL if redirect_stdout else None stderr = subprocess.DEVNULL if redirect_stderr else None + patched_subprocess = functools.partial( subprocess.run, shell=shell, @@ -140,27 +167,20 @@ def targs( stderr=stderr, ) - if not dry_run: - patched_run_command = functools.partial( - run_command, - run=patched_subprocess, - shell=shell, - ) - else: - patched_run_command = functools.partial( - run_command, - run=print, - shell=True, - ) + execute_command = functools.partial( + run_command, + run=print if dry_run else patched_subprocess, + shell=True if dry_run else shell, + ) max_procs = utils.max_procs() if max_procs == 0 else max_procs if max_procs == 1: - for r in commands: - patched_run_command(r) + for cmd in commands: + execute_command(cmd) else: - with multiprocessing.Pool(max_procs) as p: - p.map(patched_run_command, commands) + with multiprocessing.Pool(max_procs) as pool: + pool.map(execute_command, commands) if __name__ == "__main__": diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index 8d58342..f76898d 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -1,4 +1,3 @@ -import json import os import os.path from collections.abc import Iterable @@ -56,10 +55,16 @@ def link_file(old_filename: str, new_filename: str, symbolic: bool) -> None: help="select the template engine to use", ) @click.option( - "-k", "--key", default="_abspath", help="select the key to use as the source file" + "-k", + "--key", + default="_abspath", + help="select the key to use as the source file", ) @click.option( - "--stream", is_flag=True, default=False, help="Input is a stream of JSON objects" + "--stream", + is_flag=True, + default=False, + help="Input is a stream of JSON objects", ) @click.option( "-p", @@ -68,7 +73,11 @@ def link_file(old_filename: str, new_filename: str, symbolic: bool) -> None: default=False, help="use predefined template", ) -@click.option("--read-from", default="-", type=click.File("r")) +@click.option( + "--read-from", + default="-", + type=click.File("r"), +) @click.option( "--abort-on-path-exist", is_flag=True, @@ -83,7 +92,11 @@ def link_file(old_filename: str, new_filename: str, symbolic: bool) -> None: help="perform a trial run with no changes made", ) @click.option( - "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" + "-v", + "--verbose", + is_flag=True, + default=False, + help="explain what is being done", ) @click.version_option() @click.argument("output-pattern") @@ -102,7 +115,6 @@ def tln( dry_run: bool, verbose: bool, ) -> None: - data: Iterable[dict[str, Any]] if stream: data = map(utils.json_loads, read_from) diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index e9c4721..4fda28c 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -1,4 +1,3 @@ -import json import os.path import shutil from collections.abc import Iterable @@ -10,7 +9,7 @@ from .. import config, template, utils def move_file(old_filename: str, new_filename: str) -> None: - # Create new directories if needed + """Moves a file to a new location, creating necessary directories if needed.""" dirs = os.path.dirname(new_filename) if dirs: os.makedirs(dirs, exist_ok=True) @@ -24,56 +23,74 @@ def move_file(old_filename: str, new_filename: str) -> None: "--interactive", is_flag=True, default=False, - help="prompt before renaming files", + help="Prompt before renaming files.", ) @click.option( "-e", "--editor", is_flag=True, default=False, - help="Open an editor before renaming files to allow manual changes", + help="Open an editor before renaming files to allow manual changes.", +) +@click.option( + "-f", + "--force", + is_flag=True, + default=False, + help="Force rename, even if a file exists.", ) -@click.option("-f", "--force", is_flag=True, default=False, help="force rename") @click.option( "-t", "--template-engine", default="python", type=click.Choice(["python", "jinja2"]), - help="select the template engine to use", + help="Select the template engine to use.", ) @click.option( - "-k", "--key", default="_abspath", help="select the key to use as the source file" + "-k", + "--key", + default="_abspath", + help="Select the key to use as the source file.", ) @click.option( "-s", "--stream", is_flag=True, default=False, - help="Input is a stream of JSON objects", + help="Read input as stream of JSON objects.", ) @click.option( "-p", "--use-predefined-template", is_flag=True, default=False, - help="use predefined template", + help="Use a predefined template.", +) +@click.option( + "--read-from", + default="-", + type=click.File("r"), + help="Input file (default: stdin)", ) -@click.option("--read-from", default="-", type=click.File("r")) @click.option( "--abort-on-path-exist", is_flag=True, default=False, - help="exit if a renamed path already exists", + help="Exit if a renamed path already exists.", ) @click.option( "-n", "--dry-run", is_flag=True, default=False, - help="perform a trial run with no changes made", + help="Perform a trial run without making changes.", ) @click.option( - "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" + "-v", + "--verbose", + is_flag=True, + default=False, + help="Explain what is being done.", ) @click.version_option() @click.argument("output-pattern") @@ -93,11 +110,11 @@ def tmv( ) -> None: """Rename files based on the OUTPUT_PATTERN. - It reads in a JSON list containing objects or a stream of objects (if the - --stream option is used). The object needs to contain a key, named as - the specified option KEY (default: _abspath), which points to the file to - be moved. The rest of the keys will be supplied to the templating engine to - generate the new filename. + Reads a JSON list containing objects or a stream of JSON objects (if + --stream is used). The object must contain a key (specified via --key, + default: _abspath) that points to the file to be renamed. The rest of the + keys will be supplied to the templating engine to generate the new + filename. """ data: Iterable[dict[str, Any]] diff --git a/patternutils/config.py b/patternutils/config.py index 2ede863..fab41be 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -29,7 +29,20 @@ def load_template( def load_template( template_name: str, command_name: Optional[CommandNames] ) -> tuple[str, TemplateExtensions]: - """Load a template from the config directory.""" + """Load a template from the config directory. + + Args: + template_name: The name of the template file (without extension). + command_name: The command requesting the template. + + Returns: + A tuple containing the template content as a string and its engine type. + + Raises: + FileNotFoundError: If no matching template is found. + RuntimeError: If multiple templates are found for the given name. + ValueError: If the extracted template extension is invalid. + """ files = find_templates(template_name, command_name) if len(files) == 1: @@ -42,14 +55,32 @@ def load_template( raise RuntimeError("Multiple files found!") output_pattern = template_lines.replace("\n", "") - template_engine = cast(TemplateExtensions, os.path.splitext(template_file)[1][1:]) + extension = os.path.splitext(template_file)[1][1:].lower() + if extension not in ("regex", "python", "jinja2"): + raise ValueError( + f"Invalid template extension '{extension}' in '{template_file}'." + ) + + template_engine = cast(TemplateExtensions, extension) return output_pattern, template_engine def find_templates( template_name: str, command_name: Optional[CommandNames] = None ) -> list[str]: + """Finds matching template files based on the template name and command. + + Args: + template_name: The name of the template file (without extension). + command_name: The command requesting the template. + + Returns: + A list of matching template file paths. + + Raises: + ValueError: If `command_name` is invalid. + """ if command_name is None: # CONFIG_PATH/*/TEMPLATE_NAME.* @@ -68,10 +99,11 @@ def find_templates( else: raise ValueError(f"Unknown command '{command_name}'.") - regex = re.compile( - os.path.join(CONFIG_PATH, f"{path_sub_regex}", f"{template_name}.{extension}") + pattern = re.compile( + os.path.join(CONFIG_PATH, path_sub_regex, f"{template_name}.{extension}") ) - - files = filter(regex.search, glob.iglob(os.path.join(CONFIG_PATH, "*", "*"))) - - return list(files) + return [ + file + for file in glob.iglob(os.path.join(CONFIG_PATH, "*", "*")) + if pattern.search(file) + ] diff --git a/patternutils/match.py b/patternutils/match.py index 6120594..9ff49f9 100644 --- a/patternutils/match.py +++ b/patternutils/match.py @@ -2,6 +2,18 @@ from typing import Pattern def apply(subject: str, regex_pattern: Pattern[str]) -> dict[str, str]: + """Applies a regex pattern to a subject string and extracts named groups. + + Args: + subject: The string to be matched. + regex_pattern: A compiled regex pattern. + + Returns: + A dictionary containing matched named groups, including `_subject`. + + Raises: + ValueError: If the subject does not match the regex pattern. + """ if (match := regex_pattern.search(subject)) is not None: groupdict = match.groupdict() groupdict["_subject"] = subject diff --git a/patternutils/template.py b/patternutils/template.py index d918e15..c02b687 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -15,24 +15,31 @@ else: jinja_env = jinja2.Environment() def to_datetime(value: str, format: str = "%Y-%m-%d") -> datetime: + """Converts a string to a datetime object.""" return datetime.strptime(value, format) def format_datetime(value: datetime, format: str = "%Y-%m-%d") -> str: + """Formats a datetime object as a string.""" return value.strftime(format) def to_int(value: str, base: int = 10) -> int: + """Converts a string to an integer.""" return int(value, base=base) def to_float(value: str) -> float: + """Converts a string to a float.""" return float(value) def quote(value: str) -> str: + """Quotes a string safely for shell execution.""" return shlex.quote(value) def splitpath(value: str) -> tuple[str, str]: + """Splits a path into (directory, filename).""" return os.path.split(value) def splitext(value: str) -> tuple[str, str]: + """Splits a file path into (root, extension).""" return os.path.splitext(value) jinja_env.filters["datetime"] = to_datetime @@ -47,6 +54,18 @@ else: def get_render_function( template: str, *, engine: TemplateEngines = "python" ) -> Callable[..., str]: + """Returns a function that renders a template using the specified engine. + + Args: + template: The template string. + engine: The template engine to use ('python' or 'jinja2'). + + Returns: + A function that takes parameters and renders the template. + + Raises: + RuntimeError: If Jinja2 is selected but not installed. + """ if engine == "jinja2": if jinja_feature: env_template = jinja_env.from_string(template) diff --git a/patternutils/utils.py b/patternutils/utils.py index fed3046..85734db 100644 --- a/patternutils/utils.py +++ b/patternutils/utils.py @@ -6,11 +6,20 @@ import click def max_procs() -> int: + """Returns the number of CPU cores available, or 1 if unavailable.""" cpu_count = os.cpu_count() return 1 if cpu_count is None else cpu_count * 2 def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str]]: + """Opens an interactive editor for modifying dictionary or list entries. + + Args: + data: A dictionary (keys are editable) or a list of strings. + + Returns: + A dictionary of modified entries or None if no changes were made. + """ longest = len(max(data, key=len)) @@ -38,15 +47,35 @@ def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str]]: def json_dumps(data: Any, human_readable: bool = False) -> str: - config: dict[str, Any] = ( - {"indent": 4, "sort_keys": True} - if human_readable - else {"separators": (",", ":")} + """Serializes data to JSON with optional human-readable formatting. + + Args: + data: The data to serialize. + human_readable: Whether to pretty-print the JSON. + + Returns: + A JSON string. + """ + return json.dumps( + data, + indent=4 if human_readable else None, + sort_keys=human_readable, + separators=(", ", ": ") if not human_readable else None, ) - return json.dumps(data, **config) def json_loads(data: Any) -> Any: + """Deserializes a JSON string into a Python object. + + Args: + data: A JSON string. + + Returns: + The deserialized Python object. + + Raises: + SystemExit: If the JSON is invalid. + """ try: return json.loads(data) except json.JSONDecodeError as e: @@ -57,11 +86,27 @@ def json_loads(data: Any) -> Any: def walk( directory: str, recursive: bool = False, match_directories: bool = False ) -> Generator[os.DirEntry[str], None, None]: - for entry in os.scandir(directory): - is_dir = entry.is_dir() - if recursive and is_dir: - yield from walk(entry.path, recursive, match_directories) - elif entry.is_file() or (match_directories and is_dir): - yield entry - else: - continue + """Yields directory entries, optionally recursing into subdirectories. + + Args: + directory: The root directory to scan. + recursive: Whether to recurse into subdirectories. + match_directories: Whether to include directories in the results. + + Yields: + os.DirEntry objects matching the criteria. + """ + try: + for entry in os.scandir(directory): + if entry.is_dir(): + if recursive: + yield from walk(entry.path, recursive, match_directories) + if match_directories: + yield entry + elif entry.is_file(): + yield entry + else: + continue + except FileNotFoundError: + click.secho(f"Directory not found: {directory}", fg="red", err=True) + raise SystemExit(1) -- cgit v1.3.1 From 7f98df02693578f69266e8f2630a50787bc06041 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 14:57:18 +0200 Subject: Simplify find template --- patternutils/config.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/patternutils/config.py b/patternutils/config.py index fab41be..7f67f03 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -45,14 +45,16 @@ def load_template( """ files = find_templates(template_name, command_name) - if len(files) == 1: - template_file = files[0] - with open(template_file, encoding="utf-8") as f: - template_lines = f.read() - elif not files: - raise FileNotFoundError - elif len(files) > 1: - raise RuntimeError("Multiple files found!") + + if not files: + raise FileNotFoundError(f"No template found for '{template_name}'.") + + if len(files) > 1: + raise RuntimeError(f"Multiple template files found for '{template_name}'.") + + template_file = files[0] + with open(template_file, encoding="utf-8") as f: + template_lines = f.read() output_pattern = template_lines.replace("\n", "") extension = os.path.splitext(template_file)[1][1:].lower() -- cgit v1.3.1 From 6062fa5cc245d709c74ec7b6b9e2ed0af3f70224 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 14:58:26 +0200 Subject: Simplify apply regex in pmatch --- patternutils/commands/pmatch.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/patternutils/commands/pmatch.py b/patternutils/commands/pmatch.py index 62fc256..20f71a1 100644 --- a/patternutils/commands/pmatch.py +++ b/patternutils/commands/pmatch.py @@ -34,13 +34,18 @@ def apply_regex( except ValueError: click.secho(f"'{subject}' did not match!", fg="red", err=True) yield None - else: - match["_path"] = f.path - match["_name"] = f.name - match["_abspath"] = os.path.abspath(f.path) - match["_realpath"] = os.path.realpath(f.path) - match["_relpath"] = os.path.relpath(f.path) - yield match + continue + + match.update( + { + "_path": entry.path, + "_name": entry.name, + "_abspath": os.path.abspath(entry.path), + "_realpath": os.path.realpath(entry.path), + "_relpath": os.path.relpath(entry.path), + } + ) + yield match @click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) -- cgit v1.3.1 From fd05c120f5fc0db663c3a9b7a99c0b9c2216cbcb Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 14:58:48 +0200 Subject: Add --abort-on-key-not-found in tmv --- patternutils/commands/tmv.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index 4fda28c..150f67d 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -78,6 +78,12 @@ def move_file(old_filename: str, new_filename: str) -> None: default=False, help="Exit if a renamed path already exists.", ) +@click.option( + "--abort-on-key-not-found", + is_flag=True, + default=False, + help="Exit if the specified key (specified by the --key option) is not found in the input JSON.", +) @click.option( "-n", "--dry-run", @@ -101,6 +107,7 @@ def tmv( force: bool, template_engine: template.TemplateEngines, abort_on_path_exist: bool, + abort_on_key_not_found: bool, use_predefined_template: bool, read_from: TextIO, key: str, @@ -145,7 +152,12 @@ def tmv( click.secho("Jinja2 not installed!", fg="red", err=True) raise SystemExit(1) - new_filenames = dict((entry[key], render(**entry)) for entry in data) + try: + new_filenames = {entry[key]: render(**entry) for entry in data} + except KeyError: + click.secho(f"Key '{key}' not found in input data.", fg="red", err=True) + if abort_on_key_not_found: + raise SystemExit(1) if editor: try: -- cgit v1.3.1 From 42731192deaaf7265fac89bbe62526c6373e9bf4 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 14:59:08 +0200 Subject: Update PKGBUILD --- PKGBUILD/PKGBUILD | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/PKGBUILD/PKGBUILD b/PKGBUILD/PKGBUILD index c4aeba8..c4d66af 100644 --- a/PKGBUILD/PKGBUILD +++ b/PKGBUILD/PKGBUILD @@ -1,26 +1,23 @@ # Maintainer: Dennis Fink pkgname=patternutils -pkgver=0.0.12 +pkgver=0.0.13 pkgrel=2 pkgdesc="Combine regular expressions with template engines in a powerful matter." arch=('any') url="https://projects.metalgamer.eu/patternutils" license=('GPL3') -depends=('python' 'python-click' 'python-jinja' 'python-pygments' 'python-feedparser') -source=('https://download.metalgamer.eu/patternutils/patternutils-0.0.12.tar.gz') -sha512sums=('2d39fce29eda388436f2c11da1df8016436f0441e1c77c53aa1b7fa863e7862073629ee4dfb7d082abea0b70760c2535554fec0a0bfc6cd8674f688c6f37c771') - -prepare() { - sed -i 's/==/>=/g' "$srcdir/$pkgname-$pkgver/setup.py" -} +depends=('python' 'python-click' 'python-jinja' 'python-pygments' 'python-feedparser' 'python-pymediainfo') +makedepends=(python-build python-installer python-wheel) +source=('https://download.metalgamer.eu/patternutils/patternutils-0.0.13.tar.gz') +sha512sums=('b7dd8562a14193bbe04002b0f4073f03a424633ba6effb483fac01c511dcec6fbd092120d9b4b0f728adefe273d21bec4d3cc754ce26c46a5cc06fa1f05b1043') build() { cd "$srcdir/$pkgname-$pkgver" - python setup.py build + python -m build --wheel --no-isolation } package() { cd "$srcdir/$pkgname-$pkgver" - python setup.py install --root="$pkgdir" --optimize=1 + python -m installer --destdir="$pkgdir" dist/*.whl } -- cgit v1.3.1 From 8e3ef3dd8bf34e27881856378502456021ba407a Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 15:36:24 +0200 Subject: Make typing more clear and use an overlay environment for jinja2 to load files from the config folder --- patternutils/commands/patterncfg.py | 29 ++++++++++++---------- patternutils/commands/targs.py | 3 ++- patternutils/commands/tln.py | 3 ++- patternutils/commands/tmv.py | 3 ++- patternutils/config.py | 48 ++++++++++++++++++++++++------------- patternutils/template.py | 23 ++++++++++++++---- patternutils/types.py | 14 +++++++++++ 7 files changed, 86 insertions(+), 37 deletions(-) create mode 100644 patternutils/types.py diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 3c75711..ee71d86 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -1,7 +1,7 @@ import itertools import os import os.path -from typing import Literal, Optional +from typing import Literal, Optional, get_args import click @@ -15,13 +15,16 @@ else: has_pygments = True -from .. import config, template +from .. import config +from ..types import ( + PredefinedCommands, + RegexCommands, + TemplateCommands, + TemplateExtensions, +) -CURRENT_SUPPORTED_PROGRAMS: tuple[config.CommandNames, ...] = ( - "pmatch", - "tmv", - "targs", - "tln", +CURRENT_SUPPORTED_PROGRAMS: tuple[RegexCommands | TemplateCommands, ...] = tuple( + itertools.chain(get_args(RegexCommands), get_args(TemplateCommands)) ) @@ -46,7 +49,7 @@ def list() -> None: click.secho(directory, fg="blue") for filename in os.listdir(os.path.join(config.CONFIG_PATH, directory)): click.echo(f"└── {filename}") - except FileNotFoundError as e: + except FileNotFoundError: click.secho( f"Config directory '{config.CONFIG_PATH}' not found! Run 'patterncfg init' first.", fg="red", @@ -66,13 +69,13 @@ def list() -> None: @click.argument("command", required=True, type=click.Choice(CURRENT_SUPPORTED_PROGRAMS)) @click.argument("name") def add( - template_engine: Optional[template.TemplateEngines], + template_engine: Optional[TemplateExtensions], command: str, name: str, ) -> None: """Creates a new template file for a given command.""" - fileext: template.TemplateEngines | Literal["regex"] | None = template_engine + fileext: TemplateExtensions | Literal["regex"] | None = template_engine if command == "pmatch": fileext = "regex" @@ -89,7 +92,7 @@ def add( help="Specify the command from which to remove the file.", ) @click.argument("name") -def remove(command: Optional[config.CommandNames], name: str) -> None: +def remove(command: Optional[PredefinedCommands], name: str) -> None: """Removes a specified template file.""" files = config.find_templates(name, command) @@ -128,7 +131,7 @@ def remove(command: Optional[config.CommandNames], name: str) -> None: help="Colorize output using pygments if available.", ) @click.argument("name") -def view(name: str, command: config.CommandNames, color: bool) -> None: +def view(name: str, command: PredefinedCommands, color: bool) -> None: """Displays the contents of a template file.""" files = config.find_templates(name, command) @@ -182,7 +185,7 @@ def view(name: str, command: config.CommandNames, color: bool) -> None: help="Specify the command from which to edit the file.", ) @click.argument("name") -def edit(name: str, command: config.CommandNames) -> None: +def edit(name: str, command: PredefinedCommands) -> None: """Opens a template file in an editor.""" files = config.find_templates(name, command) diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index 85acade..8280faa 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -8,6 +8,7 @@ from typing import Any, Callable, TextIO import click from .. import config, template, utils +from ..types import TemplateExtensions def run_command( @@ -105,7 +106,7 @@ def targs( command: str, read_from: TextIO, shell: bool, - template_engine: template.TemplateEngines, + template_engine: TemplateExtensions, max_procs: int, redirect_stdout: bool, redirect_stderr: bool, diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index f76898d..d125f96 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -6,6 +6,7 @@ from typing import Any, TextIO import click from .. import config, template, utils +from ..types import TemplateExtensions def link_file(old_filename: str, new_filename: str, symbolic: bool) -> None: @@ -106,7 +107,7 @@ def tln( editor: bool, force: bool, symbolic: bool, - template_engine: template.TemplateEngines, + template_engine: TemplateExtensions, use_predefined_template: bool, read_from: TextIO, key: str, diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index 150f67d..9198171 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -6,6 +6,7 @@ from typing import Any, TextIO import click from .. import config, template, utils +from ..types import TemplateExtensions def move_file(old_filename: str, new_filename: str) -> None: @@ -105,7 +106,7 @@ def tmv( interactive: bool, editor: bool, force: bool, - template_engine: template.TemplateEngines, + template_engine: TemplateExtensions, abort_on_path_exist: bool, abort_on_key_not_found: bool, use_predefined_template: bool, diff --git a/patternutils/config.py b/patternutils/config.py index 7f67f03..b236ec2 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -1,34 +1,37 @@ import glob import os.path import re -from typing import Literal, Optional, cast, overload +from typing import Optional, cast, get_args, overload import click -TemplateExtensions = Literal["python", "jinja2", "regex"] -CommandNames = Literal["pmatch", "tmv", "targs", "tln"] +from .types import ( + PredefinedCommands, + PredefinedExtensions, + RegexCommands, + RegexExtensions, + TemplateCommands, + TemplateExtensions, +) CONFIG_PATH = click.get_app_dir("patternutils") -REGEX_PROGRAMS = ("pmatch",) -TEMPLATE_PROGRAMS = ("tmv", "targs", "tln") - @overload def load_template( - template_name: str, command_name: Literal["pmatch"] -) -> tuple[str, Literal["regex"]]: ... + template_name: str, command_name: RegexCommands +) -> tuple[str, RegexExtensions]: ... @overload def load_template( - template_name: str, command_name: Literal["tmv", "targs", "tln"] -) -> tuple[str, Literal["python", "jinja2"]]: ... + template_name: str, command_name: TemplateCommands +) -> tuple[str, TemplateExtensions]: ... def load_template( - template_name: str, command_name: Optional[CommandNames] -) -> tuple[str, TemplateExtensions]: + template_name: str, command_name: Optional[PredefinedCommands] +) -> tuple[str, PredefinedExtensions]: """Load a template from the config directory. Args: @@ -69,7 +72,7 @@ def load_template( def find_templates( - template_name: str, command_name: Optional[CommandNames] = None + template_name: str, command_name: Optional[PredefinedCommands] = None ) -> list[str]: """Finds matching template files based on the template name and command. @@ -90,17 +93,28 @@ def find_templates( extension = ".*" else: path_sub_regex = f"(globals|{command_name})" - if command_name in REGEX_PROGRAMS: - extension = "regex" - elif command_name in TEMPLATE_PROGRAMS: + + if command_name in get_args(RegexCommands): + extensions = get_args(RegexExtensions) + elif command_name in get_args(TemplateCommands): # CONFIG_PATH/globals/TEMPLATE_NAME.jinja2 # CONFIG_PATH/globals/TEMPLATE_NAME.python # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.jinja2 # CONFIG_PATH/COMMAND_NAME/TEMPLATE_NAME.python - extension = "(jinja2|python)" + extensions = get_args(TemplateExtensions) else: raise ValueError(f"Unknown command '{command_name}'.") + if len(extensions) > 0: + if len(extensions) > 1: + extension = f"({'|'.join(extensions)})" + else: + extension = extensions[0] + else: + raise ValueError( + f"Could not determine file extension for command '{command_name}'." + ) + pattern = re.compile( os.path.join(CONFIG_PATH, path_sub_regex, f"{template_name}.{extension}") ) diff --git a/patternutils/template.py b/patternutils/template.py index c02b687..86e5a97 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -1,6 +1,7 @@ -from typing import Callable, Literal, cast +from typing import Callable, Optional, cast -TemplateEngines = Literal["python", "jinja2"] +from .config import CONFIG_PATH +from .types import TemplateCommands, TemplateExtensions try: import jinja2 @@ -52,7 +53,10 @@ else: def get_render_function( - template: str, *, engine: TemplateEngines = "python" + template: str, + *, + engine: TemplateExtensions = "python", + command_name: Optional[TemplateCommands] = None, ) -> Callable[..., str]: """Returns a function that renders a template using the specified engine. @@ -68,7 +72,18 @@ def get_render_function( """ if engine == "jinja2": if jinja_feature: - env_template = jinja_env.from_string(template) + if command_name is not None: + jinja_env_overlay = jinja_env.overlay( + loader=jinja2.ChoiceLoader( + [ + jinja2.FileSystemLoader(CONFIG_PATH / command_name), + jinja2.FileSystemLoader(CONFIG_PATH / "globals"), + ] + ) + ) + else: + jinja_env_overlay = jinja_env + env_template = jinja_env_overlay.from_string(template) return cast(Callable[..., str], env_template.render) else: raise RuntimeError("Jinja2 is required but not installed!") diff --git a/patternutils/types.py b/patternutils/types.py new file mode 100644 index 0000000..cf5c8f0 --- /dev/null +++ b/patternutils/types.py @@ -0,0 +1,14 @@ +from typing import Literal + +PlainCommands = Literal["pmediainfo"] + +RegexCommands = Literal["pmatch", "pjson"] +RegexExtensions = Literal["regex"] + +TemplateCommands = Literal["tmv", "targs", "tln"] +TemplateExtensions = Literal["python", "jinja2"] + +PredefinedCommands = RegexCommands | TemplateCommands +PredefinedExtensions = TemplateExtensions | RegexExtensions + +CommandNames = PlainCommands | TemplateCommands | RegexCommands -- cgit v1.3.1 From 83e24b1e572c9755c1be69e520ea081fadac136c Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 16:32:15 +0200 Subject: Fix jinja env overlay --- patternutils/commands/targs.py | 2 +- patternutils/commands/tln.py | 4 +++- patternutils/commands/tmv.py | 8 ++++++-- patternutils/template.py | 24 ++++++++++++------------ 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index 8280faa..3bb0ce8 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -143,7 +143,7 @@ def targs( raise SystemExit(1) try: - render = template.get_render_function(command, engine=template_engine) + render = template.get_render_function(command, "targs", engine=template_engine) except RuntimeError: click.secho("Jinja2 not installed!", fg="red", err=True) raise SystemExit(1) diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index d125f96..1de4ccd 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -135,7 +135,9 @@ def tln( raise SystemExit try: - render = template.get_render_function(output_pattern, engine=template_engine) + render = template.get_render_function( + output_pattern, "tln", engine=template_engine + ) except RuntimeError: click.secho("jinja2 not installed!", fg="red", err=True) raise SystemExit diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index 9198171..7ddcf8e 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -148,13 +148,17 @@ def tmv( raise SystemExit(1) try: - render = template.get_render_function(output_pattern, engine=template_engine) + render = template.get_render_function( + output_pattern, "tmv", engine=template_engine + ) except RuntimeError: click.secho("Jinja2 not installed!", fg="red", err=True) raise SystemExit(1) + new_filenames = dict() try: - new_filenames = {entry[key]: render(**entry) for entry in data} + for entry in data: + new_filenames[entry[key]] = render(**entry) except KeyError: click.secho(f"Key '{key}' not found in input data.", fg="red", err=True) if abort_on_key_not_found: diff --git a/patternutils/template.py b/patternutils/template.py index 86e5a97..ce09768 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -1,4 +1,5 @@ -from typing import Callable, Optional, cast +import os.path +from typing import Callable, cast from .config import CONFIG_PATH from .types import TemplateCommands, TemplateExtensions @@ -54,9 +55,9 @@ else: def get_render_function( template: str, + command_name: TemplateCommands, *, engine: TemplateExtensions = "python", - command_name: Optional[TemplateCommands] = None, ) -> Callable[..., str]: """Returns a function that renders a template using the specified engine. @@ -72,17 +73,16 @@ def get_render_function( """ if engine == "jinja2": if jinja_feature: - if command_name is not None: - jinja_env_overlay = jinja_env.overlay( - loader=jinja2.ChoiceLoader( - [ - jinja2.FileSystemLoader(CONFIG_PATH / command_name), - jinja2.FileSystemLoader(CONFIG_PATH / "globals"), - ] - ) + jinja_env_overlay = jinja_env.overlay( + loader=jinja2.ChoiceLoader( + [ + jinja2.FileSystemLoader( + os.path.join(CONFIG_PATH, command_name) + ), + jinja2.FileSystemLoader(os.path.join(CONFIG_PATH, "globals")), + ] ) - else: - jinja_env_overlay = jinja_env + ) env_template = jinja_env_overlay.from_string(template) return cast(Callable[..., str], env_template.render) else: -- cgit v1.3.1 From 840ad324f1e6056be66faba3bdad636053332f70 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 16:34:38 +0200 Subject: Make jina2 a required dependency --- patternutils/template.py | 101 +++++++++++++++++++++++------------------------ pyproject.toml | 4 +- 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/patternutils/template.py b/patternutils/template.py index ce09768..39cc3f3 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -1,56 +1,58 @@ import os.path +import shlex +from datetime import datetime from typing import Callable, cast +import jinja2 + from .config import CONFIG_PATH from .types import TemplateCommands, TemplateExtensions -try: - import jinja2 -except ImportError: - jinja_feature = False -else: - import os.path - import shlex - from datetime import datetime +jinja_env = jinja2.Environment() + + +def to_datetime(value: str, format: str = "%Y-%m-%d") -> datetime: + """Converts a string to a datetime object.""" + return datetime.strptime(value, format) + + +def format_datetime(value: datetime, format: str = "%Y-%m-%d") -> str: + """Formats a datetime object as a string.""" + return value.strftime(format) + + +def to_int(value: str, base: int = 10) -> int: + """Converts a string to an integer.""" + return int(value, base=base) + - jinja_feature = True - jinja_env = jinja2.Environment() +def to_float(value: str) -> float: + """Converts a string to a float.""" + return float(value) - def to_datetime(value: str, format: str = "%Y-%m-%d") -> datetime: - """Converts a string to a datetime object.""" - return datetime.strptime(value, format) - def format_datetime(value: datetime, format: str = "%Y-%m-%d") -> str: - """Formats a datetime object as a string.""" - return value.strftime(format) +def quote(value: str) -> str: + """Quotes a string safely for shell execution.""" + return shlex.quote(value) - def to_int(value: str, base: int = 10) -> int: - """Converts a string to an integer.""" - return int(value, base=base) - def to_float(value: str) -> float: - """Converts a string to a float.""" - return float(value) +def splitpath(value: str) -> tuple[str, str]: + """Splits a path into (directory, filename).""" + return os.path.split(value) - def quote(value: str) -> str: - """Quotes a string safely for shell execution.""" - return shlex.quote(value) - def splitpath(value: str) -> tuple[str, str]: - """Splits a path into (directory, filename).""" - return os.path.split(value) +def splitext(value: str) -> tuple[str, str]: + """Splits a file path into (root, extension).""" + return os.path.splitext(value) - def splitext(value: str) -> tuple[str, str]: - """Splits a file path into (root, extension).""" - return os.path.splitext(value) - jinja_env.filters["datetime"] = to_datetime - jinja_env.filters["datetimeformat"] = format_datetime - jinja_env.filters["int"] = to_int - jinja_env.filters["float"] = to_float - jinja_env.filters["quote"] = quote - jinja_env.filters["splitpath"] = splitpath - jinja_env.filters["splitext"] = splitext +jinja_env.filters["datetime"] = to_datetime +jinja_env.filters["datetimeformat"] = format_datetime +jinja_env.filters["int"] = to_int +jinja_env.filters["float"] = to_float +jinja_env.filters["quote"] = quote +jinja_env.filters["splitpath"] = splitpath +jinja_env.filters["splitext"] = splitext def get_render_function( @@ -72,20 +74,15 @@ def get_render_function( RuntimeError: If Jinja2 is selected but not installed. """ if engine == "jinja2": - if jinja_feature: - jinja_env_overlay = jinja_env.overlay( - loader=jinja2.ChoiceLoader( - [ - jinja2.FileSystemLoader( - os.path.join(CONFIG_PATH, command_name) - ), - jinja2.FileSystemLoader(os.path.join(CONFIG_PATH, "globals")), - ] - ) + jinja_env_overlay = jinja_env.overlay( + loader=jinja2.ChoiceLoader( + [ + jinja2.FileSystemLoader(os.path.join(CONFIG_PATH, command_name)), + jinja2.FileSystemLoader(os.path.join(CONFIG_PATH, "globals")), + ] ) - env_template = jinja_env_overlay.from_string(template) - return cast(Callable[..., str], env_template.render) - else: - raise RuntimeError("Jinja2 is required but not installed!") + ) + env_template = jinja_env_overlay.from_string(template) + return cast(Callable[..., str], env_template.render) else: return template.format diff --git a/pyproject.toml b/pyproject.toml index 9df713e..da0d5f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,15 +9,13 @@ license = {text = "GPL-3.0-or-later"} requires-python = ">=3.12, <4" dependencies = [ "click >=8.1.8, <9.0.0", + "Jinja2 >=3.1.5, <4.0.0", ] [project.urls] repository = "https://projects.metalgamer.eu/patternutils" [project.optional-dependencies] -jinja2 = [ - "Jinja2 >=3.1.5, <4.0.0", -] pygments = [ "Pygments >=2.19.1, <3.0.0", ] -- cgit v1.3.1 From bd3e6604802280147bb5913e5021b64aadd25d0c Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Mon, 14 Jul 2025 16:46:07 +0200 Subject: Renamve global variable --- patternutils/template.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/patternutils/template.py b/patternutils/template.py index 39cc3f3..0e9e1f7 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -8,7 +8,7 @@ import jinja2 from .config import CONFIG_PATH from .types import TemplateCommands, TemplateExtensions -jinja_env = jinja2.Environment() +JINJA_ENV = jinja2.Environment() def to_datetime(value: str, format: str = "%Y-%m-%d") -> datetime: @@ -46,13 +46,13 @@ def splitext(value: str) -> tuple[str, str]: return os.path.splitext(value) -jinja_env.filters["datetime"] = to_datetime -jinja_env.filters["datetimeformat"] = format_datetime -jinja_env.filters["int"] = to_int -jinja_env.filters["float"] = to_float -jinja_env.filters["quote"] = quote -jinja_env.filters["splitpath"] = splitpath -jinja_env.filters["splitext"] = splitext +JINJA_ENV.filters["datetime"] = to_datetime +JINJA_ENV.filters["datetimeformat"] = format_datetime +JINJA_ENV.filters["int"] = to_int +JINJA_ENV.filters["float"] = to_float +JINJA_ENV.filters["quote"] = quote +JINJA_ENV.filters["splitpath"] = splitpath +JINJA_ENV.filters["splitext"] = splitext def get_render_function( @@ -74,7 +74,7 @@ def get_render_function( RuntimeError: If Jinja2 is selected but not installed. """ if engine == "jinja2": - jinja_env_overlay = jinja_env.overlay( + jinja_env_overlay = JINJA_ENV.overlay( loader=jinja2.ChoiceLoader( [ jinja2.FileSystemLoader(os.path.join(CONFIG_PATH, command_name)), -- cgit v1.3.1 From f12ec039aba104e95d152ca001a5d03053e7e952 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Thu, 14 Aug 2025 23:12:47 +0200 Subject: Better timing --- patternutils/commands/patterncfg.py | 6 +----- patternutils/commands/targs.py | 17 +++++++++-------- patternutils/commands/tln.py | 16 ++++++++-------- patternutils/config.py | 2 +- patternutils/template.py | 4 ++-- patternutils/types.py | 6 +++--- 6 files changed, 24 insertions(+), 27 deletions(-) diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index ee71d86..5972397 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -18,14 +18,10 @@ else: from .. import config from ..types import ( PredefinedCommands, - RegexCommands, - TemplateCommands, TemplateExtensions, ) -CURRENT_SUPPORTED_PROGRAMS: tuple[RegexCommands | TemplateCommands, ...] = tuple( - itertools.chain(get_args(RegexCommands), get_args(TemplateCommands)) -) +CURRENT_SUPPORTED_PROGRAMS: tuple[PredefinedCommands] = get_args(PredefinedCommands) @click.group(context_settings={"help_option_names": ("-h", "--help", "-?")}) diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index 3bb0ce8..a90313a 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -15,7 +15,7 @@ def run_command( command: str, run: functools.partial[subprocess.CompletedProcess[str]] | Callable[..., None], shell: bool, -) -> None: +) -> subprocess.CompletedProcess[str] | None: """Executes a given command using the provided run function. Args: @@ -23,7 +23,7 @@ def run_command( run: A callable function for execution (e.g., subprocess.run or print). shell: Whether to run the command in a shell. """ - run(shlex.split(command) if not shell else command) + return run(shlex.split(command) if not shell else command) @click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) @@ -105,16 +105,17 @@ def run_command( def targs( command: str, read_from: TextIO, - shell: bool, + stream: bool, + interactive: bool, + editor: bool, template_engine: TemplateExtensions, - max_procs: int, + use_predefined_template: bool, + shell: bool, redirect_stdout: bool, redirect_stderr: bool, - use_predefined_template: bool, - stream: bool, - editor: bool, - verbose: bool, + max_procs: int, dry_run: bool, + verbose: bool, ) -> None: """Execute commands based on a template string. diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index 1de4ccd..4e1e616 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -9,14 +9,14 @@ from .. import config, template, utils from ..types import TemplateExtensions -def link_file(old_filename: str, new_filename: str, symbolic: bool) -> None: - if dirs := os.path.dirname(new_filename): +def link_file(source: str, destination: str, symbolic: bool) -> None: + if dirs := os.path.dirname(destination): os.makedirs(dirs, exist_ok=True) if symbolic: - os.symlink(old_filename, new_filename) + os.symlink(source, destination) else: - os.link(old_filename, new_filename) + os.link(source, destination) @click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) @@ -164,12 +164,12 @@ def tln( if has_existing and abort_on_path_exist: raise SystemExit - files_to_move = new_filenames.items() if force else non_existing.items() + files_to_link = new_filenames.items() if force else non_existing.items() - for old, new in files_to_move: + for src, dst in files_to_link: if verbose or interactive: - click.echo(f"{old} -> {new}") + click.echo(f"{src} -> {dst}") if not (interactive and not click.confirm("Is the match correct?")): if not dry_run: - link_file(old, new, symbolic) + link_file(src, dst, symbolic) diff --git a/patternutils/config.py b/patternutils/config.py index b236ec2..4d38b21 100644 --- a/patternutils/config.py +++ b/patternutils/config.py @@ -62,7 +62,7 @@ def load_template( output_pattern = template_lines.replace("\n", "") extension = os.path.splitext(template_file)[1][1:].lower() - if extension not in ("regex", "python", "jinja2"): + if extension not in get_args(PredefinedExtensions): raise ValueError( f"Invalid template extension '{extension}' in '{template_file}'." ) diff --git a/patternutils/template.py b/patternutils/template.py index 0e9e1f7..19de66c 100644 --- a/patternutils/template.py +++ b/patternutils/template.py @@ -1,7 +1,7 @@ import os.path import shlex from datetime import datetime -from typing import Callable, cast +from typing import Callable import jinja2 @@ -83,6 +83,6 @@ def get_render_function( ) ) env_template = jinja_env_overlay.from_string(template) - return cast(Callable[..., str], env_template.render) + return env_template.render else: return template.format diff --git a/patternutils/types.py b/patternutils/types.py index cf5c8f0..ad27ebf 100644 --- a/patternutils/types.py +++ b/patternutils/types.py @@ -8,7 +8,7 @@ RegexExtensions = Literal["regex"] TemplateCommands = Literal["tmv", "targs", "tln"] TemplateExtensions = Literal["python", "jinja2"] -PredefinedCommands = RegexCommands | TemplateCommands -PredefinedExtensions = TemplateExtensions | RegexExtensions +PredefinedCommands = Literal[RegexCommands, TemplateCommands] +PredefinedExtensions = Literal[TemplateExtensions, RegexExtensions] -CommandNames = PlainCommands | TemplateCommands | RegexCommands +CommandNames = Literal[PlainCommands, TemplateCommands, RegexCommands] -- cgit v1.3.1 From 5ff1d81cfed7bcd00eafa7059db61b91e29e1d9c Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Thu, 14 Aug 2025 23:14:36 +0200 Subject: better typing for edit --- patternutils/commands/targs.py | 2 +- patternutils/utils.py | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index a90313a..b6fc509 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -154,7 +154,7 @@ def targs( if editor: try: if (new_commands := utils.edit(commands)) is not None: - commands = list(new_commands.values()) + commands = new_commands except RuntimeError: click.secho("Your edit is not parseable!", fg="red", err=True) raise SystemExit(1) diff --git a/patternutils/utils.py b/patternutils/utils.py index 85734db..22d4123 100644 --- a/patternutils/utils.py +++ b/patternutils/utils.py @@ -1,6 +1,6 @@ import json import os -from typing import Any, Generator, Optional +from typing import Any, Generator, Optional, overload import click @@ -11,7 +11,15 @@ def max_procs() -> int: return 1 if cpu_count is None else cpu_count * 2 -def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str]]: +@overload +def edit(data: dict[str, str]) -> Optional[dict[str, str]]: ... + + +@overload +def edit(data: list[str]) -> Optional[list[str]]: ... + + +def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str] | list[str]]: """Opens an interactive editor for modifying dictionary or list entries. Args: @@ -21,24 +29,27 @@ def edit(data: dict[str, str] | list[str]) -> Optional[dict[str, str]]: A dictionary of modified entries or None if no changes were made. """ - longest = len(max(data, key=len)) - if isinstance(data, dict): - temporary = [f"{key.ljust(longest)}\t{value}\n" for key, value in data.items()] + longest = len(max(data, key=len)) + temporary = [f"{key.ljust(longest)}\t{value}" for key, value in data.items()] else: - temporary = [f"{value.ljust(longest)}\t{value}\n" for value in data] + temporary = data try: - if (edited := click.edit("".join(temporary))) is not None: - new_data = dict() - for line in edited.split("\n"): - if line and "\t" in line: - old, new = line.split("\t") - new_data[old.strip()] = new - if new_data: - return new_data + if (edited := click.edit("\n".join(temporary))) is not None: + if isinstance(data, dict): + new_data = dict() + for line in edited.split("\n"): + if line and "\t" in line: + old, new = line.split("\t") + new_data[old.strip()] = new + + if new_data: + return new_data + else: + raise RuntimeError else: - raise RuntimeError + return edited.split("\n") else: return None except click.UsageError: -- cgit v1.3.1 From c7f602eb1015337d4a9ddb9c99afcb7b96efab77 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Thu, 14 Aug 2025 23:16:29 +0200 Subject: As jinja in not optional anymore, simplify getting the render function --- patternutils/commands/targs.py | 11 +++++------ patternutils/commands/tln.py | 27 +++++++++++++++++++-------- patternutils/commands/tmv.py | 13 +++++-------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/patternutils/commands/targs.py b/patternutils/commands/targs.py index b6fc509..a4f91e0 100644 --- a/patternutils/commands/targs.py +++ b/patternutils/commands/targs.py @@ -143,12 +143,11 @@ def targs( ) raise SystemExit(1) - try: - render = template.get_render_function(command, "targs", engine=template_engine) - except RuntimeError: - click.secho("Jinja2 not installed!", fg="red", err=True) - raise SystemExit(1) - + render = template.get_render_function( + command, + "targs", + engine=template_engine, + ) commands = [render(r) for r in data] if editor: diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py index 4e1e616..cd2d4fe 100644 --- a/patternutils/commands/tln.py +++ b/patternutils/commands/tln.py @@ -85,6 +85,12 @@ def link_file(source: str, destination: str, symbolic: bool) -> None: default=False, help="exit if a renamed path already exists", ) +@click.option( + "--abort-on-key-not-found", + is_flag=True, + default=False, + help="Exit if the specified key (specified by the --key option) is not found in the input JSON.", +) @click.option( "-n", "--dry-run", @@ -113,6 +119,7 @@ def tln( key: str, stream: bool, abort_on_path_exist: bool, + abort_on_key_not_found: bool, dry_run: bool, verbose: bool, ) -> None: @@ -134,15 +141,19 @@ def tln( click.secho("Multiple files found!", fg="red", err=True) raise SystemExit + render = template.get_render_function( + output_pattern, + "tln", + engine=template_engine, + ) + new_filenames = dict() try: - render = template.get_render_function( - output_pattern, "tln", engine=template_engine - ) - except RuntimeError: - click.secho("jinja2 not installed!", fg="red", err=True) - raise SystemExit - - new_filenames = dict((entry["_abspath"], render(**entry)) for entry in data) + for entry in data: + new_filenames[entry[key]] = render(**entry) + except KeyError: + click.secho(f"Key '{key}' not found in input data.", fg="red", err=True) + if abort_on_key_not_found: + raise SystemExit(1) if editor: try: diff --git a/patternutils/commands/tmv.py b/patternutils/commands/tmv.py index 7ddcf8e..58a75e5 100644 --- a/patternutils/commands/tmv.py +++ b/patternutils/commands/tmv.py @@ -147,14 +147,11 @@ def tmv( ) raise SystemExit(1) - try: - render = template.get_render_function( - output_pattern, "tmv", engine=template_engine - ) - except RuntimeError: - click.secho("Jinja2 not installed!", fg="red", err=True) - raise SystemExit(1) - + render = template.get_render_function( + output_pattern, + "tmv", + engine=template_engine, + ) new_filenames = dict() try: for entry in data: -- cgit v1.3.1