From d3f7d81c7bfedc8e8dd80816beeaeedcc4d6ff98 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Wed, 4 Dec 2024 14:09:54 +0100 Subject: [PATCH 01/12] Introduce KPOps operation and manifest resources for deployment (#541) Closes #539, #538 --- .../docs/resources/variables/cli_env_vars.env | 2 + docs/docs/resources/variables/cli_env_vars.md | 1 + .../resources/variables/config_env_vars.env | 3 + .../resources/variables/config_env_vars.md | 1 + docs/docs/schema/config.json | 18 ++ docs/docs/user/references/cli-commands.md | 28 +-- kpops/api/__init__.py | 42 ++-- kpops/api/operation.py | 9 + kpops/cli/main.py | 80 +++---- kpops/component_handlers/helm_wrapper/helm.py | 1 + kpops/components/base_components/helm_app.py | 11 +- .../base_components/models/resource.py | 4 +- .../base_components/pipeline_component.py | 16 +- .../producer/producer_app.py | 31 ++- .../streams_bootstrap/streams/streams_app.py | 34 ++- kpops/config/__init__.py | 14 +- .../manifests/__init__.py | 0 kpops/manifests/argo.py | 34 +++ kpops/utils/cli_commands.py | 12 +- .../config.yaml} | 0 .../defaults.yaml} | 0 .../pipeline.yaml | 0 .../config.yaml} | 4 +- .../defaults.yaml | 0 .../pipeline.yaml | 0 tests/cli/test_init.py | 26 ++- tests/conftest.py | 3 +- tests/manifest/__init__.py | 0 tests/manifest/test_argo_enricher.py | 66 ++++++ .../resources/manifest-pipeline/defaults.yaml | 22 ++ .../resources/manifest-pipeline/pipeline.yaml | 40 ++++ .../test_deploy_argo_mode/manifest.yaml | 218 ++++++++++++++++++ .../test_deploy_manifest_mode/manifest.yaml | 107 +++++++++ .../test_manifest/test_python_api/resources | 137 ++++------- tests/pipeline/test_manifest.py | 52 ++++- 35 files changed, 792 insertions(+), 224 deletions(-) create mode 100644 kpops/api/operation.py rename tests/cli/snapshots/test_init/test_init_project/defaults.yaml => kpops/manifests/__init__.py (100%) create mode 100644 kpops/manifests/argo.py rename tests/cli/snapshots/test_init/{test_init_project/config_exclude_opt.yaml => test_init_project_exclude_optional/config.yaml} (100%) rename tests/cli/snapshots/test_init/{test_init_project/pipeline.yaml => test_init_project_exclude_optional/defaults.yaml} (100%) create mode 100644 tests/cli/snapshots/test_init/test_init_project_exclude_optional/pipeline.yaml rename tests/cli/snapshots/test_init/{test_init_project/config_include_opt.yaml => test_init_project_include_optional/config.yaml} (91%) create mode 100644 tests/cli/snapshots/test_init/test_init_project_include_optional/defaults.yaml create mode 100644 tests/cli/snapshots/test_init/test_init_project_include_optional/pipeline.yaml create mode 100644 tests/manifest/__init__.py create mode 100644 tests/manifest/test_argo_enricher.py create mode 100644 tests/pipeline/resources/manifest-pipeline/defaults.yaml create mode 100644 tests/pipeline/resources/manifest-pipeline/pipeline.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml diff --git a/docs/docs/resources/variables/cli_env_vars.env b/docs/docs/resources/variables/cli_env_vars.env index 21436ded7..2aca45807 100644 --- a/docs/docs/resources/variables/cli_env_vars.env +++ b/docs/docs/resources/variables/cli_env_vars.env @@ -14,6 +14,8 @@ KPOPS_DOTENV_PATH # No default value, not required # Suffix your environment files with this value (e.g. # defaults_development.yaml for environment=development). KPOPS_ENVIRONMENT # No default value, not required +# How KPOps should operate. +KPOPS_OPERATION_MODE=managed # Paths to dir containing 'pipeline.yaml' or files named # 'pipeline.yaml'. KPOPS_PIPELINE_PATHS # No default value, required diff --git a/docs/docs/resources/variables/cli_env_vars.md b/docs/docs/resources/variables/cli_env_vars.md index da6a2d994..b4cead3ce 100644 --- a/docs/docs/resources/variables/cli_env_vars.md +++ b/docs/docs/resources/variables/cli_env_vars.md @@ -5,5 +5,6 @@ These variables take precedence over the commands' flags. If a variable is set, |KPOPS_CONFIG_PATH |. |False |Path to the dir containing config.yaml files | |KPOPS_DOTENV_PATH | |False |Path to dotenv file. Multiple files can be provided. The files will be loaded in order, with each file overriding the previous one. | |KPOPS_ENVIRONMENT | |False |The environment you want to generate and deploy the pipeline to. Suffix your environment files with this value (e.g. defaults_development.yaml for environment=development).| +|KPOPS_OPERATION_MODE|managed |False |How KPOps should operate. | |KPOPS_PIPELINE_PATHS| |True |Paths to dir containing 'pipeline.yaml' or files named 'pipeline.yaml'. | |KPOPS_PIPELINE_STEPS| |False |Comma separated list of steps to apply the command on | diff --git a/docs/docs/resources/variables/config_env_vars.env b/docs/docs/resources/variables/config_env_vars.env index f558d4d19..b64bac2e0 100644 --- a/docs/docs/resources/variables/config_env_vars.env +++ b/docs/docs/resources/variables/config_env_vars.env @@ -58,3 +58,6 @@ KPOPS_HELM_DIFF_CONFIG__IGNORE # No default value, required # Whether to retain clean up jobs in the cluster or uninstall the, # after completion. KPOPS_RETAIN_CLEAN_JOBS=False +# operation_mode +# The operation mode of KPOps (managed, manifest, argo). +KPOPS_OPERATION_MODE=managed diff --git a/docs/docs/resources/variables/config_env_vars.md b/docs/docs/resources/variables/config_env_vars.md index 8685acba0..6b79a743c 100644 --- a/docs/docs/resources/variables/config_env_vars.md +++ b/docs/docs/resources/variables/config_env_vars.md @@ -19,3 +19,4 @@ These variables take precedence over the settings in `config.yaml`. Variables ma |KPOPS_HELM_CONFIG__API_VERSION | |False |Kubernetes API version used for `Capabilities.APIVersions` |helm_config.api_version | |KPOPS_HELM_DIFF_CONFIG__IGNORE | |True |Set of keys that should not be checked. |helm_diff_config.ignore | |KPOPS_RETAIN_CLEAN_JOBS |False |False |Whether to retain clean up jobs in the cluster or uninstall the, after completion.|retain_clean_jobs | +|KPOPS_OPERATION_MODE |managed |False |The operation mode of KPOps (managed, manifest, argo). |operation_mode | diff --git a/docs/docs/schema/config.json b/docs/docs/schema/config.json index 949c42791..02d04ea6e 100644 --- a/docs/docs/schema/config.json +++ b/docs/docs/schema/config.json @@ -118,6 +118,15 @@ "title": "KafkaRestConfig", "type": "object" }, + "OperationMode": { + "enum": [ + "argo", + "manifest", + "managed" + ], + "title": "OperationMode", + "type": "string" + }, "SchemaRegistryConfig": { "additionalProperties": false, "description": "Configuration for Schema Registry.", @@ -239,6 +248,15 @@ }, "description": "Configuration for Kafka REST Proxy." }, + "operation_mode": { + "allOf": [ + { + "$ref": "#/$defs/OperationMode" + } + ], + "default": "managed", + "description": "The operation mode of KPOps (managed, manifest, argo)." + }, "pipeline_base_dir": { "default": ".", "description": "Base directory to the pipelines (default is current working directory)", diff --git a/docs/docs/user/references/cli-commands.md b/docs/docs/user/references/cli-commands.md index d10ba44cc..bbbd7cd3f 100644 --- a/docs/docs/user/references/cli-commands.md +++ b/docs/docs/user/references/cli-commands.md @@ -20,7 +20,6 @@ $ kpops [OPTIONS] COMMAND [ARGS]... * `destroy`: Destroy pipeline steps * `generate`: Generate enriched pipeline representation * `init`: Initialize a new KPOps project. -* `manifest`: Render final resource representation * `reset`: Reset pipeline steps * `schema`: Generate JSON schema. @@ -74,6 +73,7 @@ $ kpops deploy [OPTIONS] PIPELINE_PATHS... * `--dry-run / --execute`: Whether to dry run the command or execute it [default: dry-run] * `--verbose / --no-verbose`: Enable verbose printing [default: no-verbose] * `--parallel / --no-parallel`: Enable or disable parallel execution of pipeline steps. If enabled, multiple steps can be processed concurrently. If disabled, steps will be processed sequentially. [default: no-parallel] +* `--operation-mode [argo|manifest|managed]`: How KPOps should operate. [env var: KPOPS_OPERATION_MODE; default: managed] * `--help`: Show this message and exit. ## `kpops destroy` @@ -142,31 +142,7 @@ $ kpops init [OPTIONS] PATH **Options**: -* `--config-include-opt / --no-config-include-opt`: Whether to include non-required settings in the generated 'config.yaml' [default: no-config-include-opt] -* `--help`: Show this message and exit. - -## `kpops manifest` - -In addition to generate, render final resource representation for each pipeline step, e.g. Kubernetes manifests. - -**Usage**: - -```console -$ kpops manifest [OPTIONS] PIPELINE_PATHS... -``` - -**Arguments**: - -* `PIPELINE_PATHS...`: Paths to dir containing 'pipeline.yaml' or files named 'pipeline.yaml'. [env var: KPOPS_PIPELINE_PATHS;required] - -**Options**: - -* `--dotenv FILE`: Path to dotenv file. Multiple files can be provided. The files will be loaded in order, with each file overriding the previous one. [env var: KPOPS_DOTENV_PATH] -* `--config DIRECTORY`: Path to the dir containing config.yaml files [env var: KPOPS_CONFIG_PATH; default: .] -* `--steps TEXT`: Comma separated list of steps to apply the command on [env var: KPOPS_PIPELINE_STEPS] -* `--filter-type [include|exclude]`: Whether the --steps option should include/exclude the steps [default: include] -* `--environment TEXT`: The environment you want to generate and deploy the pipeline to. Suffix your environment files with this value (e.g. defaults_development.yaml for environment=development). [env var: KPOPS_ENVIRONMENT] -* `--verbose / --no-verbose`: Enable verbose printing [default: no-verbose] +* `--config-include-optional / --no-config-include-optional`: Whether to include non-required settings in the generated 'config.yaml' [default: no-config-include-optional] * `--help`: Show this message and exit. ## `kpops reset` diff --git a/kpops/api/__init__.py b/kpops/api/__init__.py index f376af704..5fd6c856d 100644 --- a/kpops/api/__init__.py +++ b/kpops/api/__init__.py @@ -1,10 +1,12 @@ from __future__ import annotations import asyncio +from collections.abc import Iterator from pathlib import Path from typing import TYPE_CHECKING from kpops.api.logs import log, log_action +from kpops.api.operation import OperationMode from kpops.api.options import FilterType from kpops.api.registry import Registry from kpops.component_handlers import ComponentHandlers @@ -14,6 +16,7 @@ from kpops.component_handlers.schema_handler.schema_handler import SchemaHandler from kpops.component_handlers.topic.handler import TopicHandler from kpops.component_handlers.topic.proxy_wrapper import ProxyWrapper +from kpops.components.base_components.models.resource import Resource from kpops.config import KpopsConfig from kpops.pipeline import ( Pipeline, @@ -22,7 +25,6 @@ from kpops.utils.cli_commands import init_project if TYPE_CHECKING: - from kpops.components.base_components.models.resource import Resource from kpops.components.base_components.pipeline_component import PipelineComponent from kpops.config import KpopsConfig @@ -35,6 +37,7 @@ def generate( filter_type: FilterType = FilterType.INCLUDE, environment: str | None = None, verbose: bool = False, + operation_mode: OperationMode = OperationMode.MANAGED, ) -> Pipeline: """Generate enriched pipeline representation. @@ -45,13 +48,11 @@ def generate( :param filter_type: Whether `steps` should include/exclude the steps. :param environment: The environment to generate and deploy the pipeline to. :param verbose: Enable verbose printing. + :param operation_mode: How KPOps should operate. :return: Generated `Pipeline` object. """ kpops_config = KpopsConfig.create( - config, - dotenv, - environment, - verbose, + config, dotenv, environment, verbose, operation_mode ) pipeline = _create_pipeline(pipeline_path, kpops_config, environment) log.info(f"Picked up pipeline '{pipeline_path.parent.name}'") @@ -69,26 +70,16 @@ def generate( return pipeline -def manifest( +def manifest_deploy( pipeline_path: Path, dotenv: list[Path] | None = None, config: Path = Path(), steps: set[str] | None = None, filter_type: FilterType = FilterType.INCLUDE, environment: str | None = None, - verbose: bool = False, -) -> list[Resource]: - """Generate pipeline, return final resource representations for each step. - - :param pipeline_path: Path to pipeline definition yaml file. - :param dotenv: Paths to dotenv files. - :param config: Path to the dir containing config.yaml files. - :param steps: Set of steps (components) to apply the command on. - :param filter_type: Whether `steps` should include/exclude the steps. - :param environment: The environment to generate and deploy the pipeline to. - :param verbose: Enable verbose printing. - :return: Resources. - """ + verbose: bool = True, + operation_mode: OperationMode = OperationMode.MANIFEST, +) -> Iterator[Resource]: pipeline = generate( pipeline_path=pipeline_path, dotenv=dotenv, @@ -97,12 +88,11 @@ def manifest( filter_type=filter_type, environment=environment, verbose=verbose, + operation_mode=operation_mode, ) - resources: list[Resource] = [] for component in pipeline.components: - resource = component.manifest() - resources.append(resource) - return resources + resource = component.manifest_deploy() + yield resource def deploy( @@ -301,12 +291,12 @@ async def async_clean(): def init( path: Path, - config_include_opt: bool = False, + config_include_optional: bool = False, ): """Initiate a default empty project. :param path: Directory in which the project should be initiated. - :param conf_incl_opt: Whether to include non-required settings + :param config_include_optional: Whether to include non-required settings in the generated config file. """ if not path.exists(): @@ -314,7 +304,7 @@ def init( elif next(path.iterdir(), False): log.warning("Please provide a path to an empty directory.") return - init_project(path, config_include_opt) + init_project(path, config_include_optional) def _create_pipeline( diff --git a/kpops/api/operation.py b/kpops/api/operation.py new file mode 100644 index 000000000..6b7558398 --- /dev/null +++ b/kpops/api/operation.py @@ -0,0 +1,9 @@ +from __future__ import annotations + +import enum + + +class OperationMode(str, enum.Enum): + ARGO = "argo" + MANIFEST = "manifest" + MANAGED = "managed" diff --git a/kpops/cli/main.py b/kpops/cli/main.py index ff0a77338..0d6af160e 100644 --- a/kpops/cli/main.py +++ b/kpops/cli/main.py @@ -5,6 +5,7 @@ import typer import kpops.api as kpops +from kpops.api.operation import OperationMode from kpops.api.options import FilterType from kpops.cli.utils import ( collect_pipeline_paths, @@ -110,6 +111,11 @@ "Suffix your environment files with this value (e.g. defaults_development.yaml for environment=development). " ), ) +OPERATION_MODE_OPTION: OperationMode = typer.Option( + default=OperationMode.MANAGED, + envvar=f"{ENV_PREFIX}OPERATION_MODE", + help="How KPOps should operate.", +) def parse_steps(steps: str | None) -> set[str] | None: @@ -119,9 +125,9 @@ def parse_steps(steps: str | None) -> set[str] | None: @app.command(help="Initialize a new KPOps project.") def init( path: Path = PROJECT_PATH, - config_include_opt: bool = CONFIG_INCLUDE_OPTIONAL, + config_include_optional: bool = CONFIG_INCLUDE_OPTIONAL, ): - kpops.init(path, config_include_opt=config_include_opt) + kpops.init(path, config_include_optional=config_include_optional) @app.command( @@ -180,34 +186,6 @@ def generate( print_yaml(pipeline.to_yaml()) -@app.command( - short_help="Render final resource representation", - help="In addition to generate, render final resource representation for each pipeline step, e.g. Kubernetes manifests.", -) -def manifest( - pipeline_paths: list[Path] = PIPELINE_PATHS_ARG, - dotenv: list[Path] | None = DOTENV_PATH_OPTION, - config: Path = CONFIG_PATH_OPTION, - steps: str | None = PIPELINE_STEPS, - filter_type: FilterType = FILTER_TYPE, - environment: str | None = ENVIRONMENT, - verbose: bool = VERBOSE_OPTION, -): - for pipeline_file_path in collect_pipeline_paths(pipeline_paths): - resources = kpops.manifest( - pipeline_path=pipeline_file_path, - dotenv=dotenv, - config=config, - steps=parse_steps(steps), - filter_type=filter_type, - environment=environment, - verbose=verbose, - ) - for resource in resources: - for rendered_manifest in resource: - print_yaml(rendered_manifest) - - @app.command(help="Deploy pipeline steps") def deploy( pipeline_paths: list[Path] = PIPELINE_PATHS_ARG, @@ -219,19 +197,37 @@ def deploy( dry_run: bool = DRY_RUN, verbose: bool = VERBOSE_OPTION, parallel: bool = PARALLEL, + operation_mode: OperationMode = OPERATION_MODE_OPTION, ): - for pipeline_file_path in collect_pipeline_paths(pipeline_paths): - kpops.deploy( - pipeline_path=pipeline_file_path, - dotenv=dotenv, - config=config, - steps=parse_steps(steps), - filter_type=filter_type, - environment=environment, - dry_run=dry_run, - verbose=verbose, - parallel=parallel, - ) + match operation_mode: + case OperationMode.MANAGED: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + kpops.deploy( + pipeline_path=pipeline_file_path, + dotenv=dotenv, + config=config, + steps=parse_steps(steps), + filter_type=filter_type, + environment=environment, + dry_run=dry_run, + verbose=verbose, + parallel=parallel, + ) + case _: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + resources = kpops.manifest_deploy( + pipeline_file_path, + dotenv, + config, + parse_steps(steps), + filter_type, + environment, + verbose, + operation_mode, + ) + for resource in resources: + for rendered_manifest in resource: + print_yaml(rendered_manifest) @app.command(help="Destroy pipeline steps") diff --git a/kpops/component_handlers/helm_wrapper/helm.py b/kpops/component_handlers/helm_wrapper/helm.py index 5ff76fb81..3fd38df20 100644 --- a/kpops/component_handlers/helm_wrapper/helm.py +++ b/kpops/component_handlers/helm_wrapper/helm.py @@ -27,6 +27,7 @@ from kpops.components.base_components.models.resource import Resource + log = logging.getLogger("Helm") diff --git a/kpops/components/base_components/helm_app.py b/kpops/components/base_components/helm_app.py index 3990b3f1c..a2658b0e3 100644 --- a/kpops/components/base_components/helm_app.py +++ b/kpops/components/base_components/helm_app.py @@ -8,6 +8,7 @@ from pydantic import Field, model_serializer from typing_extensions import override +from kpops.api import OperationMode from kpops.component_handlers.helm_wrapper.dry_run_handler import DryRunHandler from kpops.component_handlers.helm_wrapper.helm import Helm from kpops.component_handlers.helm_wrapper.helm_diff import HelmDiff @@ -28,6 +29,7 @@ ) from kpops.components.base_components.models.resource import Resource from kpops.config import get_config +from kpops.manifests.argo import ArgoSyncWave, enrich_annotations from kpops.utils.colorify import magentaify from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import exclude_by_name @@ -142,12 +144,17 @@ def template_flags(self) -> HelmTemplateFlags: ) @override - def manifest(self) -> Resource: + def manifest_deploy(self) -> Resource: + values = self.to_helm_values() + if get_config().operation_mode is OperationMode.ARGO: + sync_wave = ArgoSyncWave(sync_wave=1) + values = enrich_annotations(values, sync_wave.key, sync_wave.value) + return self.helm.template( self.helm_release_name, self.helm_chart, self.namespace, - self.to_helm_values(), + values, self.template_flags, ) diff --git a/kpops/components/base_components/models/resource.py b/kpops/components/base_components/models/resource.py index 08c01f344..e6867081d 100644 --- a/kpops/components/base_components/models/resource.py +++ b/kpops/components/base_components/models/resource.py @@ -1,5 +1,5 @@ -from collections.abc import Mapping, Sequence +from collections.abc import Mapping from typing import Any, TypeAlias # representation of final resource for component, e.g. a list of Kubernetes manifests -Resource: TypeAlias = Sequence[Mapping[str, Any]] +Resource: TypeAlias = list[Mapping[str, Any]] diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 5b6798af6..28445fe17 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -229,8 +229,20 @@ def inflate(self) -> list[PipelineComponent]: """ return [self] - def manifest(self) -> Resource: - """Render final component resources, e.g. Kubernetes manifests.""" + def manifest_deploy(self) -> Resource: + """Render Kubernetes manifests for deploy.""" + return [] + + def manifest_destroy(self) -> Resource: + """Render Kubernetes manifests resources for destroy.""" + return [] + + def manifest_reset(self) -> Resource: + """Render Kubernetes manifests resources for reset.""" + return [] + + def manifest_clean(self) -> Resource: + """Render Kubernetes manifests resources for clean.""" return [] async def deploy(self, dry_run: bool) -> None: diff --git a/kpops/components/streams_bootstrap/producer/producer_app.py b/kpops/components/streams_bootstrap/producer/producer_app.py index 21cda9ebd..c31393a19 100644 --- a/kpops/components/streams_bootstrap/producer/producer_app.py +++ b/kpops/components/streams_bootstrap/producer/producer_app.py @@ -4,7 +4,9 @@ from pydantic import Field, ValidationError, computed_field from typing_extensions import override +from kpops.api import OperationMode from kpops.components.base_components.kafka_app import KafkaAppCleaner +from kpops.components.base_components.models.resource import Resource from kpops.components.common.app_type import AppType from kpops.components.common.topic import ( KafkaTopic, @@ -15,7 +17,9 @@ StreamsBootstrap, ) from kpops.components.streams_bootstrap.producer.model import ProducerAppValues +from kpops.config import get_config from kpops.const.file_type import DEFAULTS_YAML, PIPELINE_YAML +from kpops.manifests.argo import ArgoHook, enrich_annotations from kpops.utils.docstring import describe_attr log = logging.getLogger("ProducerApp") @@ -31,6 +35,20 @@ def helm_chart(self) -> str: f"{self.repo_config.repository_name}/{AppType.CLEANUP_PRODUCER_APP.value}" ) + @override + def manifest_deploy(self) -> Resource: + values = self.to_helm_values() + if get_config().operation_mode is OperationMode.ARGO: + post_delete = ArgoHook.POST_DELETE + values = enrich_annotations(values, post_delete.key, post_delete.value) + return self.helm.template( + self.helm_release_name, + self.helm_chart, + self.namespace, + values, + self.template_flags, + ) + class ProducerApp(StreamsBootstrap): """Producer component. @@ -57,9 +75,11 @@ class ProducerApp(StreamsBootstrap): @computed_field @cached_property def _cleaner(self) -> ProducerAppCleaner: - return ProducerAppCleaner( + cleaner = ProducerAppCleaner( **self.model_dump(by_alias=True, exclude={"_cleaner", "from_", "to"}) ) + cleaner.values.name_override = None + return cleaner @override def apply_to_outputs(self, name: str, topic: TopicConfig) -> None: @@ -123,3 +143,12 @@ async def clean(self, dry_run: bool) -> None: """Destroy and clean.""" await super().clean(dry_run) await self._cleaner.clean(dry_run) + + def manifest_deploy(self) -> Resource: + manifests = super().manifest_deploy() + operation_mode = get_config().operation_mode + + if operation_mode is OperationMode.ARGO: + manifests.extend(self._cleaner.manifest_deploy()) + + return manifests diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index ac3ffae68..39677bfe2 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -4,9 +4,11 @@ from pydantic import Field, ValidationError, computed_field from typing_extensions import override +from kpops.api.operation import OperationMode from kpops.component_handlers.kubernetes.pvc_handler import PVCHandler from kpops.components.base_components.helm_app import HelmApp from kpops.components.base_components.kafka_app import KafkaAppCleaner +from kpops.components.base_components.models.resource import Resource from kpops.components.common.app_type import AppType from kpops.components.common.topic import KafkaTopic from kpops.components.streams_bootstrap.base import ( @@ -15,7 +17,9 @@ from kpops.components.streams_bootstrap.streams.model import ( StreamsAppValues, ) +from kpops.config import get_config from kpops.const.file_type import DEFAULTS_YAML, PIPELINE_YAML +from kpops.manifests.argo import ArgoHook, enrich_annotations from kpops.utils.docstring import describe_attr log = logging.getLogger("StreamsApp") @@ -44,6 +48,20 @@ async def clean(self, dry_run: bool) -> None: if self.values.stateful_set and self.values.persistence.enabled: await self.clean_pvcs(dry_run) + @override + def manifest_deploy(self) -> Resource: + values = self.to_helm_values() + if get_config().operation_mode is OperationMode.ARGO: + post_delete = ArgoHook.POST_DELETE + values = enrich_annotations(values, post_delete.key, post_delete.value) + return self.helm.template( + self.helm_release_name, + self.helm_chart, + self.namespace, + values, + self.template_flags, + ) + async def clean_pvcs(self, dry_run: bool) -> None: app_full_name = super(HelmApp, self).full_name pvc_handler = PVCHandler(app_full_name, self.namespace) @@ -63,9 +81,11 @@ class StreamsApp(StreamsBootstrap): @computed_field @cached_property def _cleaner(self) -> StreamsAppCleaner: - return StreamsAppCleaner( + cleaner = StreamsAppCleaner( **self.model_dump(by_alias=True, exclude={"_cleaner", "from_", "to"}) ) + cleaner.values.name_override = None + return cleaner @property @override @@ -152,3 +172,15 @@ async def clean(self, dry_run: bool) -> None: """Destroy and clean.""" await super().clean(dry_run) await self._cleaner.clean(dry_run) + + @override + def manifest_deploy(self) -> Resource: + manifests = super().manifest_deploy() + if get_config().operation_mode is OperationMode.ARGO: + manifests.extend(self._cleaner.manifest_deploy()) + + return manifests + + @override + def manifest_clean(self) -> Resource: + return [] diff --git a/kpops/config/__init__.py b/kpops/config/__init__.py index a7d0dc281..7398d5e7c 100644 --- a/kpops/config/__init__.py +++ b/kpops/config/__init__.py @@ -12,6 +12,7 @@ ) from typing_extensions import override +from kpops.api.operation import OperationMode from kpops.component_handlers.helm_wrapper.model import HelmConfig, HelmDiffConfig from kpops.utils.docstring import describe_object from kpops.utils.pydantic import YamlConfigSettingsSource @@ -120,8 +121,16 @@ class KpopsConfig(BaseSettings): default=False, description="Whether to retain clean up jobs in the cluster or uninstall the, after completion.", ) + operation_mode: OperationMode = Field( + default=OperationMode.MANAGED, + description="The operation mode of KPOps (managed, manifest, argo).", + ) - model_config = SettingsConfigDict(env_prefix=ENV_PREFIX, env_nested_delimiter="__") + model_config = SettingsConfigDict( + env_prefix=ENV_PREFIX, + env_nested_delimiter="__", + use_enum_values=True, + ) @classmethod def create( @@ -130,6 +139,7 @@ def create( dotenv: list[Path] | None = None, environment: str | None = None, verbose: bool = False, + operation_mode: OperationMode | None = None, ) -> KpopsConfig: cls.setup_logging_level(verbose) YamlConfigSettingsSource.config_dir = config_dir @@ -137,6 +147,8 @@ def create( cls._instance = KpopsConfig( _env_file=dotenv # pyright: ignore[reportCallIssue] ) + if operation_mode: + cls._instance.operation_mode = operation_mode return cls._instance @staticmethod diff --git a/tests/cli/snapshots/test_init/test_init_project/defaults.yaml b/kpops/manifests/__init__.py similarity index 100% rename from tests/cli/snapshots/test_init/test_init_project/defaults.yaml rename to kpops/manifests/__init__.py diff --git a/kpops/manifests/argo.py b/kpops/manifests/argo.py new file mode 100644 index 000000000..3ecabdaf9 --- /dev/null +++ b/kpops/manifests/argo.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +import enum +from typing import Any + +from pydantic import BaseModel + + +def enrich_annotations( + helm_values: dict[str, Any], key: str, value: str +) -> dict[str, Any]: + annotations = helm_values.setdefault("annotations", {}) + annotations[key] = value + return helm_values + + +class ArgoHook(str, enum.Enum): + POST_DELETE = "PostDelete" + + @property + def key(self) -> str: + return "argocd.argoproj.io/hook" + + +class ArgoSyncWave(BaseModel): + sync_wave: int = 0 + + @property + def key(self) -> str: + return "argocd.argoproj.io/sync-wave" + + @property + def value(self) -> str: + return str(self.sync_wave) diff --git a/kpops/utils/cli_commands.py b/kpops/utils/cli_commands.py index ba1b295ad..2f994b494 100644 --- a/kpops/utils/cli_commands.py +++ b/kpops/utils/cli_commands.py @@ -52,7 +52,7 @@ def create_config(file_name: str, dir_path: Path, include_optional: bool) -> Non file_path = Path(dir_path / (file_name + ".yaml")) file_path.touch(exist_ok=False) with file_path.open(mode="w") as conf: - conf.write("# " + describe_object(KpopsConfig.__doc__)) # Write title + conf.write(f"# {describe_object(KpopsConfig.__doc__)}") # Write title non_required = extract_config_fields_for_yaml( collect_fields(KpopsConfig), False ) @@ -60,10 +60,16 @@ def create_config(file_name: str, dir_path: Path, include_optional: bool) -> Non for k in non_required: required.pop(k, None) conf.write("\n\n# Required fields\n") - conf.write(yaml.dump(required)) + conf.write(yaml.safe_dump(required)) + if include_optional: + dump = KpopsConfig(**non_required).model_dump( + mode="json", exclude_none=False + ) + for k in required: + dump.pop(k, None) conf.write("\n# Non-required fields\n") - conf.write(yaml.dump(non_required)) + conf.write(yaml.safe_dump(dump)) def init_project(path: Path, conf_incl_opt: bool): diff --git a/tests/cli/snapshots/test_init/test_init_project/config_exclude_opt.yaml b/tests/cli/snapshots/test_init/test_init_project_exclude_optional/config.yaml similarity index 100% rename from tests/cli/snapshots/test_init/test_init_project/config_exclude_opt.yaml rename to tests/cli/snapshots/test_init/test_init_project_exclude_optional/config.yaml diff --git a/tests/cli/snapshots/test_init/test_init_project/pipeline.yaml b/tests/cli/snapshots/test_init/test_init_project_exclude_optional/defaults.yaml similarity index 100% rename from tests/cli/snapshots/test_init/test_init_project/pipeline.yaml rename to tests/cli/snapshots/test_init/test_init_project_exclude_optional/defaults.yaml diff --git a/tests/cli/snapshots/test_init/test_init_project_exclude_optional/pipeline.yaml b/tests/cli/snapshots/test_init/test_init_project_exclude_optional/pipeline.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cli/snapshots/test_init/test_init_project/config_include_opt.yaml b/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml similarity index 91% rename from tests/cli/snapshots/test_init/test_init_project/config_include_opt.yaml rename to tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml index 3c86a269a..19b7f5d95 100644 --- a/tests/cli/snapshots/test_init/test_init_project/config_include_opt.yaml +++ b/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml @@ -9,13 +9,15 @@ helm_config: api_version: null context: null debug: false -helm_diff_config: {} +helm_diff_config: + ignore: [] kafka_connect: timeout: 30 url: http://localhost:8083/ kafka_rest: timeout: 30 url: http://localhost:8082/ +operation_mode: managed pipeline_base_dir: . retain_clean_jobs: false schema_registry: diff --git a/tests/cli/snapshots/test_init/test_init_project_include_optional/defaults.yaml b/tests/cli/snapshots/test_init/test_init_project_include_optional/defaults.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cli/snapshots/test_init/test_init_project_include_optional/pipeline.yaml b/tests/cli/snapshots/test_init/test_init_project_include_optional/pipeline.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cli/test_init.py b/tests/cli/test_init.py index 3109d16fc..6a5c61303 100644 --- a/tests/cli/test_init.py +++ b/tests/cli/test_init.py @@ -1,5 +1,6 @@ from pathlib import Path +import pytest from pytest_snapshot.plugin import Snapshot from typer.testing import CliRunner @@ -22,23 +23,24 @@ def test_create_config(tmp_path: Path): assert len(opt_conf.read_text()) > len(req_conf.read_text()) -def test_init_project(tmp_path: Path, snapshot: Snapshot): +@pytest.mark.usefixtures("mock_env", "load_yaml_file_clear_cache", "clear_kpops_config") +def test_init_project_exclude_optional(tmp_path: Path, snapshot: Snapshot): + req_path = tmp_path / "req" + req_path.mkdir() + kpops.init(req_path, config_include_optional=False) + snapshot.assert_match(Path(req_path / "config.yaml").read_text(), "config.yaml") + snapshot.assert_match(Path(req_path / "pipeline.yaml").read_text(), "pipeline.yaml") + snapshot.assert_match(Path(req_path / "defaults.yaml").read_text(), "defaults.yaml") + + +def test_init_project_include_optional(tmp_path: Path, snapshot: Snapshot): opt_path = tmp_path / "opt" opt_path.mkdir() - kpops.init(opt_path, config_include_opt=False) - snapshot.assert_match( - Path(opt_path / "config.yaml").read_text(), "config_exclude_opt.yaml" - ) + kpops.init(opt_path, config_include_optional=True) + snapshot.assert_match(Path(opt_path / "config.yaml").read_text(), "config.yaml") snapshot.assert_match(Path(opt_path / "pipeline.yaml").read_text(), "pipeline.yaml") snapshot.assert_match(Path(opt_path / "defaults.yaml").read_text(), "defaults.yaml") - req_path = tmp_path / "req" - req_path.mkdir() - kpops.init(req_path, config_include_opt=True) - snapshot.assert_match( - Path(req_path / "config.yaml").read_text(), "config_include_opt.yaml" - ) - def test_init_project_from_cli_with_bad_path(tmp_path: Path): bad_path = Path(tmp_path / "random_file.yaml") diff --git a/tests/conftest.py b/tests/conftest.py index a819c26af..4983aa325 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,7 +7,6 @@ import pytest -from kpops.config import KpopsConfig from kpops.utils.environment import ENV, Environment from kpops.utils.yaml import load_yaml_file @@ -56,6 +55,8 @@ def custom_components() -> Iterator[None]: @pytest.fixture(scope="module") def clear_kpops_config() -> Iterator[None]: + from kpops.config import KpopsConfig + yield KpopsConfig._instance = None diff --git a/tests/manifest/__init__.py b/tests/manifest/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/manifest/test_argo_enricher.py b/tests/manifest/test_argo_enricher.py new file mode 100644 index 000000000..0ee4165a1 --- /dev/null +++ b/tests/manifest/test_argo_enricher.py @@ -0,0 +1,66 @@ +from typing import Any + +import pytest + +from kpops.manifests.argo import ArgoHook, ArgoSyncWave, enrich_annotations + + +@pytest.fixture +def empty_manifest() -> dict[str, Any]: + return {} + + +@pytest.fixture +def manifest_with_annotations() -> dict[str, Any]: + return {"annotations": {"existing-annotation": "annotation-value"}} + + +def test_argo_hook_enrich_empty_manifest(empty_manifest: dict[str, Any]): + hook = ArgoHook.POST_DELETE + enriched_manifest = enrich_annotations(empty_manifest, hook.key, hook.value) + assert enriched_manifest["annotations"][hook.key] == hook.value + assert len(enriched_manifest["annotations"]) == 1 + + +def test_argo_hook_enrich_existing_annotations( + manifest_with_annotations: dict[str, Any], +): + hook = ArgoHook.POST_DELETE + enriched_manifest = enrich_annotations( + manifest_with_annotations, hook.key, hook.value + ) + assert enriched_manifest["annotations"][hook.key] == hook.value + assert enriched_manifest["annotations"]["existing-annotation"] == "annotation-value" + + +def test_argo_sync_wave_enrich_empty_manifest(empty_manifest): + sync_wave = ArgoSyncWave(sync_wave=1) + enriched_manifest = enrich_annotations( + empty_manifest, sync_wave.key, sync_wave.value + ) + assert enriched_manifest["annotations"][sync_wave.key] == sync_wave.value + assert len(enriched_manifest["annotations"]) == 1 + + +def test_argo_sync_wave_enrich_existing_annotations( + manifest_with_annotations: dict[str, Any], +): + sync_wave = ArgoSyncWave(sync_wave=2) + enriched_manifest = enrich_annotations( + manifest_with_annotations, sync_wave.key, sync_wave.value + ) + assert enriched_manifest["annotations"][sync_wave.key] == sync_wave.value + assert enriched_manifest["annotations"]["existing-annotation"] == "annotation-value" + + +def test_argo_sync_wave_multiple_enrichments(empty_manifest: dict[str, Any]): + sync_wave_1 = ArgoSyncWave(sync_wave=1) + sync_wave_2 = ArgoSyncWave(sync_wave=2) + enriched_manifest = enrich_annotations( + empty_manifest, sync_wave_1.key, sync_wave_1.value + ) + enriched_manifest = enrich_annotations( + enriched_manifest, sync_wave_2.key, sync_wave_2.value + ) + assert enriched_manifest["annotations"][sync_wave_1.key] == sync_wave_2.value + assert len(enriched_manifest["annotations"]) == 1 diff --git a/tests/pipeline/resources/manifest-pipeline/defaults.yaml b/tests/pipeline/resources/manifest-pipeline/defaults.yaml new file mode 100644 index 000000000..d24ae3b07 --- /dev/null +++ b/tests/pipeline/resources/manifest-pipeline/defaults.yaml @@ -0,0 +1,22 @@ +streams-bootstrap: + version: "3.0.3" + values: + kafka: + bootstrapServers: ${config.kafka_brokers} + schemaRegistryUrl: ${config.schema_registry.url} + +producer-app: {} # inherits from streams-bootstrap + +streams-app: # inherits from streams-bootstrap + values: + prometheus: + jmx: + enabled: false + to: + topics: + ${error_topic_name}: + type: error + value_schema: com.bakdata.kafka.DeadLetter + partitions_count: 1 + configs: + cleanup.policy: compact,delete diff --git a/tests/pipeline/resources/manifest-pipeline/pipeline.yaml b/tests/pipeline/resources/manifest-pipeline/pipeline.yaml new file mode 100644 index 000000000..cf5f7342c --- /dev/null +++ b/tests/pipeline/resources/manifest-pipeline/pipeline.yaml @@ -0,0 +1,40 @@ +- type: my-producer-app + values: + image: "my-registry/my-producer-image" + imageTag: "1.0.0" + + to: + topics: + my-producer-app-output-topic: + type: output + my-labeled-producer-app-topic-output: + label: my-producer-app-output-topic-label + + +- type: my-streams-app + values: + image: "my-registry/my-streams-app-image" + imageTag: "1.0.0" + kafka: + applicationId: "my-streams-app-id" + + from: + topics: + my-input-topic: + type: input + my-labeled-input-topic: + label: my-input-topic-label + my-input-pattern: + type: pattern + my-labeled-input-pattern: + type: pattern + label: my-input-topic-labeled-pattern + + to: + topics: + my-output-topic: + type: output + my-error-topic: + type: error + my-labeled-topic-output: + label: my-output-topic-label diff --git a/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml new file mode 100644 index 000000000..e64bce0b3 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml @@ -0,0 +1,218 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/sync-wave: '1' + labels: + app: resources-manifest-pipeline-my-producer-app + chart: producer-app-3.0.3 + release: resources-manifest-pipeline-my-producer-app + name: resources-manifest-pipeline-my-producer-app +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-producer-app + release: resources-manifest-pipeline-my-producer-app + spec: + containers: + - env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_OUTPUT_TOPIC + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-producer-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-producer-app + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/hook: PostDelete + labels: + app: resources-manifest-pipeline-my-producer-app-clean + chart: producer-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-producer-app-clean + name: resources-manifest-pipeline-my-producer-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-producer-app-clean + release: resources-manifest-pipeline-my-producer-app-clean + spec: + containers: + - args: + - clean + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_OUTPUT_TOPIC + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-producer-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-producer-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + argocd.argoproj.io/sync-wave: '1' + consumerGroup: my-streams-app-id + labels: + app: resources-manifest-pipeline-my-streams-app + chart: streams-app-3.0.3 + release: resources-manifest-pipeline-my-streams-app + name: resources-manifest-pipeline-my-streams-app +spec: + replicas: 1 + selector: + matchLabels: + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app + spec: + containers: + - env: + - name: ENV_PREFIX + value: APP_ + - name: APP_VOLATILE_GROUP_INSTANCE_ID + value: 'true' + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-Dcom.sun.management.jmxremote.port=5555 -Dcom.sun.management.jmxremote.authenticate=false + -Dcom.sun.management.jmxremote.ssl=false -XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + terminationGracePeriodSeconds: 300 + +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/hook: PostDelete + labels: + app: resources-manifest-pipeline-my-streams-app-clean + chart: streams-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-streams-app-clean + name: resources-manifest-pipeline-my-streams-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + release: resources-manifest-pipeline-my-streams-app-clean + spec: + containers: + - args: + - reset + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + diff --git a/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml new file mode 100644 index 000000000..f7086850d --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-producer-app + chart: producer-app-3.0.3 + release: resources-manifest-pipeline-my-producer-app + name: resources-manifest-pipeline-my-producer-app +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-producer-app + release: resources-manifest-pipeline-my-producer-app + spec: + containers: + - env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_OUTPUT_TOPIC + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-producer-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-producer-app + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + consumerGroup: my-streams-app-id + labels: + app: resources-manifest-pipeline-my-streams-app + chart: streams-app-3.0.3 + release: resources-manifest-pipeline-my-streams-app + name: resources-manifest-pipeline-my-streams-app +spec: + replicas: 1 + selector: + matchLabels: + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app + spec: + containers: + - env: + - name: ENV_PREFIX + value: APP_ + - name: APP_VOLATILE_GROUP_INSTANCE_ID + value: 'true' + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-Dcom.sun.management.jmxremote.port=5555 -Dcom.sun.management.jmxremote.authenticate=false + -Dcom.sun.management.jmxremote.ssl=false -XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + terminationGracePeriodSeconds: 300 + diff --git a/tests/pipeline/snapshots/test_manifest/test_python_api/resources b/tests/pipeline/snapshots/test_manifest/test_python_api/resources index eca5af9eb..723353c93 100644 --- a/tests/pipeline/snapshots/test_manifest/test_python_api/resources +++ b/tests/pipeline/snapshots/test_manifest/test_python_api/resources @@ -4,130 +4,100 @@ kind: Job metadata: labels: - app: resources-custom-config-app1 - chart: producer-app-2.9.0 - release: resources-custom-config-app1 - name: resources-custom-config-app1 + app: resources-manifest-pipeline-my-producer-app + chart: producer-app-3.0.3 + release: resources-manifest-pipeline-my-producer-app + name: resources-manifest-pipeline-my-producer-app spec: backoffLimit: 6 template: metadata: labels: - app: resources-custom-config-app1 - release: resources-custom-config-app1 + app: resources-manifest-pipeline-my-producer-app + release: resources-manifest-pipeline-my-producer-app spec: - affinity: null containers: - env: - name: ENV_PREFIX value: APP_ - - name: APP_BROKERS + - name: APP_BOOTSTRAP_SERVERS value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - name: APP_SCHEMA_REGISTRY_URL value: http://localhost:8081/ - - name: APP_DEBUG - value: 'false' - name: APP_OUTPUT_TOPIC - value: resources-custom-config-app1 + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, - name: JAVA_TOOL_OPTIONS value: '-XX:MaxRAMPercentage=75.0 ' - image: producerApp:latest + image: my-registry/my-producer-image:1.0.0 imagePullPolicy: Always - name: resources-custom-config-app1 + name: resources-manifest-pipeline-my-producer-app resources: limits: cpu: 500m memory: 2G requests: cpu: 200m - memory: 2G + memory: 300Mi restartPolicy: OnFailure --- -- !!python/object:kpops.component_handlers.kubernetes.model.KubernetesManifest - data: - apiVersion: v1 - data: - jmx-kafka-streams-app-prometheus.yml: "jmxUrl: service:jmx:rmi:///jndi/rmi://localhost:5555/jmxrmi\n\ - lowercaseOutputName: true\nlowercaseOutputLabelNames: true\nssl: false\nrules:\n\ - \ - pattern: \".*\"\n" - kind: ConfigMap - metadata: - labels: - app: resources-custom-config-app2 - chart: streams-app-2.9.0 - heritage: Helm - release: resources-custom-config-app2 - name: resources-custom-config-app2-jmx-configmap - !!python/object:kpops.component_handlers.kubernetes.model.KubernetesManifest data: apiVersion: apps/v1 kind: Deployment metadata: + annotations: + consumerGroup: my-streams-app-id labels: - app: resources-custom-config-app2 - chart: streams-app-2.9.0 - pipeline: resources-custom-config - release: resources-custom-config-app2 - name: resources-custom-config-app2 + app: resources-manifest-pipeline-my-streams-app + chart: streams-app-3.0.3 + release: resources-manifest-pipeline-my-streams-app + name: resources-manifest-pipeline-my-streams-app spec: replicas: 1 selector: matchLabels: - app: resources-custom-config-app2 - release: resources-custom-config-app2 + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app template: metadata: - annotations: - prometheus.io/port: '5556' - prometheus.io/scrape: 'true' labels: - app: resources-custom-config-app2 - pipeline: resources-custom-config - release: resources-custom-config-app2 + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app spec: - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - podAffinityTerm: - labelSelector: - matchExpressions: - - key: app - operator: In - values: - - resources-custom-config-app2 - topologyKey: kubernetes.io/hostname - weight: 1 containers: - env: - name: ENV_PREFIX value: APP_ - - name: STREAMS_LARGE_MESSAGE_ID_GENERATOR - value: com.bakdata.kafka.MurmurHashIdGenerator - - name: KAFKA_JMX_PORT - value: '5555' - name: APP_VOLATILE_GROUP_INSTANCE_ID value: 'true' - - name: APP_BROKERS + - name: APP_BOOTSTRAP_SERVERS value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - name: APP_SCHEMA_REGISTRY_URL value: http://localhost:8081/ - - name: APP_DEBUG - value: 'false' - name: APP_INPUT_TOPICS - value: resources-custom-config-app1 + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern - name: APP_OUTPUT_TOPIC - value: resources-custom-config-app2 + value: my-output-topic - name: APP_ERROR_TOPIC - value: resources-custom-config-app2-error + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id - name: JAVA_TOOL_OPTIONS value: '-Dcom.sun.management.jmxremote.port=5555 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -XX:MaxRAMPercentage=75.0 ' - image: some-image:latest + image: my-registry/my-streams-app-image:1.0.0 imagePullPolicy: Always - name: resources-custom-config-app2 - ports: - - containerPort: 5555 - name: jmx + name: resources-manifest-pipeline-my-streams-app resources: limits: cpu: 500m @@ -135,31 +105,4 @@ requests: cpu: 200m memory: 300Mi - - command: - - java - - -XX:+UnlockExperimentalVMOptions - - -XX:+UseCGroupMemoryLimitForHeap - - -XX:MaxRAMFraction=1 - - -XshowSettings:vm - - -jar - - jmx_prometheus_httpserver.jar - - '5556' - - /etc/jmx-streams-app/jmx-kafka-streams-app-prometheus.yml - image: solsson/kafka-prometheus-jmx-exporter@sha256:6f82e2b0464f50da8104acd7363fb9b995001ddff77d248379f8788e78946143 - name: prometheus-jmx-exporter - ports: - - containerPort: 5556 - resources: - limits: - cpu: 300m - memory: 2G - requests: - cpu: 100m - memory: 500Mi - volumeMounts: - - mountPath: /etc/jmx-streams-app - name: jmx-config - volumes: - - configMap: - name: resources-custom-config-app2-jmx-configmap - name: jmx-config + terminationGracePeriodSeconds: 300 diff --git a/tests/pipeline/test_manifest.py b/tests/pipeline/test_manifest.py index 84b742ae0..983859a44 100644 --- a/tests/pipeline/test_manifest.py +++ b/tests/pipeline/test_manifest.py @@ -1,3 +1,4 @@ +from collections.abc import Iterator from pathlib import Path from unittest.mock import ANY, MagicMock @@ -42,10 +43,12 @@ def test_default_config(self, mock_execute: MagicMock): result = runner.invoke( app, [ - "manifest", + "deploy", str(RESOURCE_PATH / "custom-config/pipeline.yaml"), "--environment", "development", + "--operation-mode", + "manifest", ], catch_exceptions=False, ) @@ -72,12 +75,14 @@ def test_custom_config(self, mock_execute: MagicMock): result = runner.invoke( app, [ - "manifest", + "deploy", str(RESOURCE_PATH / "custom-config/pipeline.yaml"), "--config", str(RESOURCE_PATH / "custom-config"), "--environment", "development", + "--operation-mode", + "manifest", ], catch_exceptions=False, ) @@ -106,10 +111,12 @@ def test_manifest_command(self, snapshot: Snapshot): result = runner.invoke( app, [ - "manifest", + "deploy", str(RESOURCE_PATH / "custom-config/pipeline.yaml"), "--environment", "development", + "--operation-mode", + "manifest", ], catch_exceptions=False, ) @@ -117,11 +124,12 @@ def test_manifest_command(self, snapshot: Snapshot): snapshot.assert_match(result.stdout, MANIFEST_YAML) def test_python_api(self, snapshot: Snapshot): - resources = kpops.manifest( - RESOURCE_PATH / "custom-config/pipeline.yaml", + generator = kpops.manifest_deploy( + RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML, environment="development", ) - assert isinstance(resources, list) + assert isinstance(generator, Iterator) + resources = list(generator) assert len(resources) == 2 snapshot.assert_match(yaml.dump_all(resources), "resources") @@ -129,8 +137,38 @@ def test_streams_bootstrap(self, snapshot: Snapshot): result = runner.invoke( app, [ - "manifest", + "deploy", str(RESOURCE_PATH / "streams-bootstrap" / PIPELINE_YAML), + "--operation-mode", + "manifest", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_deploy_manifest_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "deploy", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "manifest", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_deploy_argo_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "deploy", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "argo", ], catch_exceptions=False, ) From ec6858a7878588793e599198435ced4f42e22567 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Thu, 5 Dec 2024 16:37:00 +0100 Subject: [PATCH 02/12] Define Pydantic model to representing Kubernetes manifest (#546) Closes #548 --- kpops/api/__init__.py | 4 +- kpops/cli/main.py | 2 +- kpops/component_handlers/helm_wrapper/helm.py | 8 +- .../helm_wrapper/helm_diff.py | 15 +- .../component_handlers/helm_wrapper/model.py | 2 +- .../component_handlers/helm_wrapper/utils.py | 2 +- kpops/component_handlers/kubernetes/model.py | 30 ---- kpops/components/base_components/helm_app.py | 5 +- .../base_components/models/resource.py | 5 - .../base_components/pipeline_component.py | 18 +- .../producer/producer_app.py | 10 +- .../streams_bootstrap/streams/streams_app.py | 12 +- kpops/manifests/kubernetes.py | 80 +++++++++ .../helm_wrapper/test_dry_run_handler.py | 27 ++- .../helm_wrapper/test_helm_diff.py | 157 +++++++++++++++--- .../helm_wrapper/test_helm_wrapper.py | 75 ++++++--- tests/component_handlers/kubernetes/model.py | 4 +- tests/components/test_helm_app.py | 2 +- tests/{manifest => manifests}/__init__.py | 0 .../test_argo_enricher.py | 0 tests/manifests/test_kubernetes_model.py | 125 ++++++++++++++ .../test_python_api/manifest.yaml | 107 ++++++++++++ .../test_manifest/test_python_api/resources | 108 ------------ tests/pipeline/test_manifest.py | 14 +- 24 files changed, 581 insertions(+), 231 deletions(-) delete mode 100644 kpops/component_handlers/kubernetes/model.py create mode 100644 kpops/manifests/kubernetes.py rename tests/{manifest => manifests}/__init__.py (100%) rename tests/{manifest => manifests}/test_argo_enricher.py (100%) create mode 100644 tests/manifests/test_kubernetes_model.py create mode 100644 tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml delete mode 100644 tests/pipeline/snapshots/test_manifest/test_python_api/resources diff --git a/kpops/api/__init__.py b/kpops/api/__init__.py index 5fd6c856d..d0fe34428 100644 --- a/kpops/api/__init__.py +++ b/kpops/api/__init__.py @@ -16,8 +16,8 @@ from kpops.component_handlers.schema_handler.schema_handler import SchemaHandler from kpops.component_handlers.topic.handler import TopicHandler from kpops.component_handlers.topic.proxy_wrapper import ProxyWrapper -from kpops.components.base_components.models.resource import Resource from kpops.config import KpopsConfig +from kpops.manifests.kubernetes import KubernetesManifest from kpops.pipeline import ( Pipeline, PipelineGenerator, @@ -79,7 +79,7 @@ def manifest_deploy( environment: str | None = None, verbose: bool = True, operation_mode: OperationMode = OperationMode.MANIFEST, -) -> Iterator[Resource]: +) -> Iterator[tuple[KubernetesManifest, ...]]: pipeline = generate( pipeline_path=pipeline_path, dotenv=dotenv, diff --git a/kpops/cli/main.py b/kpops/cli/main.py index 0d6af160e..27afb1d94 100644 --- a/kpops/cli/main.py +++ b/kpops/cli/main.py @@ -227,7 +227,7 @@ def deploy( ) for resource in resources: for rendered_manifest in resource: - print_yaml(rendered_manifest) + print_yaml(rendered_manifest.model_dump()) @app.command(help="Destroy pipeline steps") diff --git a/kpops/component_handlers/helm_wrapper/helm.py b/kpops/component_handlers/helm_wrapper/helm.py index 3fd38df20..d4b519c27 100644 --- a/kpops/component_handlers/helm_wrapper/helm.py +++ b/kpops/component_handlers/helm_wrapper/helm.py @@ -20,13 +20,11 @@ RepoAuthFlags, Version, ) -from kpops.component_handlers.kubernetes.model import KubernetesManifest +from kpops.manifests.kubernetes import KubernetesManifest if TYPE_CHECKING: from collections.abc import Iterable, Iterator - from kpops.components.base_components.models.resource import Resource - log = logging.getLogger("Helm") @@ -162,7 +160,7 @@ def template( namespace: str, values: dict[str, Any], flags: HelmTemplateFlags | None = None, - ) -> Resource: + ) -> tuple[KubernetesManifest, ...]: """From Helm: Render chart templates locally and display the output. Any values that would normally be looked up or retrieved in-cluster will @@ -193,7 +191,7 @@ def template( command.extend(flags.to_command()) output = self.__execute(command) manifests = KubernetesManifest.from_yaml(output) - return list(manifests) + return tuple(manifests) def get_manifest(self, release_name: str, namespace: str) -> Iterable[HelmTemplate]: command = [ diff --git a/kpops/component_handlers/helm_wrapper/helm_diff.py b/kpops/component_handlers/helm_wrapper/helm_diff.py index e90edc433..5004ee52c 100644 --- a/kpops/component_handlers/helm_wrapper/helm_diff.py +++ b/kpops/component_handlers/helm_wrapper/helm_diff.py @@ -2,7 +2,7 @@ from collections.abc import Iterable, Iterator from kpops.component_handlers.helm_wrapper.model import HelmDiffConfig, HelmTemplate -from kpops.component_handlers.kubernetes.model import KubernetesManifest +from kpops.manifests.kubernetes import KubernetesManifest from kpops.utils.dict_differ import Change, render_diff log = logging.getLogger("HelmDiff") @@ -16,7 +16,7 @@ def __init__(self, config: HelmDiffConfig) -> None: def calculate_changes( current_release: Iterable[HelmTemplate], new_release: Iterable[HelmTemplate], - ) -> Iterator[Change[KubernetesManifest, KubernetesManifest]]: + ) -> Iterator[Change[KubernetesManifest | None, KubernetesManifest | None]]: """Compare 2 releases and generate a Change object for each difference. :param current_release: Iterable containing HelmTemplate objects for the current release @@ -33,12 +33,15 @@ def calculate_changes( new_resource = new_release_index.pop(current_resource.filepath, None) yield Change( current_resource.manifest, - new_resource.manifest if new_resource else KubernetesManifest(), + new_resource.manifest if new_resource else None, ) # collect added files for new_resource in new_release_index.values(): - yield Change(KubernetesManifest(), new_resource.manifest) + yield Change( + None, + new_resource.manifest, + ) def log_helm_diff( self, @@ -48,8 +51,8 @@ def log_helm_diff( ) -> None: for change in self.calculate_changes(current_release, new_release): if diff := render_diff( - change.old_value.data, - change.new_value.data, + change.old_value.model_dump() if change.old_value else {}, + change.new_value.model_dump() if change.new_value else {}, ignore=self.config.ignore, ): logger.info("\n" + diff) diff --git a/kpops/component_handlers/helm_wrapper/model.py b/kpops/component_handlers/helm_wrapper/model.py index b81328e46..d23f2c299 100644 --- a/kpops/component_handlers/helm_wrapper/model.py +++ b/kpops/component_handlers/helm_wrapper/model.py @@ -6,7 +6,7 @@ from typing_extensions import override from kpops.component_handlers.helm_wrapper.exception import ParseError -from kpops.component_handlers.kubernetes.model import KubernetesManifest +from kpops.manifests.kubernetes import KubernetesManifest from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import DescConfigModel diff --git a/kpops/component_handlers/helm_wrapper/utils.py b/kpops/component_handlers/helm_wrapper/utils.py index aa618f6a1..add4b8bcc 100644 --- a/kpops/component_handlers/helm_wrapper/utils.py +++ b/kpops/component_handlers/helm_wrapper/utils.py @@ -1,5 +1,5 @@ -from kpops.component_handlers.kubernetes.model import K8S_LABEL_MAX_LEN from kpops.component_handlers.kubernetes.utils import trim +from kpops.manifests.kubernetes import K8S_LABEL_MAX_LEN RELEASE_NAME_MAX_LEN = 53 diff --git a/kpops/component_handlers/kubernetes/model.py b/kpops/component_handlers/kubernetes/model.py deleted file mode 100644 index 5970de1bf..000000000 --- a/kpops/component_handlers/kubernetes/model.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import annotations - -import json -from collections import UserDict -from collections.abc import Iterator - -import yaml - -from kpops.utils.types import JsonType - -K8S_LABEL_MAX_LEN = 63 - - -class KubernetesManifest(UserDict[str, JsonType]): - """Representation of a Kubernetes API object as YAML/JSON mapping.""" - - @classmethod - def from_yaml( - cls, /, content: str - ) -> Iterator[KubernetesManifest]: # TODO: typing.Self for Python 3.11+ - manifests: Iterator[dict[str, JsonType]] = yaml.load_all(content, yaml.Loader) - for manifest in manifests: - yield cls(manifest) - - @classmethod - def from_json( - cls, /, content: str - ) -> KubernetesManifest: # TODO: typing.Self for Python 3.11+ - manifest: dict[str, JsonType] = json.loads(content) - return cls(manifest) diff --git a/kpops/components/base_components/helm_app.py b/kpops/components/base_components/helm_app.py index a2658b0e3..38d768359 100644 --- a/kpops/components/base_components/helm_app.py +++ b/kpops/components/base_components/helm_app.py @@ -22,14 +22,13 @@ create_helm_name_override, create_helm_release_name, ) -from kpops.component_handlers.kubernetes.model import K8S_LABEL_MAX_LEN from kpops.components.base_components.kubernetes_app import ( KubernetesApp, KubernetesAppValues, ) -from kpops.components.base_components.models.resource import Resource from kpops.config import get_config from kpops.manifests.argo import ArgoSyncWave, enrich_annotations +from kpops.manifests.kubernetes import K8S_LABEL_MAX_LEN, KubernetesManifest from kpops.utils.colorify import magentaify from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import exclude_by_name @@ -144,7 +143,7 @@ def template_flags(self) -> HelmTemplateFlags: ) @override - def manifest_deploy(self) -> Resource: + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: values = self.to_helm_values() if get_config().operation_mode is OperationMode.ARGO: sync_wave = ArgoSyncWave(sync_wave=1) diff --git a/kpops/components/base_components/models/resource.py b/kpops/components/base_components/models/resource.py index e6867081d..e69de29bb 100644 --- a/kpops/components/base_components/models/resource.py +++ b/kpops/components/base_components/models/resource.py @@ -1,5 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeAlias - -# representation of final resource for component, e.g. a list of Kubernetes manifests -Resource: TypeAlias = list[Mapping[str, Any]] diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 28445fe17..b37a1da83 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -13,7 +13,6 @@ FromTopic, InputTopicTypes, ) -from kpops.components.base_components.models.resource import Resource from kpops.components.base_components.models.to_section import ( ToSection, ) @@ -22,6 +21,7 @@ OutputTopicTypes, TopicConfig, ) +from kpops.manifests.kubernetes import KubernetesManifest from kpops.utils.docstring import describe_attr @@ -229,21 +229,21 @@ def inflate(self) -> list[PipelineComponent]: """ return [self] - def manifest_deploy(self) -> Resource: + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: """Render Kubernetes manifests for deploy.""" - return [] + return () - def manifest_destroy(self) -> Resource: + def manifest_destroy(self) -> tuple[KubernetesManifest, ...]: """Render Kubernetes manifests resources for destroy.""" - return [] + return () - def manifest_reset(self) -> Resource: + def manifest_reset(self) -> tuple[KubernetesManifest, ...]: """Render Kubernetes manifests resources for reset.""" - return [] + return () - def manifest_clean(self) -> Resource: + def manifest_clean(self) -> tuple[KubernetesManifest, ...]: """Render Kubernetes manifests resources for clean.""" - return [] + return () async def deploy(self, dry_run: bool) -> None: """Deploy component, e.g. to Kubernetes cluster. diff --git a/kpops/components/streams_bootstrap/producer/producer_app.py b/kpops/components/streams_bootstrap/producer/producer_app.py index c31393a19..47d78d75b 100644 --- a/kpops/components/streams_bootstrap/producer/producer_app.py +++ b/kpops/components/streams_bootstrap/producer/producer_app.py @@ -6,7 +6,6 @@ from kpops.api import OperationMode from kpops.components.base_components.kafka_app import KafkaAppCleaner -from kpops.components.base_components.models.resource import Resource from kpops.components.common.app_type import AppType from kpops.components.common.topic import ( KafkaTopic, @@ -20,6 +19,7 @@ from kpops.config import get_config from kpops.const.file_type import DEFAULTS_YAML, PIPELINE_YAML from kpops.manifests.argo import ArgoHook, enrich_annotations +from kpops.manifests.kubernetes import KubernetesManifest from kpops.utils.docstring import describe_attr log = logging.getLogger("ProducerApp") @@ -36,11 +36,12 @@ def helm_chart(self) -> str: ) @override - def manifest_deploy(self) -> Resource: + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: values = self.to_helm_values() if get_config().operation_mode is OperationMode.ARGO: post_delete = ArgoHook.POST_DELETE values = enrich_annotations(values, post_delete.key, post_delete.value) + return self.helm.template( self.helm_release_name, self.helm_chart, @@ -144,11 +145,12 @@ async def clean(self, dry_run: bool) -> None: await super().clean(dry_run) await self._cleaner.clean(dry_run) - def manifest_deploy(self) -> Resource: + @override + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: manifests = super().manifest_deploy() operation_mode = get_config().operation_mode if operation_mode is OperationMode.ARGO: - manifests.extend(self._cleaner.manifest_deploy()) + manifests = manifests + self._cleaner.manifest_deploy() return manifests diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index 39677bfe2..cdffbcd35 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -8,7 +8,6 @@ from kpops.component_handlers.kubernetes.pvc_handler import PVCHandler from kpops.components.base_components.helm_app import HelmApp from kpops.components.base_components.kafka_app import KafkaAppCleaner -from kpops.components.base_components.models.resource import Resource from kpops.components.common.app_type import AppType from kpops.components.common.topic import KafkaTopic from kpops.components.streams_bootstrap.base import ( @@ -20,6 +19,7 @@ from kpops.config import get_config from kpops.const.file_type import DEFAULTS_YAML, PIPELINE_YAML from kpops.manifests.argo import ArgoHook, enrich_annotations +from kpops.manifests.kubernetes import KubernetesManifest from kpops.utils.docstring import describe_attr log = logging.getLogger("StreamsApp") @@ -49,7 +49,7 @@ async def clean(self, dry_run: bool) -> None: await self.clean_pvcs(dry_run) @override - def manifest_deploy(self) -> Resource: + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: values = self.to_helm_values() if get_config().operation_mode is OperationMode.ARGO: post_delete = ArgoHook.POST_DELETE @@ -174,13 +174,13 @@ async def clean(self, dry_run: bool) -> None: await self._cleaner.clean(dry_run) @override - def manifest_deploy(self) -> Resource: + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: manifests = super().manifest_deploy() if get_config().operation_mode is OperationMode.ARGO: - manifests.extend(self._cleaner.manifest_deploy()) + manifests = manifests + self._cleaner.manifest_deploy() return manifests @override - def manifest_clean(self) -> Resource: - return [] + def manifest_clean(self) -> tuple[KubernetesManifest, ...]: + return () diff --git a/kpops/manifests/kubernetes.py b/kpops/manifests/kubernetes.py new file mode 100644 index 000000000..342bcf585 --- /dev/null +++ b/kpops/manifests/kubernetes.py @@ -0,0 +1,80 @@ +from collections.abc import Iterator +from typing import Any + +import pydantic +import yaml +from pydantic import ConfigDict, Field +from typing_extensions import override + +from kpops.utils.pydantic import CamelCaseConfigModel, by_alias + +K8S_LABEL_MAX_LEN = 63 + + +class ObjectMeta(CamelCaseConfigModel): + """Metadata for all Kubernetes objects. + + https://gtsystem.github.io/lightkube-models/1.19/models/meta_v1/#objectmeta + + """ + + annotations: dict[str, str] | None = None + creation_timestamp: str | None = Field( + default=None, description="Timestamp in RFC3339 format" + ) + finalizers: list[str] | None = None + labels: dict[str, str] | None = None + name: str | None = None + namespace: str | None = None + resource_version: str | None = None + uid: str | None = None + + model_config = ConfigDict(extra="allow") + + @pydantic.model_serializer(mode="wrap", when_used="always") + def serialize_model( + self, + default_serialize_handler: pydantic.SerializerFunctionWrapHandler, + info: pydantic.SerializationInfo, + ) -> dict[str, Any]: + result = default_serialize_handler(self) + return { + by_alias(self, name): value + for name, value in result.items() + if name in self.model_fields_set + } + + +class KubernetesManifest(CamelCaseConfigModel): + api_version: str + kind: str + metadata: ObjectMeta + _required: set[str] = pydantic.PrivateAttr({"api_version", "kind"}) + + model_config = ConfigDict(extra="allow") + + @classmethod + def from_yaml( + cls, /, content: str + ) -> Iterator["KubernetesManifest"]: # TODO: typing.Self for Python 3.11+ + manifests: Iterator[dict[str, Any]] = yaml.load_all(content, yaml.Loader) + for manifest in manifests: + yield cls(**manifest) + + @pydantic.model_serializer(mode="wrap", when_used="always") + def serialize_model( + self, + default_serialize_handler: pydantic.SerializerFunctionWrapHandler, + info: pydantic.SerializationInfo, + ) -> dict[str, Any]: + include = self._required | self.model_fields_set + result = default_serialize_handler(self) + return { + by_alias(self, name): value + for name, value in result.items() + if name in include + } + + @override + def model_dump(self, **_: Any) -> dict[str, Any]: + return super().model_dump(mode="json") diff --git a/tests/component_handlers/helm_wrapper/test_dry_run_handler.py b/tests/component_handlers/helm_wrapper/test_dry_run_handler.py index 0e05ad09f..b33411001 100644 --- a/tests/component_handlers/helm_wrapper/test_dry_run_handler.py +++ b/tests/component_handlers/helm_wrapper/test_dry_run_handler.py @@ -8,7 +8,7 @@ from kpops.component_handlers.helm_wrapper.dry_run_handler import DryRunHandler from kpops.component_handlers.helm_wrapper.model import HelmTemplate -from kpops.component_handlers.kubernetes.model import KubernetesManifest +from kpops.manifests.kubernetes import KubernetesManifest log = Logger("TestLogger") @@ -35,7 +35,14 @@ def test_should_print_helm_diff_when_release_is_new( ): helm_mock.get_manifest.return_value = iter(()) new_release = iter( - [HelmTemplate(Path("path.yaml"), KubernetesManifest({"a": 1}))] + [ + HelmTemplate( + Path("path.yaml"), + KubernetesManifest.model_validate( + {"apiVersion": "v1", "kind": "Deployment", "metadata": {}} + ), + ) + ] ) mock_load_manifest = mocker.patch( "kpops.component_handlers.helm_wrapper.dry_run_handler.Helm.load_manifest", @@ -61,12 +68,24 @@ def test_should_print_helm_diff_when_release_exists( caplog: LogCaptureFixture, ): current_release = [ - HelmTemplate(Path("path.yaml"), KubernetesManifest({"a": 1})) + HelmTemplate( + Path("path.yaml"), + KubernetesManifest.model_validate( + {"apiVersion": "v1", "kind": "Deployment", "metadata": {}} + ), + ) ] helm_mock.get_manifest.return_value = iter(current_release) new_release = iter( - [HelmTemplate(Path("path.yaml"), KubernetesManifest({"a": 1}))] + [ + HelmTemplate( + Path("path.yaml"), + KubernetesManifest.model_validate( + {"apiVersion": "v1", "kind": "Deployment", "metadata": {}} + ), + ) + ] ) mock_load_manifest = mocker.patch( "kpops.component_handlers.helm_wrapper.dry_run_handler.Helm.load_manifest", diff --git a/tests/component_handlers/helm_wrapper/test_helm_diff.py b/tests/component_handlers/helm_wrapper/test_helm_diff.py index ce64ec4ae..8373b5f0c 100644 --- a/tests/component_handlers/helm_wrapper/test_helm_diff.py +++ b/tests/component_handlers/helm_wrapper/test_helm_diff.py @@ -6,7 +6,7 @@ from kpops.component_handlers.helm_wrapper.helm_diff import HelmDiff from kpops.component_handlers.helm_wrapper.model import HelmDiffConfig, HelmTemplate -from kpops.component_handlers.kubernetes.model import KubernetesManifest +from kpops.manifests.kubernetes import KubernetesManifest, ObjectMeta from kpops.utils.dict_differ import Change logger = logging.getLogger("TestHelmDiff") @@ -18,11 +18,34 @@ def helm_diff(self) -> HelmDiff: return HelmDiff(HelmDiffConfig()) def test_calculate_changes_unchanged(self, helm_diff: HelmDiff): - templates = [HelmTemplate(Path("a.yaml"), KubernetesManifest())] + templates = [ + HelmTemplate( + Path("a.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({}), + } + ), + ) + ] assert list(helm_diff.calculate_changes(templates, templates)) == [ Change( - old_value={}, - new_value={}, + old_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({}), + } + ), + new_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({}), + } + ), ), ] @@ -31,26 +54,86 @@ def test_calculate_changes_matching(self, helm_diff: HelmDiff): assert list( helm_diff.calculate_changes( [ - HelmTemplate(Path("a.yaml"), KubernetesManifest({"a": 1})), - HelmTemplate(Path("b.yaml"), KubernetesManifest({"b": 1})), + HelmTemplate( + Path("a.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "1"}), + } + ), + ), + HelmTemplate( + Path("b.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"b": "1"}), + } + ), + ), ], [ - HelmTemplate(Path("a.yaml"), KubernetesManifest({"a": 2})), - HelmTemplate(Path("c.yaml"), KubernetesManifest({"c": 1})), + HelmTemplate( + Path("a.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "2"}), + } + ), + ), + HelmTemplate( + Path("c.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"c": "1"}), + } + ), + ), ], ) ) == [ Change( - old_value={"a": 1}, - new_value={"a": 2}, + old_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "1"}), + } + ), + new_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "2"}), + } + ), ), Change( - old_value={"b": 1}, - new_value={}, + old_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"b": "1"}), + } + ), + new_value=None, ), Change( - old_value={}, - new_value={"c": 1}, + old_value=None, + new_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"c": "1"}), + } + ), ), ] @@ -58,12 +141,30 @@ def test_calculate_changes_new_release(self, helm_diff: HelmDiff): # test no current release assert list( helm_diff.calculate_changes( - (), [HelmTemplate(Path("a.yaml"), KubernetesManifest({"a": 1}))] + (), + [ + HelmTemplate( + Path("a.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "1"}), + } + ), + ) + ], ) ) == [ Change( - old_value={}, - new_value={"a": 1}, + old_value=None, + new_value=KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "1"}), + } + ), ), ] @@ -71,6 +172,24 @@ def test_log_helm_diff(self, helm_diff: HelmDiff, caplog: LogCaptureFixture): helm_diff.log_helm_diff( logger, (), - [HelmTemplate(Path("a.yaml"), KubernetesManifest({"a": 1}))], + [ + HelmTemplate( + Path("a.yaml"), + KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": ObjectMeta.model_validate({"a": "1"}), + } + ), + ) + ], ) - assert caplog.messages == ["\n\x1b[32m+ a: 1\n\x1b[0m"] + assert caplog.messages == [ + "\n" + "\x1b[32m+ apiVersion: v1\n" + "\x1b[0m\x1b[32m+ kind: Deployment\n" + "\x1b[0m\x1b[32m+ metadata:\n" + "\x1b[0m\x1b[32m+ a: '1'\n" + "\x1b[0m" + ] diff --git a/tests/component_handlers/helm_wrapper/test_helm_wrapper.py b/tests/component_handlers/helm_wrapper/test_helm_wrapper.py index 23c855251..3d80e59b2 100644 --- a/tests/component_handlers/helm_wrapper/test_helm_wrapper.py +++ b/tests/component_handlers/helm_wrapper/test_helm_wrapper.py @@ -13,12 +13,12 @@ HelmConfig, HelmTemplateFlags, HelmUpgradeInstallFlags, - KubernetesManifest, ParseError, RepoAuthFlags, Version, ) from kpops.components.common.app_type import AppType +from kpops.manifests.kubernetes import KubernetesManifest class TestHelmWrapper: @@ -292,7 +292,7 @@ def test_validate_console_output(self): def test_helm_template(self): path = Path("test2.yaml") - manifest = KubernetesManifest( + manifest = KubernetesManifest.model_validate( { "apiVersion": "v1", "kind": "ServiceAccount", @@ -309,12 +309,16 @@ def test_load_manifest_with_no_notes(self): MANIFEST: --- # Source: chart/templates/test3a.yaml - data: - - a: 1 - - b: 2 + apiVersion: v1 + kind: Pod + metadata: + name: test-3a --- # Source: chart/templates/test3b.yaml - foo: bar + apiVersion: v1 + kind: Pod + metadata: + name: test-3b """ ) helm_templates = list(Helm.load_manifest(stdout)) @@ -323,11 +327,21 @@ def test_load_manifest_with_no_notes(self): isinstance(helm_template, HelmTemplate) for helm_template in helm_templates ) assert helm_templates[0].filepath == Path("chart/templates/test3a.yaml") - assert helm_templates[0].manifest == KubernetesManifest( - {"data": [{"a": 1}, {"b": 2}]} + assert helm_templates[0].manifest == KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": {"name": "test-3a"}, + } ) assert helm_templates[1].filepath == Path("chart/templates/test3b.yaml") - assert helm_templates[1].manifest == KubernetesManifest({"foo": "bar"}) + assert helm_templates[1].manifest == KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": {"name": "test-3b"}, + } + ) def test_raise_parse_error_when_helm_content_is_invalid(self): stdout = dedent( @@ -372,12 +386,16 @@ def test_load_manifest(self): MANIFEST: --- # Source: chart/templates/test3a.yaml - data: - - a: 1 - - b: 2 + apiVersion: v1 + kind: Pod + metadata: + name: test-3a --- # Source: chart/templates/test3b.yaml - foo: bar + apiVersion: v1 + kind: Pod + metadata: + name: test-3b NOTES: 1. Get the application URL by running these commands: @@ -393,20 +411,31 @@ def test_load_manifest(self): isinstance(helm_template, HelmTemplate) for helm_template in helm_templates ) assert helm_templates[0].filepath == Path("chart/templates/test3a.yaml") - assert helm_templates[0].manifest == KubernetesManifest( - {"data": [{"a": 1}, {"b": 2}]} + assert helm_templates[0].manifest == KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": {"name": "test-3a"}, + } ) assert helm_templates[1].filepath == Path("chart/templates/test3b.yaml") - assert helm_templates[1].manifest == KubernetesManifest({"foo": "bar"}) + assert helm_templates[1].manifest == KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": {"name": "test-3b"}, + } + ) def test_helm_get_manifest(self, helm: Helm, mock_execute: MagicMock): mock_execute.return_value = dedent( """ --- # Source: chart/templates/test.yaml - data: - - a: 1 - - b: 2 + apiVersion: v1 + kind: Pod + metadata: + name: my-pod """ ) helm_templates = list(helm.get_manifest("test-release", "test-namespace")) @@ -422,8 +451,12 @@ def test_helm_get_manifest(self, helm: Helm, mock_execute: MagicMock): ) assert len(helm_templates) == 1 assert helm_templates[0].filepath == Path("chart/templates/test.yaml") - assert helm_templates[0].manifest == KubernetesManifest( - {"data": [{"a": 1}, {"b": 2}]} + assert helm_templates[0].manifest == KubernetesManifest.model_validate( + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": {"name": "my-pod"}, + } ) mock_execute.side_effect = ReleaseNotFoundException() diff --git a/tests/component_handlers/kubernetes/model.py b/tests/component_handlers/kubernetes/model.py index 334c1f937..06c492def 100644 --- a/tests/component_handlers/kubernetes/model.py +++ b/tests/component_handlers/kubernetes/model.py @@ -2,7 +2,7 @@ import pytest -from kpops.component_handlers.kubernetes.model import KubernetesManifest +from kpops.manifests.kubernetes import KubernetesManifest class TestKubernetesManifest: @@ -23,7 +23,7 @@ class TestKubernetesManifest: ), [ KubernetesManifest( - { + **{ "apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"labels": {"foo": "bar"}}, diff --git a/tests/components/test_helm_app.py b/tests/components/test_helm_app.py index 0d0649747..f72514299 100644 --- a/tests/components/test_helm_app.py +++ b/tests/components/test_helm_app.py @@ -9,8 +9,8 @@ HelmUpgradeInstallFlags, RepoAuthFlags, ) -from kpops.component_handlers.kubernetes.model import K8S_LABEL_MAX_LEN from kpops.components.base_components.helm_app import HelmApp, HelmAppValues +from kpops.manifests.kubernetes import K8S_LABEL_MAX_LEN from kpops.utils.colorify import magentaify diff --git a/tests/manifest/__init__.py b/tests/manifests/__init__.py similarity index 100% rename from tests/manifest/__init__.py rename to tests/manifests/__init__.py diff --git a/tests/manifest/test_argo_enricher.py b/tests/manifests/test_argo_enricher.py similarity index 100% rename from tests/manifest/test_argo_enricher.py rename to tests/manifests/test_argo_enricher.py diff --git a/tests/manifests/test_kubernetes_model.py b/tests/manifests/test_kubernetes_model.py new file mode 100644 index 000000000..d1fbcd623 --- /dev/null +++ b/tests/manifests/test_kubernetes_model.py @@ -0,0 +1,125 @@ +from textwrap import dedent + +import pytest + +from kpops.manifests.kubernetes import KubernetesManifest, ObjectMeta + + +class TestCRD(KubernetesManifest): + api_version: str = "v1" + kind: str = "TestCRD" + + +@pytest.fixture +def crd_manifest() -> TestCRD: + return TestCRD(metadata=ObjectMeta.model_validate({"foo": "bar"})) + + +@pytest.fixture +def example_manifest() -> KubernetesManifest: + """Fixture providing an example KubernetesManifest instance.""" + metadata = ObjectMeta( + name="example", + namespace="default", + labels={"app": "test"}, + ) + return KubernetesManifest( + api_version="v1", + kind="Deployment", + metadata=metadata, + ) + + +def test_serialize_model_include_required_fields(crd_manifest: TestCRD): + """Test that the serialize_model method excludes unset fields.""" + serialized = crd_manifest.model_dump() + expected_serialized = { + "apiVersion": "v1", + "kind": "TestCRD", + "metadata": {"foo": "bar"}, + } + assert serialized == expected_serialized + + +def test_serialize_model_excludes_none(example_manifest: KubernetesManifest): + """Test that the serialize_model method excludes unset fields.""" + serialized = example_manifest.model_dump() + expected_serialized = { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": { + "name": "example", + "namespace": "default", + "labels": {"app": "test"}, + }, + } + assert serialized == expected_serialized + + +def test_serialize_model_includes_required_fields(): + """Test that required fields are always included in serialization.""" + metadata = ObjectMeta(name="example", namespace="default") + manifest = KubernetesManifest(api_version="v1", kind="Pod", metadata=metadata) + serialized = manifest.model_dump() + assert "apiVersion" in serialized + assert "kind" in serialized + assert "metadata" in serialized + + +def test_from_yaml_parsing(): + """Test the from_yaml method parses YAML into KubernetesManifest objects.""" + yaml_content = dedent(""" + --- + apiVersion: v1 + kind: Service + metadata: + name: test-service + namespace: test-namespace + + --- + apiVersion: v1 + kind: Pod + metadata: + name: test-pod + namespace: test-namespace + """) + manifests = list(KubernetesManifest.from_yaml(yaml_content)) + assert len(manifests) == 2 + assert manifests[0].api_version == "v1" + assert manifests[0].kind == "Service" + assert manifests[0].metadata.name == "test-service" + assert manifests[1].kind == "Pod" + assert manifests[1].metadata.name == "test-pod" + + +def test_model_dump_json_output(example_manifest: KubernetesManifest): + """Test the model_dump method for JSON output.""" + dumped = example_manifest.model_dump() + expected_dumped = { + "apiVersion": "v1", + "kind": "Deployment", + "metadata": { + "name": "example", + "namespace": "default", + "labels": {"app": "test"}, + }, + } + assert dumped == expected_dumped + + +def test_objectmeta_serialization(): + """Test ObjectMeta serialization with optional fields.""" + metadata = ObjectMeta( + name="example", + namespace="default", + labels={"app": "test"}, + annotations=None, # This field should be included + ) + serialized = metadata.model_dump() + expected_serialized = { + "annotations": None, + "name": "example", + "namespace": "default", + "labels": {"app": "test"}, + } + assert serialized == expected_serialized diff --git a/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml new file mode 100644 index 000000000..f7086850d --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-producer-app + chart: producer-app-3.0.3 + release: resources-manifest-pipeline-my-producer-app + name: resources-manifest-pipeline-my-producer-app +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-producer-app + release: resources-manifest-pipeline-my-producer-app + spec: + containers: + - env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_OUTPUT_TOPIC + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-producer-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-producer-app + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + consumerGroup: my-streams-app-id + labels: + app: resources-manifest-pipeline-my-streams-app + chart: streams-app-3.0.3 + release: resources-manifest-pipeline-my-streams-app + name: resources-manifest-pipeline-my-streams-app +spec: + replicas: 1 + selector: + matchLabels: + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app + release: resources-manifest-pipeline-my-streams-app + spec: + containers: + - env: + - name: ENV_PREFIX + value: APP_ + - name: APP_VOLATILE_GROUP_INSTANCE_ID + value: 'true' + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-Dcom.sun.management.jmxremote.port=5555 -Dcom.sun.management.jmxremote.authenticate=false + -Dcom.sun.management.jmxremote.ssl=false -XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + terminationGracePeriodSeconds: 300 + diff --git a/tests/pipeline/snapshots/test_manifest/test_python_api/resources b/tests/pipeline/snapshots/test_manifest/test_python_api/resources deleted file mode 100644 index 723353c93..000000000 --- a/tests/pipeline/snapshots/test_manifest/test_python_api/resources +++ /dev/null @@ -1,108 +0,0 @@ -- !!python/object:kpops.component_handlers.kubernetes.model.KubernetesManifest - data: - apiVersion: batch/v1 - kind: Job - metadata: - labels: - app: resources-manifest-pipeline-my-producer-app - chart: producer-app-3.0.3 - release: resources-manifest-pipeline-my-producer-app - name: resources-manifest-pipeline-my-producer-app - spec: - backoffLimit: 6 - template: - metadata: - labels: - app: resources-manifest-pipeline-my-producer-app - release: resources-manifest-pipeline-my-producer-app - spec: - containers: - - env: - - name: ENV_PREFIX - value: APP_ - - name: APP_BOOTSTRAP_SERVERS - value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - - name: APP_SCHEMA_REGISTRY_URL - value: http://localhost:8081/ - - name: APP_OUTPUT_TOPIC - value: my-producer-app-output-topic - - name: APP_LABELED_OUTPUT_TOPICS - value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, - - name: JAVA_TOOL_OPTIONS - value: '-XX:MaxRAMPercentage=75.0 ' - image: my-registry/my-producer-image:1.0.0 - imagePullPolicy: Always - name: resources-manifest-pipeline-my-producer-app - resources: - limits: - cpu: 500m - memory: 2G - requests: - cpu: 200m - memory: 300Mi - restartPolicy: OnFailure ---- -- !!python/object:kpops.component_handlers.kubernetes.model.KubernetesManifest - data: - apiVersion: apps/v1 - kind: Deployment - metadata: - annotations: - consumerGroup: my-streams-app-id - labels: - app: resources-manifest-pipeline-my-streams-app - chart: streams-app-3.0.3 - release: resources-manifest-pipeline-my-streams-app - name: resources-manifest-pipeline-my-streams-app - spec: - replicas: 1 - selector: - matchLabels: - app: resources-manifest-pipeline-my-streams-app - release: resources-manifest-pipeline-my-streams-app - template: - metadata: - labels: - app: resources-manifest-pipeline-my-streams-app - release: resources-manifest-pipeline-my-streams-app - spec: - containers: - - env: - - name: ENV_PREFIX - value: APP_ - - name: APP_VOLATILE_GROUP_INSTANCE_ID - value: 'true' - - name: APP_BOOTSTRAP_SERVERS - value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - - name: APP_SCHEMA_REGISTRY_URL - value: http://localhost:8081/ - - name: APP_INPUT_TOPICS - value: my-input-topic - - name: APP_INPUT_PATTERN - value: my-input-pattern - - name: APP_OUTPUT_TOPIC - value: my-output-topic - - name: APP_ERROR_TOPIC - value: resources-manifest-pipeline-my-streams-app-error - - name: APP_LABELED_OUTPUT_TOPICS - value: my-output-topic-label=my-labeled-topic-output, - - name: APP_LABELED_INPUT_TOPICS - value: my-input-topic-label=my-labeled-input-topic, - - name: APP_LABELED_INPUT_PATTERNS - value: my-input-topic-labeled-pattern=my-labeled-input-pattern, - - name: APP_APPLICATION_ID - value: my-streams-app-id - - name: JAVA_TOOL_OPTIONS - value: '-Dcom.sun.management.jmxremote.port=5555 -Dcom.sun.management.jmxremote.authenticate=false - -Dcom.sun.management.jmxremote.ssl=false -XX:MaxRAMPercentage=75.0 ' - image: my-registry/my-streams-app-image:1.0.0 - imagePullPolicy: Always - name: resources-manifest-pipeline-my-streams-app - resources: - limits: - cpu: 500m - memory: 2G - requests: - cpu: 200m - memory: 300Mi - terminationGracePeriodSeconds: 300 diff --git a/tests/pipeline/test_manifest.py b/tests/pipeline/test_manifest.py index 983859a44..65c132cf4 100644 --- a/tests/pipeline/test_manifest.py +++ b/tests/pipeline/test_manifest.py @@ -3,7 +3,7 @@ from unittest.mock import ANY, MagicMock import pytest -import yaml +from _pytest.capture import CaptureFixture from pytest_mock import MockerFixture from pytest_snapshot.plugin import Snapshot from typer.testing import CliRunner @@ -13,6 +13,8 @@ from kpops.component_handlers.helm_wrapper.helm import Helm from kpops.component_handlers.helm_wrapper.model import HelmConfig, Version from kpops.const.file_type import PIPELINE_YAML +from kpops.manifests.kubernetes import KubernetesManifest +from kpops.utils.yaml import print_yaml MANIFEST_YAML = "manifest.yaml" @@ -123,7 +125,7 @@ def test_manifest_command(self, snapshot: Snapshot): assert result.exit_code == 0, result.stdout snapshot.assert_match(result.stdout, MANIFEST_YAML) - def test_python_api(self, snapshot: Snapshot): + def test_python_api(self, capsys: CaptureFixture, snapshot: Snapshot): generator = kpops.manifest_deploy( RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML, environment="development", @@ -131,7 +133,13 @@ def test_python_api(self, snapshot: Snapshot): assert isinstance(generator, Iterator) resources = list(generator) assert len(resources) == 2 - snapshot.assert_match(yaml.dump_all(resources), "resources") + for resource in resources: + for manifest in resource: + assert isinstance(manifest, KubernetesManifest) + print_yaml(manifest.model_dump()) + + captured = capsys.readouterr() + snapshot.assert_match(captured.out, MANIFEST_YAML) def test_streams_bootstrap(self, snapshot: Snapshot): result = runner.invoke( From 2071c1b809f17e0f9b61538f3546d20f468f4429 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Tue, 10 Dec 2024 17:02:01 +0000 Subject: [PATCH 03/12] Manifest toSection with Strimzi KafkaTopic (#545) Closes #537 --- config.yaml | 3 + .../resources/variables/config_env_vars.env | 3 + .../resources/variables/config_env_vars.md | 1 + docs/docs/schema/config.json | 31 +++++++ kpops/components/streams_bootstrap/base.py | 13 +++ kpops/config/__init__.py | 35 ++++++++ kpops/manifests/strimzi/__init__.py | 0 kpops/manifests/strimzi/kafka_topic.py | 89 +++++++++++++++++++ .../config.yaml | 1 + tests/conftest.py | 2 +- tests/manifests/strimzi/__init__.py | 0 tests/manifests/strimzi/test_kafka_topic.py | 77 ++++++++++++++++ .../test_deploy_argo_mode/manifest.yaml | 73 +++++++++++++++ .../test_deploy_manifest_mode/manifest.yaml | 73 +++++++++++++++ .../test_python_api/manifest.yaml | 73 +++++++++++++++ .../test_streams_bootstrap/manifest.yaml | 73 +++++++++++++++ tests/test_kpops_config.py | 25 +++++- 17 files changed, 567 insertions(+), 5 deletions(-) create mode 100644 kpops/manifests/strimzi/__init__.py create mode 100644 kpops/manifests/strimzi/kafka_topic.py create mode 100644 tests/manifests/strimzi/__init__.py create mode 100644 tests/manifests/strimzi/test_kafka_topic.py diff --git a/config.yaml b/config.yaml index 359b51a21..aa32d7d3c 100644 --- a/config.yaml +++ b/config.yaml @@ -1,2 +1,5 @@ kafka_brokers: "http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092" pipeline_base_dir: tests/pipeline +strimzi_topic: + label: + strimzi.io/cluster: my-cluster diff --git a/docs/docs/resources/variables/config_env_vars.env b/docs/docs/resources/variables/config_env_vars.env index b64bac2e0..baaf4fdbf 100644 --- a/docs/docs/resources/variables/config_env_vars.env +++ b/docs/docs/resources/variables/config_env_vars.env @@ -61,3 +61,6 @@ KPOPS_RETAIN_CLEAN_JOBS=False # operation_mode # The operation mode of KPOps (managed, manifest, argo). KPOPS_OPERATION_MODE=managed +# strimzi_topic +# Configuration for Strimzi Kafka Topics. +KPOPS_STRIMZI_TOPIC # No default value, not required diff --git a/docs/docs/resources/variables/config_env_vars.md b/docs/docs/resources/variables/config_env_vars.md index 6b79a743c..f7fcd5303 100644 --- a/docs/docs/resources/variables/config_env_vars.md +++ b/docs/docs/resources/variables/config_env_vars.md @@ -20,3 +20,4 @@ These variables take precedence over the settings in `config.yaml`. Variables ma |KPOPS_HELM_DIFF_CONFIG__IGNORE | |True |Set of keys that should not be checked. |helm_diff_config.ignore | |KPOPS_RETAIN_CLEAN_JOBS |False |False |Whether to retain clean up jobs in the cluster or uninstall the, after completion.|retain_clean_jobs | |KPOPS_OPERATION_MODE |managed |False |The operation mode of KPOps (managed, manifest, argo). |operation_mode | +|KPOPS_STRIMZI_TOPIC | |False |Configuration for Strimzi Kafka Topics. |strimzi_topic | diff --git a/docs/docs/schema/config.json b/docs/docs/schema/config.json index 02d04ea6e..bbf12c5ac 100644 --- a/docs/docs/schema/config.json +++ b/docs/docs/schema/config.json @@ -162,6 +162,25 @@ "title": "SchemaRegistryConfig", "type": "object" }, + "StrimziTopicConfig": { + "additionalProperties": false, + "description": "Configuration for Strimzi Kafka Topics.", + "properties": { + "label": { + "additionalProperties": { + "type": "string" + }, + "description": "The label to identify the KafkaTopic resources managed by the Topic Operator. This does not have to be the name of the Kafka cluster. It can be the label assigned to the KafkaTopic resource. If you deploy more than one Topic Operator, the labels must be unique for each. That is, the operators cannot manage the same resources.", + "title": "Label", + "type": "object" + } + }, + "required": [ + "label" + ], + "title": "StrimziTopicConfig", + "type": "object" + }, "TopicNameConfig": { "additionalProperties": false, "description": "Configure the topic name variables you can use in the pipeline definition.", @@ -283,6 +302,18 @@ }, "description": "Configuration for Schema Registry." }, + "strimzi_topic": { + "anyOf": [ + { + "$ref": "#/$defs/StrimziTopicConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Configuration for Strimzi Kafka Topics." + }, "topic_name_config": { "allOf": [ { diff --git a/kpops/components/streams_bootstrap/base.py b/kpops/components/streams_bootstrap/base.py index 47973624b..a4ab5780e 100644 --- a/kpops/components/streams_bootstrap/base.py +++ b/kpops/components/streams_bootstrap/base.py @@ -7,11 +7,14 @@ import pydantic from pydantic import Field +from typing_extensions import override from kpops.component_handlers.helm_wrapper.model import HelmRepoConfig from kpops.components.base_components import KafkaApp from kpops.components.base_components.helm_app import HelmApp from kpops.components.streams_bootstrap.model import StreamsBootstrapValues +from kpops.manifests.kubernetes import KubernetesManifest +from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic from kpops.utils.docstring import describe_attr if TYPE_CHECKING: @@ -83,3 +86,13 @@ def warning_for_latest_image_tag(self) -> Self: f"The image tag for component '{self.name}' is set or defaulted to 'latest'. Please, consider providing a stable image tag." ) return self + + @override + def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: + resource = super().manifest_deploy() + if self.to: + resource = resource + tuple( + StrimziKafkaTopic.from_topic(topic) for topic in self.to.kafka_topics + ) + + return resource diff --git a/kpops/config/__init__.py b/kpops/config/__init__.py index 7398d5e7c..07ecce58c 100644 --- a/kpops/config/__init__.py +++ b/kpops/config/__init__.py @@ -4,6 +4,7 @@ from pathlib import Path from typing import ClassVar +import pydantic from pydantic import AnyHttpUrl, Field, PrivateAttr, TypeAdapter from pydantic_settings import ( BaseSettings, @@ -12,6 +13,7 @@ ) from typing_extensions import override +from kpops.api.exception import ValidationError from kpops.api.operation import OperationMode from kpops.component_handlers.helm_wrapper.model import HelmConfig, HelmDiffConfig from kpops.utils.docstring import describe_object @@ -19,6 +21,35 @@ ENV_PREFIX = "KPOPS_" +log = logging.getLogger("KPOpsConfig") + + +class StrimziTopicConfig(BaseSettings): + """Configuration for Strimzi Kafka Topics.""" + + label_: dict[str, str] = Field( + alias="label", + description="The label to identify the KafkaTopic resources managed by the Topic Operator. This does not have to be the name of the Kafka cluster. It can be the label assigned to the KafkaTopic resource. If you deploy more than one Topic Operator, the labels must be unique for each. That is, the operators cannot manage the same resources.", + ) + + @property + def cluster_labels(self) -> tuple[str, str]: + """Return the defined strimzi_topic.label as a tuple.""" + return next(iter(self.label_.items())) + + @pydantic.field_validator("label_", mode="after") + @classmethod + def label_validator(cls, label: dict[str, str]) -> dict[str, str]: + if len(label) == 0: + msg = "'strimzi_topic.label' must contain a single key-value pair." + raise ValidationError(msg) + if len(label) > 1: + log.warning( + "'resource_label' only reads the first entry in the dictionary. Other defined labels will be ignored." + ) + + return label + class TopicNameConfig(BaseSettings): """Configure the topic name variables you can use in the pipeline definition.""" @@ -125,6 +156,10 @@ class KpopsConfig(BaseSettings): default=OperationMode.MANAGED, description="The operation mode of KPOps (managed, manifest, argo).", ) + strimzi_topic: StrimziTopicConfig | None = Field( + default=None, + description=describe_object(StrimziTopicConfig.__doc__), + ) model_config = SettingsConfigDict( env_prefix=ENV_PREFIX, diff --git a/kpops/manifests/strimzi/__init__.py b/kpops/manifests/strimzi/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kpops/manifests/strimzi/kafka_topic.py b/kpops/manifests/strimzi/kafka_topic.py new file mode 100644 index 000000000..4b9a4b667 --- /dev/null +++ b/kpops/manifests/strimzi/kafka_topic.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from pydantic import ConfigDict, Field, model_validator + +from kpops.api.exception import ValidationError +from kpops.components.common.topic import KafkaTopic +from kpops.config import get_config +from kpops.manifests.kubernetes import KubernetesManifest, ObjectMeta +from kpops.utils.docstring import describe_attr +from kpops.utils.pydantic import CamelCaseConfigModel + +if TYPE_CHECKING: + try: + from typing import Self # pyright: ignore[reportAttributeAccessIssue] + except ImportError: + from typing_extensions import Self + + +class TopicSpec(CamelCaseConfigModel): + """Specification of a Kafka topic. + + :param partitions: The number of partitions the topic should have. This cannot be decreased after topic creation. It can be increased after topic creation, but it is important to understand the consequences that has, especially for topics with semantic partitioning. When absent this will default to the broker configuration for `num.partitions`. + :param replicas: The number of replicas the topic should have. When absent this will default to the broker configuration for `default.replication.factor`. + :param config: The topic configuration. Topic config reference: https://docs.confluent.io/platform/current/installation/configuration/topic-configs.html + + """ + + partitions: int = Field( + default=1, ge=1, description=describe_attr("partitions", __doc__) + ) + replicas: int = Field( + default=1, ge=1, le=32767, description=describe_attr("replicas", __doc__) + ) + config: dict[str, Any] | None = Field( + default=None, description=describe_attr("config", __doc__) + ) + + model_config = ConfigDict(extra="allow") + + @model_validator(mode="before") + @classmethod + def set_defaults_if_none(cls, values: Any) -> Any: + if values.get("partitions") is None: + values["partitions"] = 1 + if values.get("replicas") is None: + values["replicas"] = 1 + return values + + +class StrimziKafkaTopic(KubernetesManifest): + """Represents a Strimzi Kafka Topic CRD. + + CRD definition: https://github.com/strimzi/strimzi-kafka-operator/blob/main/install/cluster-operator/043-Crd-kafkatopic.yaml + example: https://github.com/strimzi/strimzi-kafka-operator/blob/main/examples/topic/kafka-topic.yaml + """ + + api_version: str = "kafka.strimzi.io/v1beta2" + kind: str = "KafkaTopic" + metadata: ObjectMeta + spec: TopicSpec + status: dict[str, Any] | None = None + + @classmethod + def from_topic(cls, topic: KafkaTopic) -> Self: + strimzi_topic = get_config().strimzi_topic + if not strimzi_topic: + msg = "When manifesting KafkaTopic you must define 'strimzi_topic.resource_label' in the config.yaml" + raise ValidationError(msg) + cluster_domain, cluster_name = strimzi_topic.cluster_labels + + metadata = ObjectMeta.model_validate( + { + "name": topic.name, + "labels": {cluster_domain: cluster_name}, + } + ) + spec = TopicSpec.model_validate( + { + "partitions": topic.config.partitions_count, + "replicas": topic.config.replication_factor, + "config": topic.config.configs, + } + ) + return cls( + metadata=metadata, + spec=spec, + ) diff --git a/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml b/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml index 19b7f5d95..438094f12 100644 --- a/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml +++ b/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml @@ -24,6 +24,7 @@ schema_registry: enabled: false timeout: 30 url: http://localhost:8081/ +strimzi_topic: null topic_name_config: default_error_topic_name: ${pipeline.name}-${component.name}-error default_output_topic_name: ${pipeline.name}-${component.name} diff --git a/tests/conftest.py b/tests/conftest.py index 4983aa325..777c87416 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -57,8 +57,8 @@ def custom_components() -> Iterator[None]: def clear_kpops_config() -> Iterator[None]: from kpops.config import KpopsConfig - yield KpopsConfig._instance = None + yield KUBECONFIG = """ diff --git a/tests/manifests/strimzi/__init__.py b/tests/manifests/strimzi/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/manifests/strimzi/test_kafka_topic.py b/tests/manifests/strimzi/test_kafka_topic.py new file mode 100644 index 000000000..a519c2e94 --- /dev/null +++ b/tests/manifests/strimzi/test_kafka_topic.py @@ -0,0 +1,77 @@ +from unittest.mock import MagicMock + +import pytest +from pydantic import ValidationError as PydanticValidationError +from pytest_mock import MockerFixture + +from kpops.api.exception import ValidationError +from kpops.components.common.topic import KafkaTopic, TopicConfig +from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic, TopicSpec + + +@pytest.fixture +def kafka_topic() -> KafkaTopic: + return KafkaTopic( + name="test-topic", + config=TopicConfig.model_validate( + { + "partitions_count": 3, + "replication_factor": 2, + "configs": {"cleanup.policy": "compact"}, + }, + ), + ) + + +def test_topic_spec_defaults(): + spec = TopicSpec() + assert spec.partitions == 1 + assert spec.replicas == 1 + assert spec.config is None + + +def test_topic_spec_custom_values(): + spec = TopicSpec(partitions=3, replicas=2, config={"retention.ms": "60000"}) + assert spec.partitions == 3 + assert spec.replicas == 2 + assert spec.config == {"retention.ms": "60000"} + + +def test_topic_spec_validation(): + with pytest.raises(PydanticValidationError): + TopicSpec(partitions=0) # Less than 1, should raise validation error + + with pytest.raises(PydanticValidationError): + TopicSpec(replicas=40000) # Exceeds max value, should raise validation error + + +def test_strimzi_kafka_topic_from_topic(kafka_topic: KafkaTopic, mocker: MockerFixture): + mock_config = MagicMock() + mock_config.strimzi_topic.cluster_labels = ("bakdata.com/cluster", "my-cluster") + mocker.patch( + "kpops.manifests.strimzi.kafka_topic.get_config", return_value=mock_config + ) + + strimzi_topic = StrimziKafkaTopic.from_topic(kafka_topic) + + # Check metadata + assert strimzi_topic.metadata.name == kafka_topic.name + assert strimzi_topic.metadata.labels == {"bakdata.com/cluster": "my-cluster"} + + # Check spec + assert strimzi_topic.spec.partitions == kafka_topic.config.partitions_count + assert strimzi_topic.spec.replicas == kafka_topic.config.replication_factor + assert strimzi_topic.spec.config == kafka_topic.config.configs + + +def test_strimzi_kafka_topic_missing_config(kafka_topic, mocker): + mock_config = MagicMock() + mock_config.strimzi_topic = None + mocker.patch( + "kpops.manifests.strimzi.kafka_topic.get_config", return_value=mock_config + ) + + with pytest.raises( + ValidationError, match="must define 'strimzi_topic.resource_label'" + ): + StrimziKafkaTopic.from_topic(kafka_topic) diff --git a/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml index e64bce0b3..336d3d726 100644 --- a/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_deploy_argo_mode/manifest.yaml @@ -43,6 +43,30 @@ spec: memory: 300Mi restartPolicy: OnFailure +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: batch/v1 kind: Job @@ -156,6 +180,55 @@ spec: memory: 300Mi terminationGracePeriodSeconds: 300 +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + --- apiVersion: batch/v1 kind: Job diff --git a/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml index f7086850d..7b6d5b8aa 100644 --- a/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_deploy_manifest_mode/manifest.yaml @@ -41,6 +41,30 @@ spec: memory: 300Mi restartPolicy: OnFailure +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: apps/v1 kind: Deployment @@ -105,3 +129,52 @@ spec: memory: 300Mi terminationGracePeriodSeconds: 300 +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml index f7086850d..7b6d5b8aa 100644 --- a/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml @@ -41,6 +41,30 @@ spec: memory: 300Mi restartPolicy: OnFailure +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: apps/v1 kind: Deployment @@ -105,3 +129,52 @@ spec: memory: 300Mi terminationGracePeriodSeconds: 300 +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/snapshots/test_manifest/test_streams_bootstrap/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_streams_bootstrap/manifest.yaml index 075777bf9..a1dd22945 100644 --- a/tests/pipeline/snapshots/test_manifest/test_streams_bootstrap/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_streams_bootstrap/manifest.yaml @@ -70,6 +70,30 @@ spec: successfulJobsHistoryLimit: 1 suspend: false +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: v1 data: @@ -209,3 +233,52 @@ spec: name: resources-streams-bootstrap-my-streams-app name: config +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-streams-bootstrap-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/test_kpops_config.py b/tests/test_kpops_config.py index 0f35ddf37..e86096b21 100644 --- a/tests/test_kpops_config.py +++ b/tests/test_kpops_config.py @@ -1,14 +1,17 @@ import re from pathlib import Path +import pydantic import pytest -from pydantic import AnyHttpUrl, AnyUrl, TypeAdapter, ValidationError +from pydantic import AnyHttpUrl, AnyUrl, TypeAdapter +from kpops.api.exception import ValidationError from kpops.config import ( KafkaConnectConfig, KafkaRestConfig, KpopsConfig, SchemaRegistryConfig, + StrimziTopicConfig, get_config, set_config, ) @@ -43,7 +46,7 @@ def test_kpops_config_with_default_values(): def test_kpops_config_with_different_invalid_urls(): - with pytest.raises(ValidationError): + with pytest.raises(pydantic.ValidationError): KpopsConfig( kafka_brokers="http://broker:9092", kafka_connect=KafkaConnectConfig( @@ -51,7 +54,7 @@ def test_kpops_config_with_different_invalid_urls(): ), ) - with pytest.raises(ValidationError): + with pytest.raises(pydantic.ValidationError): KpopsConfig( kafka_brokers="http://broker:9092", kafka_rest=KafkaRestConfig( @@ -59,7 +62,7 @@ def test_kpops_config_with_different_invalid_urls(): ), ) - with pytest.raises(ValidationError): + with pytest.raises(pydantic.ValidationError): KpopsConfig( kafka_brokers="http://broker:9092", schema_registry=SchemaRegistryConfig( @@ -69,6 +72,7 @@ def test_kpops_config_with_different_invalid_urls(): ) +@pytest.mark.usefixtures("clear_kpops_config") def test_global_kpops_config_not_initialized_error(): with pytest.raises( RuntimeError, @@ -90,3 +94,16 @@ def test_set_global_kpops_config(): ) set_config(config) assert get_config() == config + + +def test_strimzi_topic_config_valid(): + config = StrimziTopicConfig.model_validate({"label": {"key": "value"}}) + assert config.cluster_labels == ("key", "value") + + +def test_strimzi_topic_config_empty_label(): + with pytest.raises( + ValidationError, + match="'strimzi_topic.label' must contain a single key-value pair.", + ): + StrimziTopicConfig.model_validate({"label": {}}) From 35bec1adccef9767dca8ef3af2e87ca41b47c548 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Wed, 11 Dec 2024 13:09:35 +0000 Subject: [PATCH 04/12] Manifest Kubernetes resources for `destroy` command (#552) closes #553 --- docs/docs/user/references/cli-commands.md | 1 + kpops/api/__init__.py | 25 +++++++ kpops/cli/main.py | 42 ++++++++--- kpops/components/streams_bootstrap/base.py | 8 ++ .../manifest.yaml | 0 .../manifest.yaml | 73 +++++++++++++++++++ .../manifest.yaml | 73 +++++++++++++++++++ .../manifest.yaml | 73 +++++++++++++++++++ tests/pipeline/test_manifest.py | 50 ++++++++++++- 9 files changed, 332 insertions(+), 13 deletions(-) rename tests/pipeline/snapshots/test_manifest/{test_python_api => test_manifest_deploy_python_api}/manifest.yaml (100%) create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_destroy_argo_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_destroy_manifest_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_destroy_python_api/manifest.yaml diff --git a/docs/docs/user/references/cli-commands.md b/docs/docs/user/references/cli-commands.md index bbbd7cd3f..4eeb36010 100644 --- a/docs/docs/user/references/cli-commands.md +++ b/docs/docs/user/references/cli-commands.md @@ -100,6 +100,7 @@ $ kpops destroy [OPTIONS] PIPELINE_PATHS... * `--dry-run / --execute`: Whether to dry run the command or execute it [default: dry-run] * `--verbose / --no-verbose`: Enable verbose printing [default: no-verbose] * `--parallel / --no-parallel`: Enable or disable parallel execution of pipeline steps. If enabled, multiple steps can be processed concurrently. If disabled, steps will be processed sequentially. [default: no-parallel] +* `--operation-mode [argo|manifest|managed]`: How KPOps should operate. [env var: KPOPS_OPERATION_MODE; default: managed] * `--help`: Show this message and exit. ## `kpops generate` diff --git a/kpops/api/__init__.py b/kpops/api/__init__.py index d0fe34428..02a57b5d2 100644 --- a/kpops/api/__init__.py +++ b/kpops/api/__init__.py @@ -95,6 +95,31 @@ def manifest_deploy( yield resource +def manifest_destroy( + pipeline_path: Path, + dotenv: list[Path] | None = None, + config: Path = Path(), + steps: set[str] | None = None, + filter_type: FilterType = FilterType.INCLUDE, + environment: str | None = None, + verbose: bool = True, + operation_mode: OperationMode = OperationMode.MANIFEST, +) -> Iterator[tuple[KubernetesManifest, ...]]: + pipeline = generate( + pipeline_path=pipeline_path, + dotenv=dotenv, + config=config, + steps=steps, + filter_type=filter_type, + environment=environment, + verbose=verbose, + operation_mode=operation_mode, + ) + for component in pipeline.components: + resource = component.manifest_destroy() + yield resource + + def deploy( pipeline_path: Path, dotenv: list[Path] | None = None, diff --git a/kpops/cli/main.py b/kpops/cli/main.py index 27afb1d94..dc9d19deb 100644 --- a/kpops/cli/main.py +++ b/kpops/cli/main.py @@ -241,19 +241,37 @@ def destroy( dry_run: bool = DRY_RUN, verbose: bool = VERBOSE_OPTION, parallel: bool = PARALLEL, + operation_mode: OperationMode = OPERATION_MODE_OPTION, ): - for pipeline_file_path in collect_pipeline_paths(pipeline_paths): - kpops.destroy( - pipeline_path=pipeline_file_path, - dotenv=dotenv, - config=config, - steps=parse_steps(steps), - filter_type=filter_type, - environment=environment, - dry_run=dry_run, - verbose=verbose, - parallel=parallel, - ) + match operation_mode: + case OperationMode.MANAGED: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + kpops.destroy( + pipeline_path=pipeline_file_path, + dotenv=dotenv, + config=config, + steps=parse_steps(steps), + filter_type=filter_type, + environment=environment, + dry_run=dry_run, + verbose=verbose, + parallel=parallel, + ) + case _: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + resources = kpops.manifest_destroy( + pipeline_file_path, + dotenv, + config, + parse_steps(steps), + filter_type, + environment, + verbose, + operation_mode, + ) + for resource in resources: + for rendered_manifest in resource: + print_yaml(rendered_manifest.model_dump()) @app.command(help="Reset pipeline steps") diff --git a/kpops/components/streams_bootstrap/base.py b/kpops/components/streams_bootstrap/base.py index a4ab5780e..d776a56a3 100644 --- a/kpops/components/streams_bootstrap/base.py +++ b/kpops/components/streams_bootstrap/base.py @@ -96,3 +96,11 @@ def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: ) return resource + + @override + def manifest_destroy(self) -> tuple[KubernetesManifest, ...]: + if self.to: + return tuple( + StrimziKafkaTopic.from_topic(topic) for topic in self.to.kafka_topics + ) + return () diff --git a/tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_deploy_python_api/manifest.yaml similarity index 100% rename from tests/pipeline/snapshots/test_manifest/test_python_api/manifest.yaml rename to tests/pipeline/snapshots/test_manifest/test_manifest_deploy_python_api/manifest.yaml diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_argo_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_argo_mode/manifest.yaml new file mode 100644 index 000000000..a27b34a41 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_argo_mode/manifest.yaml @@ -0,0 +1,73 @@ +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_manifest_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_manifest_mode/manifest.yaml new file mode 100644 index 000000000..a27b34a41 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_manifest_mode/manifest.yaml @@ -0,0 +1,73 @@ +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_python_api/manifest.yaml new file mode 100644 index 000000000..a27b34a41 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_destroy_python_api/manifest.yaml @@ -0,0 +1,73 @@ +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/test_manifest.py b/tests/pipeline/test_manifest.py index 65c132cf4..fe3ec10ba 100644 --- a/tests/pipeline/test_manifest.py +++ b/tests/pipeline/test_manifest.py @@ -125,7 +125,9 @@ def test_manifest_command(self, snapshot: Snapshot): assert result.exit_code == 0, result.stdout snapshot.assert_match(result.stdout, MANIFEST_YAML) - def test_python_api(self, capsys: CaptureFixture, snapshot: Snapshot): + def test_manifest_deploy_python_api( + self, capsys: CaptureFixture, snapshot: Snapshot + ): generator = kpops.manifest_deploy( RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML, environment="development", @@ -182,3 +184,49 @@ def test_deploy_argo_mode(self, snapshot: Snapshot): ) assert result.exit_code == 0, result.stdout snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_destroy_manifest_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "destroy", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "manifest", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_destroy_argo_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "destroy", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "argo", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_destroy_python_api( + self, capsys: CaptureFixture, snapshot: Snapshot + ): + generator = kpops.manifest_destroy( + RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML, + environment="development", + ) + assert isinstance(generator, Iterator) + resources = list(generator) + assert len(resources) == 2 + for resource in resources: + for manifest in resource: + assert isinstance(manifest, KubernetesManifest) + print_yaml(manifest.model_dump()) + + captured = capsys.readouterr() + snapshot.assert_match(captured.out, MANIFEST_YAML) From 681ac7ef7197b3c63af91fba483ebc1d737a40c0 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Thu, 12 Dec 2024 12:53:26 +0000 Subject: [PATCH 05/12] Manifest Kubernetes resources for `clean` command (#559) Closes #554 --- docs/docs/resources/examples/defaults.md | 11 +- docs/docs/user/references/cli-commands.md | 1 + examples | 2 +- kpops/api/__init__.py | 25 +++++ kpops/cli/main.py | 48 ++++++-- .../producer/producer_app.py | 6 + .../streams_bootstrap/streams/streams_app.py | 2 + .../test_generate/atm-fraud/pipeline.yaml | 10 -- .../test_generate/word-count/pipeline.yaml | 86 ++++++--------- .../manifest.yaml | 0 .../manifest.yaml | 104 ++++++++++++++++++ .../manifest.yaml | 104 ++++++++++++++++++ tests/pipeline/test_manifest.py | 46 ++++++++ 13 files changed, 367 insertions(+), 78 deletions(-) create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_clean_argo_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_clean_manifest_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_clean_python_api/manifest.yaml diff --git a/docs/docs/resources/examples/defaults.md b/docs/docs/resources/examples/defaults.md index f70d2dfa9..01ce227a0 100644 --- a/docs/docs/resources/examples/defaults.md +++ b/docs/docs/resources/examples/defaults.md @@ -2,15 +2,22 @@ ## [KPOps examples](https://github.com/bakdata/kpops-examples){target=_blank} -Shared defaults for [ATM Fraud Pipeline](https://github.com/bakdata/kpops-examples/tree/main/atm-fraud){target=_blank} and [Word-count Pipeline](https://github.com/bakdata/kpops-examples/tree/main/word-count){target=_blank} +Defaults for [ATM Fraud Pipeline](https://github.com/bakdata/kpops-examples/tree/main/atm-fraud){target=_blank} ??? example "defaults.yaml" ```yaml --8<-- - https://raw.githubusercontent.com/bakdata/kpops-examples/main/defaults.yaml + https://raw.githubusercontent.com/bakdata/kpops-examples/main/atm-fraud/defaults.yaml --8<-- ``` + +Defaults for [Word-count Pipeline](https://github.com/bakdata/kpops-examples/tree/main/word-count){target=_blank} + +??? example "defaults.yaml" +`yaml --8<-- https://raw.githubusercontent.com/bakdata/kpops-examples/main/word-count/defaults.yaml --8<--` + + diff --git a/docs/docs/user/references/cli-commands.md b/docs/docs/user/references/cli-commands.md index 4eeb36010..575e4dd51 100644 --- a/docs/docs/user/references/cli-commands.md +++ b/docs/docs/user/references/cli-commands.md @@ -47,6 +47,7 @@ $ kpops clean [OPTIONS] PIPELINE_PATHS... * `--dry-run / --execute`: Whether to dry run the command or execute it [default: dry-run] * `--verbose / --no-verbose`: Enable verbose printing [default: no-verbose] * `--parallel / --no-parallel`: Enable or disable parallel execution of pipeline steps. If enabled, multiple steps can be processed concurrently. If disabled, steps will be processed sequentially. [default: no-parallel] +* `--operation-mode [argo|manifest|managed]`: How KPOps should operate. [env var: KPOPS_OPERATION_MODE; default: managed] * `--help`: Show this message and exit. ## `kpops deploy` diff --git a/examples b/examples index 5ea436622..c28564d3e 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 5ea436622c3ca857a44762a9b5dd5de678fdc1d4 +Subproject commit c28564d3e986802c1e5ab0869be99593f60c6285 diff --git a/kpops/api/__init__.py b/kpops/api/__init__.py index 02a57b5d2..07d3507cf 100644 --- a/kpops/api/__init__.py +++ b/kpops/api/__init__.py @@ -120,6 +120,31 @@ def manifest_destroy( yield resource +def manifest_clean( + pipeline_path: Path, + dotenv: list[Path] | None = None, + config: Path = Path(), + steps: set[str] | None = None, + filter_type: FilterType = FilterType.INCLUDE, + environment: str | None = None, + verbose: bool = True, + operation_mode: OperationMode = OperationMode.MANIFEST, +) -> Iterator[tuple[KubernetesManifest, ...]]: + pipeline = generate( + pipeline_path=pipeline_path, + dotenv=dotenv, + config=config, + steps=steps, + filter_type=filter_type, + environment=environment, + verbose=verbose, + operation_mode=operation_mode, + ) + for component in pipeline.components: + resource = component.manifest_clean() + yield resource + + def deploy( pipeline_path: Path, dotenv: list[Path] | None = None, diff --git a/kpops/cli/main.py b/kpops/cli/main.py index dc9d19deb..9503e13ca 100644 --- a/kpops/cli/main.py +++ b/kpops/cli/main.py @@ -5,6 +5,7 @@ import typer import kpops.api as kpops +from kpops.api import log from kpops.api.operation import OperationMode from kpops.api.options import FilterType from kpops.cli.utils import ( @@ -311,19 +312,42 @@ def clean( dry_run: bool = DRY_RUN, verbose: bool = VERBOSE_OPTION, parallel: bool = PARALLEL, + operation_mode: OperationMode = OPERATION_MODE_OPTION, ): - for pipeline_file_path in collect_pipeline_paths(pipeline_paths): - kpops.clean( - pipeline_path=pipeline_file_path, - dotenv=dotenv, - config=config, - steps=parse_steps(steps), - filter_type=filter_type, - environment=environment, - dry_run=dry_run, - verbose=verbose, - parallel=parallel, - ) + match operation_mode: + case OperationMode.MANAGED: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + kpops.clean( + pipeline_path=pipeline_file_path, + dotenv=dotenv, + config=config, + steps=parse_steps(steps), + filter_type=filter_type, + environment=environment, + dry_run=dry_run, + verbose=verbose, + parallel=parallel, + ) + case OperationMode.MANIFEST: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + resources = kpops.manifest_clean( + pipeline_file_path, + dotenv, + config, + parse_steps(steps), + filter_type, + environment, + verbose, + operation_mode, + ) + for resource in resources: + for rendered_manifest in resource: + print_yaml(rendered_manifest.model_dump()) + case OperationMode.ARGO: + log.warning( + "No cleanup jobs are manifested in Argo mode. The cleanup jobs with Argo hooks are manifested with 'deploy' command. \n" + " If you wish to see the cleanup job manifest use the 'manifest' operation mode." + ) def version_callback(show_version: bool) -> None: diff --git a/kpops/components/streams_bootstrap/producer/producer_app.py b/kpops/components/streams_bootstrap/producer/producer_app.py index 0dd654458..02585ea7d 100644 --- a/kpops/components/streams_bootstrap/producer/producer_app.py +++ b/kpops/components/streams_bootstrap/producer/producer_app.py @@ -166,3 +166,9 @@ def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: manifests = manifests + self._cleaner.manifest_deploy() return manifests + + @override + def manifest_clean(self) -> tuple[KubernetesManifest, ...]: + if get_config().operation_mode is OperationMode.MANIFEST: + return self._cleaner.manifest_deploy() + return () diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index 5b828acef..70fecc285 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -187,4 +187,6 @@ def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: @override def manifest_clean(self) -> tuple[KubernetesManifest, ...]: + if get_config().operation_mode is OperationMode.MANIFEST: + return self._cleaner.manifest_deploy() return () diff --git a/tests/pipeline/snapshots/test_example/test_generate/atm-fraud/pipeline.yaml b/tests/pipeline/snapshots/test_example/test_generate/atm-fraud/pipeline.yaml index d15d6f76a..806bc5a17 100644 --- a/tests/pipeline/snapshots/test_example/test_generate/atm-fraud/pipeline.yaml +++ b/tests/pipeline/snapshots/test_example/test_generate/atm-fraud/pipeline.yaml @@ -1,5 +1,4 @@ - _cleaner: - debug: true name: account-producer namespace: ${NAMESPACE} prefix: atm-fraud- @@ -27,7 +26,6 @@ schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ suspend: true version: 2.9.0 - debug: true name: account-producer namespace: ${NAMESPACE} prefix: atm-fraud- @@ -61,7 +59,6 @@ suspend: true version: 2.9.0 - _cleaner: - debug: true name: transaction-avro-producer namespace: ${NAMESPACE} prefix: atm-fraud- @@ -92,7 +89,6 @@ schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ suspend: true version: 2.9.0 - debug: true name: transaction-avro-producer namespace: ${NAMESPACE} prefix: atm-fraud- @@ -129,7 +125,6 @@ suspend: true version: 2.9.0 - _cleaner: - debug: true name: transaction-joiner namespace: ${NAMESPACE} prefix: atm-fraud- @@ -165,7 +160,6 @@ outputTopic: atm-fraud-transaction-joiner-topic schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ version: 2.9.0 - debug: true name: transaction-joiner namespace: ${NAMESPACE} prefix: atm-fraud- @@ -211,7 +205,6 @@ schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ version: 2.9.0 - _cleaner: - debug: true name: fraud-detector namespace: ${NAMESPACE} prefix: atm-fraud- @@ -247,7 +240,6 @@ outputTopic: atm-fraud-fraud-detector-topic schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ version: 2.9.0 - debug: true name: fraud-detector namespace: ${NAMESPACE} prefix: atm-fraud- @@ -293,7 +285,6 @@ schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ version: 2.9.0 - _cleaner: - debug: true name: account-linker namespace: ${NAMESPACE} prefix: atm-fraud- @@ -332,7 +323,6 @@ outputTopic: atm-fraud-account-linker-topic schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ version: 2.9.0 - debug: true from: components: account-producer: diff --git a/tests/pipeline/snapshots/test_example/test_generate/word-count/pipeline.yaml b/tests/pipeline/snapshots/test_example/test_generate/word-count/pipeline.yaml index 326ba7fac..44e616d32 100644 --- a/tests/pipeline/snapshots/test_example/test_generate/word-count/pipeline.yaml +++ b/tests/pipeline/snapshots/test_example/test_generate/word-count/pipeline.yaml @@ -1,5 +1,4 @@ - _cleaner: - debug: true name: data-producer namespace: ${NAMESPACE} prefix: word-count- @@ -12,20 +11,17 @@ type: producer-app-cleaner values: image: bakdata/kpops-demo-sentence-producer - imageTag: 1.0.0 + imageTag: 2.0.0 + kafka: + bootstrapServers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + outputTopic: word-count-data-producer-topic labels: pipeline: word-count prometheus: jmx: enabled: false replicaCount: 1 - streams: - brokers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - optimizeLeaveGroupBehavior: false - outputTopic: word-count-data-producer-topic - schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ - version: 2.9.0 - debug: true + version: 3.1.0 name: data-producer namespace: ${NAMESPACE} prefix: word-count- @@ -40,25 +36,22 @@ word-count-data-producer-topic: configs: {} partitions_count: 3 - type: producer-app-v2 + type: producer-app values: image: bakdata/kpops-demo-sentence-producer - imageTag: 1.0.0 + imageTag: 2.0.0 + kafka: + bootstrapServers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + outputTopic: word-count-data-producer-topic labels: pipeline: word-count prometheus: jmx: enabled: false replicaCount: 1 - streams: - brokers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - optimizeLeaveGroupBehavior: false - outputTopic: word-count-data-producer-topic - schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ - version: 2.9.0 + version: 3.1.0 - _cleaner: - debug: true - name: word-counter + name: word-count-app namespace: ${NAMESPACE} prefix: word-count- repo_config: @@ -69,30 +62,23 @@ suffix: -clean type: streams-app-cleaner values: - commandLine: - PRODUCTIVE: false image: bakdata/kpops-demo-word-count-app - imageTag: 1.0.0 + imageTag: 2.0.0 + kafka: + bootstrapServers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + errorTopic: word-count-word-count-app-dead-letter-topic + inputTopics: + - word-count-data-producer-topic + outputTopic: word-count-word-count-app-topic labels: pipeline: word-count - persistence: - enabled: false prometheus: jmx: enabled: false replicaCount: 1 statefulSet: false - streams: - brokers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - errorTopic: word-count-word-counter-dead-letter-topic - inputTopics: - - word-count-data-producer-topic - optimizeLeaveGroupBehavior: false - outputTopic: word-count-word-counter-topic - schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ - version: 2.9.0 - debug: true - name: word-counter + version: 3.1.0 + name: word-count-app namespace: ${NAMESPACE} prefix: word-count- repo_config: @@ -103,39 +89,33 @@ to: models: {} topics: - word-count-word-counter-dead-letter-topic: + word-count-word-count-app-dead-letter-topic: configs: {} partitions_count: 1 type: error - word-count-word-counter-topic: + word-count-word-count-app-topic: configs: cleanup.policy: compact partitions_count: 3 type: output - type: streams-app-v2 + type: streams-app values: - commandLine: - PRODUCTIVE: false image: bakdata/kpops-demo-word-count-app - imageTag: 1.0.0 + imageTag: 2.0.0 + kafka: + bootstrapServers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + errorTopic: word-count-word-count-app-dead-letter-topic + inputTopics: + - word-count-data-producer-topic + outputTopic: word-count-word-count-app-topic labels: pipeline: word-count - persistence: - enabled: false prometheus: jmx: enabled: false replicaCount: 1 statefulSet: false - streams: - brokers: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 - errorTopic: word-count-word-counter-dead-letter-topic - inputTopics: - - word-count-data-producer-topic - optimizeLeaveGroupBehavior: false - outputTopic: word-count-word-counter-topic - schemaRegistryUrl: http://k8kafka-cp-schema-registry.kpops.svc.cluster.local:8081/ - version: 2.9.0 + version: 3.1.0 - _resetter: name: redis-sink-connector namespace: ${NAMESPACE} @@ -160,7 +140,7 @@ redis.database: '0' redis.hosts: redis-headless:6379 tasks.max: '1' - topics: word-count-word-counter-topic + topics: word-count-word-count-app-topic value.converter: org.apache.kafka.connect.storage.StringConverter name: redis-sink-connector prefix: word-count- diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_clean_argo_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_clean_argo_mode/manifest.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_clean_manifest_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_clean_manifest_mode/manifest.yaml new file mode 100644 index 000000000..e5a2a9a14 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_clean_manifest_mode/manifest.yaml @@ -0,0 +1,104 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-producer-app-clean + chart: producer-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-producer-app-clean + name: resources-manifest-pipeline-my-producer-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-producer-app-clean + release: resources-manifest-pipeline-my-producer-app-clean + spec: + containers: + - args: + - clean + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_OUTPUT_TOPIC + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-producer-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-producer-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + chart: streams-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-streams-app-clean + name: resources-manifest-pipeline-my-streams-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + release: resources-manifest-pipeline-my-streams-app-clean + spec: + containers: + - args: + - reset + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_clean_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_clean_python_api/manifest.yaml new file mode 100644 index 000000000..e5a2a9a14 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_clean_python_api/manifest.yaml @@ -0,0 +1,104 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-producer-app-clean + chart: producer-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-producer-app-clean + name: resources-manifest-pipeline-my-producer-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-producer-app-clean + release: resources-manifest-pipeline-my-producer-app-clean + spec: + containers: + - args: + - clean + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_OUTPUT_TOPIC + value: my-producer-app-output-topic + - name: APP_LABELED_OUTPUT_TOPICS + value: my-producer-app-output-topic-label=my-labeled-producer-app-topic-output, + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-producer-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-producer-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + chart: streams-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-streams-app-clean + name: resources-manifest-pipeline-my-streams-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + release: resources-manifest-pipeline-my-streams-app-clean + spec: + containers: + - args: + - reset + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + diff --git a/tests/pipeline/test_manifest.py b/tests/pipeline/test_manifest.py index fe3ec10ba..e0f208516 100644 --- a/tests/pipeline/test_manifest.py +++ b/tests/pipeline/test_manifest.py @@ -230,3 +230,49 @@ def test_manifest_destroy_python_api( captured = capsys.readouterr() snapshot.assert_match(captured.out, MANIFEST_YAML) + + def test_manifest_clean_manifest_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "clean", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "manifest", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_clean_argo_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "clean", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "argo", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_clean_python_api( + self, capsys: CaptureFixture, snapshot: Snapshot + ): + generator = kpops.manifest_clean( + RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML, + environment="development", + ) + assert isinstance(generator, Iterator) + resources = list(generator) + assert len(resources) == 2 + for resource in resources: + for manifest in resource: + assert isinstance(manifest, KubernetesManifest) + print_yaml(manifest.model_dump()) + + captured = capsys.readouterr() + snapshot.assert_match(captured.out, MANIFEST_YAML) From 28f3e294e3a3aa304634f9c110dd77a62de8b97f Mon Sep 17 00:00:00 2001 From: Salomon Popp Date: Thu, 12 Dec 2024 16:04:14 +0100 Subject: [PATCH 06/12] Drop support for Python 3.10 (#561) --- .github/actions/update-docs/action.yml | 2 +- .github/workflows/ci.yaml | 9 ++--- .github/workflows/publish.yaml | 1 + .github/workflows/release.yaml | 1 + hooks/gen_docs/__init__.py | 4 +-- hooks/gen_docs/gen_docs_env_vars.py | 6 ++-- kpops/api/options.py | 4 +-- .../kafka_connect/kafka_connect_handler.py | 7 +--- .../component_handlers/kafka_connect/model.py | 4 +-- kpops/component_handlers/topic/model.py | 6 ++-- .../base_defaults_component.py | 7 +--- .../base_components/kafka_connector.py | 7 +--- .../base_components/models/from_section.py | 4 +-- kpops/components/common/topic.py | 4 +-- kpops/components/streams_bootstrap/base.py | 8 +---- kpops/components/streams_bootstrap_v2/base.py | 8 +---- .../streams_bootstrap_v2/streams/model.py | 10 ++---- kpops/const/file_type.py | 4 +-- kpops/manifests/kubernetes.py | 9 +++-- kpops/manifests/strimzi/kafka_topic.py | 8 +---- kpops/utils/dict_differ.py | 15 ++++---- poetry.lock | 35 ++----------------- pyproject.toml | 9 ++--- 23 files changed, 51 insertions(+), 121 deletions(-) diff --git a/.github/actions/update-docs/action.yml b/.github/actions/update-docs/action.yml index 7ad9ab442..c748666bf 100644 --- a/.github/actions/update-docs/action.yml +++ b/.github/actions/update-docs/action.yml @@ -27,8 +27,8 @@ runs: - name: Install Python and set up Poetry uses: bakdata/ci-templates/actions/python-setup-poetry@v1.5.2 with: + python-version: "3.11" poetry-version: "1.5.1" - python-version: "3.10" - name: Install docs dependencies shell: bash diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c7f214209..3b8b2f627 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,7 +21,7 @@ jobs: os: - ubuntu-22.04 - windows-2022 - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.11", "3.12"] runs-on: ${{ matrix.os }} steps: @@ -32,8 +32,8 @@ jobs: - name: Install Python and set up Poetry uses: bakdata/ci-templates/actions/python-setup-poetry@v1.5.3 with: - poetry-version: "1.7.1" python-version: ${{ matrix.python-version }} + poetry-version: "1.7.1" - name: Check Poetry lock file consistency run: poetry lock --check @@ -43,7 +43,7 @@ jobs: - name: Lint (ruff) run: | - if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.10" ]] + if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.11" ]] then poetry run ruff check . --config pyproject.toml --output-format=github --no-fix else @@ -55,7 +55,7 @@ jobs: - name: Typing (pyright) run: | - if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.10" ]] + if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.11" ]] then echo "::add-matcher::.github/pyright-matcher.json" poetry run pre-commit run pyright --all-files @@ -93,6 +93,7 @@ jobs: needs: [test] uses: bakdata/ci-templates/.github/workflows/python-poetry-publish-snapshot.yaml@1.40.4 with: + python-version: "3.11" poetry-version: "1.7.1" secrets: pypi-token: ${{ secrets.TEST_PYPI_TOKEN }} diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index fd66ef0cd..1a9d4a2df 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -9,6 +9,7 @@ jobs: uses: bakdata/ci-templates/.github/workflows/python-poetry-publish-pypi.yaml@1.40.4 with: publish-to-test: false + python-version: "3.11" poetry-version: "1.7.1" secrets: pypi-token: "${{ secrets.PYPI_TOKEN }}" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 88a40d1c8..3acaeccd7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,6 +19,7 @@ jobs: name: Release with: release-type: ${{ inputs.release-type }} + python-version: "3.11" poetry-version: "1.7.1" changelog: true changelog-config: "./.github/changelog-config.json" diff --git a/hooks/gen_docs/__init__.py b/hooks/gen_docs/__init__.py index 5a0d63a28..fda5d4d19 100644 --- a/hooks/gen_docs/__init__.py +++ b/hooks/gen_docs/__init__.py @@ -1,10 +1,10 @@ """Documentation generation.""" from collections.abc import Iterator -from enum import Enum +from enum import StrEnum -class IterableStrEnum(str, Enum): +class IterableStrEnum(StrEnum): """Polyfill that also introduces dict-like behavior. Introduces constructors that return a ``Iterator`` object diff --git a/hooks/gen_docs/gen_docs_env_vars.py b/hooks/gen_docs/gen_docs_env_vars.py index 4b1297d0c..3b3e02a56 100644 --- a/hooks/gen_docs/gen_docs_env_vars.py +++ b/hooks/gen_docs/gen_docs_env_vars.py @@ -9,7 +9,7 @@ from dataclasses import dataclass from pathlib import Path from textwrap import fill -from typing import Any +from typing import Any, Self from pydantic_core import PydanticUndefined from pytablewriter import MarkdownTableWriter @@ -70,9 +70,7 @@ class EnvVar: corresponding_setting_name: str | None @classmethod - def from_record( - cls, record: dict[str, Any] - ) -> EnvVar: # TODO: typing.Self for Python 3.11+ + def from_record(cls, record: dict[str, Any]) -> Self: """Construct an ``EnvVar`` instance from a specific dict. Reads a dict that contains keys equivalent to the diff --git a/kpops/api/options.py b/kpops/api/options.py index 22fda2542..19c352e1a 100644 --- a/kpops/api/options.py +++ b/kpops/api/options.py @@ -1,6 +1,6 @@ from __future__ import annotations -from enum import Enum +from enum import StrEnum from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -8,7 +8,7 @@ from kpops.pipeline import ComponentFilterPredicate -class FilterType(str, Enum): +class FilterType(StrEnum): INCLUDE = "include" EXCLUDE = "exclude" diff --git a/kpops/component_handlers/kafka_connect/kafka_connect_handler.py b/kpops/component_handlers/kafka_connect/kafka_connect_handler.py index dcfd41b75..3cd27c867 100644 --- a/kpops/component_handlers/kafka_connect/kafka_connect_handler.py +++ b/kpops/component_handlers/kafka_connect/kafka_connect_handler.py @@ -1,7 +1,7 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Self from kpops.component_handlers.kafka_connect.connect_wrapper import ConnectWrapper from kpops.component_handlers.kafka_connect.exception import ( @@ -12,11 +12,6 @@ from kpops.utils.dict_differ import render_diff if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - from kpops.component_handlers.kafka_connect.model import KafkaConnectorConfig from kpops.config import KpopsConfig diff --git a/kpops/component_handlers/kafka_connect/model.py b/kpops/component_handlers/kafka_connect/model.py index 93ff76043..d975deaba 100644 --- a/kpops/component_handlers/kafka_connect/model.py +++ b/kpops/component_handlers/kafka_connect/model.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any import pydantic @@ -21,7 +21,7 @@ ) -class KafkaConnectorType(str, Enum): +class KafkaConnectorType(StrEnum): SINK = "sink" SOURCE = "source" diff --git a/kpops/component_handlers/topic/model.py b/kpops/component_handlers/topic/model.py index 5c0cf024d..db1fcf7fa 100644 --- a/kpops/component_handlers/topic/model.py +++ b/kpops/component_handlers/topic/model.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any from pydantic import BaseModel, ConfigDict @@ -28,7 +28,7 @@ class TopicResponse(BaseModel): ) -class KafkaTopicConfigSource(str, Enum): +class KafkaTopicConfigSource(StrEnum): DYNAMIC_TOPIC_CONFIG = "DYNAMIC_TOPIC_CONFIG" DEFAULT_CONFIG = "DEFAULT_CONFIG" STATIC_BROKER_CONFIG = "STATIC_BROKER_CONFIG" @@ -68,7 +68,7 @@ class TopicConfigResponse(BaseModel): ) -class KafkaBrokerConfigSource(str, Enum): +class KafkaBrokerConfigSource(StrEnum): STATIC_BROKER_CONFIG = "STATIC_BROKER_CONFIG" DYNAMIC_BROKER_CONFIG = "DYNAMIC_BROKER_CONFIG" DEFAULT_CONFIG = "DEFAULT_CONFIG" diff --git a/kpops/components/base_components/base_defaults_component.py b/kpops/components/base_components/base_defaults_component.py index 89b8d212c..06ce7702d 100644 --- a/kpops/components/base_components/base_defaults_component.py +++ b/kpops/components/base_components/base_defaults_component.py @@ -7,7 +7,7 @@ from dataclasses import asdict from functools import cached_property from pathlib import Path -from typing import Any, TypeVar +from typing import Any, Self, TypeVar import pydantic import typer @@ -34,11 +34,6 @@ from kpops.utils.types import JsonType from kpops.utils.yaml import load_yaml_file, substitute_nested -try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] -except ImportError: - from typing_extensions import Self - log = logging.getLogger("BaseDefaultsComponent") diff --git a/kpops/components/base_components/kafka_connector.py b/kpops/components/base_components/kafka_connector.py index 5453c004b..731032879 100644 --- a/kpops/components/base_components/kafka_connector.py +++ b/kpops/components/base_components/kafka_connector.py @@ -3,7 +3,7 @@ import logging from abc import ABC from functools import cached_property -from typing import Any, Literal, NoReturn +from typing import Any, Literal, NoReturn, Self import pydantic from pydantic import Field, PrivateAttr, ValidationInfo, computed_field, field_validator @@ -27,11 +27,6 @@ from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import CamelCaseConfigModel -try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] -except ImportError: - from typing_extensions import Self - log = logging.getLogger("KafkaConnector") diff --git a/kpops/components/base_components/models/from_section.py b/kpops/components/base_components/models/from_section.py index df6d7bd1e..aefa0c252 100644 --- a/kpops/components/base_components/models/from_section.py +++ b/kpops/components/base_components/models/from_section.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any, NewType from pydantic import ConfigDict, Field, model_validator @@ -8,7 +8,7 @@ from kpops.utils.pydantic import DescConfigModel -class InputTopicTypes(str, Enum): +class InputTopicTypes(StrEnum): """Input topic types. - INPUT: input topic diff --git a/kpops/components/common/topic.py b/kpops/components/common/topic.py index 94dd7838e..ec0f99170 100644 --- a/kpops/components/common/topic.py +++ b/kpops/components/common/topic.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Iterable -from enum import Enum +from enum import StrEnum from typing import Annotated, Any import pydantic @@ -11,7 +11,7 @@ from kpops.utils.pydantic import DescConfigModel, to_str -class OutputTopicTypes(str, Enum): +class OutputTopicTypes(StrEnum): """Types of output topic. - OUTPUT: output topic diff --git a/kpops/components/streams_bootstrap/base.py b/kpops/components/streams_bootstrap/base.py index d59d97fc3..03405b14a 100644 --- a/kpops/components/streams_bootstrap/base.py +++ b/kpops/components/streams_bootstrap/base.py @@ -3,7 +3,7 @@ import logging import re from abc import ABC -from typing import TYPE_CHECKING +from typing import Self import pydantic from pydantic import Field @@ -17,12 +17,6 @@ from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic from kpops.utils.docstring import describe_attr -if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - STREAMS_BOOTSTRAP_HELM_REPO = HelmRepoConfig( repository_name="bakdata-streams-bootstrap", url="https://bakdata.github.io/streams-bootstrap/", diff --git a/kpops/components/streams_bootstrap_v2/base.py b/kpops/components/streams_bootstrap_v2/base.py index 95f3281e2..59124ecf4 100644 --- a/kpops/components/streams_bootstrap_v2/base.py +++ b/kpops/components/streams_bootstrap_v2/base.py @@ -2,7 +2,7 @@ import logging from abc import ABC -from typing import TYPE_CHECKING, Any +from typing import Any, Self import pydantic from pydantic import AliasChoices, ConfigDict, Field @@ -20,12 +20,6 @@ exclude_defaults, ) -if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - STREAMS_BOOTSTRAP_HELM_REPO = HelmRepoConfig( repository_name="bakdata-streams-bootstrap", url="https://bakdata.github.io/streams-bootstrap/", diff --git a/kpops/components/streams_bootstrap_v2/streams/model.py b/kpops/components/streams_bootstrap_v2/streams/model.py index e733bb91c..2274f2ac5 100644 --- a/kpops/components/streams_bootstrap_v2/streams/model.py +++ b/kpops/components/streams_bootstrap_v2/streams/model.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any +from typing import Any, Self import pydantic from pydantic import BaseModel, ConfigDict, Field, model_validator @@ -194,9 +194,7 @@ class StreamsAppAutoScaling(CamelCaseConfigModel, DescConfigModel): model_config = ConfigDict(extra="allow") @model_validator(mode="after") - def validate_mandatory_fields_are_set( - self: StreamsAppAutoScaling, - ) -> StreamsAppAutoScaling: # TODO: typing.Self for Python 3.11+ + def validate_mandatory_fields_are_set(self) -> Self: if self.enabled and (self.consumer_group is None or self.lag_threshold is None): msg = ( "If app.autoscaling.enabled is set to true, " @@ -228,9 +226,7 @@ class PersistenceConfig(BaseModel): ) @model_validator(mode="after") - def validate_mandatory_fields_are_set( - self: PersistenceConfig, - ) -> PersistenceConfig: # TODO: typing.Self for Python 3.11+ + def validate_mandatory_fields_are_set(self) -> Self: if self.enabled and self.size is None: msg = ( "If app.persistence.enabled is set to true, " diff --git a/kpops/const/file_type.py b/kpops/const/file_type.py index 3e170be96..b0ff54312 100644 --- a/kpops/const/file_type.py +++ b/kpops/const/file_type.py @@ -1,11 +1,11 @@ from __future__ import annotations -from enum import Enum +from enum import StrEnum FILE_EXTENSION = ".yaml" -class KpopsFileType(str, Enum): +class KpopsFileType(StrEnum): """Enum representing different types of KPOps file naming conventions. Attributes: diff --git a/kpops/manifests/kubernetes.py b/kpops/manifests/kubernetes.py index f2d842ed3..f442e6b63 100644 --- a/kpops/manifests/kubernetes.py +++ b/kpops/manifests/kubernetes.py @@ -1,10 +1,11 @@ from collections.abc import Iterator -from typing import Any +from typing import Any, Self import pydantic import yaml from pydantic import ConfigDict, Field from typing_extensions import override +from yaml.loader import Loader from kpops.utils.pydantic import CamelCaseConfigModel, by_alias @@ -56,10 +57,8 @@ class KubernetesManifest(CamelCaseConfigModel): model_config = ConfigDict(extra="allow") @classmethod - def from_yaml( - cls, /, content: str - ) -> Iterator["KubernetesManifest"]: # TODO: typing.Self for Python 3.11+ - manifests: Iterator[dict[str, Any]] = yaml.load_all(content, yaml.Loader) + def from_yaml(cls, /, content: str) -> Iterator[Self]: + manifests: Iterator[dict[str, Any]] = yaml.load_all(content, Loader) for manifest in manifests: yield cls(**manifest) diff --git a/kpops/manifests/strimzi/kafka_topic.py b/kpops/manifests/strimzi/kafka_topic.py index 4b9a4b667..43c4536e0 100644 --- a/kpops/manifests/strimzi/kafka_topic.py +++ b/kpops/manifests/strimzi/kafka_topic.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import Any, Self from pydantic import ConfigDict, Field, model_validator @@ -11,12 +11,6 @@ from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import CamelCaseConfigModel -if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - class TopicSpec(CamelCaseConfigModel): """Specification of a Kafka topic. diff --git a/kpops/utils/dict_differ.py b/kpops/utils/dict_differ.py index 67b6d98c4..51d29bf7a 100644 --- a/kpops/utils/dict_differ.py +++ b/kpops/utils/dict_differ.py @@ -3,8 +3,8 @@ from collections.abc import Mapping, MutableMapping from dataclasses import dataclass from difflib import Differ -from enum import Enum -from typing import TYPE_CHECKING, Any, Generic, TypeVar +from enum import StrEnum +from typing import TYPE_CHECKING, Any, Generic, NamedTuple, TypeVar import typer import yaml @@ -16,7 +16,7 @@ differ = Differ() -class DiffType(str, Enum): +class DiffType(StrEnum): ADD = "add" CHANGE = "change" REMOVE = "remove" @@ -30,8 +30,7 @@ def from_str(label: str) -> DiffType: _N = TypeVar("_N") -@dataclass -class Change(Generic[_O, _N]): # Generic NamedTuple requires Python 3.11+ +class Change(NamedTuple, Generic[_O, _N]): old_value: _O new_value: _N @@ -41,11 +40,11 @@ def factory( ) -> Change[_O | None, _N | None]: match type: case DiffType.ADD: - return Change(None, change) + return Change(None, change) # pyright: ignore[reportReturnType] case DiffType.REMOVE: - return Change(change, None) + return Change(change, None) # pyright: ignore[reportReturnType] case DiffType.CHANGE if isinstance(change, tuple): - return Change(*change) # pyright: ignore[reportUnknownArgumentType] + return Change(*change) # pyright: ignore[reportReturnType] msg = f"{type} is not part of {DiffType}" raise ValueError(msg) diff --git a/poetry.lock b/poetry.lock index a773e4d0c..ff88f7e8c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiofiles" @@ -34,10 +34,8 @@ files = [ ] [package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] @@ -252,20 +250,6 @@ files = [ {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, ] -[[package]] -name = "exceptiongroup" -version = "1.0.4" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"}, - {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "faker" version = "22.0.0" @@ -1279,11 +1263,9 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -1799,17 +1781,6 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "typepy" version = "1.3.1" @@ -1951,5 +1922,5 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" -python-versions = ">=3.10, <3.13" -content-hash = "e307ba934678d208018611cc9567ef9bfa779fc7c024308d2c6fc6d01a32cafe" +python-versions = ">=3.11, <3.13" +content-hash = "82d4f691096d3aaa7cea1e1469b5ebec3daca4d649376c493af809d1978198e6" diff --git a/pyproject.toml b/pyproject.toml index abaaf358d..1b7d73dac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ kpops = "kpops.cli.main:app" [tool.poetry.dependencies] -python = ">=3.10, <3.13" +python = ">=3.11, <3.13" anyio = "^4.3.0" pydantic = "^2.5.3" pydantic-settings = "^2.0.3" @@ -73,11 +73,8 @@ reportUnknownLambdaType = "warning" reportUnknownVariableType = "warning" reportUnknownMemberType = "warning" -reportIncompatibleVariableOverride = false -reportIncompatibleMethodOverride = false -# FIXME: causes issues on Python 3.10 -# reportIncompatibleVariableOverride = "warning" -# reportIncompatibleMethodOverride = "warning" +reportIncompatibleVariableOverride = "warning" +reportIncompatibleMethodOverride = "warning" [tool.ruff] output-format = "grouped" From 658242eb4858a1ae77d353acb6a5c5437e631593 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Fri, 13 Dec 2024 09:01:17 +0100 Subject: [PATCH 07/12] Manifest Kubernetes resources for `reset` command (#563) Closes #556 --- docs/docs/user/references/cli-commands.md | 1 + kpops/api/__init__.py | 25 ++++ kpops/cli/main.py | 42 +++++-- .../streams_bootstrap/streams/streams_app.py | 23 ++++ .../manifest.yaml | 107 ++++++++++++++++++ .../manifest.yaml | 107 ++++++++++++++++++ .../manifest.yaml | 107 ++++++++++++++++++ tests/pipeline/test_manifest.py | 46 ++++++++ 8 files changed, 446 insertions(+), 12 deletions(-) create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml create mode 100644 tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml diff --git a/docs/docs/user/references/cli-commands.md b/docs/docs/user/references/cli-commands.md index 575e4dd51..20e871574 100644 --- a/docs/docs/user/references/cli-commands.md +++ b/docs/docs/user/references/cli-commands.md @@ -171,6 +171,7 @@ $ kpops reset [OPTIONS] PIPELINE_PATHS... * `--dry-run / --execute`: Whether to dry run the command or execute it [default: dry-run] * `--verbose / --no-verbose`: Enable verbose printing [default: no-verbose] * `--parallel / --no-parallel`: Enable or disable parallel execution of pipeline steps. If enabled, multiple steps can be processed concurrently. If disabled, steps will be processed sequentially. [default: no-parallel] +* `--operation-mode [argo|manifest|managed]`: How KPOps should operate. [env var: KPOPS_OPERATION_MODE; default: managed] * `--help`: Show this message and exit. ## `kpops schema` diff --git a/kpops/api/__init__.py b/kpops/api/__init__.py index 07d3507cf..21b047ce9 100644 --- a/kpops/api/__init__.py +++ b/kpops/api/__init__.py @@ -120,6 +120,31 @@ def manifest_destroy( yield resource +def manifest_reset( + pipeline_path: Path, + dotenv: list[Path] | None = None, + config: Path = Path(), + steps: set[str] | None = None, + filter_type: FilterType = FilterType.INCLUDE, + environment: str | None = None, + verbose: bool = True, + operation_mode: OperationMode = OperationMode.MANIFEST, +) -> Iterator[tuple[KubernetesManifest, ...]]: + pipeline = generate( + pipeline_path=pipeline_path, + dotenv=dotenv, + config=config, + steps=steps, + filter_type=filter_type, + environment=environment, + verbose=verbose, + operation_mode=operation_mode, + ) + for component in pipeline.components: + resource = component.manifest_reset() + yield resource + + def manifest_clean( pipeline_path: Path, dotenv: list[Path] | None = None, diff --git a/kpops/cli/main.py b/kpops/cli/main.py index 9503e13ca..f372c7603 100644 --- a/kpops/cli/main.py +++ b/kpops/cli/main.py @@ -286,19 +286,37 @@ def reset( dry_run: bool = DRY_RUN, verbose: bool = VERBOSE_OPTION, parallel: bool = PARALLEL, + operation_mode: OperationMode = OPERATION_MODE_OPTION, ): - for pipeline_file_path in collect_pipeline_paths(pipeline_paths): - kpops.reset( - pipeline_path=pipeline_file_path, - dotenv=dotenv, - config=config, - steps=parse_steps(steps), - filter_type=filter_type, - environment=environment, - dry_run=dry_run, - verbose=verbose, - parallel=parallel, - ) + match operation_mode: + case OperationMode.MANAGED: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + kpops.reset( + pipeline_path=pipeline_file_path, + dotenv=dotenv, + config=config, + steps=parse_steps(steps), + filter_type=filter_type, + environment=environment, + dry_run=dry_run, + verbose=verbose, + parallel=parallel, + ) + case _: + for pipeline_file_path in collect_pipeline_paths(pipeline_paths): + resources = kpops.manifest_reset( + pipeline_file_path, + dotenv, + config, + parse_steps(steps), + filter_type, + environment, + verbose, + operation_mode, + ) + for resource in resources: + for rendered_manifest in resource: + print_yaml(rendered_manifest.model_dump()) @app.command(help="Clean pipeline steps") diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index 70fecc285..98403bfe5 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -20,6 +20,7 @@ from kpops.const.file_type import DEFAULTS_YAML, PIPELINE_YAML from kpops.manifests.argo import ArgoHook, enrich_annotations from kpops.manifests.kubernetes import KubernetesManifest +from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic from kpops.utils.docstring import describe_attr log = logging.getLogger("StreamsApp") @@ -66,6 +67,19 @@ def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: self.template_flags, ) + @override + def manifest_reset(self) -> tuple[KubernetesManifest, ...]: + self.values.kafka.delete_output = False + values = self.to_helm_values() + + return self.helm.template( + self.helm_release_name, + self.helm_chart, + self.namespace, + values, + self.template_flags, + ) + async def clean_pvcs(self, dry_run: bool) -> None: app_full_name = super(HelmApp, self).full_name pvc_handler = PVCHandler(app_full_name, self.namespace) @@ -185,6 +199,15 @@ def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: return manifests + @override + def manifest_reset(self) -> tuple[KubernetesManifest, ...]: + resource = self._cleaner.manifest_reset() + if self.to: + resource = resource + tuple( + StrimziKafkaTopic.from_topic(topic) for topic in self.to.kafka_topics + ) + return resource + @override def manifest_clean(self) -> tuple[KubernetesManifest, ...]: if get_config().operation_mode is OperationMode.MANIFEST: diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml new file mode 100644 index 000000000..63dc20d35 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + chart: streams-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-streams-app-clean + name: resources-manifest-pipeline-my-streams-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + release: resources-manifest-pipeline-my-streams-app-clean + spec: + containers: + - args: + - reset + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml new file mode 100644 index 000000000..63dc20d35 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + chart: streams-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-streams-app-clean + name: resources-manifest-pipeline-my-streams-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + release: resources-manifest-pipeline-my-streams-app-clean + spec: + containers: + - args: + - reset + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml new file mode 100644 index 000000000..63dc20d35 --- /dev/null +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + chart: streams-app-cleanup-job-3.0.3 + release: resources-manifest-pipeline-my-streams-app-clean + name: resources-manifest-pipeline-my-streams-app-clean +spec: + backoffLimit: 6 + template: + metadata: + labels: + app: resources-manifest-pipeline-my-streams-app-clean + release: resources-manifest-pipeline-my-streams-app-clean + spec: + containers: + - args: + - reset + env: + - name: ENV_PREFIX + value: APP_ + - name: APP_BOOTSTRAP_SERVERS + value: http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092 + - name: APP_SCHEMA_REGISTRY_URL + value: http://localhost:8081/ + - name: APP_INPUT_TOPICS + value: my-input-topic + - name: APP_INPUT_PATTERN + value: my-input-pattern + - name: APP_OUTPUT_TOPIC + value: my-output-topic + - name: APP_ERROR_TOPIC + value: resources-manifest-pipeline-my-streams-app-error + - name: APP_LABELED_OUTPUT_TOPICS + value: my-output-topic-label=my-labeled-topic-output, + - name: APP_LABELED_INPUT_TOPICS + value: my-input-topic-label=my-labeled-input-topic, + - name: APP_LABELED_INPUT_PATTERNS + value: my-input-topic-labeled-pattern=my-labeled-input-pattern, + - name: APP_APPLICATION_ID + value: my-streams-app-id + - name: JAVA_TOOL_OPTIONS + value: '-XX:MaxRAMPercentage=75.0 ' + image: my-registry/my-streams-app-image:1.0.0 + imagePullPolicy: Always + name: resources-manifest-pipeline-my-streams-app-clean + resources: + limits: + cpu: 500m + memory: 2G + requests: + cpu: 200m + memory: 300Mi + restartPolicy: OnFailure + ttlSecondsAfterFinished: 30 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-error-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: resources-manifest-pipeline-my-streams-app-error +spec: + config: + cleanup.policy: compact,delete + partitions: 1 + replicas: 1 + diff --git a/tests/pipeline/test_manifest.py b/tests/pipeline/test_manifest.py index e0f208516..87fe9b5a0 100644 --- a/tests/pipeline/test_manifest.py +++ b/tests/pipeline/test_manifest.py @@ -231,6 +231,52 @@ def test_manifest_destroy_python_api( captured = capsys.readouterr() snapshot.assert_match(captured.out, MANIFEST_YAML) + def test_manifest_reset_manifest_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "reset", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "manifest", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_reset_argo_mode(self, snapshot: Snapshot): + result = runner.invoke( + app, + [ + "reset", + str(RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML), + "--operation-mode", + "argo", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.stdout + snapshot.assert_match(result.stdout, MANIFEST_YAML) + + def test_manifest_reset_python_api( + self, capsys: CaptureFixture, snapshot: Snapshot + ): + generator = kpops.manifest_reset( + RESOURCE_PATH / "manifest-pipeline" / PIPELINE_YAML, + environment="development", + ) + assert isinstance(generator, Iterator) + resources = list(generator) + assert len(resources) == 2 + for resource in resources: + for manifest in resource: + assert isinstance(manifest, KubernetesManifest) + print_yaml(manifest.model_dump()) + + captured = capsys.readouterr() + snapshot.assert_match(captured.out, MANIFEST_YAML) + def test_manifest_clean_manifest_mode(self, snapshot: Snapshot): result = runner.invoke( app, From b045250e99936a73ada469ef661f7718e29430db Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Tue, 17 Dec 2024 09:46:51 +0100 Subject: [PATCH 08/12] Add topic manifestation of ProducerApps for reset command (#566) --- .../producer/producer_app.py | 9 +++++++ .../manifest.yaml | 24 +++++++++++++++++++ .../manifest.yaml | 24 +++++++++++++++++++ .../manifest.yaml | 24 +++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/kpops/components/streams_bootstrap/producer/producer_app.py b/kpops/components/streams_bootstrap/producer/producer_app.py index 02585ea7d..93626ac9b 100644 --- a/kpops/components/streams_bootstrap/producer/producer_app.py +++ b/kpops/components/streams_bootstrap/producer/producer_app.py @@ -21,6 +21,7 @@ from kpops.const.file_type import DEFAULTS_YAML, PIPELINE_YAML from kpops.manifests.argo import ArgoHook, enrich_annotations from kpops.manifests.kubernetes import K8S_CRON_JOB_NAME_MAX_LEN, KubernetesManifest +from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic from kpops.utils.docstring import describe_attr log = logging.getLogger("ProducerApp") @@ -167,6 +168,14 @@ def manifest_deploy(self) -> tuple[KubernetesManifest, ...]: return manifests + @override + def manifest_reset(self) -> tuple[KubernetesManifest, ...]: + if self.to: + return tuple( + StrimziKafkaTopic.from_topic(topic) for topic in self.to.kafka_topics + ) + return () + @override def manifest_clean(self) -> tuple[KubernetesManifest, ...]: if get_config().operation_mode is OperationMode.MANIFEST: diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml index 63dc20d35..fb5a29c61 100644 --- a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_argo_mode/manifest.yaml @@ -1,3 +1,27 @@ +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: batch/v1 kind: Job diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml index 63dc20d35..fb5a29c61 100644 --- a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_manifest_mode/manifest.yaml @@ -1,3 +1,27 @@ +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: batch/v1 kind: Job diff --git a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml index 63dc20d35..fb5a29c61 100644 --- a/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml +++ b/tests/pipeline/snapshots/test_manifest/test_manifest_reset_python_api/manifest.yaml @@ -1,3 +1,27 @@ +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-producer-app-output-topic +spec: + config: {} + partitions: 1 + replicas: 1 + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + labels: + strimzi.io/cluster: my-cluster + name: my-labeled-producer-app-topic-output +spec: + config: {} + partitions: 1 + replicas: 1 + --- apiVersion: batch/v1 kind: Job From c1570248a83e32ee1492e344de7c932ad88584f7 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Tue, 17 Dec 2024 13:19:55 +0100 Subject: [PATCH 09/12] Add documentation for operation-mode in KPOps (#565) --- .../docs/user/core-concepts/operation-mode.md | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 docs/docs/user/core-concepts/operation-mode.md diff --git a/docs/docs/user/core-concepts/operation-mode.md b/docs/docs/user/core-concepts/operation-mode.md new file mode 100644 index 000000000..91b8cc6ea --- /dev/null +++ b/docs/docs/user/core-concepts/operation-mode.md @@ -0,0 +1,116 @@ +# Operation Modes in KPOps + +KPOps supports three operation modes—`managed`, `manifest`, and `argo`. These modes determine how resources are managed and allow users to tailor their deployment strategy. + +- **Managed Mode** (default): KPOps uses Helm, and communicates with services like Kafka Rest Proxy, and Kafka Connect under the hood to manage the installation/(graceful) deletion of applications, creation/deletion of Kafka topics, creation/deletion of Connectors defined in your `pipeline.yaml`. +- **Manifest Mode**: Focuses on generating Kubernetes manifests. +- **Argo Mode**: Extends the functionality to include ArgoCD-specific hooks for certain operations, facilitating GitOps workflows with automated cleanup and reset tasks. + +--- + +## Configuring Operation Modes + +It is possible to configure the operation mode in the `config.yaml` file. Please refer to the [Configuration documentation page](https://bakdata.github.io/kpops/9.0/user/core-concepts/config/). +Alternatively, you can to pass the `--operation-mode ` option in the CLI to override the operation mode of the `config.yaml`. You can refer to the [CLI commands documentation](https://bakdata.github.io/kpops/9.0/user/references/cli-commands/#kpops-deploy) for more details. + +--- + +## Generated Resources by Mode and Operation + +### `deploy` + +#### **Manifest Mode** + +- **streams-bootstrap Applications**: + - Depending on your pipeline configuration, Kubernetes `Job`, `Deployment`, `ConfigMap`, and `Service` resources. + - Please refer to [streams-bootstrap Helm Charts](https://github.com/bakdata/streams-bootstrap/tree/master/charts). +- **Topics**: + - Strimzi `KafkaTopic` CRDs. + +#### **Argo Mode** + +- **streams-bootstrap Applications**: + - Depending on your pipeline configuration, Kubernetes `Job`, `Deployment`, `ConfigMap`, and `Service` resources. + - Additional Argo `sync-wave` annotation to ensure Kafka topics are created first (default `sync-wave=0`) before deploying apps (lower priority `sync-wave>0`). All components of each sync wave are deployed in parallel by Argo. + - Please refer to [streams-bootstrap Helm Charts](https://github.com/bakdata/streams-bootstrap/tree/master/charts). +- **Topics**: + - Strimzi `KafkaTopic` CRDs. +- **Cleanup Jobs**: + - Kubernetes `Job` resources configured **with** ArgoCD `PostDelete` hooks, ensuring cleanup tasks are executed after ArgoCD application deletion. + +--- + +### `reset` + +#### **Manifest Mode** + +- **Topics**: + - Strimzi `KafkaTopic` CRDs. +- **Reset Jobs**: + - Kubernetes `Job` resources for resetting Kafka Streams application states. + +#### **Argo Mode** + +- **Topics**: + - Strimzi `KafkaTopic` CRDs. +- **Reset Jobs**: + - Kubernetes `Job` resources **without** ArgoCD `PostDelete` hooks, providing a simpler reset process. + +--- + +### `clean` + +#### **Manifest Mode** + +- **Clean Jobs**: + - Kubernetes `Job` resources for cleaning up temporary resources or artifacts using application container images. + +#### **Argo Mode** + +- **Not Applicable**: + - The `clean` command is not supported in Argo mode. The clean is instead achieved through cleanup job hooks during the `deploy` command. + +--- + +### `destroy` + +#### **Manifest Mode** + +- **Topics**: + - Strimzi `KafkaTopic` CRDs. + +#### **Argo Mode** + +- **Topics**: + - Strimzi `KafkaTopic` CRDs. + +--- + +## Use Cases for Each Mode + +### Manifest Mode + +- **Flexibility**: Use the generated manifests in manual workflows or integrate with any Kubernetes deployment tool. +- **Version Control**: Commit generated manifests to a Git repository for tracking changes and rollback. + +### Argo Mode + +- **GitOps Integration**: Simplifies workflows when using ArgoCD for automated deployments and lifecycle management. +- **PostDelete Hooks**: Automatically cleans up resources after deletion of ArgoCD applications. + +--- + +## Summary of Resource Generation by Operation and Mode + +| Resource Type | `deploy` | `reset` | `clean` | `destroy` | +| ------------- | -------------------------------- | ------------------- | ------------------- | ------------------- | +| Producer Apps | Manifest: Generated | N/A | N/A | N/A | +| | Argo: Generated | | | | +| Streams Apps | Manifest: Generated | N/A | N/A | N/A | +| | Argo: Generated | | | | +| Topics | Manifest: Generated | Manifest: Generated | N/A | Manifest: Generated | +| | Argo: Generated | Argo: Generated | | Argo: Generated | +| Cleanup Jobs | Manifest: N/A | N/A | Manifest: Generated | N/A | +| | Argo: With `PostDelete` hooks | N/A | N/A | N/A | +| Reset Jobs | Manifest: N/A | Manifest: Generated | N/A | N/A | +| | Argo: Without `PostDelete` hooks | | | | From ccda83e1471c0436bdbe66d3e6824370ecc0339a Mon Sep 17 00:00:00 2001 From: Salomon Popp Date: Thu, 19 Dec 2024 15:35:08 +0100 Subject: [PATCH 10/12] Set Python target version to 3.11 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 313afa7bf..16559f3a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,7 +79,7 @@ reportIncompatibleMethodOverride = "warning" [tool.ruff] output-format = "grouped" show-fixes = true -target-version = "py310" +target-version = "py311" extend-exclude = ["tests/*snapshots/*"] [tool.ruff.lint] From ecc8f62a2e509f878c4e6913d6c39399ba0385b5 Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Fri, 20 Dec 2024 12:13:30 +0100 Subject: [PATCH 11/12] Hide `operation_mode` from KPOps config (#571) --- .../resources/variables/config_env_vars.env | 6 +- .../resources/variables/config_env_vars.md | 2 +- docs/docs/schema/config.json | 62 +- docs/docs/schema/defaults.json | 222 ++- docs/docs/schema/pipeline.json | 167 +- .../docs/user/core-concepts/operation-mode.md | 7 +- .../kafka_connect/timeout.py | 4 +- kpops/components/common/kubernetes_model.py | 2 +- kpops/config/__init__.py | 10 +- kpops/utils/gen_schema.py | 3 + poetry.lock | 1775 +++++++---------- .../config.yaml | 1 - tests/manifests/test_kubernetes_model.py | 6 +- 13 files changed, 1082 insertions(+), 1185 deletions(-) diff --git a/docs/docs/resources/variables/config_env_vars.env b/docs/docs/resources/variables/config_env_vars.env index baaf4fdbf..15d42bfc3 100644 --- a/docs/docs/resources/variables/config_env_vars.env +++ b/docs/docs/resources/variables/config_env_vars.env @@ -58,9 +58,9 @@ KPOPS_HELM_DIFF_CONFIG__IGNORE # No default value, required # Whether to retain clean up jobs in the cluster or uninstall the, # after completion. KPOPS_RETAIN_CLEAN_JOBS=False -# operation_mode -# The operation mode of KPOps (managed, manifest, argo). -KPOPS_OPERATION_MODE=managed # strimzi_topic # Configuration for Strimzi Kafka Topics. KPOPS_STRIMZI_TOPIC # No default value, not required +# operation_mode +# The operation mode of KPOps (managed, manifest, argo). +KPOPS_OPERATION_MODE=managed diff --git a/docs/docs/resources/variables/config_env_vars.md b/docs/docs/resources/variables/config_env_vars.md index f7fcd5303..5c96440bf 100644 --- a/docs/docs/resources/variables/config_env_vars.md +++ b/docs/docs/resources/variables/config_env_vars.md @@ -19,5 +19,5 @@ These variables take precedence over the settings in `config.yaml`. Variables ma |KPOPS_HELM_CONFIG__API_VERSION | |False |Kubernetes API version used for `Capabilities.APIVersions` |helm_config.api_version | |KPOPS_HELM_DIFF_CONFIG__IGNORE | |True |Set of keys that should not be checked. |helm_diff_config.ignore | |KPOPS_RETAIN_CLEAN_JOBS |False |False |Whether to retain clean up jobs in the cluster or uninstall the, after completion.|retain_clean_jobs | -|KPOPS_OPERATION_MODE |managed |False |The operation mode of KPOps (managed, manifest, argo). |operation_mode | |KPOPS_STRIMZI_TOPIC | |False |Configuration for Strimzi Kafka Topics. |strimzi_topic | +|KPOPS_OPERATION_MODE |managed |False |The operation mode of KPOps (managed, manifest, argo). |operation_mode | diff --git a/docs/docs/schema/config.json b/docs/docs/schema/config.json index 76b57e0ff..6ed30ef70 100644 --- a/docs/docs/schema/config.json +++ b/docs/docs/schema/config.json @@ -118,15 +118,6 @@ "title": "KafkaRestConfig", "type": "object" }, - "OperationMode": { - "enum": [ - "argo", - "manifest", - "managed" - ], - "title": "OperationMode", - "type": "string" - }, "SchemaRegistryConfig": { "additionalProperties": false, "description": "Configuration for Schema Registry.", @@ -212,7 +203,11 @@ "type": "boolean" }, "helm_config": { - "$ref": "#/$defs/HelmConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmConfig" + } + ], "default": { "api_version": null, "context": null, @@ -221,7 +216,11 @@ "description": "Global flags for Helm." }, "helm_diff_config": { - "$ref": "#/$defs/HelmDiffConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmDiffConfig" + } + ], "default": { "ignore": [] }, @@ -236,23 +235,28 @@ "type": "string" }, "kafka_connect": { - "$ref": "#/$defs/KafkaConnectConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConnectConfig" + } + ], "default": { "timeout": 30, "url": "http://localhost:8083/" - } + }, + "description": "Configuration for Kafka Connect." }, "kafka_rest": { - "$ref": "#/$defs/KafkaRestConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaRestConfig" + } + ], "default": { "timeout": 30, "url": "http://localhost:8082/" - } - }, - "operation_mode": { - "$ref": "#/$defs/OperationMode", - "default": "managed", - "description": "The operation mode of KPOps (managed, manifest, argo)." + }, + "description": "Configuration for Kafka REST Proxy." }, "pipeline_base_dir": { "default": ".", @@ -268,12 +272,17 @@ "type": "boolean" }, "schema_registry": { - "$ref": "#/$defs/SchemaRegistryConfig", + "allOf": [ + { + "$ref": "#/$defs/SchemaRegistryConfig" + } + ], "default": { "enabled": false, "timeout": 30, "url": "http://localhost:8081/" - } + }, + "description": "Configuration for Schema Registry." }, "strimzi_topic": { "anyOf": [ @@ -288,11 +297,16 @@ "description": "Configuration for Strimzi Kafka Topics." }, "topic_name_config": { - "$ref": "#/$defs/TopicNameConfig", + "allOf": [ + { + "$ref": "#/$defs/TopicNameConfig" + } + ], "default": { "default_error_topic_name": "${pipeline.name}-${component.name}-error", "default_output_topic_name": "${pipeline.name}-${component.name}" - } + }, + "description": "Configure the topic name variables you can use in the pipeline definition." } }, "required": [ diff --git a/docs/docs/schema/defaults.json b/docs/docs/schema/defaults.json index 13ae2df9a..fb978b0d9 100644 --- a/docs/docs/schema/defaults.json +++ b/docs/docs/schema/defaults.json @@ -170,11 +170,14 @@ }, "type": { "const": "helm-app", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Helm app values" }, "version": { @@ -226,7 +229,11 @@ "description": "Helm repository configuration.", "properties": { "repo_auth_flags": { - "$ref": "#/$defs/RepoAuthFlags", + "allOf": [ + { + "$ref": "#/$defs/RepoAuthFlags" + } + ], "default": { "ca_file": null, "cert_file": null, @@ -439,7 +446,11 @@ "description": "Base class for all Kafka connectors.\nShould only be used to set defaults", "properties": { "config": { - "$ref": "#/$defs/KafkaConnectorConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConnectorConfig" + } + ], "description": "Connector config" }, "from": { @@ -480,7 +491,11 @@ "title": "Resetter Namespace" }, "resetter_values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Overriding Kafka Connect resetter Helm values, e.g. to override the image tag etc." }, "to": { @@ -572,7 +587,11 @@ "description": "Kafka sink connector model.", "properties": { "config": { - "$ref": "#/$defs/KafkaConnectorConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConnectorConfig" + } + ], "description": "Connector config" }, "from": { @@ -613,7 +632,11 @@ "title": "Resetter Namespace" }, "resetter_values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Overriding Kafka Connect resetter Helm values, e.g. to override the image tag etc." }, "to": { @@ -630,8 +653,7 @@ }, "type": { "const": "kafka-sink-connector", - "title": "Type", - "type": "string" + "title": "Type" } }, "required": [ @@ -647,7 +669,11 @@ "description": "Kafka source connector model.", "properties": { "config": { - "$ref": "#/$defs/KafkaConnectorConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConnectorConfig" + } + ], "description": "Connector config" }, "from": { @@ -701,7 +727,11 @@ "title": "Resetter Namespace" }, "resetter_values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Overriding Kafka Connect resetter Helm values, e.g. to override the image tag etc." }, "to": { @@ -718,8 +748,7 @@ }, "type": { "const": "kafka-source-connector", - "title": "Type", - "type": "string" + "title": "Type" } }, "required": [ @@ -826,7 +855,11 @@ "description": "Topic(s) into which the component will write output" }, "values": { - "$ref": "#/$defs/KubernetesAppValues", + "allOf": [ + { + "$ref": "#/$defs/KubernetesAppValues" + } + ], "description": "Kubernetes app values" } }, @@ -1268,7 +1301,11 @@ "title": "Name" }, "schema": { - "$ref": "#/$defs/ProtocolSchema", + "allOf": [ + { + "$ref": "#/$defs/ProtocolSchema" + } + ], "default": "TCP", "description": "Protocol for port. Must be UDP, TCP, or SCTP." }, @@ -1296,7 +1333,11 @@ "description": "An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).", "properties": { "preference": { - "$ref": "#/$defs/NodeSelectorTerm", + "allOf": [ + { + "$ref": "#/$defs/NodeSelectorTerm" + } + ], "description": "A node selector term, associated with the corresponding weight." }, "weight": { @@ -1341,7 +1382,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -1369,11 +1414,14 @@ }, "type": { "const": "producer-app", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/ProducerAppValues", + "allOf": [ + { + "$ref": "#/$defs/ProducerAppValues" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -1395,7 +1443,6 @@ }, "ProducerAppV2": { "additionalProperties": true, - "deprecated": true, "description": "Producer component.\nThis producer holds configuration to use as values for the streams-bootstrap producer Helm chart. Note that the producer does not support error topics.", "properties": { "from": { @@ -1421,7 +1468,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -1449,11 +1500,14 @@ }, "type": { "const": "producer-app-v2", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/ProducerAppV2Values", + "allOf": [ + { + "$ref": "#/$defs/ProducerAppV2Values" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -1517,7 +1571,11 @@ "title": "Nameoverride" }, "streams": { - "$ref": "#/$defs/ProducerStreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/ProducerStreamsConfig" + } + ], "description": "Kafka Streams settings" }, "tolerations": { @@ -1729,7 +1787,11 @@ "description": "" }, "kafka": { - "$ref": "#/$defs/ProducerConfig", + "allOf": [ + { + "$ref": "#/$defs/ProducerConfig" + } + ], "description": "Kafka Streams settings" }, "livenessProbe": { @@ -2435,7 +2497,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -2463,11 +2529,14 @@ }, "type": { "const": "streams-app", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/StreamsAppValues", + "allOf": [ + { + "$ref": "#/$defs/StreamsAppValues" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -2489,7 +2558,6 @@ }, "StreamsAppV2": { "additionalProperties": true, - "deprecated": true, "description": "StreamsAppV2 component that configures a streams-bootstrap-v2 app.", "properties": { "from": { @@ -2522,7 +2590,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -2550,11 +2622,14 @@ }, "type": { "const": "streams-app-v2", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/StreamsAppV2Values", + "allOf": [ + { + "$ref": "#/$defs/StreamsAppV2Values" + } + ], "description": "streams-bootstrap-v2 Helm values" }, "version": { @@ -2630,7 +2705,11 @@ "title": "Nameoverride" }, "persistence": { - "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__PersistenceConfig", + "allOf": [ + { + "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__PersistenceConfig" + } + ], "default": { "enabled": false, "size": null, @@ -2645,7 +2724,11 @@ "type": "boolean" }, "streams": { - "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__StreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__StreamsConfig" + } + ], "description": "streams-bootstrap-v2 streams section" }, "tolerations": { @@ -2842,7 +2925,11 @@ "description": "Configuration for JMX Exporter." }, "kafka": { - "$ref": "#/$defs/kpops__components__streams_bootstrap__streams__model__StreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/kpops__components__streams_bootstrap__streams__model__StreamsConfig" + } + ], "description": "streams-bootstrap kafka section" }, "livenessProbe": { @@ -3103,7 +3190,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -3130,7 +3221,11 @@ "description": "Topic(s) into which the component will write output" }, "values": { - "$ref": "#/$defs/StreamsBootstrapValues", + "allOf": [ + { + "$ref": "#/$defs/StreamsBootstrapValues" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -3151,7 +3246,6 @@ }, "StreamsBootstrapV2": { "additionalProperties": true, - "deprecated": true, "description": "Base for components with a streams-bootstrap-v2 Helm chart.", "properties": { "from": { @@ -3184,7 +3278,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -3211,7 +3309,11 @@ "description": "Topic(s) into which the component will write output" }, "values": { - "$ref": "#/$defs/StreamsBootstrapV2Values", + "allOf": [ + { + "$ref": "#/$defs/StreamsBootstrapV2Values" + } + ], "description": "streams-bootstrap-v2 Helm values" }, "version": { @@ -3274,7 +3376,11 @@ "title": "Nameoverride" }, "streams": { - "$ref": "#/$defs/KafkaStreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaStreamsConfig" + } + ], "description": "" }, "tolerations": { @@ -3447,7 +3553,11 @@ "description": "" }, "kafka": { - "$ref": "#/$defs/KafkaConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConfig" + } + ], "description": "Kafka configuration for the streams-bootstrap app." }, "livenessProbe": { @@ -3661,7 +3771,11 @@ "description": "Represents the different Kubernetes tolerations.\nhttps://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/", "properties": { "effect": { - "$ref": "#/$defs/Effects", + "allOf": [ + { + "$ref": "#/$defs/Effects" + } + ], "description": "The effect to tolerate." }, "key": { @@ -3670,7 +3784,11 @@ "type": "string" }, "operator": { - "$ref": "#/$defs/Operation", + "allOf": [ + { + "$ref": "#/$defs/Operation" + } + ], "description": "The operator ('Exists' or 'Equal')." }, "tolerationSeconds": { @@ -3814,7 +3932,11 @@ "description": "The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s).", "properties": { "podAffinityTerm": { - "$ref": "#/$defs/PodAffinityTerm", + "allOf": [ + { + "$ref": "#/$defs/PodAffinityTerm" + } + ], "description": "A pod affinity term, associated with the corresponding weight." }, "weight": { diff --git a/docs/docs/schema/pipeline.json b/docs/docs/schema/pipeline.json index 2a438d1e0..4afa89596 100644 --- a/docs/docs/schema/pipeline.json +++ b/docs/docs/schema/pipeline.json @@ -170,11 +170,14 @@ }, "type": { "const": "helm-app", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Helm app values" }, "version": { @@ -226,7 +229,11 @@ "description": "Helm repository configuration.", "properties": { "repo_auth_flags": { - "$ref": "#/$defs/RepoAuthFlags", + "allOf": [ + { + "$ref": "#/$defs/RepoAuthFlags" + } + ], "default": { "ca_file": null, "cert_file": null, @@ -406,7 +413,11 @@ "description": "Kafka sink connector model.", "properties": { "config": { - "$ref": "#/$defs/KafkaConnectorConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConnectorConfig" + } + ], "description": "Connector config" }, "from": { @@ -447,7 +458,11 @@ "title": "Resetter Namespace" }, "resetter_values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Overriding Kafka Connect resetter Helm values, e.g. to override the image tag etc." }, "to": { @@ -464,8 +479,7 @@ }, "type": { "const": "kafka-sink-connector", - "title": "Type", - "type": "string" + "title": "Type" } }, "required": [ @@ -481,7 +495,11 @@ "description": "Kafka source connector model.", "properties": { "config": { - "$ref": "#/$defs/KafkaConnectorConfig", + "allOf": [ + { + "$ref": "#/$defs/KafkaConnectorConfig" + } + ], "description": "Connector config" }, "from": { @@ -535,7 +553,11 @@ "title": "Resetter Namespace" }, "resetter_values": { - "$ref": "#/$defs/HelmAppValues", + "allOf": [ + { + "$ref": "#/$defs/HelmAppValues" + } + ], "description": "Overriding Kafka Connect resetter Helm values, e.g. to override the image tag etc." }, "to": { @@ -552,8 +574,7 @@ }, "type": { "const": "kafka-source-connector", - "title": "Type", - "type": "string" + "title": "Type" } }, "required": [ @@ -940,7 +961,11 @@ "title": "Name" }, "schema": { - "$ref": "#/$defs/ProtocolSchema", + "allOf": [ + { + "$ref": "#/$defs/ProtocolSchema" + } + ], "default": "TCP", "description": "Protocol for port. Must be UDP, TCP, or SCTP." }, @@ -968,7 +993,11 @@ "description": "An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).", "properties": { "preference": { - "$ref": "#/$defs/NodeSelectorTerm", + "allOf": [ + { + "$ref": "#/$defs/NodeSelectorTerm" + } + ], "description": "A node selector term, associated with the corresponding weight." }, "weight": { @@ -1013,7 +1042,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -1041,11 +1074,14 @@ }, "type": { "const": "producer-app", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/ProducerAppValues", + "allOf": [ + { + "$ref": "#/$defs/ProducerAppValues" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -1067,7 +1103,6 @@ }, "ProducerAppV2": { "additionalProperties": true, - "deprecated": true, "description": "Producer component.\nThis producer holds configuration to use as values for the streams-bootstrap producer Helm chart. Note that the producer does not support error topics.", "properties": { "from": { @@ -1093,7 +1128,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -1121,11 +1160,14 @@ }, "type": { "const": "producer-app-v2", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/ProducerAppV2Values", + "allOf": [ + { + "$ref": "#/$defs/ProducerAppV2Values" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -1189,7 +1231,11 @@ "title": "Nameoverride" }, "streams": { - "$ref": "#/$defs/ProducerStreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/ProducerStreamsConfig" + } + ], "description": "Kafka Streams settings" }, "tolerations": { @@ -1401,7 +1447,11 @@ "description": "" }, "kafka": { - "$ref": "#/$defs/ProducerConfig", + "allOf": [ + { + "$ref": "#/$defs/ProducerConfig" + } + ], "description": "Kafka Streams settings" }, "livenessProbe": { @@ -2107,7 +2157,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -2135,11 +2189,14 @@ }, "type": { "const": "streams-app", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/StreamsAppValues", + "allOf": [ + { + "$ref": "#/$defs/StreamsAppValues" + } + ], "description": "streams-bootstrap Helm values" }, "version": { @@ -2161,7 +2218,6 @@ }, "StreamsAppV2": { "additionalProperties": true, - "deprecated": true, "description": "StreamsAppV2 component that configures a streams-bootstrap-v2 app.", "properties": { "from": { @@ -2194,7 +2250,11 @@ "type": "string" }, "repo_config": { - "$ref": "#/$defs/HelmRepoConfig", + "allOf": [ + { + "$ref": "#/$defs/HelmRepoConfig" + } + ], "default": { "repo_auth_flags": { "ca_file": null, @@ -2222,11 +2282,14 @@ }, "type": { "const": "streams-app-v2", - "title": "Type", - "type": "string" + "title": "Type" }, "values": { - "$ref": "#/$defs/StreamsAppV2Values", + "allOf": [ + { + "$ref": "#/$defs/StreamsAppV2Values" + } + ], "description": "streams-bootstrap-v2 Helm values" }, "version": { @@ -2302,7 +2365,11 @@ "title": "Nameoverride" }, "persistence": { - "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__PersistenceConfig", + "allOf": [ + { + "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__PersistenceConfig" + } + ], "default": { "enabled": false, "size": null, @@ -2317,7 +2384,11 @@ "type": "boolean" }, "streams": { - "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__StreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/kpops__components__streams_bootstrap_v2__streams__model__StreamsConfig" + } + ], "description": "streams-bootstrap-v2 streams section" }, "tolerations": { @@ -2514,7 +2585,11 @@ "description": "Configuration for JMX Exporter." }, "kafka": { - "$ref": "#/$defs/kpops__components__streams_bootstrap__streams__model__StreamsConfig", + "allOf": [ + { + "$ref": "#/$defs/kpops__components__streams_bootstrap__streams__model__StreamsConfig" + } + ], "description": "streams-bootstrap kafka section" }, "livenessProbe": { @@ -2771,7 +2846,11 @@ "description": "Represents the different Kubernetes tolerations.\nhttps://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/", "properties": { "effect": { - "$ref": "#/$defs/Effects", + "allOf": [ + { + "$ref": "#/$defs/Effects" + } + ], "description": "The effect to tolerate." }, "key": { @@ -2780,7 +2859,11 @@ "type": "string" }, "operator": { - "$ref": "#/$defs/Operation", + "allOf": [ + { + "$ref": "#/$defs/Operation" + } + ], "description": "The operator ('Exists' or 'Equal')." }, "tolerationSeconds": { @@ -2924,7 +3007,11 @@ "description": "The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s).", "properties": { "podAffinityTerm": { - "$ref": "#/$defs/PodAffinityTerm", + "allOf": [ + { + "$ref": "#/$defs/PodAffinityTerm" + } + ], "description": "A pod affinity term, associated with the corresponding weight." }, "weight": { diff --git a/docs/docs/user/core-concepts/operation-mode.md b/docs/docs/user/core-concepts/operation-mode.md index 91b8cc6ea..484f27860 100644 --- a/docs/docs/user/core-concepts/operation-mode.md +++ b/docs/docs/user/core-concepts/operation-mode.md @@ -10,8 +10,11 @@ KPOps supports three operation modes—`managed`, `manifest`, and `argo`. These ## Configuring Operation Modes -It is possible to configure the operation mode in the `config.yaml` file. Please refer to the [Configuration documentation page](https://bakdata.github.io/kpops/9.0/user/core-concepts/config/). -Alternatively, you can to pass the `--operation-mode ` option in the CLI to override the operation mode of the `config.yaml`. You can refer to the [CLI commands documentation](https://bakdata.github.io/kpops/9.0/user/references/cli-commands/#kpops-deploy) for more details. +You can configure the operation mode using one of the following methods: + +1. **Command-Line Option**: Pass the `--operation-mode ` flag when running a CLI command. Refer to the [CLI commands documentation](https://bakdata.github.io/kpops/9.0/user/references/cli-commands/#kpops-deploy) for more details. + +2. **Environment Variable**: Set the operation mode by defining the `KPOPS_OPERATION_MODE` environment variable. --- diff --git a/kpops/component_handlers/kafka_connect/timeout.py b/kpops/component_handlers/kafka_connect/timeout.py index bb036ed29..30503b3e2 100644 --- a/kpops/component_handlers/kafka_connect/timeout.py +++ b/kpops/component_handlers/kafka_connect/timeout.py @@ -1,6 +1,6 @@ import asyncio +import builtins import logging -from asyncio import TimeoutError from collections.abc import Coroutine from typing import Any, TypeVar @@ -21,7 +21,7 @@ async def timeout(coro: Coroutine[Any, Any, T], *, secs: int = 0) -> T | None: return await task else: return await asyncio.wait_for(task, timeout=secs) - except TimeoutError: + except builtins.TimeoutError: log.exception( f"Kafka Connect operation {coro.__name__} timed out after {secs} seconds. To increase the duration, set the `timeout` option in config.yaml." ) diff --git a/kpops/components/common/kubernetes_model.py b/kpops/components/common/kubernetes_model.py index 967182218..1b4a688b7 100644 --- a/kpops/components/common/kubernetes_model.py +++ b/kpops/components/common/kubernetes_model.py @@ -18,7 +18,7 @@ try: from typing import Self # pyright: ignore[reportAttributeAccessIssue] except ImportError: - from typing_extensions import Self + from typing import Self class ServiceType(str, enum.Enum): diff --git a/kpops/config/__init__.py b/kpops/config/__init__.py index 07ecce58c..9e4f269b8 100644 --- a/kpops/config/__init__.py +++ b/kpops/config/__init__.py @@ -6,6 +6,7 @@ import pydantic from pydantic import AnyHttpUrl, Field, PrivateAttr, TypeAdapter +from pydantic.json_schema import SkipJsonSchema from pydantic_settings import ( BaseSettings, PydanticBaseSettingsSource, @@ -152,14 +153,15 @@ class KpopsConfig(BaseSettings): default=False, description="Whether to retain clean up jobs in the cluster or uninstall the, after completion.", ) - operation_mode: OperationMode = Field( - default=OperationMode.MANAGED, - description="The operation mode of KPOps (managed, manifest, argo).", - ) strimzi_topic: StrimziTopicConfig | None = Field( default=None, description=describe_object(StrimziTopicConfig.__doc__), ) + operation_mode: SkipJsonSchema[OperationMode] = Field( + default=OperationMode.MANAGED, + description="The operation mode of KPOps (managed, manifest, argo).", + exclude=True, + ) model_config = SettingsConfigDict( env_prefix=ENV_PREFIX, diff --git a/kpops/utils/gen_schema.py b/kpops/utils/gen_schema.py index 539e2cf3a..13b8c4b62 100644 --- a/kpops/utils/gen_schema.py +++ b/kpops/utils/gen_schema.py @@ -1,3 +1,6 @@ +# FIXME: pyright breaks here. Investigate why this is happening. +# type: ignore[reportGeneralTypeIssues] + import inspect import json import logging diff --git a/poetry.lock b/poetry.lock index 7df2cc53c..54e505815 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,76 +1,73 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiofiles" -version = "23.2.1" +version = "23.1.0" description = "File support for asyncio." optional = false -python-versions = ">=3.7" +python-versions = ">=3.7,<4.0" files = [ - {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, - {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, + {file = "aiofiles-23.1.0-py3-none-any.whl", hash = "sha256:9312414ae06472eb6f1d163f555e466a23aed1c8f60c30cccf7121dba2e53eb2"}, + {file = "aiofiles-23.1.0.tar.gz", hash = "sha256:edd247df9a19e0db16534d4baaf536d6609a43e1de5401d7a4c1c148753a1635"}, ] [[package]] name = "annotated-types" -version = "0.7.0" +version = "0.5.0" description = "Reusable constraint types to use with typing.Annotated" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, + {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, + {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, ] [[package]] name = "anyio" -version = "4.7.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, - {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, ] [package.dependencies] idna = ">=2.8" sniffio = ">=1.1" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] -trio = ["trio (>=0.26.1)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] [[package]] name = "attrs" -version = "24.3.0" +version = "22.1.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.8" +python-versions = ">=3.5" files = [ - {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, - {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] +docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "babel" -version = "2.16.0" +version = "2.13.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, - {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, + {file = "Babel-2.13.0-py3-none-any.whl", hash = "sha256:fbfcae1575ff78e26c7449136f1abbefc3c13ce542eeb13d43d50d8b047216ec"}, + {file = "Babel-2.13.0.tar.gz", hash = "sha256:04c3e2d28d2b7681644508f836be388ae49e0cfe91465095340395b60d00f210"}, ] [package.extras] @@ -78,192 +75,89 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "beautifulsoup4" -version = "4.12.3" +version = "4.11.1" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, - {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, + {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, + {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] -cchardet = ["cchardet"] -chardet = ["chardet"] -charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] [[package]] name = "cachetools" -version = "5.5.0" +version = "5.2.0" description = "Extensible memoizing collections and decorators" optional = false -python-versions = ">=3.7" +python-versions = "~=3.7" files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, + {file = "cachetools-5.2.0-py3-none-any.whl", hash = "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db"}, + {file = "cachetools-5.2.0.tar.gz", hash = "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757"}, ] [[package]] name = "certifi" -version = "2024.12.14" +version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, ] [[package]] name = "cfgv" -version = "3.4.0" +version = "3.3.1" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6.1" files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] [[package]] name = "chardet" -version = "5.2.0" +version = "5.1.0" description = "Universal encoding detector for Python 3" optional = false python-versions = ">=3.7" files = [ - {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, - {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, + {file = "chardet-5.1.0-py3-none-any.whl", hash = "sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9"}, + {file = "chardet-5.1.0.tar.gz", hash = "sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5"}, ] [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "2.1.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +python-versions = ">=3.6.0" +files = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] +[package.extras] +unicode-backport = ["unicodedata2"] + [[package]] name = "click" -version = "8.1.7" +version = "8.1.3" 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"}, + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] [package.dependencies] @@ -296,13 +190,13 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "croniter" -version = "3.0.4" +version = "3.0.3" description = "croniter provides iteration for datetime object with cron like format" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.6" files = [ - {file = "croniter-3.0.4-py2.py3-none-any.whl", hash = "sha256:96e14cdd5dcb479dd48d7db14b53d8434b188dfb9210448bef6f65663524a6f0"}, - {file = "croniter-3.0.4.tar.gz", hash = "sha256:f9dcd4bdb6c97abedb6f09d6ed3495b13ede4d4544503fa580b6372a56a0c520"}, + {file = "croniter-3.0.3-py2.py3-none-any.whl", hash = "sha256:b3bd11f270dc54ccd1f2397b813436015a86d30ffc5a7a9438eec1ed916f2101"}, + {file = "croniter-3.0.3.tar.gz", hash = "sha256:34117ec1741f10a7bd0ec3ad7d8f0eb8fa457a2feb9be32e6a2250e158957668"}, ] [package.dependencies] @@ -311,13 +205,13 @@ pytz = ">2021.1" [[package]] name = "dataproperty" -version = "1.0.1" +version = "1.0.0" description = "Python library for extract property from data." optional = false python-versions = ">=3.7" files = [ - {file = "DataProperty-1.0.1-py3-none-any.whl", hash = "sha256:0b8b07d4fb6453fcf975b53d35dea41f3cfd69c9d79b5010c3cf224ff0407a7a"}, - {file = "DataProperty-1.0.1.tar.gz", hash = "sha256:723e5729fa6e885e127a771a983ee1e0e34bb141aca4ffe1f0bfa7cde34650a4"}, + {file = "DataProperty-1.0.0-py3-none-any.whl", hash = "sha256:9949307255ef2718d820312d4c068db1429f0fe54610b775c90551350ad84711"}, + {file = "DataProperty-1.0.0.tar.gz", hash = "sha256:a7dab3e8b64b9839aaeb7cee109ec93ec3a03c025c247c545ee988c5d5be4fcf"}, ] [package.dependencies] @@ -347,68 +241,67 @@ tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytes [[package]] name = "distlib" -version = "0.3.9" +version = "0.3.6" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, - {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, ] [[package]] name = "faker" -version = "33.1.0" +version = "22.0.0" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" files = [ - {file = "Faker-33.1.0-py3-none-any.whl", hash = "sha256:d30c5f0e2796b8970de68978365247657486eb0311c5abe88d0b895b68dff05d"}, - {file = "faker-33.1.0.tar.gz", hash = "sha256:1c925fc0e86a51fc46648b504078c88d0cd48da1da2595c4e712841cab43a1e4"}, + {file = "Faker-22.0.0-py3-none-any.whl", hash = "sha256:9c22c0a734ca01c6e4f2259eab5dab9081905a9d67b27272aea5c9feeb5a3789"}, + {file = "Faker-22.0.0.tar.gz", hash = "sha256:1d5dc0a75da7bc40741ee4c84d99dc087b97bd086d4222ad06ac4dd2219bcf3f"}, ] [package.dependencies] python-dateutil = ">=2.4" -typing-extensions = "*" [[package]] name = "fastavro" -version = "1.9.7" +version = "1.9.4" description = "Fast read/write of AVRO files" optional = false python-versions = ">=3.8" files = [ - {file = "fastavro-1.9.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc811fb4f7b5ae95f969cda910241ceacf82e53014c7c7224df6f6e0ca97f52f"}, - {file = "fastavro-1.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb8749e419a85f251bf1ac87d463311874972554d25d4a0b19f6bdc56036d7cf"}, - {file = "fastavro-1.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b2f9bafa167cb4d1c3dd17565cb5bf3d8c0759e42620280d1760f1e778e07fc"}, - {file = "fastavro-1.9.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e87d04b235b29f7774d226b120da2ca4e60b9e6fdf6747daef7f13f218b3517a"}, - {file = "fastavro-1.9.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b525c363e267ed11810aaad8fbdbd1c3bd8837d05f7360977d72a65ab8c6e1fa"}, - {file = "fastavro-1.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:6312fa99deecc319820216b5e1b1bd2d7ebb7d6f221373c74acfddaee64e8e60"}, - {file = "fastavro-1.9.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ec8499dc276c2d2ef0a68c0f1ad11782b2b956a921790a36bf4c18df2b8d4020"}, - {file = "fastavro-1.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d9d96f98052615ab465c63ba8b76ed59baf2e3341b7b169058db104cbe2aa0"}, - {file = "fastavro-1.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:919f3549e07a8a8645a2146f23905955c35264ac809f6c2ac18142bc5b9b6022"}, - {file = "fastavro-1.9.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9de1fa832a4d9016724cd6facab8034dc90d820b71a5d57c7e9830ffe90f31e4"}, - {file = "fastavro-1.9.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1d09227d1f48f13281bd5ceac958650805aef9a4ef4f95810128c1f9be1df736"}, - {file = "fastavro-1.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:2db993ae6cdc63e25eadf9f93c9e8036f9b097a3e61d19dca42536dcc5c4d8b3"}, - {file = "fastavro-1.9.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4e1289b731214a7315884c74b2ec058b6e84380ce9b18b8af5d387e64b18fc44"}, - {file = "fastavro-1.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eac69666270a76a3a1d0444f39752061195e79e146271a568777048ffbd91a27"}, - {file = "fastavro-1.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9be089be8c00f68e343bbc64ca6d9a13e5e5b0ba8aa52bcb231a762484fb270e"}, - {file = "fastavro-1.9.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d576eccfd60a18ffa028259500df67d338b93562c6700e10ef68bbd88e499731"}, - {file = "fastavro-1.9.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee9bf23c157bd7dcc91ea2c700fa3bd924d9ec198bb428ff0b47fa37fe160659"}, - {file = "fastavro-1.9.7-cp312-cp312-win_amd64.whl", hash = "sha256:b6b2ccdc78f6afc18c52e403ee68c00478da12142815c1bd8a00973138a166d0"}, - {file = "fastavro-1.9.7-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7313def3aea3dacface0a8b83f6d66e49a311149aa925c89184a06c1ef99785d"}, - {file = "fastavro-1.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:536f5644737ad21d18af97d909dba099b9e7118c237be7e4bd087c7abde7e4f0"}, - {file = "fastavro-1.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2af559f30383b79cf7d020a6b644c42ffaed3595f775fe8f3d7f80b1c43dfdc5"}, - {file = "fastavro-1.9.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:edc28ab305e3c424de5ac5eb87b48d1e07eddb6aa08ef5948fcda33cc4d995ce"}, - {file = "fastavro-1.9.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ec2e96bdabd58427fe683329b3d79f42c7b4f4ff6b3644664a345a655ac2c0a1"}, - {file = "fastavro-1.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:3b683693c8a85ede496ebebe115be5d7870c150986e34a0442a20d88d7771224"}, - {file = "fastavro-1.9.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:58f76a5c9a312fbd37b84e49d08eb23094d36e10d43bc5df5187bc04af463feb"}, - {file = "fastavro-1.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56304401d2f4f69f5b498bdd1552c13ef9a644d522d5de0dc1d789cf82f47f73"}, - {file = "fastavro-1.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fcce036c6aa06269fc6a0428050fcb6255189997f5e1a728fc461e8b9d3e26b"}, - {file = "fastavro-1.9.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:17de68aae8c2525f5631d80f2b447a53395cdc49134f51b0329a5497277fc2d2"}, - {file = "fastavro-1.9.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7c911366c625d0a997eafe0aa83ffbc6fd00d8fd4543cb39a97c6f3b8120ea87"}, - {file = "fastavro-1.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:912283ed48578a103f523817fdf0c19b1755cea9b4a6387b73c79ecb8f8f84fc"}, - {file = "fastavro-1.9.7.tar.gz", hash = "sha256:13e11c6cb28626da85290933027cd419ce3f9ab8e45410ef24ce6b89d20a1f6c"}, + {file = "fastavro-1.9.4-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:60cb38f07462a7fb4e4440ed0de67d3d400ae6b3d780f81327bebde9aa55faef"}, + {file = "fastavro-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:063d01d197fc929c20adc09ca9f0ca86d33ac25ee0963ce0b438244eee8315ae"}, + {file = "fastavro-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a9053fcfbc895f2a16a4303af22077e3a8fdcf1cd5d6ed47ff2ef22cbba2f0"}, + {file = "fastavro-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:02bf1276b7326397314adf41b34a4890f6ffa59cf7e0eb20b9e4ab0a143a1598"}, + {file = "fastavro-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56bed9eca435389a8861e6e2d631ec7f8f5dda5b23f93517ac710665bd34ca29"}, + {file = "fastavro-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:0cd2099c8c672b853e0b20c13e9b62a69d3fbf67ee7c59c7271ba5df1680310d"}, + {file = "fastavro-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:af8c6d8c43a02b5569c093fc5467469541ac408c79c36a5b0900d3dd0b3ba838"}, + {file = "fastavro-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a138710bd61580324d23bc5e3df01f0b82aee0a76404d5dddae73d9e4c723f"}, + {file = "fastavro-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:903d97418120ca6b6a7f38a731166c1ccc2c4344ee5e0470d09eb1dc3687540a"}, + {file = "fastavro-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c443eeb99899d062dbf78c525e4614dd77e041a7688fa2710c224f4033f193ae"}, + {file = "fastavro-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ac26ab0774d1b2b7af6d8f4300ad20bbc4b5469e658a02931ad13ce23635152f"}, + {file = "fastavro-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:cf7247874c22be856ba7d1f46a0f6e0379a6025f1a48a7da640444cbac6f570b"}, + {file = "fastavro-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:68912f2020e1b3d70557260b27dd85fb49a4fc6bfab18d384926127452c1da4c"}, + {file = "fastavro-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6925ce137cdd78e109abdb0bc33aad55de6c9f2d2d3036b65453128f2f5f5b92"}, + {file = "fastavro-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b928cd294e36e35516d0deb9e104b45be922ba06940794260a4e5dbed6c192a"}, + {file = "fastavro-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:90c9838bc4c991ffff5dd9d88a0cc0030f938b3fdf038cdf6babde144b920246"}, + {file = "fastavro-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:eca6e54da571b06a3c5a72dbb7212073f56c92a6fbfbf847b91c347510f8a426"}, + {file = "fastavro-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a4b02839ac261100cefca2e2ad04cdfedc556cb66b5ec735e0db428e74b399de"}, + {file = "fastavro-1.9.4-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:4451ee9a305a73313a1558d471299f3130e4ecc10a88bf5742aa03fb37e042e6"}, + {file = "fastavro-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8524fccfb379565568c045d29b2ebf71e1f2c0dd484aeda9fe784ef5febe1a8"}, + {file = "fastavro-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33d0a00a6e09baa20f6f038d7a2ddcb7eef0e7a9980e947a018300cb047091b8"}, + {file = "fastavro-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:23d7e5b29c9bf6f26e8be754b2c8b919838e506f78ef724de7d22881696712fc"}, + {file = "fastavro-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e6ab3ee53944326460edf1125b2ad5be2fadd80f7211b13c45fa0c503b4cf8d"}, + {file = "fastavro-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:64d335ec2004204c501f8697c385d0a8f6b521ac82d5b30696f789ff5bc85f3c"}, + {file = "fastavro-1.9.4-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:7e05f44c493e89e73833bd3ff3790538726906d2856f59adc8103539f4a1b232"}, + {file = "fastavro-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:253c63993250bff4ee7b11fb46cf3a4622180a783bedc82a24c6fdcd1b10ca2a"}, + {file = "fastavro-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24d6942eb1db14640c2581e0ecd1bbe0afc8a83731fcd3064ae7f429d7880cb7"}, + {file = "fastavro-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d47bb66be6091cd48cfe026adcad11c8b11d7d815a2949a1e4ccf03df981ca65"}, + {file = "fastavro-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c293897f12f910e58a1024f9c77f565aa8e23b36aafda6ad8e7041accc57a57f"}, + {file = "fastavro-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:f05d2afcb10a92e2a9e580a3891f090589b3e567fdc5641f8a46a0b084f120c3"}, + {file = "fastavro-1.9.4.tar.gz", hash = "sha256:56b8363e360a1256c94562393dc7f8611f3baf2b3159f64fb2b9c6b87b14e876"}, ] [package.extras] @@ -419,19 +312,18 @@ zstandard = ["zstandard"] [[package]] name = "filelock" -version = "3.16.1" +version = "3.8.2" description = "A platform independent file lock." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, - {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, + {file = "filelock-3.8.2-py3-none-any.whl", hash = "sha256:8df285554452285f79c035efb0c861eb33a4bcfa5b7a137016e32e6a90f9792c"}, + {file = "filelock-3.8.2.tar.gz", hash = "sha256:7565f628ea56bfcd8e54e42bdc55da899c85c1abfe1b5bcfd147e9188cebb3b2"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] -typing = ["typing-extensions (>=4.12.2)"] +docs = ["furo (>=2022.9.29)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +testing = ["covdefaults (>=2.2.2)", "coverage (>=6.5)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] [[package]] name = "ghp-import" @@ -452,13 +344,13 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "griffe" -version = "1.5.1" +version = "0.45.2" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "griffe-1.5.1-py3-none-any.whl", hash = "sha256:ad6a7980f8c424c9102160aafa3bcdf799df0e75f7829d75af9ee5aef656f860"}, - {file = "griffe-1.5.1.tar.gz", hash = "sha256:72964f93e08c553257706d6cd2c42d1c172213feb48b2be386f243380b405d4b"}, + {file = "griffe-0.45.2-py3-none-any.whl", hash = "sha256:297ec8530d0c68e5b98ff86fb588ebc3aa3559bb5dc21f3caea8d9542a350133"}, + {file = "griffe-0.45.2.tar.gz", hash = "sha256:83ce7dcaafd8cb7f43cbf1a455155015a1eb624b1ffd93249e5e1c4a22b2fdb2"}, ] [package.dependencies] @@ -475,26 +367,15 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] -[[package]] -name = "hjson" -version = "3.1.0" -description = "Hjson, a user interface for JSON." -optional = false -python-versions = "*" -files = [ - {file = "hjson-3.1.0-py3-none-any.whl", hash = "sha256:65713cdcf13214fb554eb8b4ef803419733f4f5e551047c9b711098ab7186b89"}, - {file = "hjson-3.1.0.tar.gz", hash = "sha256:55af475a27cf83a7969c808399d7bccdec8fb836a07ddbd574587593b9cdcf75"}, -] - [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.4" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, + {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, ] [package.dependencies] @@ -505,17 +386,17 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] +trio = ["trio (>=0.22.0,<0.25.0)"] [[package]] name = "httpx" -version = "0.27.2" +version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, - {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, ] [package.dependencies] @@ -530,17 +411,16 @@ brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.3" +version = "2.5.10" description = "File identification library for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd"}, - {file = "identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02"}, + {file = "identify-2.5.10-py2.py3-none-any.whl", hash = "sha256:fb7c2feaeca6976a3ffa31ec3236a6911fbc51aec9acc111de2aed99f244ade2"}, + {file = "identify-2.5.10.tar.gz", hash = "sha256:dce9e31fee7dbc45fea36a9e855c316b8fbf807e65a862f160840bb5a2bf5dfd"}, ] [package.extras] @@ -548,38 +428,35 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.10" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.6" +python-versions = ">=3.5" files = [ - {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, - {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - [[package]] name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = "*" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.2" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] [package.dependencies] @@ -590,152 +467,111 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jsonschema" -version = "4.23.0" +version = "4.17.3" description = "An implementation of JSON Schema validation for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, - {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, + {file = "jsonschema-4.17.3-py3-none-any.whl", hash = "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6"}, + {file = "jsonschema-4.17.3.tar.gz", hash = "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d"}, ] [package.dependencies] -attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" -referencing = ">=0.28.4" -rpds-py = ">=0.7.1" +attrs = ">=17.4.0" +pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] - -[[package]] -name = "jsonschema-specifications" -version = "2024.10.1" -description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -optional = false -python-versions = ">=3.9" -files = [ - {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, - {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, -] - -[package.dependencies] -referencing = ">=0.31.0" +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] [[package]] name = "lightkube" -version = "0.15.8" +version = "0.15.3" description = "Lightweight kubernetes client library" optional = false python-versions = "*" files = [ - {file = "lightkube-0.15.8-py3-none-any.whl", hash = "sha256:236f6d11e9281764a8ae896ab2c28a4bc943dc0576822445064577eaa90677ba"}, - {file = "lightkube-0.15.8.tar.gz", hash = "sha256:ac950d24ddbb59904708730f13ce254b05b6255a471dfab027cbe44c4123bfc6"}, + {file = "lightkube-0.15.3-py3-none-any.whl", hash = "sha256:0f1c5e3b80f727df161965eff9cd6bc029c47e5a8569ab3e1acc429fd8c73db1"}, + {file = "lightkube-0.15.3.tar.gz", hash = "sha256:235b66409b67e06ce26bd5c7ae27e105bb6016ce0962d144e272a31155545e27"}, ] [package.dependencies] -httpx = ">=0.24.0,<0.28.0" +httpx = ">=0.24.0" lightkube-models = ">=1.15.12.0" PyYAML = "*" -[package.extras] -dev = ["pytest", "pytest-asyncio (<0.17.0)", "respx"] - [[package]] name = "lightkube-models" -version = "1.32.0.8" +version = "1.30.0.8" description = "Models and Resources for lightkube module" optional = false python-versions = "*" files = [ - {file = "lightkube-models-1.32.0.8.tar.gz", hash = "sha256:97f6c2ab554a23a69554dd56ffbd94173fb416af6490c3a21b1e0b8e13a2bafe"}, - {file = "lightkube_models-1.32.0.8-py3-none-any.whl", hash = "sha256:73786dac63085521f4c88aa69d86bfdc76a67da997c1770e5bdcef8482e4b2a0"}, + {file = "lightkube-models-1.30.0.8.tar.gz", hash = "sha256:d1fe87b6680a04d27440bb746f2bf2fb665e1515bab12efc3ace65118ecb7eac"}, + {file = "lightkube_models-1.30.0.8-py3-none-any.whl", hash = "sha256:34c43ae4824214eb8bc5e219da57c319ba411a51f503f79510d8c1ae6966ecb5"}, ] [[package]] name = "markdown" -version = "3.7" -description = "Python implementation of John Gruber's Markdown." +version = "3.3.7" +description = "Python implementation of Markdown." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, - {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, + {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, + {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, ] [package.extras] -docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "3.0.2" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, - {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] [[package]] @@ -789,13 +625,13 @@ test = ["coverage", "flake8 (>=3.0)", "shtab"] [[package]] name = "mkdocs" -version = "1.6.1" +version = "1.5.3" description = "Project documentation with Markdown." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, - {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, + {file = "mkdocs-1.5.3-py3-none-any.whl", hash = "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1"}, + {file = "mkdocs-1.5.3.tar.gz", hash = "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"}, ] [package.dependencies] @@ -803,29 +639,29 @@ click = ">=7.0" colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} ghp-import = ">=1.0" jinja2 = ">=2.11.1" -markdown = ">=3.3.6" +markdown = ">=3.2.1" markupsafe = ">=2.0.1" mergedeep = ">=1.3.4" -mkdocs-get-deps = ">=0.2.0" packaging = ">=20.5" pathspec = ">=0.11.1" +platformdirs = ">=2.2.0" pyyaml = ">=5.1" pyyaml-env-tag = ">=0.1" watchdog = ">=2.0" [package.extras] i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] [[package]] name = "mkdocs-autorefs" -version = "1.2.0" +version = "1.0.1" description = "Automatically link across pages in MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_autorefs-1.2.0-py3-none-any.whl", hash = "sha256:d588754ae89bd0ced0c70c06f58566a4ee43471eeeee5202427da7de9ef85a2f"}, - {file = "mkdocs_autorefs-1.2.0.tar.gz", hash = "sha256:a86b93abff653521bda71cf3fc5596342b7a23982093915cb74273f67522190f"}, + {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, + {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, ] [package.dependencies] @@ -835,79 +671,59 @@ mkdocs = ">=1.1" [[package]] name = "mkdocs-exclude-search" -version = "0.6.6" +version = "0.6.5" description = "A mkdocs plugin that lets you exclude selected files or sections from the search index." optional = false python-versions = ">=3.6" files = [ - {file = "mkdocs-exclude-search-0.6.6.tar.gz", hash = "sha256:3cdff1b9afdc1b227019cd1e124f401453235b92153d60c0e5e651a76be4f044"}, - {file = "mkdocs_exclude_search-0.6.6-py3-none-any.whl", hash = "sha256:2b4b941d1689808db533fe4a6afba75ce76c9bab8b21d4e31efc05fd8c4e0a4f"}, + {file = "mkdocs-exclude-search-0.6.5.tar.gz", hash = "sha256:6a126367653caf946c56e446ff30ffdec931438a3e2a8740feff3f8682d52a54"}, + {file = "mkdocs_exclude_search-0.6.5-py3-none-any.whl", hash = "sha256:475e372dd17195700acd00213bcc804280d63f39cb7a0c76a801aceefd2807a6"}, ] [package.dependencies] mkdocs = ">=1.0.4" -[[package]] -name = "mkdocs-get-deps" -version = "0.2.0" -description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, - {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, -] - -[package.dependencies] -mergedeep = ">=1.3.4" -platformdirs = ">=2.2.0" -pyyaml = ">=5.1" - [[package]] name = "mkdocs-glightbox" -version = "0.3.7" +version = "0.3.4" description = "MkDocs plugin supports image lightbox with GLightbox." optional = false python-versions = "*" files = [ - {file = "mkdocs-glightbox-0.3.7.tar.gz", hash = "sha256:4e890140a97dd4ad128cb92174384bd0ac33adec3304bbd2b7c48d0847685c4f"}, - {file = "mkdocs_glightbox-0.3.7-py3-none-any.whl", hash = "sha256:9659631a9829d93d8fb0ce3a20a10261c258605ba4dc87a3b7b5d847b93a276d"}, + {file = "mkdocs-glightbox-0.3.4.tar.gz", hash = "sha256:96aaf98216f83c0d0fad2e42a8d805cfa6329d6ab25b54265012ccb2154010d8"}, + {file = "mkdocs_glightbox-0.3.4-py3-none-any.whl", hash = "sha256:8f894435b4f75231164e5d9fb023c01e922e6769e74a121e822c4914f310a41d"}, ] [[package]] name = "mkdocs-macros-plugin" -version = "1.3.7" +version = "1.0.5" description = "Unleash the power of MkDocs with macros and variables" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_macros_plugin-1.3.7-py3-none-any.whl", hash = "sha256:02432033a5b77fb247d6ec7924e72fc4ceec264165b1644ab8d0dc159c22ce59"}, - {file = "mkdocs_macros_plugin-1.3.7.tar.gz", hash = "sha256:17c7fd1a49b94defcdb502fd453d17a1e730f8836523379d21292eb2be4cb523"}, + {file = "mkdocs-macros-plugin-1.0.5.tar.gz", hash = "sha256:fe348d75f01c911f362b6d998c57b3d85b505876dde69db924f2c512c395c328"}, + {file = "mkdocs_macros_plugin-1.0.5-py3-none-any.whl", hash = "sha256:f60e26f711f5a830ddf1e7980865bf5c0f1180db56109803cdd280073c1a050a"}, ] [package.dependencies] -hjson = "*" jinja2 = "*" mkdocs = ">=0.17" -packaging = "*" -pathspec = "*" python-dateutil = "*" pyyaml = "*" -super-collections = "*" termcolor = "*" [package.extras] -test = ["mkdocs-d2-plugin", "mkdocs-include-markdown-plugin", "mkdocs-macros-test", "mkdocs-material (>=6.2)", "mkdocs-test"] +test = ["mkdocs-include-markdown-plugin", "mkdocs-macros-test", "mkdocs-material (>=6.2)"] [[package]] name = "mkdocs-material" -version = "9.5.49" +version = "9.4.6" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.49-py3-none-any.whl", hash = "sha256:c3c2d8176b18198435d3a3e119011922f3e11424074645c24019c2dcf08a360e"}, - {file = "mkdocs_material-9.5.49.tar.gz", hash = "sha256:3671bb282b4f53a1c72e08adbe04d2481a98f85fed392530051f80ff94a9621d"}, + {file = "mkdocs_material-9.4.6-py3-none-any.whl", hash = "sha256:78802035d5768a78139c84ad7dce0c6493e8f7dc4861727d36ed91d1520a54da"}, + {file = "mkdocs_material-9.4.6.tar.gz", hash = "sha256:09665e60df7ee9e5ff3a54af173f6d45be718b1ee7dd962bcff3102b81fb0c14"}, ] [package.dependencies] @@ -915,8 +731,8 @@ babel = ">=2.10,<3.0" colorama = ">=0.4,<1.0" jinja2 = ">=3.0,<4.0" markdown = ">=3.2,<4.0" -mkdocs = ">=1.6,<2.0" -mkdocs-material-extensions = ">=1.3,<2.0" +mkdocs = ">=1.5.3,<2.0" +mkdocs-material-extensions = ">=1.2,<2.0" paginate = ">=0.5,<1.0" pygments = ">=2.16,<3.0" pymdown-extensions = ">=10.2,<11.0" @@ -924,30 +740,30 @@ regex = ">=2022.4" requests = ">=2.26,<3.0" [package.extras] -git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] -imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] +git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2,<2.0)"] +imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=9.4,<10.0)"] recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] [[package]] name = "mkdocs-material-extensions" -version = "1.3.1" +version = "1.3" description = "Extension pack for Python Markdown and MkDocs Material." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, - {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, + {file = "mkdocs_material_extensions-1.3-py3-none-any.whl", hash = "sha256:0297cc48ba68a9fdd1ef3780a3b41b534b0d0df1d1181a44676fda5f464eeadc"}, + {file = "mkdocs_material_extensions-1.3.tar.gz", hash = "sha256:f0446091503acb110a7cab9349cbc90eeac51b58d1caa92a704a81ca1e24ddbd"}, ] [[package]] name = "mkdocstrings" -version = "0.25.2" +version = "0.25.1" description = "Automatic documentation from sources, for MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc"}, - {file = "mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc"}, + {file = "mkdocstrings-0.25.1-py3-none-any.whl", hash = "sha256:da01fcc2670ad61888e8fe5b60afe9fee5781017d67431996832d63e887c2e51"}, + {file = "mkdocstrings-0.25.1.tar.gz", hash = "sha256:c3a2515f31577f311a9ee58d089e4c51fc6046dbd9e9b4c3de4c3194667fe9bf"}, ] [package.dependencies] @@ -968,133 +784,126 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.10.9" +version = "1.10.3" description = "A Python handler for mkdocstrings." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings_python-1.10.9-py3-none-any.whl", hash = "sha256:cbe98710a6757dfd4dff79bf36cb9731908fb4c69dd2736b15270ae7a488243d"}, - {file = "mkdocstrings_python-1.10.9.tar.gz", hash = "sha256:f344aaa47e727d8a2dc911e063025e58e2b7fb31a41110ccc3902aa6be7ca196"}, + {file = "mkdocstrings_python-1.10.3-py3-none-any.whl", hash = "sha256:11ff6d21d3818fb03af82c3ea6225b1534837e17f790aa5f09626524171f949b"}, + {file = "mkdocstrings_python-1.10.3.tar.gz", hash = "sha256:321cf9c732907ab2b1fedaafa28765eaa089d89320f35f7206d00ea266889d03"}, ] [package.dependencies] -griffe = ">=0.49" -mkdocs-autorefs = ">=1.0" +griffe = ">=0.44" mkdocstrings = ">=0.25" [[package]] name = "networkx" -version = "3.4.2" +version = "3.1" description = "Python package for creating and manipulating graphs and networks" optional = false -python-versions = ">=3.10" +python-versions = ">=3.8" files = [ - {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, - {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, + {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, + {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, ] [package.extras] -default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"] -developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] -doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"] -example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] -extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] -test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] +default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] +test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.7.0" description = "Node.js virtual environment builder" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, ] +[package.dependencies] +setuptools = "*" + [[package]] name = "packaging" -version = "24.2" +version = "22.0" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-22.0-py3-none-any.whl", hash = "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3"}, + {file = "packaging-22.0.tar.gz", hash = "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3"}, ] [[package]] name = "paginate" -version = "0.5.7" +version = "0.5.6" description = "Divides large result sets into pages for easier browsing" optional = false python-versions = "*" files = [ - {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, - {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, + {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, ] -[package.extras] -dev = ["pytest", "tox"] -lint = ["black"] - [[package]] name = "path" -version = "16.16.0" +version = "16.7.1" description = "A module wrapper for os.path" optional = false python-versions = ">=3.8" files = [ - {file = "path-16.16.0-py3-none-any.whl", hash = "sha256:d981989cf87598adc9f5b71ec5192d314a384836e81b4b1f34197138dc4ae659"}, - {file = "path-16.16.0.tar.gz", hash = "sha256:a6a6d916c910dc17e0ddc883358756c5a33d1b6dbdf5d6de86554f399053af58"}, + {file = "path-16.7.1-py3-none-any.whl", hash = "sha256:57f6ac8209c2b8fd3c515cf013e3b288af43460dddacf1d0249839aabcc14517"}, + {file = "path-16.7.1.tar.gz", hash = "sha256:2b477f5887033f3cbea1cfd8553ee6a6a498eb2540a19f4aa082822aadcea30a"}, ] [package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["appdirs", "more-itertools", "packaging", "pygments", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "pywin32"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["appdirs", "packaging", "pygments", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "pywin32"] [[package]] name = "pathspec" -version = "0.12.1" +version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] [[package]] name = "pathvalidate" -version = "3.2.1" +version = "3.0.0" description = "pathvalidate is a Python library to sanitize/validate a string such as filenames/file-paths/etc." optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "pathvalidate-3.2.1-py3-none-any.whl", hash = "sha256:9a6255eb8f63c9e2135b9be97a5ce08f10230128c4ae7b3e935378b82b22c4c9"}, - {file = "pathvalidate-3.2.1.tar.gz", hash = "sha256:f5d07b1e2374187040612a1fcd2bcb2919f8db180df254c9581bb90bf903377d"}, + {file = "pathvalidate-3.0.0-py3-none-any.whl", hash = "sha256:dcdb89f0bde6fd5eba6f2202a7863f657afbc810ef32f60e9258d58ede8155ac"}, + {file = "pathvalidate-3.0.0.tar.gz", hash = "sha256:cfca1886f3cd8862b10bce18a87f4dc02d6418399e539ede2b010dc8588991ce"}, ] [package.extras] -docs = ["Sphinx (>=2.4)", "sphinx-rtd-theme (>=1.2.2)", "urllib3 (<2)"] -readme = ["path (>=13,<17)", "readmemaker (>=1.1.0)"] -test = ["Faker (>=1.0.8)", "allpairspy (>=2)", "click (>=6.2)", "pytest (>=6.0.1)", "pytest-md-report (>=0.6.2)"] +test = ["Faker (>=1.0.8)", "allpairspy (>=2)", "click (>=6.2)", "pytest (>=6.0.1)", "pytest-discord (>=0.1.2)", "pytest-md-report (>=0.3)"] [[package]] name = "platformdirs" -version = "4.3.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +version = "2.6.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, + {file = "platformdirs-2.6.0-py3-none-any.whl", hash = "sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca"}, + {file = "platformdirs-2.6.0.tar.gz", hash = "sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] +docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"] +test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -1113,18 +922,18 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "polyfactory" -version = "2.18.1" +version = "2.13.0" description = "Mock data generation factories" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "polyfactory-2.18.1-py3-none-any.whl", hash = "sha256:1a2b0715e08bfe9f14abc838fc013ab8772cb90e66f2e601e15e1127f0bc1b18"}, - {file = "polyfactory-2.18.1.tar.gz", hash = "sha256:17c9db18afe4fb8d7dd8e5ba296e69da0fcf7d0f3b63d1840eb10d135aed5aad"}, + {file = "polyfactory-2.13.0-py3-none-any.whl", hash = "sha256:03acb0718f4efb2458c62eb8a2c888294c5b5bf2db31e0efc15a57ecc9eb3c2e"}, + {file = "polyfactory-2.13.0.tar.gz", hash = "sha256:d1e6d8952789de61dca2c32f3e3c9362d7681cf405cf9a41267915e0e33f7639"}, ] [package.dependencies] faker = "*" -typing-extensions = ">=4.6.0" +typing-extensions = "*" [package.extras] attrs = ["attrs (>=22.2.0)"] @@ -1137,13 +946,13 @@ sqlalchemy = ["sqlalchemy (>=1.4.29)"] [[package]] name = "pre-commit" -version = "2.21.0" +version = "2.20.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.7" files = [ - {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, - {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, + {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, + {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, ] [package.dependencies] @@ -1151,135 +960,114 @@ cfgv = ">=2.0.0" identify = ">=1.0.0" nodeenv = ">=0.11.1" pyyaml = ">=5.1" -virtualenv = ">=20.10.0" +toml = "*" +virtualenv = ">=20.0.8" [[package]] name = "pydantic" -version = "2.10.3" +version = "2.6.0" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, - {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, + {file = "pydantic-2.6.0-py3-none-any.whl", hash = "sha256:1440966574e1b5b99cf75a13bec7b20e3512e8a61b894ae252f56275e2c465ae"}, + {file = "pydantic-2.6.0.tar.gz", hash = "sha256:ae887bd94eb404b09d86e4d12f93893bdca79d766e738528c6fa1c849f3c6bcf"}, ] [package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.27.1" -typing-extensions = ">=4.12.2" +annotated-types = ">=0.4.0" +pydantic-core = "2.16.1" +typing-extensions = ">=4.6.1" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.27.1" -description = "Core functionality for Pydantic validation and serialization" +version = "2.16.1" +description = "" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, - {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, - {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, - {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, - {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, - {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, - {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, - {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, - {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, - {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, - {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, - {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, - {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, - {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, - {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, - {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, - {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, - {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, - {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, - {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, - {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, - {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, - {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, - {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, - {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, - {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, - {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, - {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, + {file = "pydantic_core-2.16.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:300616102fb71241ff477a2cbbc847321dbec49428434a2f17f37528721c4948"}, + {file = "pydantic_core-2.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5511f962dd1b9b553e9534c3b9c6a4b0c9ded3d8c2be96e61d56f933feef9e1f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98f0edee7ee9cc7f9221af2e1b95bd02810e1c7a6d115cfd82698803d385b28f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9795f56aa6b2296f05ac79d8a424e94056730c0b860a62b0fdcfe6340b658cc8"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c45f62e4107ebd05166717ac58f6feb44471ed450d07fecd90e5f69d9bf03c48"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462d599299c5971f03c676e2b63aa80fec5ebc572d89ce766cd11ca8bcb56f3f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ebaa4bf6386a3b22eec518da7d679c8363fb7fb70cf6972161e5542f470798"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:99f9a50b56713a598d33bc23a9912224fc5d7f9f292444e6664236ae471ddf17"}, + {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8ec364e280db4235389b5e1e6ee924723c693cbc98e9d28dc1767041ff9bc388"}, + {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:653a5dfd00f601a0ed6654a8b877b18d65ac32c9d9997456e0ab240807be6cf7"}, + {file = "pydantic_core-2.16.1-cp310-none-win32.whl", hash = "sha256:1661c668c1bb67b7cec96914329d9ab66755911d093bb9063c4c8914188af6d4"}, + {file = "pydantic_core-2.16.1-cp310-none-win_amd64.whl", hash = "sha256:561be4e3e952c2f9056fba5267b99be4ec2afadc27261505d4992c50b33c513c"}, + {file = "pydantic_core-2.16.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:102569d371fadc40d8f8598a59379c37ec60164315884467052830b28cc4e9da"}, + {file = "pydantic_core-2.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:735dceec50fa907a3c314b84ed609dec54b76a814aa14eb90da31d1d36873a5e"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e83ebbf020be727d6e0991c1b192a5c2e7113eb66e3def0cd0c62f9f266247e4"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:30a8259569fbeec49cfac7fda3ec8123486ef1b729225222f0d41d5f840b476f"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920c4897e55e2881db6a6da151198e5001552c3777cd42b8a4c2f72eedc2ee91"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5247a3d74355f8b1d780d0f3b32a23dd9f6d3ff43ef2037c6dcd249f35ecf4c"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5bea8012df5bb6dda1e67d0563ac50b7f64a5d5858348b5c8cb5043811c19d"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ed3025a8a7e5a59817b7494686d449ebfbe301f3e757b852c8d0d1961d6be864"}, + {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06f0d5a1d9e1b7932477c172cc720b3b23c18762ed7a8efa8398298a59d177c7"}, + {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:150ba5c86f502c040b822777e2e519b5625b47813bd05f9273a8ed169c97d9ae"}, + {file = "pydantic_core-2.16.1-cp311-none-win32.whl", hash = "sha256:d6cbdf12ef967a6aa401cf5cdf47850559e59eedad10e781471c960583f25aa1"}, + {file = "pydantic_core-2.16.1-cp311-none-win_amd64.whl", hash = "sha256:afa01d25769af33a8dac0d905d5c7bb2d73c7c3d5161b2dd6f8b5b5eea6a3c4c"}, + {file = "pydantic_core-2.16.1-cp311-none-win_arm64.whl", hash = "sha256:1a2fe7b00a49b51047334d84aafd7e39f80b7675cad0083678c58983662da89b"}, + {file = "pydantic_core-2.16.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f478ec204772a5c8218e30eb813ca43e34005dff2eafa03931b3d8caef87d51"}, + {file = "pydantic_core-2.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1936ef138bed2165dd8573aa65e3095ef7c2b6247faccd0e15186aabdda7f66"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99d3a433ef5dc3021c9534a58a3686c88363c591974c16c54a01af7efd741f13"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd88f40f2294440d3f3c6308e50d96a0d3d0973d6f1a5732875d10f569acef49"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fac641bbfa43d5a1bed99d28aa1fded1984d31c670a95aac1bf1d36ac6ce137"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72bf9308a82b75039b8c8edd2be2924c352eda5da14a920551a8b65d5ee89253"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb4363e6c9fc87365c2bc777a1f585a22f2f56642501885ffc7942138499bf54"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:20f724a023042588d0f4396bbbcf4cffd0ddd0ad3ed4f0d8e6d4ac4264bae81e"}, + {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fb4370b15111905bf8b5ba2129b926af9470f014cb0493a67d23e9d7a48348e8"}, + {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23632132f1fd608034f1a56cc3e484be00854db845b3a4a508834be5a6435a6f"}, + {file = "pydantic_core-2.16.1-cp312-none-win32.whl", hash = "sha256:b9f3e0bffad6e238f7acc20c393c1ed8fab4371e3b3bc311020dfa6020d99212"}, + {file = "pydantic_core-2.16.1-cp312-none-win_amd64.whl", hash = "sha256:a0b4cfe408cd84c53bab7d83e4209458de676a6ec5e9c623ae914ce1cb79b96f"}, + {file = "pydantic_core-2.16.1-cp312-none-win_arm64.whl", hash = "sha256:d195add190abccefc70ad0f9a0141ad7da53e16183048380e688b466702195dd"}, + {file = "pydantic_core-2.16.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:502c062a18d84452858f8aea1e520e12a4d5228fc3621ea5061409d666ea1706"}, + {file = "pydantic_core-2.16.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8c032ccee90b37b44e05948b449a2d6baed7e614df3d3f47fe432c952c21b60"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920f4633bee43d7a2818e1a1a788906df5a17b7ab6fe411220ed92b42940f818"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f5d37ff01edcbace53a402e80793640c25798fb7208f105d87a25e6fcc9ea06"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:399166f24c33a0c5759ecc4801f040dbc87d412c1a6d6292b2349b4c505effc9"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac89ccc39cd1d556cc72d6752f252dc869dde41c7c936e86beac5eb555041b66"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73802194f10c394c2bedce7a135ba1d8ba6cff23adf4217612bfc5cf060de34c"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8fa00fa24ffd8c31fac081bf7be7eb495be6d248db127f8776575a746fa55c95"}, + {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:601d3e42452cd4f2891c13fa8c70366d71851c1593ed42f57bf37f40f7dca3c8"}, + {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07982b82d121ed3fc1c51faf6e8f57ff09b1325d2efccaa257dd8c0dd937acca"}, + {file = "pydantic_core-2.16.1-cp38-none-win32.whl", hash = "sha256:d0bf6f93a55d3fa7a079d811b29100b019784e2ee6bc06b0bb839538272a5610"}, + {file = "pydantic_core-2.16.1-cp38-none-win_amd64.whl", hash = "sha256:fbec2af0ebafa57eb82c18c304b37c86a8abddf7022955d1742b3d5471a6339e"}, + {file = "pydantic_core-2.16.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a497be217818c318d93f07e14502ef93d44e6a20c72b04c530611e45e54c2196"}, + {file = "pydantic_core-2.16.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:694a5e9f1f2c124a17ff2d0be613fd53ba0c26de588eb4bdab8bca855e550d95"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d4dfc66abea3ec6d9f83e837a8f8a7d9d3a76d25c9911735c76d6745950e62c"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8655f55fe68c4685673265a650ef71beb2d31871c049c8b80262026f23605ee3"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21e3298486c4ea4e4d5cc6fb69e06fb02a4e22089304308817035ac006a7f506"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71b4a48a7427f14679f0015b13c712863d28bb1ab700bd11776a5368135c7d60"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dca874e35bb60ce4f9f6665bfbfad050dd7573596608aeb9e098621ac331dc"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa496cd45cda0165d597e9d6f01e36c33c9508f75cf03c0a650018c5048f578e"}, + {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5317c04349472e683803da262c781c42c5628a9be73f4750ac7d13040efb5d2d"}, + {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c29d54ed4501a30cd71015bf982fa95e4a60117b44e1a200290ce687d3e640"}, + {file = "pydantic_core-2.16.1-cp39-none-win32.whl", hash = "sha256:ba07646f35e4e49376c9831130039d1b478fbfa1215ae62ad62d2ee63cf9c18f"}, + {file = "pydantic_core-2.16.1-cp39-none-win_amd64.whl", hash = "sha256:2133b0e412a47868a358713287ff9f9a328879da547dc88be67481cdac529118"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d25ef0c33f22649b7a088035fd65ac1ce6464fa2876578df1adad9472f918a76"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99c095457eea8550c9fa9a7a992e842aeae1429dab6b6b378710f62bfb70b394"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b49c604ace7a7aa8af31196abbf8f2193be605db6739ed905ecaf62af31ccae0"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56da23034fe66221f2208c813d8aa509eea34d97328ce2add56e219c3a9f41c"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cebf8d56fee3b08ad40d332a807ecccd4153d3f1ba8231e111d9759f02edfd05"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1ae8048cba95f382dba56766525abca438328455e35c283bb202964f41a780b0"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:780daad9e35b18d10d7219d24bfb30148ca2afc309928e1d4d53de86822593dc"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c94b5537bf6ce66e4d7830c6993152940a188600f6ae044435287753044a8fe2"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:adf28099d061a25fbcc6531febb7a091e027605385de9fe14dd6a97319d614cf"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:644904600c15816a1f9a1bafa6aab0d21db2788abcdf4e2a77951280473f33e1"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bce04f09f0552b66fca0c4e10da78d17cb0e71c205864bab4e9595122cb9d9"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877045a7969ace04d59516d5d6a7dee13106822f99a5d8df5e6822941f7bedc8"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9c46e556ee266ed3fb7b7a882b53df3c76b45e872fdab8d9cf49ae5e91147fd7"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4eebbd049008eb800f519578e944b8dc8e0f7d59a5abb5924cc2d4ed3a1834ff"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c0be58529d43d38ae849a91932391eb93275a06b93b79a8ab828b012e916a206"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b1fc07896fc1851558f532dffc8987e526b682ec73140886c831d773cef44b76"}, + {file = "pydantic_core-2.16.1.tar.gz", hash = "sha256:daff04257b49ab7f4b3f73f98283d3dbb1a65bf3500d55c7beac3c66c310fe34"}, ] [package.dependencies] @@ -1287,37 +1075,32 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.7.0" +version = "2.0.3" description = "Settings management using Pydantic" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pydantic_settings-2.7.0-py3-none-any.whl", hash = "sha256:e00c05d5fa6cbbb227c84bd7487c5c1065084119b750df7c8c1a554aed236eb5"}, - {file = "pydantic_settings-2.7.0.tar.gz", hash = "sha256:ac4bfd4a36831a48dbf8b2d9325425b549a0a6f18cea118436d728eb4f1c4d66"}, + {file = "pydantic_settings-2.0.3-py3-none-any.whl", hash = "sha256:ddd907b066622bd67603b75e2ff791875540dc485b7307c4fffc015719da8625"}, + {file = "pydantic_settings-2.0.3.tar.gz", hash = "sha256:962dc3672495aad6ae96a4390fac7e593591e144625e5112d359f8f67fb75945"}, ] [package.dependencies] -pydantic = ">=2.7.0" +pydantic = ">=2.0.1" python-dotenv = ">=0.21.0" -[package.extras] -azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] -toml = ["tomli (>=2.0.1)"] -yaml = ["pyyaml (>=6.0.1)"] - [[package]] name = "pygments" -version = "2.18.0" +version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, ] [package.extras] -windows-terminal = ["colorama (>=0.4.6)"] +plugins = ["importlib-metadata"] [[package]] name = "pyhumps" @@ -1332,17 +1115,17 @@ files = [ [[package]] name = "pymdown-extensions" -version = "10.12" +version = "10.3.1" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, - {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, + {file = "pymdown_extensions-10.3.1-py3-none-any.whl", hash = "sha256:8cba67beb2a1318cdaf742d09dff7c0fc4cafcc290147ade0f8fb7b71522711a"}, + {file = "pymdown_extensions-10.3.1.tar.gz", hash = "sha256:f6c79941498a458852853872e379e7bab63888361ba20992fc8b4f8a9b61735e"}, ] [package.dependencies] -markdown = ">=3.6" +markdown = ">=3.2" pyyaml = "*" [package.extras] @@ -1350,23 +1133,52 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pyright" -version = "1.1.391" +version = "1.1.352" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.391-py3-none-any.whl", hash = "sha256:54fa186f8b3e8a55a44ebfa842636635688670c6896dcf6cf4a7fc75062f4d15"}, - {file = "pyright-1.1.391.tar.gz", hash = "sha256:66b2d42cdf5c3cbab05f2f4b76e8bec8aa78e679bfa0b6ad7b923d9e027cadb2"}, + {file = "pyright-1.1.352-py3-none-any.whl", hash = "sha256:0040cf173c6a60704e553bfd129dfe54de59cc76d0b2b80f77cfab4f50701d64"}, + {file = "pyright-1.1.352.tar.gz", hash = "sha256:a621c0dfbcf1291b3610641a07380fefaa1d0e182890a1b2a7f13b446e8109a9"}, ] [package.dependencies] nodeenv = ">=1.6.0" -typing-extensions = ">=4.1" [package.extras] -all = ["nodejs-wheel-binaries", "twine (>=3.4.1)"] +all = ["twine (>=3.4.1)"] dev = ["twine (>=3.4.1)"] -nodejs = ["nodejs-wheel-binaries"] + +[[package]] +name = "pyrsistent" +version = "0.19.2" +description = "Persistent/Functional/Immutable data structures" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyrsistent-0.19.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d6982b5a0237e1b7d876b60265564648a69b14017f3b5f908c5be2de3f9abb7a"}, + {file = "pyrsistent-0.19.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:187d5730b0507d9285a96fca9716310d572e5464cadd19f22b63a6976254d77a"}, + {file = "pyrsistent-0.19.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:055ab45d5911d7cae397dc418808d8802fb95262751872c841c170b0dbf51eed"}, + {file = "pyrsistent-0.19.2-cp310-cp310-win32.whl", hash = "sha256:456cb30ca8bff00596519f2c53e42c245c09e1a4543945703acd4312949bfd41"}, + {file = "pyrsistent-0.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:b39725209e06759217d1ac5fcdb510e98670af9e37223985f330b611f62e7425"}, + {file = "pyrsistent-0.19.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aede922a488861de0ad00c7630a6e2d57e8023e4be72d9d7147a9fcd2d30712"}, + {file = "pyrsistent-0.19.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879b4c2f4d41585c42df4d7654ddffff1239dc4065bc88b745f0341828b83e78"}, + {file = "pyrsistent-0.19.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43bec251bbd10e3cb58ced80609c5c1eb238da9ca78b964aea410fb820d00d6"}, + {file = "pyrsistent-0.19.2-cp37-cp37m-win32.whl", hash = "sha256:d690b18ac4b3e3cab73b0b7aa7dbe65978a172ff94970ff98d82f2031f8971c2"}, + {file = "pyrsistent-0.19.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3ba4134a3ff0fc7ad225b6b457d1309f4698108fb6b35532d015dca8f5abed73"}, + {file = "pyrsistent-0.19.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a178209e2df710e3f142cbd05313ba0c5ebed0a55d78d9945ac7a4e09d923308"}, + {file = "pyrsistent-0.19.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e371b844cec09d8dc424d940e54bba8f67a03ebea20ff7b7b0d56f526c71d584"}, + {file = "pyrsistent-0.19.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111156137b2e71f3a9936baf27cb322e8024dac3dc54ec7fb9f0bcf3249e68bb"}, + {file = "pyrsistent-0.19.2-cp38-cp38-win32.whl", hash = "sha256:e5d8f84d81e3729c3b506657dddfe46e8ba9c330bf1858ee33108f8bb2adb38a"}, + {file = "pyrsistent-0.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:9cd3e9978d12b5d99cbdc727a3022da0430ad007dacf33d0bf554b96427f33ab"}, + {file = "pyrsistent-0.19.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f1258f4e6c42ad0b20f9cfcc3ada5bd6b83374516cd01c0960e3cb75fdca6770"}, + {file = "pyrsistent-0.19.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21455e2b16000440e896ab99e8304617151981ed40c29e9507ef1c2e4314ee95"}, + {file = "pyrsistent-0.19.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd880614c6237243ff53a0539f1cb26987a6dc8ac6e66e0c5a40617296a045e"}, + {file = "pyrsistent-0.19.2-cp39-cp39-win32.whl", hash = "sha256:71d332b0320642b3261e9fee47ab9e65872c2bd90260e5d225dabeed93cbd42b"}, + {file = "pyrsistent-0.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:dec3eac7549869365fe263831f576c8457f6c833937c68542d08fde73457d291"}, + {file = "pyrsistent-0.19.2-py3-none-any.whl", hash = "sha256:ea6b79a02a28550c98b6ca9c35b9f492beaa54d7c5c9e9949555893c8a9234d0"}, + {file = "pyrsistent-0.19.2.tar.gz", hash = "sha256:bfa0351be89c9fcbcb8c9879b826f4353be10f58f8a677efab0c017bf7137ec2"}, +] [[package]] name = "pytablereader" @@ -1403,28 +1215,28 @@ url = ["retryrequests (>=0.1,<1)"] [[package]] name = "pytablewriter" -version = "1.2.0" +version = "1.0.0" description = "pytablewriter is a Python library to write a table in various formats: AsciiDoc / CSV / Elasticsearch / HTML / JavaScript / JSON / LaTeX / LDJSON / LTSV / Markdown / MediaWiki / NumPy / Excel / Pandas / Python / reStructuredText / SQLite / TOML / TSV / YAML." optional = false python-versions = ">=3.7" files = [ - {file = "pytablewriter-1.2.0-py3-none-any.whl", hash = "sha256:4a30e2bb4bf5bc1069b1d2b2bc41947577c4517ab0875b23a5b194d296f543d8"}, - {file = "pytablewriter-1.2.0.tar.gz", hash = "sha256:0204a4bb684a22140d640f2599f09e137bcdc18b3dd49426f4a555016e246b46"}, + {file = "pytablewriter-1.0.0-py3-none-any.whl", hash = "sha256:d789a363a71de312e7c6f18ba57f15e14b1b73b910ab636ba7b943779b5024a5"}, + {file = "pytablewriter-1.0.0.tar.gz", hash = "sha256:3c81496ad5c119741f8adc59218574a3be12ba5d3fb190a595cd301d1625d404"}, ] [package.dependencies] -DataProperty = ">=1.0.1,<2" +DataProperty = ">=0.55.0,<2" mbstrdecoder = ">=1.0.0,<2" pathvalidate = ">=2.3.0,<4" pytablereader = {version = ">=0.31.3,<2", optional = true, markers = "extra == \"from\""} setuptools = ">=38.3.0" tabledata = ">=1.3.1,<2" tcolorpy = ">=0.0.5,<1" -typepy = {version = ">=1.3.2,<2", extras = ["datetime"]} +typepy = {version = ">=1.2.0,<2", extras = ["datetime"]} [package.extras] -all = ["PyYAML (>=3.11,<7)", "SimpleSQLite (>=1.3.2,<2)", "XlsxWriter (>=0.9.6,<4)", "dominate (>=2.1.5,<3)", "elasticsearch (>=8.0.1,<9)", "loguru (>=0.4.1,<1)", "pandas (>=0.25.3,<3)", "pytablereader (>=0.31.3,<2)", "pytablewriter-altcol-theme (>=0.1.0,<1)", "pytablewriter-altrow-theme (>=0.2.0,<1)", "simplejson (>=3.8.1,<4)", "toml (>=0.9.3,<1)", "xlwt"] -docs = ["PyYAML (>=3.11,<7)", "SimpleSQLite (>=1.3.2,<2)", "Sphinx (>=2.4)", "XlsxWriter (>=0.9.6,<4)", "dominate (>=2.1.5,<3)", "elasticsearch (>=8.0.1,<9)", "loguru (>=0.4.1,<1)", "pandas (>=0.25.3,<3)", "pytablereader (>=0.31.3,<2)", "pytablewriter-altcol-theme (>=0.1.0,<1)", "pytablewriter-altrow-theme (>=0.2.0,<1)", "simplejson (>=3.8.1,<4)", "sphinx-rtd-theme (>=1.2.2)", "toml (>=0.9.3,<1)", "xlwt"] +all = ["PyYAML (>=3.11,<7)", "SimpleSQLite (>=1.3.2,<2)", "XlsxWriter (>=0.9.6,<4)", "dominate (>=2.1.5,<3)", "elasticsearch (>=8.0.1,<9)", "loguru (>=0.4.1,<1)", "pandas (>=0.25.3,<3)", "pytablereader (>=0.31.3,<2)", "pytablewriter-altrow-theme (>=0.0.2,<1)", "simplejson (>=3.8.1,<4)", "toml (>=0.9.3,<1)", "xlwt"] +docs = ["PyYAML (>=3.11,<7)", "SimpleSQLite (>=1.3.2,<2)", "Sphinx (>=2.4)", "XlsxWriter (>=0.9.6,<4)", "dominate (>=2.1.5,<3)", "elasticsearch (>=8.0.1,<9)", "loguru (>=0.4.1,<1)", "pandas (>=0.25.3,<3)", "pytablereader (>=0.31.3,<2)", "pytablewriter-altrow-theme (>=0.0.2,<1)", "simplejson (>=3.8.1,<4)", "sphinx-rtd-theme (>=1.2.2)", "toml (>=0.9.3,<1)", "xlwt"] es = ["elasticsearch (>=8.0.1,<9)"] es8 = ["elasticsearch (>=8.0.1,<9)"] excel = ["XlsxWriter (>=0.9.6,<4)", "xlwt"] @@ -1433,20 +1245,20 @@ html = ["dominate (>=2.1.5,<3)"] logging = ["loguru (>=0.4.1,<1)"] pandas = ["pandas (>=0.25.3,<3)"] sqlite = ["SimpleSQLite (>=1.3.2,<2)"] -test = ["PyYAML (>=3.11,<7)", "SimpleSQLite (>=1.3.2,<2)", "XlsxWriter (>=0.9.6,<4)", "beautifulsoup4 (>=4.10)", "dominate (>=2.1.5,<3)", "elasticsearch (>=8.0.1,<9)", "loguru (>=0.4.1,<1)", "pandas (>=0.25.3,<3)", "pytablereader (>=0.31.3,<2)", "pytablereader[excel,sqlite] (>=0.31.3)", "pytablewriter-altcol-theme (>=0.1.0,<1)", "pytablewriter-altrow-theme (>=0.2.0,<1)", "pytest (>=6.0.1)", "pytest-md-report (>=0.4.1)", "simplejson (>=3.8.1,<4)", "sqliteschema (>=1.3.0)", "tablib (>=3.2.0)", "toml (>=0.9.3,<1)", "xlwt"] -theme = ["pytablewriter-altcol-theme (>=0.1.0,<1)", "pytablewriter-altrow-theme (>=0.2.0,<1)"] +test = ["PyYAML (>=3.11,<7)", "SimpleSQLite (>=1.3.2,<2)", "XlsxWriter (>=0.9.6,<4)", "beautifulsoup4 (>=4.10)", "dominate (>=2.1.5,<3)", "elasticsearch (>=8.0.1,<9)", "idna (<3)", "loguru (>=0.4.1,<1)", "pandas (>=0.25.3,<3)", "pytablereader (>=0.31.3,<2)", "pytablereader[excel,sqlite] (>=0.31.3)", "pytablewriter-altrow-theme (>=0.0.2,<1)", "pytest (>=6.0.1)", "pytest-md-report (>=0.1)", "simplejson (>=3.8.1,<4)", "sqliteschema (>=1.3.0)", "tablib (>=3.2.0)", "toml (>=0.9.3,<1)", "xlwt"] +theme = ["pytablewriter-altrow-theme (>=0.0.2,<1)"] toml = ["toml (>=0.9.3,<1)"] yaml = ["PyYAML (>=3.11,<7)"] [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, - {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, + {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, + {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, ] [package.dependencies] @@ -1556,13 +1368,13 @@ pytest = ">=7.0.0" [[package]] name = "python-dateutil" -version = "2.9.0.post0" +version = "2.8.2" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] [package.dependencies] @@ -1570,13 +1382,13 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "1.0.1" +version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, ] [package.extras] @@ -1584,95 +1396,94 @@ cli = ["click (>=5.0)"] [[package]] name = "python-schema-registry-client" -version = "2.6.0" -description = "Python Rest Client to interact against Schema Registry confluent server" +version = "2.4.3" +description = "Python Rest Client to interact against Schema Registry Confluent Server to manage Avro Schemas" optional = false -python-versions = "<4.0,>=3.8" +python-versions = "*" files = [ - {file = "python_schema_registry_client-2.6.0-py3-none-any.whl", hash = "sha256:a0688a9cd6e2a616a79fb46a6615c531cd5f9e2a5145f5c95932f792417731cb"}, - {file = "python_schema_registry_client-2.6.0.tar.gz", hash = "sha256:e5495899c2bf4fd33bc6689a2068a3423dc94875677f3fd343b6e492a7877ba0"}, + {file = "python-schema-registry-client-2.4.3.tar.gz", hash = "sha256:1552f0929b1f76365dce0334651728600e7c7e4bc4351fea2e4c3f08382b57dd"}, ] [package.dependencies] -aiofiles = ">=23.1.0,<24.0.0" -fastavro = ">=1.7.3,<2.0.0" -httpx = ">=0.26,<0.28" -jsonschema = ">=4.17.3,<5.0.0" +aiofiles = ">=0.7.0" +fastavro = ">=1.4.4" +httpx = ">=0.19.0" +jsonschema = ">=3.2.0" [package.extras] -faust = ["faust-streaming (>=0.10.11,<0.12.0)"] +docs = ["mkautodoc", "mkdocs", "mkdocs-material"] +faust = ["faust-streaming"] +tests = ["autoflake", "black", "codecov", "dataclasses-avroschema", "faker", "flake8", "isort", "mypy (==0.782)", "pydantic", "pytest", "pytest-asyncio (<0.19.0)", "pytest-cov", "pytest-mock"] [[package]] name = "pytz" -version = "2024.2" +version = "2023.3" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, - {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, ] [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.1" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] [[package]] @@ -1689,140 +1500,119 @@ files = [ [package.dependencies] pyyaml = "*" -[[package]] -name = "referencing" -version = "0.35.1" -description = "JSON Referencing + Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, - {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -rpds-py = ">=0.7.0" - [[package]] name = "regex" -version = "2024.11.6" +version = "2022.10.31" description = "Alternative regular expression module, to replace re." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, - {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, - {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, - {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, - {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, - {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, - {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, - {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, - {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, - {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, - {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, - {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, - {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, - {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, - {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, - {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, - {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, - {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, - {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, - {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, - {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, - {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, - {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, - {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, - {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, - {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, - {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, - {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, - {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, - {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, - {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, + {file = "regex-2022.10.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8ff454ef0bb061e37df03557afda9d785c905dab15584860f982e88be73015f"}, + {file = "regex-2022.10.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1eba476b1b242620c266edf6325b443a2e22b633217a9835a52d8da2b5c051f9"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0e5af9a9effb88535a472e19169e09ce750c3d442fb222254a276d77808620b"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d03fe67b2325cb3f09be029fd5da8df9e6974f0cde2c2ac6a79d2634e791dd57"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9d0b68ac1743964755ae2d89772c7e6fb0118acd4d0b7464eaf3921c6b49dd4"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a45b6514861916c429e6059a55cf7db74670eaed2052a648e3e4d04f070e001"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b0886885f7323beea6f552c28bff62cbe0983b9fbb94126531693ea6c5ebb90"}, + {file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5aefb84a301327ad115e9d346c8e2760009131d9d4b4c6b213648d02e2abe144"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:702d8fc6f25bbf412ee706bd73019da5e44a8400861dfff7ff31eb5b4a1276dc"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a3c1ebd4ed8e76e886507c9eddb1a891673686c813adf889b864a17fafcf6d66"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:50921c140561d3db2ab9f5b11c5184846cde686bb5a9dc64cae442926e86f3af"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7db345956ecce0c99b97b042b4ca7326feeec6b75facd8390af73b18e2650ffc"}, + {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:763b64853b0a8f4f9cfb41a76a4a85a9bcda7fdda5cb057016e7706fde928e66"}, + {file = "regex-2022.10.31-cp310-cp310-win32.whl", hash = "sha256:44136355e2f5e06bf6b23d337a75386371ba742ffa771440b85bed367c1318d1"}, + {file = "regex-2022.10.31-cp310-cp310-win_amd64.whl", hash = "sha256:bfff48c7bd23c6e2aec6454aaf6edc44444b229e94743b34bdcdda2e35126cf5"}, + {file = "regex-2022.10.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b4b1fe58cd102d75ef0552cf17242705ce0759f9695334a56644ad2d83903fe"}, + {file = "regex-2022.10.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:542e3e306d1669b25936b64917285cdffcd4f5c6f0247636fec037187bd93542"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c27cc1e4b197092e50ddbf0118c788d9977f3f8f35bfbbd3e76c1846a3443df7"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8e38472739028e5f2c3a4aded0ab7eadc447f0d84f310c7a8bb697ec417229e"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76c598ca73ec73a2f568e2a72ba46c3b6c8690ad9a07092b18e48ceb936e9f0c"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c28d3309ebd6d6b2cf82969b5179bed5fefe6142c70f354ece94324fa11bf6a1"}, + {file = "regex-2022.10.31-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9af69f6746120998cd9c355e9c3c6aec7dff70d47247188feb4f829502be8ab4"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a5f9505efd574d1e5b4a76ac9dd92a12acb2b309551e9aa874c13c11caefbe4f"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5ff525698de226c0ca743bfa71fc6b378cda2ddcf0d22d7c37b1cc925c9650a5"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe7fda2fe7c8890d454f2cbc91d6c01baf206fbc96d89a80241a02985118c0c"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2cdc55ca07b4e70dda898d2ab7150ecf17c990076d3acd7a5f3b25cb23a69f1c"}, + {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:44a6c2f6374e0033873e9ed577a54a3602b4f609867794c1a3ebba65e4c93ee7"}, + {file = "regex-2022.10.31-cp311-cp311-win32.whl", hash = "sha256:d8716f82502997b3d0895d1c64c3b834181b1eaca28f3f6336a71777e437c2af"}, + {file = "regex-2022.10.31-cp311-cp311-win_amd64.whl", hash = "sha256:61edbca89aa3f5ef7ecac8c23d975fe7261c12665f1d90a6b1af527bba86ce61"}, + {file = "regex-2022.10.31-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a069c8483466806ab94ea9068c34b200b8bfc66b6762f45a831c4baaa9e8cdd"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d26166acf62f731f50bdd885b04b38828436d74e8e362bfcb8df221d868b5d9b"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac741bf78b9bb432e2d314439275235f41656e189856b11fb4e774d9f7246d81"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75f591b2055523fc02a4bbe598aa867df9e953255f0b7f7715d2a36a9c30065c"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bddd61d2a3261f025ad0f9ee2586988c6a00c780a2fb0a92cea2aa702c54"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef4163770525257876f10e8ece1cf25b71468316f61451ded1a6f44273eedeb5"}, + {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7b280948d00bd3973c1998f92e22aa3ecb76682e3a4255f33e1020bd32adf443"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d0213671691e341f6849bf33cd9fad21f7b1cb88b89e024f33370733fec58742"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:22e7ebc231d28393dfdc19b185d97e14a0f178bedd78e85aad660e93b646604e"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8ad241da7fac963d7573cc67a064c57c58766b62a9a20c452ca1f21050868dfa"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:586b36ebda81e6c1a9c5a5d0bfdc236399ba6595e1397842fd4a45648c30f35e"}, + {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0653d012b3bf45f194e5e6a41df9258811ac8fc395579fa82958a8b76286bea4"}, + {file = "regex-2022.10.31-cp36-cp36m-win32.whl", hash = "sha256:144486e029793a733e43b2e37df16a16df4ceb62102636ff3db6033994711066"}, + {file = "regex-2022.10.31-cp36-cp36m-win_amd64.whl", hash = "sha256:c14b63c9d7bab795d17392c7c1f9aaabbffd4cf4387725a0ac69109fb3b550c6"}, + {file = "regex-2022.10.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4cac3405d8dda8bc6ed499557625585544dd5cbf32072dcc72b5a176cb1271c8"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23cbb932cc53a86ebde0fb72e7e645f9a5eec1a5af7aa9ce333e46286caef783"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74bcab50a13960f2a610cdcd066e25f1fd59e23b69637c92ad470784a51b1347"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d680ef3e4d405f36f0d6d1ea54e740366f061645930072d39bca16a10d8c93"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6910b56b700bea7be82c54ddf2e0ed792a577dfaa4a76b9af07d550af435c6"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:659175b2144d199560d99a8d13b2228b85e6019b6e09e556209dfb8c37b78a11"}, + {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1ddf14031a3882f684b8642cb74eea3af93a2be68893901b2b387c5fd92a03ec"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b683e5fd7f74fb66e89a1ed16076dbab3f8e9f34c18b1979ded614fe10cdc4d9"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2bde29cc44fa81c0a0c8686992c3080b37c488df167a371500b2a43ce9f026d1"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4919899577ba37f505aaebdf6e7dc812d55e8f097331312db7f1aab18767cce8"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:9c94f7cc91ab16b36ba5ce476f1904c91d6c92441f01cd61a8e2729442d6fcf5"}, + {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae1e96785696b543394a4e3f15f3f225d44f3c55dafe3f206493031419fedf95"}, + {file = "regex-2022.10.31-cp37-cp37m-win32.whl", hash = "sha256:c670f4773f2f6f1957ff8a3962c7dd12e4be54d05839b216cb7fd70b5a1df394"}, + {file = "regex-2022.10.31-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0caeff18b96ea90fc0eb6e3bdb2b10ab5b01a95128dfeccb64a7238decf5f0"}, + {file = "regex-2022.10.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:131d4be09bea7ce2577f9623e415cab287a3c8e0624f778c1d955ec7c281bd4d"}, + {file = "regex-2022.10.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e613a98ead2005c4ce037c7b061f2409a1a4e45099edb0ef3200ee26ed2a69a8"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052b670fafbe30966bbe5d025e90b2a491f85dfe5b2583a163b5e60a85a321ad"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa62a07ac93b7cb6b7d0389d8ef57ffc321d78f60c037b19dfa78d6b17c928ee"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5352bea8a8f84b89d45ccc503f390a6be77917932b1c98c4cdc3565137acc714"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20f61c9944f0be2dc2b75689ba409938c14876c19d02f7585af4460b6a21403e"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29c04741b9ae13d1e94cf93fca257730b97ce6ea64cfe1eba11cf9ac4e85afb6"}, + {file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:543883e3496c8b6d58bd036c99486c3c8387c2fc01f7a342b760c1ea3158a318"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7a8b43ee64ca8f4befa2bea4083f7c52c92864d8518244bfa6e88c751fa8fff"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6a9a19bea8495bb419dc5d38c4519567781cd8d571c72efc6aa959473d10221a"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6ffd55b5aedc6f25fd8d9f905c9376ca44fcf768673ffb9d160dd6f409bfda73"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4bdd56ee719a8f751cf5a593476a441c4e56c9b64dc1f0f30902858c4ef8771d"}, + {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ca88da1bd78990b536c4a7765f719803eb4f8f9971cc22d6ca965c10a7f2c4c"}, + {file = "regex-2022.10.31-cp38-cp38-win32.whl", hash = "sha256:5a260758454580f11dd8743fa98319bb046037dfab4f7828008909d0aa5292bc"}, + {file = "regex-2022.10.31-cp38-cp38-win_amd64.whl", hash = "sha256:5e6a5567078b3eaed93558842346c9d678e116ab0135e22eb72db8325e90b453"}, + {file = "regex-2022.10.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5217c25229b6a85049416a5c1e6451e9060a1edcf988641e309dbe3ab26d3e49"}, + {file = "regex-2022.10.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bf41b8b0a80708f7e0384519795e80dcb44d7199a35d52c15cc674d10b3081b"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf0da36a212978be2c2e2e2d04bdff46f850108fccc1851332bcae51c8907cc"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d403d781b0e06d2922435ce3b8d2376579f0c217ae491e273bab8d092727d244"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a37d51fa9a00d265cf73f3de3930fa9c41548177ba4f0faf76e61d512c774690"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4f781ffedd17b0b834c8731b75cce2639d5a8afe961c1e58ee7f1f20b3af185"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d243b36fbf3d73c25e48014961e83c19c9cc92530516ce3c43050ea6276a2ab7"}, + {file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:370f6e97d02bf2dd20d7468ce4f38e173a124e769762d00beadec3bc2f4b3bc4"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:597f899f4ed42a38df7b0e46714880fb4e19a25c2f66e5c908805466721760f5"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7dbdce0c534bbf52274b94768b3498abdf675a691fec5f751b6057b3030f34c1"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:22960019a842777a9fa5134c2364efaed5fbf9610ddc5c904bd3a400973b0eb8"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7f5a3ffc731494f1a57bd91c47dc483a1e10048131ffb52d901bfe2beb6102e8"}, + {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7ef6b5942e6bfc5706301a18a62300c60db9af7f6368042227ccb7eeb22d0892"}, + {file = "regex-2022.10.31-cp39-cp39-win32.whl", hash = "sha256:395161bbdbd04a8333b9ff9763a05e9ceb4fe210e3c7690f5e68cedd3d65d8e1"}, + {file = "regex-2022.10.31-cp39-cp39-win_amd64.whl", hash = "sha256:957403a978e10fb3ca42572a23e6f7badff39aa1ce2f4ade68ee452dc6807692"}, + {file = "regex-2022.10.31.tar.gz", hash = "sha256:a3a98921da9a1bf8457aeee6a551948a83601689e5ecdd736894ea9bbec77e83"}, ] [[package]] name = "requests" -version = "2.32.3" +version = "2.28.1" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7, <4" files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +charset-normalizer = ">=2,<3" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" +urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -1846,239 +1636,106 @@ pygments = ">=2.6.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] -[[package]] -name = "rpds-py" -version = "0.22.3" -description = "Python bindings to Rust's persistent data structures (rpds)" -optional = false -python-versions = ">=3.9" -files = [ - {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, - {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, - {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, - {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, - {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, - {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, - {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, - {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, - {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, - {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, - {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, - {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, - {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, -] - [[package]] name = "ruff" -version = "0.5.7" +version = "0.5.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a"}, - {file = "ruff-0.5.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be"}, - {file = "ruff-0.5.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb"}, - {file = "ruff-0.5.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e"}, - {file = "ruff-0.5.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499"}, - {file = "ruff-0.5.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e"}, - {file = "ruff-0.5.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5"}, - {file = "ruff-0.5.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e"}, - {file = "ruff-0.5.7-py3-none-win32.whl", hash = "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a"}, - {file = "ruff-0.5.7-py3-none-win_amd64.whl", hash = "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3"}, - {file = "ruff-0.5.7-py3-none-win_arm64.whl", hash = "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4"}, - {file = "ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5"}, + {file = "ruff-0.5.5-py3-none-linux_armv6l.whl", hash = "sha256:605d589ec35d1da9213a9d4d7e7a9c761d90bba78fc8790d1c5e65026c1b9eaf"}, + {file = "ruff-0.5.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00817603822a3e42b80f7c3298c8269e09f889ee94640cd1fc7f9329788d7bf8"}, + {file = "ruff-0.5.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:187a60f555e9f865a2ff2c6984b9afeffa7158ba6e1eab56cb830404c942b0f3"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe26fc46fa8c6e0ae3f47ddccfbb136253c831c3289bba044befe68f467bfb16"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad25dd9c5faac95c8e9efb13e15803cd8bbf7f4600645a60ffe17c73f60779b"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f70737c157d7edf749bcb952d13854e8f745cec695a01bdc6e29c29c288fc36e"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfd7de17cef6ab559e9f5ab859f0d3296393bc78f69030967ca4d87a541b97a0"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09b43e02f76ac0145f86a08e045e2ea452066f7ba064fd6b0cdccb486f7c3e7"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0b856cb19c60cd40198be5d8d4b556228e3dcd545b4f423d1ad812bfdca5884"}, + {file = "ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091"}, + {file = "ruff-0.5.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ac9dc814e510436e30d0ba535f435a7f3dc97f895f844f5b3f347ec8c228a523"}, + {file = "ruff-0.5.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:af9bdf6c389b5add40d89b201425b531e0a5cceb3cfdcc69f04d3d531c6be74f"}, + {file = "ruff-0.5.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d40a8533ed545390ef8315b8e25c4bb85739b90bd0f3fe1280a29ae364cc55d8"}, + {file = "ruff-0.5.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cab904683bf9e2ecbbe9ff235bfe056f0eba754d0168ad5407832928d579e7ab"}, + {file = "ruff-0.5.5-py3-none-win32.whl", hash = "sha256:696f18463b47a94575db635ebb4c178188645636f05e934fdf361b74edf1bb2d"}, + {file = "ruff-0.5.5-py3-none-win_amd64.whl", hash = "sha256:50f36d77f52d4c9c2f1361ccbfbd09099a1b2ea5d2b2222c586ab08885cf3445"}, + {file = "ruff-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3191317d967af701f1b73a31ed5788795936e423b7acce82a2b63e26eb3e89d6"}, + {file = "ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a"}, ] [[package]] name = "setuptools" -version = "75.6.0" +version = "65.6.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, - {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, + {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, + {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] -core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shellingham" -version = "1.5.4" +version = "1.4.0" description = "Tool to Detect Surrounding Shell" optional = false -python-versions = ">=3.7" +python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6" files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, + {file = "shellingham-1.4.0-py2.py3-none-any.whl", hash = "sha256:536b67a0697f2e4af32ab176c00a50ac2899c5a05e0d8e2dadac8e58888283f9"}, + {file = "shellingham-1.4.0.tar.gz", hash = "sha256:4855c2458d6904829bd34c299f11fdeed7cfefbf8a2c522e4caea6cd76b3171e"}, ] [[package]] name = "six" -version = "1.17.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] [[package]] name = "sniffio" -version = "1.3.1" +version = "1.3.0" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] [[package]] name = "soupsieve" -version = "2.6" +version = "2.3.2.post1" description = "A modern CSS selector implementation for Beautiful Soup." optional = false -python-versions = ">=3.8" -files = [ - {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, - {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, -] - -[[package]] -name = "super-collections" -version = "0.5.3" -description = "file: README.md" -optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "super_collections-0.5.3-py3-none-any.whl", hash = "sha256:907d35b25dc4070910e8254bf2f5c928348af1cf8a1f1e8259e06c666e902cff"}, - {file = "super_collections-0.5.3.tar.gz", hash = "sha256:94c1ec96c0a0d5e8e7d389ed8cde6882ac246940507c5e6b86e91945c2968d46"}, + {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"}, + {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, ] -[package.dependencies] -hjson = "*" - -[package.extras] -test = ["pytest (>=7.0)"] - [[package]] name = "tabledata" -version = "1.3.3" +version = "1.3.1" description = "tabledata is a Python library to represent tabular data. Used for pytablewriter/pytablereader/SimpleSQLite/etc." optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "tabledata-1.3.3-py3-none-any.whl", hash = "sha256:4abad1c996d8607e23b045b44dc0c5f061668f3c37585302c5f6c84c93a89962"}, - {file = "tabledata-1.3.3.tar.gz", hash = "sha256:c90daaba9a408e4397934b3ff2f6c06797d5289676420bf520c741ad43e6ff91"}, + {file = "tabledata-1.3.1-py3-none-any.whl", hash = "sha256:73e610c378670a2b9bb80e56cece24427d18c8672a36c80fcdf2a3753b19642b"}, + {file = "tabledata-1.3.1.tar.gz", hash = "sha256:6608f86171f3285f16251ed6649dcf6e953d4fe6a8e622d39b80d1954b9e7711"}, ] [package.dependencies] -DataProperty = ">=1.0.1,<2" +DataProperty = ">=0.54.2,<2" typepy = ">=1.2.0,<2" [package.extras] @@ -2087,41 +1744,52 @@ test = ["pytablewriter (>=0.46)", "pytest"] [[package]] name = "tcolorpy" -version = "0.1.6" +version = "0.1.3" description = "tcolopy is a Python library to apply true color for terminal text." optional = false python-versions = ">=3.7" files = [ - {file = "tcolorpy-0.1.6-py3-none-any.whl", hash = "sha256:8c15cb3167f30b0a433d72297e9d68667c825bd9e2af41c8dd7dfbd3d7f7e207"}, - {file = "tcolorpy-0.1.6.tar.gz", hash = "sha256:8cea0bf5f8cf03f77528a9acfbf312df935573892ba5ea3b2516e61fa54de9a5"}, + {file = "tcolorpy-0.1.3-py3-none-any.whl", hash = "sha256:4ba9e4d52696a36dc16a55c20317115fb46e4b8e02796e8e270132719bcefad4"}, + {file = "tcolorpy-0.1.3.tar.gz", hash = "sha256:43c1afe908f9968ff5ce59f129b62e392049b8e7cd6a8d3f416bd3d372bb5c7a"}, ] [package.extras] -test = ["pytest (>=6.0.1)", "pytest-md-report (>=0.5)"] +test = ["pytest", "pytest-md-report (>=0.1)"] [[package]] name = "termcolor" -version = "2.5.0" +version = "2.1.1" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, - {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, + {file = "termcolor-2.1.1-py3-none-any.whl", hash = "sha256:fa852e957f97252205e105dd55bbc23b419a70fec0085708fc0515e399f304fd"}, + {file = "termcolor-2.1.1.tar.gz", hash = "sha256:67cee2009adc6449c650f6bcf3bdeed00c8ba53a8cda5362733c53e0a39fb70b"}, ] [package.extras] tests = ["pytest", "pytest-cov"] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + [[package]] name = "typepy" -version = "1.3.2" +version = "1.3.1" description = "typepy is a Python library for variable type checker/validator/converter at a run time." optional = false python-versions = ">=3.7" files = [ - {file = "typepy-1.3.2-py3-none-any.whl", hash = "sha256:d5d1022a424132622993800f1d2cd16cfdb691ac4e3b9c325f0fcb37799db1ae"}, - {file = "typepy-1.3.2.tar.gz", hash = "sha256:b69fd48b9f50cdb3809906eef36b855b3134ff66c8893a4f8580abddb0b39517"}, + {file = "typepy-1.3.1-py3-none-any.whl", hash = "sha256:892566bff279368d63f02901aba0a3ce78cd7a319ec1f2bf6c8baab3520207a3"}, + {file = "typepy-1.3.1.tar.gz", hash = "sha256:dfc37b888d6eed8542208389efa60ec8454e06fd84b276b45b2e33897f9d7825"}, ] [package.dependencies] @@ -2153,31 +1821,30 @@ typing-extensions = ">=3.7.4.3" [[package]] name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] name = "urllib3" -version = "2.2.3" +version = "1.26.13" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, + {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "verspec" @@ -2195,61 +1862,59 @@ test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] [[package]] name = "virtualenv" -version = "20.28.0" +version = "20.17.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"}, - {file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"}, + {file = "virtualenv-20.17.1-py3-none-any.whl", hash = "sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4"}, + {file = "virtualenv-20.17.1.tar.gz", hash = "sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058"}, ] [package.dependencies] -distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<5" +distlib = ">=0.3.6,<1" +filelock = ">=3.4.1,<4" +platformdirs = ">=2.4,<3" [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] +testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] [[package]] name = "watchdog" -version = "6.0.0" +version = "2.2.0" description = "Filesystem events monitoring" optional = false -python-versions = ">=3.9" +python-versions = ">=3.6" files = [ - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, - {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, - {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, - {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, - {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, + {file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed91c3ccfc23398e7aa9715abf679d5c163394b8cad994f34f156d57a7c163dc"}, + {file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:76a2743402b794629a955d96ea2e240bd0e903aa26e02e93cd2d57b33900962b"}, + {file = "watchdog-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:920a4bda7daa47545c3201a3292e99300ba81ca26b7569575bd086c865889090"}, + {file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ceaa9268d81205876bedb1069f9feab3eccddd4b90d9a45d06a0df592a04cae9"}, + {file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1893d425ef4fb4f129ee8ef72226836619c2950dd0559bba022b0818c63a7b60"}, + {file = "watchdog-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e99c1713e4436d2563f5828c8910e5ff25abd6ce999e75f15c15d81d41980b6"}, + {file = "watchdog-2.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a5bd9e8656d07cae89ac464ee4bcb6f1b9cecbedc3bf1334683bed3d5afd39ba"}, + {file = "watchdog-2.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a048865c828389cb06c0bebf8a883cec3ae58ad3e366bcc38c61d8455a3138f"}, + {file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e722755d995035dd32177a9c633d158f2ec604f2a358b545bba5bed53ab25bca"}, + {file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af4b5c7ba60206759a1d99811b5938ca666ea9562a1052b410637bb96ff97512"}, + {file = "watchdog-2.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:619d63fa5be69f89ff3a93e165e602c08ed8da402ca42b99cd59a8ec115673e1"}, + {file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f2b0665c57358ce9786f06f5475bc083fea9d81ecc0efa4733fd0c320940a37"}, + {file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:441024df19253bb108d3a8a5de7a186003d68564084576fecf7333a441271ef7"}, + {file = "watchdog-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a410dd4d0adcc86b4c71d1317ba2ea2c92babaf5b83321e4bde2514525544d5"}, + {file = "watchdog-2.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28704c71afdb79c3f215c90231e41c52b056ea880b6be6cee035c6149d658ed1"}, + {file = "watchdog-2.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ac0bd7c206bb6df78ef9e8ad27cc1346f2b41b1fef610395607319cdab89bc1"}, + {file = "watchdog-2.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:27e49268735b3c27310883012ab3bd86ea0a96dcab90fe3feb682472e30c90f3"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:2af1a29fd14fc0a87fb6ed762d3e1ae5694dcde22372eebba50e9e5be47af03c"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:c7bd98813d34bfa9b464cf8122e7d4bec0a5a427399094d2c17dd5f70d59bc61"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_i686.whl", hash = "sha256:56fb3f40fc3deecf6e518303c7533f5e2a722e377b12507f6de891583f1b48aa"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:74535e955359d79d126885e642d3683616e6d9ab3aae0e7dcccd043bd5a3ff4f"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cf05e6ff677b9655c6e9511d02e9cc55e730c4e430b7a54af9c28912294605a4"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:d6ae890798a3560688b441ef086bb66e87af6b400a92749a18b856a134fc0318"}, + {file = "watchdog-2.2.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5aed2a700a18c194c39c266900d41f3db0c1ebe6b8a0834b9995c835d2ca66e"}, + {file = "watchdog-2.2.0-py3-none-win32.whl", hash = "sha256:d0fb5f2b513556c2abb578c1066f5f467d729f2eb689bc2db0739daf81c6bb7e"}, + {file = "watchdog-2.2.0-py3-none-win_amd64.whl", hash = "sha256:1f8eca9d294a4f194ce9df0d97d19b5598f310950d3ac3dd6e8d25ae456d4c8a"}, + {file = "watchdog-2.2.0-py3-none-win_ia64.whl", hash = "sha256:ad0150536469fa4b693531e497ffe220d5b6cd76ad2eda474a5e641ee204bbb6"}, + {file = "watchdog-2.2.0.tar.gz", hash = "sha256:83cf8bc60d9c613b66a4c018051873d6273d9e45d040eed06d6a96241bd8ec01"}, ] [package.extras] @@ -2258,4 +1923,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "82d4f691096d3aaa7cea1e1469b5ebec3daca4d649376c493af809d1978198e6" +content-hash = "82d4f691096d3aaa7cea1e1469b5ebec3daca4d649376c493af809d1978198e6" \ No newline at end of file diff --git a/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml b/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml index 438094f12..984340481 100644 --- a/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml +++ b/tests/cli/snapshots/test_init/test_init_project_include_optional/config.yaml @@ -17,7 +17,6 @@ kafka_connect: kafka_rest: timeout: 30 url: http://localhost:8082/ -operation_mode: managed pipeline_base_dir: . retain_clean_jobs: false schema_registry: diff --git a/tests/manifests/test_kubernetes_model.py b/tests/manifests/test_kubernetes_model.py index d1fbcd623..1b8aad46e 100644 --- a/tests/manifests/test_kubernetes_model.py +++ b/tests/manifests/test_kubernetes_model.py @@ -68,7 +68,8 @@ def test_serialize_model_includes_required_fields(): def test_from_yaml_parsing(): """Test the from_yaml method parses YAML into KubernetesManifest objects.""" - yaml_content = dedent(""" + yaml_content = dedent( + """ --- apiVersion: v1 kind: Service @@ -82,7 +83,8 @@ def test_from_yaml_parsing(): metadata: name: test-pod namespace: test-namespace - """) + """ + ) manifests = list(KubernetesManifest.from_yaml(yaml_content)) assert len(manifests) == 2 assert manifests[0].api_version == "v1" From 21ce117368f1fbd8646dbef8dd8960bb6cd3690d Mon Sep 17 00:00:00 2001 From: Ramin Gharib Date: Fri, 20 Dec 2024 12:31:26 +0100 Subject: [PATCH 12/12] Add migration guide v8-v9 (#562) --- docs/docs/user/migration-guide/v8-v9.md | 42 +++++++++++++++++++++++++ docs/mkdocs.yml | 1 + 2 files changed, 43 insertions(+) create mode 100644 docs/docs/user/migration-guide/v8-v9.md diff --git a/docs/docs/user/migration-guide/v8-v9.md b/docs/docs/user/migration-guide/v8-v9.md new file mode 100644 index 000000000..69004e5a9 --- /dev/null +++ b/docs/docs/user/migration-guide/v8-v9.md @@ -0,0 +1,42 @@ +# Migrate from V8 to V9 + +## [Introduce KPOps operation and manifest resources for deployment](https://github.com/bakdata/kpops/pull/541) + +The `kpops manifest` command and `kpops.manifest()` API have been **removed**. + +Resource manifesting is now integrated into the _operation_ commands (`deploy`, `destroy`, `reset`, `clean`) through the new **operation mode** feature. + +To manifest resources, you can: + +- Pass `--operation-mode manifest` when executing `kpops` commands. +- Set the operation mode by defining the `KPOPS_OPERATION_MODE` environment variable. + +## [Manifest toSection with Strimzi KafkaTopic](https://github.com/bakdata/kpops/pull/545) + +KPOps now supports generating valid Kubernetes KafkaTopic resources compatible with [Strimzi](https://github.com/strimzi/strimzi-kafka-operator/blob/main/examples/topic/kafka-topic.yaml). When using manifest or argo as the operation_mode, you must specify the Strimzi cluster label to ensure the topics are recognized by the deployed Strimzi Topic Operator. + +```diff +operation_mode: manifest + ++ strimzi_topic: ++ label: ++ strimzi.io/cluster: my-cluster + +# rest of your config +``` + + + +!!! info Standalone topic operator deployment + Refer to the [Strimzi documentation on deploying a standalone topic operator](https://strimzi.io/docs/operators/latest/deploying#deploying-the-topic-operator-standalone-str) for more details. + + + +## [Drop support for Python 3.10](https://github.com/bakdata/kpops/pull/561) + +KPOps V9 no longer supports Python 3.10. Ensure your environment is running Python 3.11 to 3.12. + +#### Action Required: + +Upgrade your Python version to a supported version (3.11 or 3.12). +Update your virtual environments and CI pipelines to reflect this change. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 720d74582..1b39c8e9d 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -131,6 +131,7 @@ nav: - Migrate from v5 to v6: user/migration-guide/v5-v6.md - Migrate from v6 to v7: user/migration-guide/v6-v7.md - Migrate from v7 to v8: user/migration-guide/v7-v8.md + - Migrate from v8 to v9: user/migration-guide/v8-v9.md - CLI usage: user/references/cli-commands.md - Editor integration: user/references/editor-integration.md - CI integration: