From ee297432b763558a28ccd0721c2999dc84884e2a Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 22 Aug 2023 13:32:41 +0200 Subject: [PATCH 01/40] Add networkx compatibility --- .../base_components/kafka_connector.py | 4 ++ .../base_components/pipeline_component.py | 14 +++++ .../producer/producer_app.py | 8 +++ .../streams_bootstrap/streams/streams_app.py | 12 +++++ kpops/pipeline_generator/pipeline.py | 51 ++++++++++++++++++- poetry.lock | 20 +++++++- pyproject.toml | 1 + 7 files changed, 108 insertions(+), 2 deletions(-) diff --git a/kpops/components/base_components/kafka_connector.py b/kpops/components/base_components/kafka_connector.py index 462614d73..cfd831ee5 100644 --- a/kpops/components/base_components/kafka_connector.py +++ b/kpops/components/base_components/kafka_connector.py @@ -411,6 +411,10 @@ class KafkaSinkConnector(KafkaConnector): exclude=True, ) + @override + def get_input_topics(self) -> list[str]: + return getattr(self.app, "topics").split(",") + @override def add_input_topics(self, topics: list[str]) -> None: existing_topics: str | None = getattr(self.app, "topics", None) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 04ed5450c..002db02cc 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -75,6 +75,20 @@ def __init__(self, **kwargs) -> None: self.set_input_topics() self.set_output_topics() + def get_input_topics(self) -> list[str]: + """ + Get all the input topics + """ + + def get_extra_output_topics(self) -> dict[str, str]: + ... + + def get_extra_input_topics(self) -> dict[str, list[str]]: + ... + + def get_output_topic(self) -> str: + ... + def add_input_topics(self, topics: list[str]) -> None: """Add given topics to the list of input topics. diff --git a/kpops/components/streams_bootstrap/producer/producer_app.py b/kpops/components/streams_bootstrap/producer/producer_app.py index 90228411f..4f6880e78 100644 --- a/kpops/components/streams_bootstrap/producer/producer_app.py +++ b/kpops/components/streams_bootstrap/producer/producer_app.py @@ -63,6 +63,14 @@ def apply_to_outputs(self, name: str, topic: TopicConfig) -> None: case _: super().apply_to_outputs(name, topic) + @override + def get_output_topic(self) -> str: + return self.app.streams.output_topic + + @override + def get_extra_output_topics(self) -> dict[str, str]: + return self.app.streams.extra_output_topics + @override def set_output_topic(self, topic_name: str) -> None: self.app.streams.output_topic = topic_name diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index c2bd7d140..e90d00a8f 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -42,6 +42,18 @@ class StreamsApp(KafkaApp): class Config(DescConfig): extra = Extra.allow + @override + def get_input_topics(self) -> list[str]: + return self.app.streams.input_topics + + @override + def get_extra_input_topics(self) -> dict[str, list[str]]: + return self.app.streams.extra_input_topics + + @override + def get_output_topic(self) -> str: + return self.app.streams.output_topic + @override def add_input_topics(self, topics: list[str]) -> None: self.app.streams.add_input_topics(topics) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index fce638d9d..1c6fed072 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -6,9 +6,11 @@ from collections.abc import Iterator from contextlib import suppress from pathlib import Path +import networkx as nx +import matplotlib.pyplot as plt import yaml -from pydantic import BaseModel +from pydantic import BaseModel, validator, Field from rich.console import Console from rich.syntax import Syntax @@ -35,6 +37,12 @@ class PipelineComponents(BaseModel): """Stores the pipeline components""" components: list[PipelineComponent] = [] + graph_components: nx.DiGraph = Field(default=nx.DiGraph(), exclude=True) + + class Config: + arbitrary_types_allowed = True + + @property def last(self) -> PipelineComponent: @@ -113,6 +121,9 @@ def __init__( self.env_components_index = create_env_components_index(environment_components) self.parse_components(component_list) self.validate() + self.generate_graph() + self.validate_graph_components() + @classmethod def load_from_yaml( @@ -160,6 +171,44 @@ def load_from_yaml( pipeline = cls(main_content, env_content, registry, config, handlers) return pipeline + def generate_graph(self): + for component in self.components: + input_topics = component.get_input_topics() + extra_input_topics = component.get_extra_input_topics() + all_input_topics: list[str] = [] + if input_topics is not None: + all_input_topics += input_topics + if extra_input_topics is not None: + all_input_topics += [ + topic + for list_topics in extra_input_topics.values() + for topic in list_topics + ] + + all_output_topics: list[str] = [] + output_topics = component.get_output_topic() + extra_output_topics = component.get_extra_output_topics() + if output_topics is not None: + all_output_topics += [output_topics] + if extra_output_topics is not None: + all_output_topics += list(extra_output_topics.values()) + + self.components.graph_components.add_node(component.name) + for input_topic in all_input_topics: + self.components.graph_components.add_node(input_topic) + self.components.graph_components.add_edge(input_topic, component.name) + + for output_topic in all_output_topics: + self.components.graph_components.add_node(output_topic) + self.components.graph_components.add_edge(component.name, output_topic) + nx.draw(self.components.graph_components, with_labels=True) + plt.show() + + + def validate_graph_components(self): + if not nx.is_directed_acyclic_graph(self.components.graph_components): + raise ValueError("Component graph contain loops!") + def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components diff --git a/poetry.lock b/poetry.lock index a673ba0c0..e28916dfc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -755,6 +755,24 @@ files = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +[[package]] +name = "networkx" +version = "3.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.8" +files = [ + {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.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.7.0" @@ -1827,4 +1845,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "62d203076f7ac783793b7aa4ad6b5263067e6b9d6d13a6965dddef1a62c40eed" +content-hash = "d359a28891312de394390134357843b05abf37d8299b7ebcd8b91b76bd3aa880" diff --git a/pyproject.toml b/pyproject.toml index 02503d2f2..495bc0074 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ cachetools = "^5.2.0" dictdiffer = "^0.9.0" python-schema-registry-client = "^2.4.1" httpx = "^0.24.1" +networkx = "^3.1" [tool.poetry.group.dev.dependencies] From 0ace3743ae7aa30c8f1f45772154881dcfc755d1 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 22 Aug 2023 13:37:32 +0200 Subject: [PATCH 02/40] Fix formatting --- kpops/pipeline_generator/pipeline.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 1c6fed072..3258984c7 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -6,11 +6,11 @@ from collections.abc import Iterator from contextlib import suppress from pathlib import Path -import networkx as nx -import matplotlib.pyplot as plt +import matplotlib.pyplot as plt +import networkx as nx import yaml -from pydantic import BaseModel, validator, Field +from pydantic import BaseModel, Field, validator from rich.console import Console from rich.syntax import Syntax @@ -42,8 +42,6 @@ class PipelineComponents(BaseModel): class Config: arbitrary_types_allowed = True - - @property def last(self) -> PipelineComponent: return self.components[-1] @@ -124,7 +122,6 @@ def __init__( self.generate_graph() self.validate_graph_components() - @classmethod def load_from_yaml( cls, @@ -204,7 +201,6 @@ def generate_graph(self): nx.draw(self.components.graph_components, with_labels=True) plt.show() - def validate_graph_components(self): if not nx.is_directed_acyclic_graph(self.components.graph_components): raise ValueError("Component graph contain loops!") From bb61f5f19910680ac67aac9dfe5ba181c41519b4 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 22 Aug 2023 13:55:01 +0200 Subject: [PATCH 03/40] Save progress with ci working --- kpops/components/base_components/kafka_connector.py | 2 +- kpops/pipeline_generator/pipeline.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/kpops/components/base_components/kafka_connector.py b/kpops/components/base_components/kafka_connector.py index cfd831ee5..c690d5365 100644 --- a/kpops/components/base_components/kafka_connector.py +++ b/kpops/components/base_components/kafka_connector.py @@ -413,7 +413,7 @@ class KafkaSinkConnector(KafkaConnector): @override def get_input_topics(self) -> list[str]: - return getattr(self.app, "topics").split(",") + return getattr(self.app, "topics", []) @override def add_input_topics(self, topics: list[str]) -> None: diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 3258984c7..547e8f504 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -120,7 +120,7 @@ def __init__( self.parse_components(component_list) self.validate() self.generate_graph() - self.validate_graph_components() + #self.validate_graph_components() @classmethod def load_from_yaml( @@ -203,7 +203,8 @@ def generate_graph(self): def validate_graph_components(self): if not nx.is_directed_acyclic_graph(self.components.graph_components): - raise ValueError("Component graph contain loops!") + print("contain loops") + #raise ValueError("Component graph contain loops!") def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components From 862aba0d3a3f61dc2e7d241ee84ca7d8f25cb501 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 22 Aug 2023 13:59:37 +0200 Subject: [PATCH 04/40] Linting --- kpops/pipeline_generator/pipeline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 547e8f504..0bb3cef44 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -10,7 +10,7 @@ import matplotlib.pyplot as plt import networkx as nx import yaml -from pydantic import BaseModel, Field, validator +from pydantic import BaseModel, Field from rich.console import Console from rich.syntax import Syntax @@ -120,7 +120,7 @@ def __init__( self.parse_components(component_list) self.validate() self.generate_graph() - #self.validate_graph_components() + # self.validate_graph_components() @classmethod def load_from_yaml( @@ -204,7 +204,7 @@ def generate_graph(self): def validate_graph_components(self): if not nx.is_directed_acyclic_graph(self.components.graph_components): print("contain loops") - #raise ValueError("Component graph contain loops!") + # raise ValueError("Component graph contain loops!") def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components From 8f46969e7f8166e623b19b421ace3ae60a0a3fd9 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 22 Aug 2023 14:13:44 +0200 Subject: [PATCH 05/40] Fix pyright --- kpops/components/base_components/pipeline_component.py | 8 ++++---- .../components/streams_bootstrap/producer/producer_app.py | 2 +- kpops/components/streams_bootstrap/streams/streams_app.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 002db02cc..789b29322 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -75,18 +75,18 @@ def __init__(self, **kwargs) -> None: self.set_input_topics() self.set_output_topics() - def get_input_topics(self) -> list[str]: + def get_input_topics(self) -> list[str] | None: """ Get all the input topics """ - def get_extra_output_topics(self) -> dict[str, str]: + def get_extra_output_topics(self) -> dict[str, str] | None: ... - def get_extra_input_topics(self) -> dict[str, list[str]]: + def get_extra_input_topics(self) -> dict[str, list[str]] | None: ... - def get_output_topic(self) -> str: + def get_output_topic(self) -> str | None: ... def add_input_topics(self, topics: list[str]) -> None: diff --git a/kpops/components/streams_bootstrap/producer/producer_app.py b/kpops/components/streams_bootstrap/producer/producer_app.py index 4f6880e78..40fcad560 100644 --- a/kpops/components/streams_bootstrap/producer/producer_app.py +++ b/kpops/components/streams_bootstrap/producer/producer_app.py @@ -64,7 +64,7 @@ def apply_to_outputs(self, name: str, topic: TopicConfig) -> None: super().apply_to_outputs(name, topic) @override - def get_output_topic(self) -> str: + def get_output_topic(self) -> str | None: return self.app.streams.output_topic @override diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index e90d00a8f..b0dde2ab5 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -43,15 +43,15 @@ class Config(DescConfig): extra = Extra.allow @override - def get_input_topics(self) -> list[str]: + def get_input_topics(self) -> list[str] | None: return self.app.streams.input_topics @override - def get_extra_input_topics(self) -> dict[str, list[str]]: + def get_extra_input_topics(self) -> dict[str, list[str]] | None: return self.app.streams.extra_input_topics @override - def get_output_topic(self) -> str: + def get_output_topic(self) -> str | None: return self.app.streams.output_topic @override From 769bd0494a046ebc899a668b4ea719874cfe1d46 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 28 Aug 2023 09:27:15 +0200 Subject: [PATCH 06/40] Test new dependency --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 495bc0074..9f9af4217 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ dictdiffer = "^0.9.0" python-schema-registry-client = "^2.4.1" httpx = "^0.24.1" networkx = "^3.1" +matplotlib = "^3.7.2" [tool.poetry.group.dev.dependencies] From a97148aedb2d921068af53b72aa81eb3e90da881 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 28 Aug 2023 09:29:05 +0200 Subject: [PATCH 07/40] Fix lock --- poetry.lock | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 418 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index e28916dfc..14c69115f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -208,6 +208,75 @@ files = [ [package.extras] test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] +[[package]] +name = "contourpy" +version = "1.1.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, + {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, + {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, + {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, + {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, + {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, + {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, +] + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] + [[package]] name = "dataproperty" version = "1.0.0" @@ -365,6 +434,63 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" +[[package]] +name = "fonttools" +version = "4.42.1" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"}, + {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"}, + {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"}, + {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"}, + {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"}, + {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"}, + {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"}, + {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"}, + {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"}, + {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"}, + {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"}, + {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"}, + {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"}, + {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"}, + {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"}, + {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"}, + {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"}, + {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"}, + {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"}, + {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"}, + {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"}, + {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"}, + {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"}, + {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"}, + {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"}, + {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"}, + {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"}, + {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"}, + {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"}, + {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"}, + {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"}, + {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"}, + {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"}, + {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "ghp-import" version = "2.1.0" @@ -526,6 +652,119 @@ pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" 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 (>=1.11)"] +[[package]] +name = "kiwisolver" +version = "1.4.5" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + [[package]] name = "markdown" version = "3.3.7" @@ -589,6 +828,67 @@ files = [ {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] +[[package]] +name = "matplotlib" +version = "3.7.2" +description = "Python plotting package" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, + {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, + {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, + {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, + {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, + {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, + {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, + {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, + {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, + {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.20" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1,<3.1" +python-dateutil = ">=2.7" + [[package]] name = "mbstrdecoder" version = "1.1.3" @@ -787,6 +1087,40 @@ files = [ [package.dependencies] setuptools = "*" +[[package]] +name = "numpy" +version = "1.25.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, + {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, + {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, + {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, + {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, + {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, + {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, + {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, + {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, + {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, + {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, + {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, +] + [[package]] name = "packaging" version = "22.0" @@ -838,6 +1172,75 @@ files = [ [package.extras] 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 = "pillow" +version = "10.0.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, + {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, + {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, + {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, + {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, + {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, + {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, + {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, + {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + [[package]] name = "platformdirs" version = "2.6.0" @@ -1002,6 +1405,20 @@ files = [ markdown = ">=3.2" pyyaml = "*" +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + [[package]] name = "pyright" version = "1.1.314" @@ -1845,4 +2262,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "d359a28891312de394390134357843b05abf37d8299b7ebcd8b91b76bd3aa880" +content-hash = "6322f70e7799d7c8fbfa564f613f6b6223c313e51d4cddd9c7f7158db92e5815" From d929459538c48d16d2deedfb39a56395c9ffb3b6 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 28 Aug 2023 15:46:13 +0200 Subject: [PATCH 08/40] Fix problem when names are not overriten --- .../base_components/kafka_connector.py | 3 ++- kpops/pipeline_generator/pipeline.py | 16 +++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/kpops/components/base_components/kafka_connector.py b/kpops/components/base_components/kafka_connector.py index c690d5365..aea3328d9 100644 --- a/kpops/components/base_components/kafka_connector.py +++ b/kpops/components/base_components/kafka_connector.py @@ -413,7 +413,8 @@ class KafkaSinkConnector(KafkaConnector): @override def get_input_topics(self) -> list[str]: - return getattr(self.app, "topics", []) + topics = getattr(self.app, "topics", None) + return topics.split(",") if topics is not None else [] @override def add_input_topics(self, topics: list[str]) -> None: diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 0bb3cef44..906ac0046 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -120,7 +120,7 @@ def __init__( self.parse_components(component_list) self.validate() self.generate_graph() - # self.validate_graph_components() + self.validate_graph_components() @classmethod def load_from_yaml( @@ -175,7 +175,7 @@ def generate_graph(self): all_input_topics: list[str] = [] if input_topics is not None: all_input_topics += input_topics - if extra_input_topics is not None: + if extra_input_topics is not None and extra_input_topics: all_input_topics += [ topic for list_topics in extra_input_topics.values() @@ -187,24 +187,26 @@ def generate_graph(self): extra_output_topics = component.get_extra_output_topics() if output_topics is not None: all_output_topics += [output_topics] - if extra_output_topics is not None: + if extra_output_topics is not None and extra_output_topics: all_output_topics += list(extra_output_topics.values()) - self.components.graph_components.add_node(component.name) + component_vertex_name = f"component-{component.name}" + self.components.graph_components.add_node(component_vertex_name) for input_topic in all_input_topics: self.components.graph_components.add_node(input_topic) self.components.graph_components.add_edge(input_topic, component.name) for output_topic in all_output_topics: self.components.graph_components.add_node(output_topic) - self.components.graph_components.add_edge(component.name, output_topic) + self.components.graph_components.add_edge( + component_vertex_name, output_topic + ) nx.draw(self.components.graph_components, with_labels=True) plt.show() def validate_graph_components(self): if not nx.is_directed_acyclic_graph(self.components.graph_components): - print("contain loops") - # raise ValueError("Component graph contain loops!") + raise ValueError("Component graph contain loops!") def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components From 7408e02daadf363baff543be9205935981b7b4bf Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 28 Aug 2023 16:06:33 +0200 Subject: [PATCH 09/40] Delete pl show --- kpops/pipeline_generator/pipeline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 906ac0046..1510669eb 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -202,7 +202,6 @@ def generate_graph(self): component_vertex_name, output_topic ) nx.draw(self.components.graph_components, with_labels=True) - plt.show() def validate_graph_components(self): if not nx.is_directed_acyclic_graph(self.components.graph_components): From a1ae5856dcdde44d0066cc037cc22dbc865f686c Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 28 Aug 2023 16:07:17 +0200 Subject: [PATCH 10/40] Deleting ploting graph --- kpops/pipeline_generator/pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 1510669eb..c82ebec7f 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -7,7 +7,6 @@ from contextlib import suppress from pathlib import Path -import matplotlib.pyplot as plt import networkx as nx import yaml from pydantic import BaseModel, Field @@ -201,7 +200,6 @@ def generate_graph(self): self.components.graph_components.add_edge( component_vertex_name, output_topic ) - nx.draw(self.components.graph_components, with_labels=True) def validate_graph_components(self): if not nx.is_directed_acyclic_graph(self.components.graph_components): From 36a86b09d1c67f0037fbbb72e38a93361744dc16 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 29 Aug 2023 11:25:26 +0200 Subject: [PATCH 11/40] Add test and fix some edge cases --- kpops/pipeline_generator/pipeline.py | 90 +++++++++++-------- .../pipeline-with-loop/defaults.yaml | 22 +++++ .../pipeline-with-loop/pipeline.yaml | 34 +++++++ tests/pipeline/test_pipeline.py | 15 ++++ 4 files changed, 126 insertions(+), 35 deletions(-) create mode 100644 tests/pipeline/resources/pipeline-with-loop/defaults.yaml create mode 100644 tests/pipeline/resources/pipeline-with-loop/pipeline.yaml diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index c82ebec7f..718063e3f 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -6,6 +6,7 @@ from collections.abc import Iterator from contextlib import suppress from pathlib import Path +import matplotlib.pyplot as pyplt import networkx as nx import yaml @@ -118,8 +119,8 @@ def __init__( self.env_components_index = create_env_components_index(environment_components) self.parse_components(component_list) self.validate() - self.generate_graph() - self.validate_graph_components() + self.__generate_graph() + self.__validate_graph_components() @classmethod def load_from_yaml( @@ -167,41 +168,60 @@ def load_from_yaml( pipeline = cls(main_content, env_content, registry, config, handlers) return pipeline - def generate_graph(self): + def __generate_graph(self): for component in self.components: - input_topics = component.get_input_topics() - extra_input_topics = component.get_extra_input_topics() - all_input_topics: list[str] = [] - if input_topics is not None: - all_input_topics += input_topics - if extra_input_topics is not None and extra_input_topics: - all_input_topics += [ - topic - for list_topics in extra_input_topics.values() - for topic in list_topics - ] - - all_output_topics: list[str] = [] - output_topics = component.get_output_topic() - extra_output_topics = component.get_extra_output_topics() - if output_topics is not None: - all_output_topics += [output_topics] - if extra_output_topics is not None and extra_output_topics: - all_output_topics += list(extra_output_topics.values()) - - component_vertex_name = f"component-{component.name}" - self.components.graph_components.add_node(component_vertex_name) - for input_topic in all_input_topics: - self.components.graph_components.add_node(input_topic) - self.components.graph_components.add_edge(input_topic, component.name) - - for output_topic in all_output_topics: - self.components.graph_components.add_node(output_topic) - self.components.graph_components.add_edge( - component_vertex_name, output_topic - ) + all_input_topics = self.__get_all_input_topics(component) + all_output_topics = self.__get_all_output_topics(component) + + component_node_name = self.__get_vertex_component_name(component) + self.components.graph_components.add_node(component_node_name) + + self.__add_ingoing_edges(all_input_topics, component_node_name) + self.__add_outgoing_edges(all_output_topics, component_node_name) - def validate_graph_components(self): + def __add_outgoing_edges( + self, all_output_topics: list[str], component_node_name: str + ) -> None: + for output_topic in all_output_topics: + self.components.graph_components.add_node(output_topic) + self.components.graph_components.add_edge(component_node_name, output_topic) + + def __add_ingoing_edges( + self, all_input_topics: list[str], component_node_name: str + ) -> None: + for input_topic in all_input_topics: + self.components.graph_components.add_node(input_topic) + self.components.graph_components.add_edge(input_topic, component_node_name) + + def __get_vertex_component_name(self, component: PipelineComponent) -> str: + component_vertex_name = f"component-{component.name}" + return component_vertex_name + + def __get_all_output_topics(self, component: PipelineComponent) -> list[str]: + all_output_topics: list[str] = [] + output_topics = component.get_output_topic() + extra_output_topics = component.get_extra_output_topics() + if output_topics is not None: + all_output_topics += [output_topics] + if extra_output_topics is not None and extra_output_topics: + all_output_topics += list(extra_output_topics.values()) + return all_output_topics + + def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: + input_topics = component.get_input_topics() + extra_input_topics = component.get_extra_input_topics() + all_input_topics: list[str] = [] + if input_topics is not None: + all_input_topics += input_topics + if extra_input_topics is not None and extra_input_topics: + all_input_topics += [ + topic + for list_topics in extra_input_topics.values() + for topic in list_topics + ] + return all_input_topics + + def __validate_graph_components(self) -> None: if not nx.is_directed_acyclic_graph(self.components.graph_components): raise ValueError("Component graph contain loops!") diff --git a/tests/pipeline/resources/pipeline-with-loop/defaults.yaml b/tests/pipeline/resources/pipeline-with-loop/defaults.yaml new file mode 100644 index 000000000..c96443b79 --- /dev/null +++ b/tests/pipeline/resources/pipeline-with-loop/defaults.yaml @@ -0,0 +1,22 @@ +pipeline-component: + prefix: "" + +kubernetes-app: + namespace: example-namespace + +kafka-connector: + namespace: example-namespace + +kafka-app: + app: + streams: + brokers: 127.0.0.1:9092 + schemaRegistryUrl: 127.0.0.1:8081 + optimizeLeaveGroupBehavior: false + +streams-app: + app: + labels: + pipeline: ${pipeline_name} + streams: + optimizeLeaveGroupBehavior: false \ No newline at end of file diff --git a/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml b/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml new file mode 100644 index 000000000..dff8b281e --- /dev/null +++ b/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml @@ -0,0 +1,34 @@ +- type: producer + name: app1 + app: + image: producer-image + to: + topics: + my-output-topic: + type: output + +- type: streams-app + name: app2 + app: + image: app2-image + from: + topics: + my-output-topic: + type: input + to: + topics: + my-app2-topic: + type: output + +- type: streams-app + name: app3 + app: + image: app3-image + from: + topics: + my-app2-topic: + type: input + to: + topics: + my-output-topic: + type: output \ No newline at end of file diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 7f129815f..26486cc76 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -480,3 +480,18 @@ def test_validate_unique_step_names(self): ], catch_exceptions=False, ) + + def test_validate_loops_on_pipeline(self): + with pytest.raises(ValueError, match="Component graph contain loops!"): + runner.invoke( + app, + [ + "generate", + "--pipeline-base-dir", + str(PIPELINE_BASE_DIR_PATH), + str(RESOURCE_PATH / "pipeline-with-loop/pipeline.yaml"), + "--defaults", + str(RESOURCE_PATH / "pipeline-with-loop"), + ], + catch_exceptions=False, + ) From c3aba1d35429668a19d9386e5cdba7e0cc2536fd Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 29 Aug 2023 11:56:05 +0200 Subject: [PATCH 12/40] remove unused dependency --- kpops/pipeline_generator/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 718063e3f..90e9fb32f 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -6,8 +6,8 @@ from collections.abc import Iterator from contextlib import suppress from pathlib import Path -import matplotlib.pyplot as pyplt +import matplotlib.pyplot as pyplt import networkx as nx import yaml from pydantic import BaseModel, Field From 747678495f7f3433b5994b08d5eb83f01d4f27bd Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 29 Aug 2023 11:56:46 +0200 Subject: [PATCH 13/40] Delete more unused depencendies --- kpops/pipeline_generator/pipeline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 90e9fb32f..2251832ec 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -7,7 +7,6 @@ from contextlib import suppress from pathlib import Path -import matplotlib.pyplot as pyplt import networkx as nx import yaml from pydantic import BaseModel, Field From f364f00804a55e0d87009fe212bf17ec016eeaf2 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 29 Aug 2023 11:57:59 +0200 Subject: [PATCH 14/40] Delete matploit for testing --- poetry.lock | 419 +------------------------------------------------ pyproject.toml | 1 - 2 files changed, 1 insertion(+), 419 deletions(-) diff --git a/poetry.lock b/poetry.lock index 14c69115f..e28916dfc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -208,75 +208,6 @@ files = [ [package.extras] test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] -[[package]] -name = "contourpy" -version = "1.1.0" -description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false -python-versions = ">=3.8" -files = [ - {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, - {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, - {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, - {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, - {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, - {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, - {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, - {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, - {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, - {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, - {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, -] - -[package.dependencies] -numpy = ">=1.16" - -[package.extras] -bokeh = ["bokeh", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] -test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] - -[[package]] -name = "cycler" -version = "0.11.0" -description = "Composable style cycles" -optional = false -python-versions = ">=3.6" -files = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, -] - [[package]] name = "dataproperty" version = "1.0.0" @@ -434,63 +365,6 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" -[[package]] -name = "fonttools" -version = "4.42.1" -description = "Tools to manipulate font files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"}, - {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"}, - {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"}, - {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"}, - {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"}, - {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"}, - {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"}, - {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"}, - {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"}, - {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"}, - {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"}, - {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"}, - {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"}, - {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"}, - {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"}, - {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"}, - {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"}, - {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"}, - {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"}, - {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"}, - {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"}, - {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"}, - {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"}, - {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"}, - {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"}, - {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"}, - {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"}, - {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"}, - {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"}, - {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"}, - {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"}, - {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"}, - {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"}, - {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"}, -] - -[package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] -graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "scipy"] -lxml = ["lxml (>=4.0,<5)"] -pathops = ["skia-pathops (>=0.5.0)"] -plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] -symfont = ["sympy"] -type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.0.0)"] -woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] - [[package]] name = "ghp-import" version = "2.1.0" @@ -652,119 +526,6 @@ pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" 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 (>=1.11)"] -[[package]] -name = "kiwisolver" -version = "1.4.5" -description = "A fast implementation of the Cassowary constraint solver" -optional = false -python-versions = ">=3.7" -files = [ - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, - {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, -] - [[package]] name = "markdown" version = "3.3.7" @@ -828,67 +589,6 @@ files = [ {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] -[[package]] -name = "matplotlib" -version = "3.7.2" -description = "Python plotting package" -optional = false -python-versions = ">=3.8" -files = [ - {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, - {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, - {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, - {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, - {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, - {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, - {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, - {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, - {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, - {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, - {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, - {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, -] - -[package.dependencies] -contourpy = ">=1.0.1" -cycler = ">=0.10" -fonttools = ">=4.22.0" -kiwisolver = ">=1.0.1" -numpy = ">=1.20" -packaging = ">=20.0" -pillow = ">=6.2.0" -pyparsing = ">=2.3.1,<3.1" -python-dateutil = ">=2.7" - [[package]] name = "mbstrdecoder" version = "1.1.3" @@ -1087,40 +787,6 @@ files = [ [package.dependencies] setuptools = "*" -[[package]] -name = "numpy" -version = "1.25.2" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.9" -files = [ - {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, - {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, - {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, - {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, - {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, - {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, - {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, - {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, - {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, - {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, - {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, - {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, -] - [[package]] name = "packaging" version = "22.0" @@ -1172,75 +838,6 @@ files = [ [package.extras] 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 = "pillow" -version = "10.0.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, - {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, - {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, - {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, - {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, - {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, - {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, - {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, - {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, - {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, - {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, - {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, - {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, - {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, - {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, - {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, - {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, - {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, - {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, - {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, - {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, - {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, - {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, - {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, - {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, - {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, - {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, - {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] - [[package]] name = "platformdirs" version = "2.6.0" @@ -1405,20 +1002,6 @@ files = [ markdown = ">=3.2" pyyaml = "*" -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -optional = false -python-versions = ">=3.6.8" -files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - [[package]] name = "pyright" version = "1.1.314" @@ -2262,4 +1845,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "6322f70e7799d7c8fbfa564f613f6b6223c313e51d4cddd9c7f7158db92e5815" +content-hash = "d359a28891312de394390134357843b05abf37d8299b7ebcd8b91b76bd3aa880" diff --git a/pyproject.toml b/pyproject.toml index 9f9af4217..495bc0074 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,6 @@ dictdiffer = "^0.9.0" python-schema-registry-client = "^2.4.1" httpx = "^0.24.1" networkx = "^3.1" -matplotlib = "^3.7.2" [tool.poetry.group.dev.dependencies] From c197969cd187be046f1fe11b44e8a80f3a3b9a16 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Wed, 30 Aug 2023 12:53:42 +0200 Subject: [PATCH 15/40] Test and changes --- kpops/pipeline_generator/pipeline.py | 1 + tests/components/test_streams_app.py | 59 +++++++++++++++++++ .../pipeline-with-loop/defaults.yaml | 2 +- .../pipeline-with-loop/pipeline.yaml | 2 +- 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 2251832ec..5c3fa4095 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -6,6 +6,7 @@ from collections.abc import Iterator from contextlib import suppress from pathlib import Path +import matplotlib.pyplot as plt import networkx as nx import yaml diff --git a/tests/components/test_streams_app.py b/tests/components/test_streams_app.py index a6373c85e..32c829bea 100644 --- a/tests/components/test_streams_app.py +++ b/tests/components/test_streams_app.py @@ -429,3 +429,62 @@ async def test_should_clean_streams_app_and_deploy_clean_up_job_and_delete_clean "test-namespace", self.STREAMS_APP_CLEAN_NAME, dry_run ), ] + + @pytest.mark.asyncio + async def test_get_topics( + self, config: PipelineConfig, handlers: ComponentHandlers + ): + streams_app = StreamsApp( + name=self.STREAMS_APP_NAME, + config=config, + handlers=handlers, + **{ + "namespace": "test-namespace", + "app": { + "streams": {"brokers": "fake-broker:9092"}, + }, + "from": { + "topics": { + "example-input": {"type": "input"}, + "b": {"type": "input"}, + "a": {"type": "input"}, + "topic-extra2": {"type": "extra", "role": "role2"}, + "topic-extra3": {"type": "extra", "role": "role2"}, + "topic-extra": {"type": "extra", "role": "role1"}, + ".*": {"type": "input-pattern"}, + "example.*": { + "type": "extra-pattern", + "role": "another-pattern", + }, + } + }, + }, + ) + assert streams_app.get_input_topics() == ["example-input", "b", "a"] + assert streams_app.get_extra_input_topics() == { + "role1": ["topic-extra"], + "role2": ["topic-extra2", "topic-extra3"], + } + + @pytest.mark.asyncio + async def test_get_output_topic( + self, config: PipelineConfig, handlers: ComponentHandlers + ): + streams_app = StreamsApp( + name=self.STREAMS_APP_NAME, + config=config, + handlers=handlers, + **{ + "namespace": "test-namespace", + "app": { + "streams": {"brokers": "fake-broker:9092"}, + }, + "from": { + "topics": { + "example-input": {"type": "input"}, + } + }, + "to": {"topics": {"example-output": {"type": "output"}}}, + }, + ) + assert streams_app.get_output_topic() == "example-output" diff --git a/tests/pipeline/resources/pipeline-with-loop/defaults.yaml b/tests/pipeline/resources/pipeline-with-loop/defaults.yaml index c96443b79..dee463477 100644 --- a/tests/pipeline/resources/pipeline-with-loop/defaults.yaml +++ b/tests/pipeline/resources/pipeline-with-loop/defaults.yaml @@ -19,4 +19,4 @@ streams-app: labels: pipeline: ${pipeline_name} streams: - optimizeLeaveGroupBehavior: false \ No newline at end of file + optimizeLeaveGroupBehavior: false diff --git a/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml b/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml index dff8b281e..d46cdd754 100644 --- a/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml +++ b/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml @@ -31,4 +31,4 @@ to: topics: my-output-topic: - type: output \ No newline at end of file + type: output From 00da489c70d6a891e28f565dfacf4d1498876e15 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 09:09:00 +0200 Subject: [PATCH 16/40] Implement comments --- kpops/pipeline_generator/pipeline.py | 14 +++++++------ tests/components/test_producer_app.py | 29 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 5c3fa4095..eec58b430 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -6,7 +6,6 @@ from collections.abc import Iterator from contextlib import suppress from pathlib import Path -import matplotlib.pyplot as plt import networkx as nx import yaml @@ -65,6 +64,10 @@ def __iter__(self) -> Iterator[PipelineComponent]: def __len__(self) -> int: return len(self.components) + def validate_graph_components(self) -> None: + if not nx.is_directed_acyclic_graph(self.graph_components): + raise ValueError("Component graph contain loops!") + def validate_unique_names(self) -> None: step_names = [component.name for component in self.components] duplicates = [name for name, count in Counter(step_names).items() if count > 1] @@ -118,9 +121,9 @@ def __init__( self.registry = registry self.env_components_index = create_env_components_index(environment_components) self.parse_components(component_list) - self.validate() self.__generate_graph() - self.__validate_graph_components() + self.validate() + @classmethod def load_from_yaml( @@ -221,9 +224,7 @@ def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: ] return all_input_topics - def __validate_graph_components(self) -> None: - if not nx.is_directed_acyclic_graph(self.components.graph_components): - raise ValueError("Component graph contain loops!") + def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components @@ -392,6 +393,7 @@ def substitute_in_component(self, component_as_dict: dict) -> dict: def validate(self) -> None: self.components.validate_unique_names() + self.components.validate_graph_components() @staticmethod def pipeline_filename_environment(path: Path, config: PipelineConfig) -> Path: diff --git a/tests/components/test_producer_app.py b/tests/components/test_producer_app.py index ff11d741e..a95811ce5 100644 --- a/tests/components/test_producer_app.py +++ b/tests/components/test_producer_app.py @@ -240,3 +240,32 @@ async def test_should_clean_producer_app_and_deploy_clean_up_job_and_delete_clea "test-namespace", self.PRODUCER_APP_CLEAN_NAME, False ), ] + + def test_get_output_topics(self, config: PipelineConfig, handlers: ComponentHandlers): + producer_app = ProducerApp( + name=self.PRODUCER_APP_NAME, + config=config, + handlers=handlers, + **{ + "namespace": "test-namespace", + "app": { + "namespace": "test-namespace", + "streams": {"brokers": "fake-broker:9092"}, + }, + "to": { + "topics": { + "${output_topic_name}": TopicConfig( + type=OutputTopicTypes.OUTPUT, partitions_count=10 + ), + "extra-topic-1": TopicConfig( + type=OutputTopicTypes.EXTRA, + role="first-extra-topic", + partitions_count=10, + ), + } + }, + }, + ) + + assert producer_app.get_output_topic() == "${output_topic_name}" + assert producer_app.get_extra_output_topics() == {"first-extra-topic": "extra-topic-1"} From d84e0eada22724d064924915eb6eee8b28d53054 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 09:11:37 +0200 Subject: [PATCH 17/40] Linting --- kpops/pipeline_generator/pipeline.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index eec58b430..2db7c5243 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -124,7 +124,6 @@ def __init__( self.__generate_graph() self.validate() - @classmethod def load_from_yaml( cls, @@ -224,8 +223,6 @@ def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: ] return all_input_topics - - def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components From 147ff746cc9b06503f5121537d5a253cc7ce6fcc Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 09:13:48 +0200 Subject: [PATCH 18/40] Format --- tests/components/test_producer_app.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/components/test_producer_app.py b/tests/components/test_producer_app.py index a95811ce5..1892a1368 100644 --- a/tests/components/test_producer_app.py +++ b/tests/components/test_producer_app.py @@ -241,7 +241,9 @@ async def test_should_clean_producer_app_and_deploy_clean_up_job_and_delete_clea ), ] - def test_get_output_topics(self, config: PipelineConfig, handlers: ComponentHandlers): + def test_get_output_topics( + self, config: PipelineConfig, handlers: ComponentHandlers + ): producer_app = ProducerApp( name=self.PRODUCER_APP_NAME, config=config, @@ -268,4 +270,6 @@ def test_get_output_topics(self, config: PipelineConfig, handlers: ComponentHand ) assert producer_app.get_output_topic() == "${output_topic_name}" - assert producer_app.get_extra_output_topics() == {"first-extra-topic": "extra-topic-1"} + assert producer_app.get_extra_output_topics() == { + "first-extra-topic": "extra-topic-1" + } From e9f871264c0b84cb0932fb4fe3a51d18fc735b8c Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 14:52:34 +0200 Subject: [PATCH 19/40] Add more graph tests --- .../base_components/pipeline_component.py | 10 ++++-- kpops/pipeline_generator/pipeline.py | 16 ++++----- .../same-topic-and-component-name/config.yaml | 7 ++++ .../defaults.yaml | 35 +++++++++++++++++++ .../pipeline.yaml | 17 +++++++++ .../simple-pipeline/config.yaml | 7 ++++ .../simple-pipeline/defaults.yaml | 35 +++++++++++++++++++ .../simple-pipeline/pipeline.yaml | 13 +++++++ tests/pipeline/test_pipeline.py | 32 +++++++++++++++-- 9 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml create mode 100644 tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml create mode 100644 tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml create mode 100644 tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/config.yaml create mode 100644 tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml create mode 100644 tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 789b29322..73a641e1b 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -77,14 +77,18 @@ def __init__(self, **kwargs) -> None: def get_input_topics(self) -> list[str] | None: """ - Get all the input topics + Get all the input topics from config. """ def get_extra_output_topics(self) -> dict[str, str] | None: - ... + """ + Get extra output topics list from config. + """ def get_extra_input_topics(self) -> dict[str, list[str]] | None: - ... + """ + Get extra input topics list from config. + """ def get_output_topic(self) -> str | None: ... diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 2db7c5243..85832c7c7 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -36,7 +36,7 @@ class PipelineComponents(BaseModel): """Stores the pipeline components""" components: list[PipelineComponent] = [] - graph_components: nx.DiGraph = Field(default=nx.DiGraph(), exclude=True) + graph: nx.DiGraph = Field(default=nx.DiGraph(), exclude=True) class Config: arbitrary_types_allowed = True @@ -65,8 +65,8 @@ def __len__(self) -> int: return len(self.components) def validate_graph_components(self) -> None: - if not nx.is_directed_acyclic_graph(self.graph_components): - raise ValueError("Component graph contain loops!") + if not nx.is_directed_acyclic_graph(self.graph): + raise ValueError("Pipeline contains cycles.") def validate_unique_names(self) -> None: step_names = [component.name for component in self.components] @@ -176,7 +176,7 @@ def __generate_graph(self): all_output_topics = self.__get_all_output_topics(component) component_node_name = self.__get_vertex_component_name(component) - self.components.graph_components.add_node(component_node_name) + self.components.graph.add_node(component_node_name) self.__add_ingoing_edges(all_input_topics, component_node_name) self.__add_outgoing_edges(all_output_topics, component_node_name) @@ -185,15 +185,15 @@ def __add_outgoing_edges( self, all_output_topics: list[str], component_node_name: str ) -> None: for output_topic in all_output_topics: - self.components.graph_components.add_node(output_topic) - self.components.graph_components.add_edge(component_node_name, output_topic) + self.components.graph.add_node(output_topic) + self.components.graph.add_edge(component_node_name, output_topic) def __add_ingoing_edges( self, all_input_topics: list[str], component_node_name: str ) -> None: for input_topic in all_input_topics: - self.components.graph_components.add_node(input_topic) - self.components.graph_components.add_edge(input_topic, component_node_name) + self.components.graph.add_node(input_topic) + self.components.graph.add_edge(input_topic, component_node_name) def __get_vertex_component_name(self, component: PipelineComponent) -> str: component_vertex_name = f"component-{component.name}" diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml new file mode 100644 index 000000000..55f990f7b --- /dev/null +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml @@ -0,0 +1,7 @@ +environment: development +defaults_path: .. +brokers: "broker:9092" +helm_diff_config: + enable: false +kafka_connect_host: "kafka_connect_host:8083" +kafka_rest_host: "kafka_rest_host:8082" diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml new file mode 100644 index 000000000..07cea9c4c --- /dev/null +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml @@ -0,0 +1,35 @@ +pipeline-component: + prefix: "" + +kubernetes-app: + namespace: example-namespace + +kafka-connector: + namespace: example-namespace + +kafka-app: + app: + streams: + brokers: 127.0.0.1:9092 + schemaRegistryUrl: 127.0.0.1:8081 + optimizeLeaveGroupBehavior: false + +streams-app: + app: + labels: + pipeline: ${pipeline_name} + streams: + optimizeLeaveGroupBehavior: false + + +producer: + to: + topics: + ${output_topic_name}: + type: output + valueSchema: com.bakdata.fake.Produced + partitions_count: 12 + configs: + cleanup.policy: compact,delete + models: + "com/bakdata/kafka/fake": 1.0.0 \ No newline at end of file diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml new file mode 100644 index 000000000..6c7545084 --- /dev/null +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml @@ -0,0 +1,17 @@ +- type: producer + name: app1 + app: + resources: + limits: + memory: 2G + requests: + memory: 2G + +- type: streams-app + name: app2-processor + app: + image: some-image + to: + topics: + app2-processor: + type: output \ No newline at end of file diff --git a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/config.yaml b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/config.yaml new file mode 100644 index 000000000..55f990f7b --- /dev/null +++ b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/config.yaml @@ -0,0 +1,7 @@ +environment: development +defaults_path: .. +brokers: "broker:9092" +helm_diff_config: + enable: false +kafka_connect_host: "kafka_connect_host:8083" +kafka_rest_host: "kafka_rest_host:8082" diff --git a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml new file mode 100644 index 000000000..07cea9c4c --- /dev/null +++ b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml @@ -0,0 +1,35 @@ +pipeline-component: + prefix: "" + +kubernetes-app: + namespace: example-namespace + +kafka-connector: + namespace: example-namespace + +kafka-app: + app: + streams: + brokers: 127.0.0.1:9092 + schemaRegistryUrl: 127.0.0.1:8081 + optimizeLeaveGroupBehavior: false + +streams-app: + app: + labels: + pipeline: ${pipeline_name} + streams: + optimizeLeaveGroupBehavior: false + + +producer: + to: + topics: + ${output_topic_name}: + type: output + valueSchema: com.bakdata.fake.Produced + partitions_count: 12 + configs: + cleanup.policy: compact,delete + models: + "com/bakdata/kafka/fake": 1.0.0 \ No newline at end of file diff --git a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml new file mode 100644 index 000000000..e8c702e6f --- /dev/null +++ b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml @@ -0,0 +1,13 @@ +- type: producer + name: app1 + app: + resources: + limits: + memory: 2G + requests: + memory: 2G + +- type: streams-app + name: app2 + app: + image: some-image diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 26486cc76..934fe05e4 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -6,7 +6,7 @@ from typer.testing import CliRunner import kpops -from kpops.cli.main import app +from kpops.cli.main import app, create_pipeline_config, setup_pipeline from kpops.pipeline_generator.pipeline import ParsingException, ValidationError runner = CliRunner() @@ -482,7 +482,7 @@ def test_validate_unique_step_names(self): ) def test_validate_loops_on_pipeline(self): - with pytest.raises(ValueError, match="Component graph contain loops!"): + with pytest.raises(ValueError, match="Pipeline contains cycles."): runner.invoke( app, [ @@ -495,3 +495,31 @@ def test_validate_loops_on_pipeline(self): ], catch_exceptions=False, ) + + def test_validate_simple_graph(self): + pipeline = kpops.generate( + RESOURCE_PATH / "pipelines-with-graphs/simple-pipeline/pipeline.yaml", + pipeline_base_dir=PIPELINE_BASE_DIR_PATH, + defaults=RESOURCE_PATH / "pipelines-with-graphs" / "simple-pipeline", + ) + assert len(pipeline.components) == 2 + assert len(pipeline.components.graph.nodes) == 3 + assert len(pipeline.components.graph.edges) == 2 + node_components = list( + filter(lambda x: "component" in x, pipeline.components.graph.nodes) + ) + assert len(pipeline.components) == len(node_components) + + def test_validate_topic_and_component_same_name(self): + pipeline = kpops.generate( + RESOURCE_PATH + / "pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml", + pipeline_base_dir=PIPELINE_BASE_DIR_PATH, + defaults=RESOURCE_PATH + / "pipelines-with-graphs" + / "same-topic-and-component-name", + ) + nodes = list(pipeline.components.graph.nodes) + edges = list(pipeline.components.graph.edges) + assert nodes[2] == f"component-{nodes[3]}" + assert (nodes[2], nodes[3]) in edges From d35bc4115bf0efd8e10b2fc538a63136f1da37e3 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 14:54:15 +0200 Subject: [PATCH 20/40] Remove unused --- tests/pipeline/test_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 934fe05e4..46554b658 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -6,7 +6,7 @@ from typer.testing import CliRunner import kpops -from kpops.cli.main import app, create_pipeline_config, setup_pipeline +from kpops.cli.main import app from kpops.pipeline_generator.pipeline import ParsingException, ValidationError runner = CliRunner() From 5262f1705d7b909da3ed4e70a91f1e28de9aa9a2 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 15:50:27 +0200 Subject: [PATCH 21/40] Implement comments --- .../same-topic-and-component-name/config.yaml | 1 + .../same-topic-and-component-name/defaults.yaml | 2 +- .../same-topic-and-component-name/pipeline.yaml | 11 +---------- .../simple-pipeline/defaults.yaml | 2 +- tests/pipeline/test_pipeline.py | 8 ++++---- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml index 55f990f7b..5c19b0e89 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/config.yaml @@ -5,3 +5,4 @@ helm_diff_config: enable: false kafka_connect_host: "kafka_connect_host:8083" kafka_rest_host: "kafka_rest_host:8082" + diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml index 07cea9c4c..e38af3f17 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml @@ -32,4 +32,4 @@ producer: configs: cleanup.policy: compact,delete models: - "com/bakdata/kafka/fake": 1.0.0 \ No newline at end of file + "com/bakdata/kafka/fake": 1.0.0 diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml index 6c7545084..5e578f0a2 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/pipeline.yaml @@ -1,12 +1,3 @@ -- type: producer - name: app1 - app: - resources: - limits: - memory: 2G - requests: - memory: 2G - - type: streams-app name: app2-processor app: @@ -14,4 +5,4 @@ to: topics: app2-processor: - type: output \ No newline at end of file + type: output diff --git a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml index 07cea9c4c..e38af3f17 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml @@ -32,4 +32,4 @@ producer: configs: cleanup.policy: compact,delete models: - "com/bakdata/kafka/fake": 1.0.0 \ No newline at end of file + "com/bakdata/kafka/fake": 1.0.0 diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 46554b658..2898b0098 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -506,7 +506,7 @@ def test_validate_simple_graph(self): assert len(pipeline.components.graph.nodes) == 3 assert len(pipeline.components.graph.edges) == 2 node_components = list( - filter(lambda x: "component" in x, pipeline.components.graph.nodes) + filter(lambda node_id: "component" in node_id, pipeline.components.graph.nodes) ) assert len(pipeline.components) == len(node_components) @@ -519,7 +519,7 @@ def test_validate_topic_and_component_same_name(self): / "pipelines-with-graphs" / "same-topic-and-component-name", ) - nodes = list(pipeline.components.graph.nodes) + component, topic = list(pipeline.components.graph.nodes) edges = list(pipeline.components.graph.edges) - assert nodes[2] == f"component-{nodes[3]}" - assert (nodes[2], nodes[3]) in edges + assert component == f"component-{topic}" + assert (component, topic) in edges From f81d573e6cfe449b76a19374b8968bb1b9f752cc Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 15:51:07 +0200 Subject: [PATCH 22/40] Reformat --- tests/pipeline/test_pipeline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 2898b0098..0114f715c 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -506,7 +506,9 @@ def test_validate_simple_graph(self): assert len(pipeline.components.graph.nodes) == 3 assert len(pipeline.components.graph.edges) == 2 node_components = list( - filter(lambda node_id: "component" in node_id, pipeline.components.graph.nodes) + filter( + lambda node_id: "component" in node_id, pipeline.components.graph.nodes + ) ) assert len(pipeline.components) == len(node_components) From 3ced2f6a3e2f78ae2230fea5e11ffa2837b3e82e Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 5 Sep 2023 16:57:36 +0200 Subject: [PATCH 23/40] Implement changes --- kpops/pipeline_generator/pipeline.py | 29 ++++++++++++--------------- tests/components/test_producer_app.py | 1 + 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 85832c7c7..83a66dd0c 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -5,6 +5,7 @@ from collections import Counter from collections.abc import Iterator from contextlib import suppress +from itertools import chain from pathlib import Path import networkx as nx @@ -170,7 +171,7 @@ def load_from_yaml( pipeline = cls(main_content, env_content, registry, config, handlers) return pipeline - def __generate_graph(self): + def __generate_graph(self) -> None: for component in self.components: all_input_topics = self.__get_all_input_topics(component) all_output_topics = self.__get_all_output_topics(component) @@ -195,18 +196,18 @@ def __add_ingoing_edges( self.components.graph.add_node(input_topic) self.components.graph.add_edge(input_topic, component_node_name) - def __get_vertex_component_name(self, component: PipelineComponent) -> str: - component_vertex_name = f"component-{component.name}" - return component_vertex_name + @staticmethod + def __get_vertex_component_name(component: PipelineComponent) -> str: + return f"component-{component.name}" def __get_all_output_topics(self, component: PipelineComponent) -> list[str]: all_output_topics: list[str] = [] - output_topics = component.get_output_topic() + output_topic = component.get_output_topic() extra_output_topics = component.get_extra_output_topics() - if output_topics is not None: - all_output_topics += [output_topics] - if extra_output_topics is not None and extra_output_topics: - all_output_topics += list(extra_output_topics.values()) + if output_topic is not None: + all_output_topics.append(output_topic) + if extra_output_topics: + all_output_topics.extend(list(extra_output_topics.values())) return all_output_topics def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: @@ -214,13 +215,9 @@ def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: extra_input_topics = component.get_extra_input_topics() all_input_topics: list[str] = [] if input_topics is not None: - all_input_topics += input_topics - if extra_input_topics is not None and extra_input_topics: - all_input_topics += [ - topic - for list_topics in extra_input_topics.values() - for topic in list_topics - ] + all_input_topics.extend(input_topics) + if extra_input_topics: + all_input_topics.extend(chain(*extra_input_topics.values())) return all_input_topics def parse_components(self, component_list: list[dict]) -> None: diff --git a/tests/components/test_producer_app.py b/tests/components/test_producer_app.py index 1892a1368..a2e6c293c 100644 --- a/tests/components/test_producer_app.py +++ b/tests/components/test_producer_app.py @@ -273,3 +273,4 @@ def test_get_output_topics( assert producer_app.get_extra_output_topics() == { "first-extra-topic": "extra-topic-1" } + assert producer_app.get_input_topics() is None From 35b7d8ca281556173200ff7cfe634c9f03c479eb Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 11 Sep 2023 12:42:55 +0200 Subject: [PATCH 24/40] Implement changes --- kpops/pipeline_generator/pipeline.py | 100 +++++++++++++-------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 83a66dd0c..a00ec7a55 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -77,6 +77,55 @@ def validate_unique_names(self) -> None: f"step names should be unique. duplicate step names: {', '.join(duplicates)}" ) + def generate_graph(self) -> None: + for component in self.components: + all_input_topics = self.__get_all_input_topics(component) + all_output_topics = self.__get_all_output_topics(component) + + component_node_name = self.__get_vertex_component_name(component) + self.graph.add_node(component_node_name) + + self.__add_ingoing_edges(all_input_topics, component_node_name) + self.__add_outgoing_edges(all_output_topics, component_node_name) + + def __add_outgoing_edges( + self, all_output_topics: list[str], component_node_name: str + ) -> None: + for output_topic in all_output_topics: + self.graph.add_node(output_topic) + self.graph.add_edge(component_node_name, output_topic) + + def __add_ingoing_edges( + self, all_input_topics: list[str], component_node_name: str + ) -> None: + for input_topic in all_input_topics: + self.graph.add_node(input_topic) + self.graph.add_edge(input_topic, component_node_name) + + @staticmethod + def __get_vertex_component_name(component: PipelineComponent) -> str: + return f"component-{component.name}" + + def __get_all_output_topics(self, component: PipelineComponent) -> list[str]: + all_output_topics: list[str] = [] + output_topic = component.get_output_topic() + extra_output_topics = component.get_extra_output_topics() + if output_topic is not None: + all_output_topics.append(output_topic) + if extra_output_topics: + all_output_topics.extend(list(extra_output_topics.values())) + return all_output_topics + + def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: + input_topics = component.get_input_topics() + extra_input_topics = component.get_extra_input_topics() + all_input_topics: list[str] = [] + if input_topics is not None: + all_input_topics.extend(input_topics) + if extra_input_topics: + all_input_topics.extend(chain(*extra_input_topics.values())) + return all_input_topics + @staticmethod def _populate_component_name(component: PipelineComponent) -> None: component.name = component.prefix + component.name @@ -122,7 +171,7 @@ def __init__( self.registry = registry self.env_components_index = create_env_components_index(environment_components) self.parse_components(component_list) - self.__generate_graph() + self.components.generate_graph() self.validate() @classmethod @@ -171,55 +220,6 @@ def load_from_yaml( pipeline = cls(main_content, env_content, registry, config, handlers) return pipeline - def __generate_graph(self) -> None: - for component in self.components: - all_input_topics = self.__get_all_input_topics(component) - all_output_topics = self.__get_all_output_topics(component) - - component_node_name = self.__get_vertex_component_name(component) - self.components.graph.add_node(component_node_name) - - self.__add_ingoing_edges(all_input_topics, component_node_name) - self.__add_outgoing_edges(all_output_topics, component_node_name) - - def __add_outgoing_edges( - self, all_output_topics: list[str], component_node_name: str - ) -> None: - for output_topic in all_output_topics: - self.components.graph.add_node(output_topic) - self.components.graph.add_edge(component_node_name, output_topic) - - def __add_ingoing_edges( - self, all_input_topics: list[str], component_node_name: str - ) -> None: - for input_topic in all_input_topics: - self.components.graph.add_node(input_topic) - self.components.graph.add_edge(input_topic, component_node_name) - - @staticmethod - def __get_vertex_component_name(component: PipelineComponent) -> str: - return f"component-{component.name}" - - def __get_all_output_topics(self, component: PipelineComponent) -> list[str]: - all_output_topics: list[str] = [] - output_topic = component.get_output_topic() - extra_output_topics = component.get_extra_output_topics() - if output_topic is not None: - all_output_topics.append(output_topic) - if extra_output_topics: - all_output_topics.extend(list(extra_output_topics.values())) - return all_output_topics - - def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: - input_topics = component.get_input_topics() - extra_input_topics = component.get_extra_input_topics() - all_input_topics: list[str] = [] - if input_topics is not None: - all_input_topics.extend(input_topics) - if extra_input_topics: - all_input_topics.extend(chain(*extra_input_topics.values())) - return all_input_topics - def parse_components(self, component_list: list[dict]) -> None: """Instantiate, enrich and inflate a list of components From 20e0c09d085ba43141253e881fd959b41fc6f838 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 11 Sep 2023 15:04:44 +0200 Subject: [PATCH 25/40] Replace link --- docs/docs/resources/examples/defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/examples/defaults.md b/docs/docs/resources/examples/defaults.md index 2b4525493..c4a1add01 100644 --- a/docs/docs/resources/examples/defaults.md +++ b/docs/docs/resources/examples/defaults.md @@ -9,7 +9,7 @@ --8<-- ``` -## [Word-count Pipeline](https://github.com/bakdata/kpops-examples/tree/main/word-count/deployment/kpops/defaults){target=_blank} +## [Word-count Pipeline](https://github.com/bakdata/kpops-examples/tree/main/word-count/deployment/kpops){target=_blank} ??? example "defaults.yaml" ```yaml From 510de2f5eb47bb601b432bd38c12495e8ccfa53e Mon Sep 17 00:00:00 2001 From: Ivan Yordanov Date: Mon, 11 Sep 2023 14:55:16 +0300 Subject: [PATCH 26/40] Fix link to kpops-examples (#357) --- docs/docs/resources/examples/defaults.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/docs/resources/examples/defaults.md b/docs/docs/resources/examples/defaults.md index c4a1add01..8a643e1aa 100644 --- a/docs/docs/resources/examples/defaults.md +++ b/docs/docs/resources/examples/defaults.md @@ -9,11 +9,18 @@ --8<-- ``` + + ## [Word-count Pipeline](https://github.com/bakdata/kpops-examples/tree/main/word-count/deployment/kpops){target=_blank} + + ??? example "defaults.yaml" ```yaml - --8<-- - https://raw.githubusercontent.com/bakdata/kpops-examples/main/word-count/deployment/kpops/defaults/defaults.yaml - --8<-- + --8<-- + https://raw.githubusercontent.com/bakdata/kpops-examples/main/word-count/deployment/kpops/defaults.yaml + --8<-- ``` + + + From f1dbe1f9a54ee5f9196764fd30da61dabc982098 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 12 Sep 2023 08:39:43 +0200 Subject: [PATCH 27/40] Fix docstring --- .../base_components/pipeline_component.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 73a641e1b..d2348d9cd 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -76,22 +76,16 @@ def __init__(self, **kwargs) -> None: self.set_output_topics() def get_input_topics(self) -> list[str] | None: - """ - Get all the input topics from config. - """ + """Get all the input topics from config.""" def get_extra_output_topics(self) -> dict[str, str] | None: - """ - Get extra output topics list from config. - """ + """Get extra output topics list from config.""" def get_extra_input_topics(self) -> dict[str, list[str]] | None: - """ - Get extra input topics list from config. - """ + """Get extra input topics list from config.""" def get_output_topic(self) -> str | None: - ... + """Get output topic from config.""" def add_input_topics(self, topics: list[str]) -> None: """Add given topics to the list of input topics. From 931731bdc7893f7baee4dd98afe03de0c5f28249 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 12 Sep 2023 08:51:00 +0200 Subject: [PATCH 28/40] Join tests --- tests/components/test_streams_app.py | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/tests/components/test_streams_app.py b/tests/components/test_streams_app.py index 32c829bea..05c081104 100644 --- a/tests/components/test_streams_app.py +++ b/tests/components/test_streams_app.py @@ -431,7 +431,7 @@ async def test_should_clean_streams_app_and_deploy_clean_up_job_and_delete_clean ] @pytest.mark.asyncio - async def test_get_topics( + async def test_get_input_output_topics( self, config: PipelineConfig, handlers: ComponentHandlers ): streams_app = StreamsApp( @@ -458,6 +458,7 @@ async def test_get_topics( }, } }, + "to": {"topics": {"example-output": {"type": "output"}}}, }, ) assert streams_app.get_input_topics() == ["example-input", "b", "a"] @@ -465,26 +466,4 @@ async def test_get_topics( "role1": ["topic-extra"], "role2": ["topic-extra2", "topic-extra3"], } - - @pytest.mark.asyncio - async def test_get_output_topic( - self, config: PipelineConfig, handlers: ComponentHandlers - ): - streams_app = StreamsApp( - name=self.STREAMS_APP_NAME, - config=config, - handlers=handlers, - **{ - "namespace": "test-namespace", - "app": { - "streams": {"brokers": "fake-broker:9092"}, - }, - "from": { - "topics": { - "example-input": {"type": "input"}, - } - }, - "to": {"topics": {"example-output": {"type": "output"}}}, - }, - ) assert streams_app.get_output_topic() == "example-output" From 0052cd1dd91898505a57fcd2bd80a7b3998b214c Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 12 Sep 2023 09:13:38 +0200 Subject: [PATCH 29/40] Increase timeout --- tests/pipeline/test_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 0114f715c..c4e06630f 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -160,7 +160,7 @@ def test_substitute_in_component(self, snapshot: SnapshotTest): snapshot.assert_match(enriched_pipeline, "test-pipeline") - @pytest.mark.timeout(0.5) + @pytest.mark.timeout(2) def test_substitute_in_component_infinite_loop(self): with pytest.raises((ValueError, ParsingException)): runner.invoke( From f9cc88a5c77721cbe0c70a4217ccec90d624cc50 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 12 Sep 2023 10:48:07 +0200 Subject: [PATCH 30/40] Save progress --- .../base_components/pipeline_component.py | 6 +++--- kpops/pipeline_generator/pipeline.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index d2348d9cd..62b2877db 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -78,15 +78,15 @@ def __init__(self, **kwargs) -> None: def get_input_topics(self) -> list[str] | None: """Get all the input topics from config.""" - def get_extra_output_topics(self) -> dict[str, str] | None: - """Get extra output topics list from config.""" - def get_extra_input_topics(self) -> dict[str, list[str]] | None: """Get extra input topics list from config.""" def get_output_topic(self) -> str | None: """Get output topic from config.""" + def get_extra_output_topics(self) -> dict[str, str] | None: + """Get extra output topics list from config.""" + def add_input_topics(self, topics: list[str]) -> None: """Add given topics to the list of input topics. diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index a00ec7a55..acd9d61b1 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -65,7 +65,7 @@ def __iter__(self) -> Iterator[PipelineComponent]: def __len__(self) -> int: return len(self.components) - def validate_graph_components(self) -> None: + def validate_graph(self) -> None: if not nx.is_directed_acyclic_graph(self.graph): raise ValueError("Pipeline contains cycles.") @@ -86,14 +86,14 @@ def generate_graph(self) -> None: self.graph.add_node(component_node_name) self.__add_ingoing_edges(all_input_topics, component_node_name) - self.__add_outgoing_edges(all_output_topics, component_node_name) + self.__add_output(all_output_topics, component_node_name) - def __add_outgoing_edges( - self, all_output_topics: list[str], component_node_name: str + def __add_output( + self, all_output_topics: list[str], source: str ) -> None: for output_topic in all_output_topics: self.graph.add_node(output_topic) - self.graph.add_edge(component_node_name, output_topic) + self.graph.add_edge(source, output_topic) def __add_ingoing_edges( self, all_input_topics: list[str], component_node_name: str @@ -104,7 +104,7 @@ def __add_ingoing_edges( @staticmethod def __get_vertex_component_name(component: PipelineComponent) -> str: - return f"component-{component.name}" + return f"component-{component.full_name}" def __get_all_output_topics(self, component: PipelineComponent) -> list[str]: all_output_topics: list[str] = [] @@ -387,7 +387,7 @@ def substitute_in_component(self, component_as_dict: dict) -> dict: def validate(self) -> None: self.components.validate_unique_names() - self.components.validate_graph_components() + self.components.validate_graph() @staticmethod def pipeline_filename_environment(path: Path, config: PipelineConfig) -> Path: From 184bc43c0fcd7157a350e2890e1ef419d762a9e9 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 12 Sep 2023 13:45:47 +0200 Subject: [PATCH 31/40] Implement changes --- .../base_components/pipeline_component.py | 30 ++++++++++++++++++ kpops/pipeline_generator/pipeline.py | 31 ++----------------- tests/components/test_producer_app.py | 6 ++-- tests/components/test_streams_app.py | 11 ++++--- .../pipeline-with-loop/defaults.yaml | 3 -- .../pipeline-with-loop/pipeline.yaml | 2 +- .../defaults.yaml | 8 ----- .../simple-pipeline/defaults.yaml | 11 ++----- .../simple-pipeline/pipeline.yaml | 2 +- 9 files changed, 46 insertions(+), 58 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 5ab9a79f3..a72f11d40 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -1,6 +1,8 @@ from __future__ import annotations from abc import ABC +from itertools import chain +from typing import Iterator from pydantic import Extra, Field @@ -128,6 +130,34 @@ def set_input_topics(self) -> None: for name, topic in self.from_.topics.items(): self.apply_from_inputs(name, topic) + def __get_all_input_topics(self) -> list[str]: + input_topics = self.get_input_topics() + extra_input_topics = self.get_extra_input_topics() + all_input_topics: list[str] = [] + if input_topics is not None: + all_input_topics.extend(input_topics) + if extra_input_topics: + all_input_topics.extend(chain(*extra_input_topics.values())) + return all_input_topics + + @property + def input_topics(self) -> Iterator[str]: + yield from self.__get_all_input_topics() + + def __get_all_output_topics(self) -> list[str]: + all_output_topics: list[str] = [] + output_topic = self.get_output_topic() + extra_output_topics = self.get_extra_output_topics() + if output_topic is not None: + all_output_topics.append(output_topic) + if extra_output_topics: + all_output_topics.extend(list(extra_output_topics.values())) + return all_output_topics + + @property + def output_topics(self): + yield from self.__get_all_output_topics() + def apply_from_inputs(self, name: str, topic: FromTopic) -> None: """Add a `from` section input to the component config diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 21aa9f86e..d9e69e752 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -79,18 +79,13 @@ def validate_unique_names(self) -> None: def generate_graph(self) -> None: for component in self.components: - all_input_topics = self.__get_all_input_topics(component) - all_output_topics = self.__get_all_output_topics(component) - component_node_name = self.__get_vertex_component_name(component) self.graph.add_node(component_node_name) - self.__add_ingoing_edges(all_input_topics, component_node_name) - self.__add_output(all_output_topics, component_node_name) + self.__add_ingoing_edges(list(component.input_topics), component_node_name) + self.__add_output(list(component.output_topics), component_node_name) - def __add_output( - self, all_output_topics: list[str], source: str - ) -> None: + def __add_output(self, all_output_topics: list[str], source: str) -> None: for output_topic in all_output_topics: self.graph.add_node(output_topic) self.graph.add_edge(source, output_topic) @@ -106,26 +101,6 @@ def __add_ingoing_edges( def __get_vertex_component_name(component: PipelineComponent) -> str: return f"component-{component.full_name}" - def __get_all_output_topics(self, component: PipelineComponent) -> list[str]: - all_output_topics: list[str] = [] - output_topic = component.get_output_topic() - extra_output_topics = component.get_extra_output_topics() - if output_topic is not None: - all_output_topics.append(output_topic) - if extra_output_topics: - all_output_topics.extend(list(extra_output_topics.values())) - return all_output_topics - - def __get_all_input_topics(self, component: PipelineComponent) -> list[str]: - input_topics = component.get_input_topics() - extra_input_topics = component.get_extra_input_topics() - all_input_topics: list[str] = [] - if input_topics is not None: - all_input_topics.extend(input_topics) - if extra_input_topics: - all_input_topics.extend(chain(*extra_input_topics.values())) - return all_input_topics - @staticmethod def _populate_component_name(component: PipelineComponent) -> None: # TODO: remove with suppress( diff --git a/tests/components/test_producer_app.py b/tests/components/test_producer_app.py index 40cf28f1f..1b168b105 100644 --- a/tests/components/test_producer_app.py +++ b/tests/components/test_producer_app.py @@ -249,7 +249,9 @@ async def test_should_clean_producer_app_and_deploy_clean_up_job_and_delete_clea ] def test_get_output_topics( - self, config: PipelineConfig, handlers: ComponentHandlers + self, + config: PipelineConfig, + handlers: ComponentHandlers, ): producer_app = ProducerApp( name=self.PRODUCER_APP_NAME, @@ -267,7 +269,6 @@ def test_get_output_topics( type=OutputTopicTypes.OUTPUT, partitions_count=10 ), "extra-topic-1": TopicConfig( - type=OutputTopicTypes.EXTRA, role="first-extra-topic", partitions_count=10, ), @@ -275,7 +276,6 @@ def test_get_output_topics( }, }, ) - assert producer_app.get_output_topic() == "${output_topic_name}" assert producer_app.get_extra_output_topics() == { "first-extra-topic": "extra-topic-1" diff --git a/tests/components/test_streams_app.py b/tests/components/test_streams_app.py index ab6e91e19..9f9d30f97 100644 --- a/tests/components/test_streams_app.py +++ b/tests/components/test_streams_app.py @@ -462,12 +462,12 @@ async def test_get_input_output_topics( "example-input": {"type": "input"}, "b": {"type": "input"}, "a": {"type": "input"}, - "topic-extra2": {"type": "extra", "role": "role2"}, - "topic-extra3": {"type": "extra", "role": "role2"}, - "topic-extra": {"type": "extra", "role": "role1"}, - ".*": {"type": "input-pattern"}, + "topic-extra2": {"role": "role2"}, + "topic-extra3": {"role": "role2"}, + "topic-extra": {"role": "role1"}, + ".*": {"type": "pattern"}, "example.*": { - "type": "extra-pattern", + "type": "pattern", "role": "another-pattern", }, } @@ -475,6 +475,7 @@ async def test_get_input_output_topics( "to": {"topics": {"example-output": {"type": "output"}}}, }, ) + assert streams_app.get_input_topics() == ["example-input", "b", "a"] assert streams_app.get_extra_input_topics() == { "role1": ["topic-extra"], diff --git a/tests/pipeline/resources/pipeline-with-loop/defaults.yaml b/tests/pipeline/resources/pipeline-with-loop/defaults.yaml index dee463477..a51f34a2d 100644 --- a/tests/pipeline/resources/pipeline-with-loop/defaults.yaml +++ b/tests/pipeline/resources/pipeline-with-loop/defaults.yaml @@ -12,11 +12,8 @@ kafka-app: streams: brokers: 127.0.0.1:9092 schemaRegistryUrl: 127.0.0.1:8081 - optimizeLeaveGroupBehavior: false streams-app: app: labels: pipeline: ${pipeline_name} - streams: - optimizeLeaveGroupBehavior: false diff --git a/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml b/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml index d46cdd754..b8f2866f6 100644 --- a/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml +++ b/tests/pipeline/resources/pipeline-with-loop/pipeline.yaml @@ -1,4 +1,4 @@ -- type: producer +- type: producer-app name: app1 app: image: producer-image diff --git a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml index e38af3f17..d8144f063 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/same-topic-and-component-name/defaults.yaml @@ -12,24 +12,16 @@ kafka-app: streams: brokers: 127.0.0.1:9092 schemaRegistryUrl: 127.0.0.1:8081 - optimizeLeaveGroupBehavior: false streams-app: app: labels: pipeline: ${pipeline_name} - streams: - optimizeLeaveGroupBehavior: false - producer: to: topics: ${output_topic_name}: type: output - valueSchema: com.bakdata.fake.Produced - partitions_count: 12 configs: cleanup.policy: compact,delete - models: - "com/bakdata/kafka/fake": 1.0.0 diff --git a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml index e38af3f17..fbd7623d1 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/defaults.yaml @@ -12,24 +12,17 @@ kafka-app: streams: brokers: 127.0.0.1:9092 schemaRegistryUrl: 127.0.0.1:8081 - optimizeLeaveGroupBehavior: false + streams-app: app: labels: pipeline: ${pipeline_name} - streams: - optimizeLeaveGroupBehavior: false - -producer: +producer-app: to: topics: ${output_topic_name}: type: output - valueSchema: com.bakdata.fake.Produced - partitions_count: 12 configs: cleanup.policy: compact,delete - models: - "com/bakdata/kafka/fake": 1.0.0 diff --git a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml index e8c702e6f..25ddbedb9 100644 --- a/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml +++ b/tests/pipeline/resources/pipelines-with-graphs/simple-pipeline/pipeline.yaml @@ -1,4 +1,4 @@ -- type: producer +- type: producer-app name: app1 app: resources: From bd724e1664125f778c58ebeb21264ea1153da745 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Tue, 12 Sep 2023 13:48:39 +0200 Subject: [PATCH 32/40] Delete unused imports --- kpops/pipeline_generator/pipeline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index d9e69e752..c128ba3a0 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -5,7 +5,6 @@ from collections import Counter from collections.abc import Iterator from contextlib import suppress -from itertools import chain from pathlib import Path import networkx as nx From 133005a4cfcec200c51c23c8d2806c2774e49d56 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Wed, 13 Sep 2023 08:54:21 +0200 Subject: [PATCH 33/40] Implement changes --- .../base_components/pipeline_component.py | 28 +++++++++---------- .../streams_bootstrap/streams/streams_app.py | 4 +++ kpops/pipeline_generator/pipeline.py | 4 +-- tests/components/test_producer_app.py | 2 +- tests/components/test_streams_app.py | 12 +++++++- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index a72f11d40..d3aebe19c 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -62,15 +62,18 @@ def __init__(self, **kwargs) -> None: def get_input_topics(self) -> list[str] | None: """Get all the input topics from config.""" + return [] def get_extra_input_topics(self) -> dict[str, list[str]] | None: """Get extra input topics list from config.""" + return {} def get_output_topic(self) -> str | None: """Get output topic from config.""" def get_extra_output_topics(self) -> dict[str, str] | None: """Get extra output topics list from config.""" + return {} @property def full_name(self) -> str: @@ -130,19 +133,18 @@ def set_input_topics(self) -> None: for name, topic in self.from_.topics.items(): self.apply_from_inputs(name, topic) - def __get_all_input_topics(self) -> list[str]: - input_topics = self.get_input_topics() - extra_input_topics = self.get_extra_input_topics() - all_input_topics: list[str] = [] - if input_topics is not None: - all_input_topics.extend(input_topics) - if extra_input_topics: - all_input_topics.extend(chain(*extra_input_topics.values())) - return all_input_topics + @property + def inputs(self) -> Iterator[str]: + yield from self.get_input_topics() + for role_topics in chain(*self.get_extra_input_topics().values()): + yield from role_topics @property - def input_topics(self) -> Iterator[str]: - yield from self.__get_all_input_topics() + def outputs(self) -> Iterator[str]: + if self.get_output_topic() is not None: + yield self.get_output_topic() + for role_topics in self.get_extra_output_topics().values(): + yield from role_topics def __get_all_output_topics(self) -> list[str]: all_output_topics: list[str] = [] @@ -154,10 +156,6 @@ def __get_all_output_topics(self) -> list[str]: all_output_topics.extend(list(extra_output_topics.values())) return all_output_topics - @property - def output_topics(self): - yield from self.__get_all_output_topics() - def apply_from_inputs(self, name: str, topic: FromTopic) -> None: """Add a `from` section input to the component config diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index 98fafd48b..e49ec66ee 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -32,6 +32,10 @@ def get_extra_input_topics(self) -> dict[str, list[str]] | None: def get_output_topic(self) -> str | None: return self.app.streams.output_topic + @override + def get_extra_output_topics(self) -> dict[str, str] | None: + return self.app.streams.extra_output_topics + @override def add_input_topics(self, topics: list[str]) -> None: self.app.streams.add_input_topics(topics) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index c128ba3a0..52057afb3 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -81,8 +81,8 @@ def generate_graph(self) -> None: component_node_name = self.__get_vertex_component_name(component) self.graph.add_node(component_node_name) - self.__add_ingoing_edges(list(component.input_topics), component_node_name) - self.__add_output(list(component.output_topics), component_node_name) + self.__add_ingoing_edges(list(component.inputs), component_node_name) + self.__add_output(list(component.outputs), component_node_name) def __add_output(self, all_output_topics: list[str], source: str) -> None: for output_topic in all_output_topics: diff --git a/tests/components/test_producer_app.py b/tests/components/test_producer_app.py index 1b168b105..4b7d2d560 100644 --- a/tests/components/test_producer_app.py +++ b/tests/components/test_producer_app.py @@ -280,4 +280,4 @@ def test_get_output_topics( assert producer_app.get_extra_output_topics() == { "first-extra-topic": "extra-topic-1" } - assert producer_app.get_input_topics() is None + assert producer_app.get_input_topics() == [] diff --git a/tests/components/test_streams_app.py b/tests/components/test_streams_app.py index 9f9d30f97..bf067200d 100644 --- a/tests/components/test_streams_app.py +++ b/tests/components/test_streams_app.py @@ -472,7 +472,14 @@ async def test_get_input_output_topics( }, } }, - "to": {"topics": {"example-output": {"type": "output"}}}, + "to": {"topics": { + "example-output": { + "type": "output" + }, + "extra-topic":{ + "role": "fake-role" + } + }}, }, ) @@ -482,3 +489,6 @@ async def test_get_input_output_topics( "role2": ["topic-extra2", "topic-extra3"], } assert streams_app.get_output_topic() == "example-output" + assert streams_app.get_extra_output_topics() == { + "fake-role": "extra-topic" + } From b956ebc1fa05bd6309b0e27aa4175cc5ba3c492e Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 09:05:57 +0200 Subject: [PATCH 34/40] Fix test --- kpops/components/base_components/pipeline_component.py | 6 +++--- kpops/pipeline_generator/pipeline.py | 8 ++++---- .../resources/pipeline-with-short-topics/defaults.yaml | 9 ++++++++- tests/pipeline/test_pipeline.py | 4 ++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index d3aebe19c..f2fcc0b17 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -136,15 +136,15 @@ def set_input_topics(self) -> None: @property def inputs(self) -> Iterator[str]: yield from self.get_input_topics() - for role_topics in chain(*self.get_extra_input_topics().values()): + for role_topics in self.get_extra_input_topics().values(): yield from role_topics @property def outputs(self) -> Iterator[str]: if self.get_output_topic() is not None: yield self.get_output_topic() - for role_topics in self.get_extra_output_topics().values(): - yield from role_topics + yield from self.get_extra_output_topics().values() + def __get_all_output_topics(self) -> list[str]: all_output_topics: list[str] = [] diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 52057afb3..970864dfc 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -81,15 +81,15 @@ def generate_graph(self) -> None: component_node_name = self.__get_vertex_component_name(component) self.graph.add_node(component_node_name) - self.__add_ingoing_edges(list(component.inputs), component_node_name) - self.__add_output(list(component.outputs), component_node_name) + self.__add_inputs(list(component.inputs), component_node_name) + self.__add_outputs(list(component.outputs), component_node_name) - def __add_output(self, all_output_topics: list[str], source: str) -> None: + def __add_outputs(self, all_output_topics: list[str], source: str) -> None: for output_topic in all_output_topics: self.graph.add_node(output_topic) self.graph.add_edge(source, output_topic) - def __add_ingoing_edges( + def __add_inputs( self, all_input_topics: list[str], component_node_name: str ) -> None: for input_topic in all_input_topics: diff --git a/tests/pipeline/resources/pipeline-with-short-topics/defaults.yaml b/tests/pipeline/resources/pipeline-with-short-topics/defaults.yaml index 00b3b2673..8138a83a0 100644 --- a/tests/pipeline/resources/pipeline-with-short-topics/defaults.yaml +++ b/tests/pipeline/resources/pipeline-with-short-topics/defaults.yaml @@ -9,6 +9,13 @@ kafka-app: schema_registry_url: "${schema_registry_url}" version: "2.4.2" +producer-app: + to: + topics: + ${output_topic_name}: + partitions_count: 3 + + streams-app: # inherits from kafka-app app: streams: @@ -19,7 +26,7 @@ streams-app: # inherits from kafka-app type: error-topic: type: error - extra-topic: + extra-topic-output: role: role from: topics: diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 85b9978b4..ca07d391d 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -528,10 +528,10 @@ def test_short_topic_definition(self): input_components = enriched_pipeline["components"][4]["from"]["components"] assert "type" not in output_topics["output-topic"] assert output_topics["error-topic"]["type"] == "error" - assert "type" not in output_topics["extra-topic"] + assert "type" not in output_topics["extra-topic-output"] assert "role" not in output_topics["output-topic"] assert "role" not in output_topics["error-topic"] - assert output_topics["extra-topic"]["role"] == "role" + assert output_topics["extra-topic-output"]["role"] == "role" assert "type" not in ["input-topic"] assert "type" not in input_topics["extra-topic"] From df16d00331eaf22ede927561c150902d17b20890 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 09:18:03 +0200 Subject: [PATCH 35/40] Solve linting --- .../base_components/pipeline_component.py | 2 -- tests/components/test_streams_app.py | 16 ++++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index f2fcc0b17..eeebdbaf9 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -1,7 +1,6 @@ from __future__ import annotations from abc import ABC -from itertools import chain from typing import Iterator from pydantic import Extra, Field @@ -145,7 +144,6 @@ def outputs(self) -> Iterator[str]: yield self.get_output_topic() yield from self.get_extra_output_topics().values() - def __get_all_output_topics(self) -> list[str]: all_output_topics: list[str] = [] output_topic = self.get_output_topic() diff --git a/tests/components/test_streams_app.py b/tests/components/test_streams_app.py index bf067200d..81b8bef0e 100644 --- a/tests/components/test_streams_app.py +++ b/tests/components/test_streams_app.py @@ -472,14 +472,12 @@ async def test_get_input_output_topics( }, } }, - "to": {"topics": { - "example-output": { - "type": "output" - }, - "extra-topic":{ - "role": "fake-role" + "to": { + "topics": { + "example-output": {"type": "output"}, + "extra-topic": {"role": "fake-role"}, } - }}, + }, }, ) @@ -489,6 +487,4 @@ async def test_get_input_output_topics( "role2": ["topic-extra2", "topic-extra3"], } assert streams_app.get_output_topic() == "example-output" - assert streams_app.get_extra_output_topics() == { - "fake-role": "extra-topic" - } + assert streams_app.get_extra_output_topics() == {"fake-role": "extra-topic"} From 8b874094339972f0fe8158e28339c0122407c307 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 09:55:09 +0200 Subject: [PATCH 36/40] Fix pyright --- .../base_components/pipeline_component.py | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index eeebdbaf9..b12264c4e 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -1,7 +1,8 @@ from __future__ import annotations from abc import ABC -from typing import Iterator +from collections.abc import Iterator +from typing import Any, Generator from pydantic import Extra, Field @@ -59,18 +60,18 @@ def __init__(self, **kwargs) -> None: self.set_input_topics() self.set_output_topics() - def get_input_topics(self) -> list[str] | None: + def get_input_topics(self) -> list[str]: """Get all the input topics from config.""" return [] - def get_extra_input_topics(self) -> dict[str, list[str]] | None: + def get_extra_input_topics(self) -> dict[str, list[str]]: """Get extra input topics list from config.""" return {} def get_output_topic(self) -> str | None: """Get output topic from config.""" - def get_extra_output_topics(self) -> dict[str, str] | None: + def get_extra_output_topics(self) -> dict[str, str]: """Get extra output topics list from config.""" return {} @@ -140,20 +141,10 @@ def inputs(self) -> Iterator[str]: @property def outputs(self) -> Iterator[str]: - if self.get_output_topic() is not None: - yield self.get_output_topic() + if output_topic := self.get_output_topic(): + yield output_topic yield from self.get_extra_output_topics().values() - def __get_all_output_topics(self) -> list[str]: - all_output_topics: list[str] = [] - output_topic = self.get_output_topic() - extra_output_topics = self.get_extra_output_topics() - if output_topic is not None: - all_output_topics.append(output_topic) - if extra_output_topics: - all_output_topics.extend(list(extra_output_topics.values())) - return all_output_topics - def apply_from_inputs(self, name: str, topic: FromTopic) -> None: """Add a `from` section input to the component config From d73f16952f3d625890ef8212fee7a663924ffd42 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 09:59:32 +0200 Subject: [PATCH 37/40] Fix linting --- kpops/components/base_components/pipeline_component.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index b12264c4e..5444f63bc 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -2,7 +2,6 @@ from abc import ABC from collections.abc import Iterator -from typing import Any, Generator from pydantic import Extra, Field From a2a3192a001f86be0cc88f06115fbb36e55a3a4a Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 11:30:54 +0200 Subject: [PATCH 38/40] Delete from implemented methods --- kpops/components/streams_bootstrap/streams/streams_app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index e49ec66ee..6bc18ee4c 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -21,11 +21,11 @@ class StreamsApp(KafkaApp): ) @override - def get_input_topics(self) -> list[str] | None: + def get_input_topics(self) -> list[str]: return self.app.streams.input_topics @override - def get_extra_input_topics(self) -> dict[str, list[str]] | None: + def get_extra_input_topics(self) -> dict[str, list[str]]: return self.app.streams.extra_input_topics @override From 5432c8a796294ef0910a44fb8a28a3e76ccc8c67 Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 12:57:26 +0200 Subject: [PATCH 39/40] Implement changes --- kpops/pipeline_generator/pipeline.py | 25 ++++++++++++------------- tests/pipeline/test_pipeline.py | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 970864dfc..0d3967d52 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -66,7 +66,7 @@ def __len__(self) -> int: def validate_graph(self) -> None: if not nx.is_directed_acyclic_graph(self.graph): - raise ValueError("Pipeline contains cycles.") + raise ValueError("Pipeline is not a valid DAG.") def validate_unique_names(self) -> None: step_names = [component.full_name for component in self.components] @@ -81,20 +81,19 @@ def generate_graph(self) -> None: component_node_name = self.__get_vertex_component_name(component) self.graph.add_node(component_node_name) - self.__add_inputs(list(component.inputs), component_node_name) - self.__add_outputs(list(component.outputs), component_node_name) + for input_topic in component.inputs: + self.__add_input(input_topic, component_node_name) - def __add_outputs(self, all_output_topics: list[str], source: str) -> None: - for output_topic in all_output_topics: - self.graph.add_node(output_topic) - self.graph.add_edge(source, output_topic) + for output_topic in component.outputs: + self.__add_output(output_topic, component_node_name) - def __add_inputs( - self, all_input_topics: list[str], component_node_name: str - ) -> None: - for input_topic in all_input_topics: - self.graph.add_node(input_topic) - self.graph.add_edge(input_topic, component_node_name) + def __add_output(self, output_topic: str, source: str) -> None: + self.graph.add_node(output_topic) + self.graph.add_edge(source, output_topic) + + def __add_input(self, input_topic: str, component_node_name: str) -> None: + self.graph.add_node(input_topic) + self.graph.add_edge(input_topic, component_node_name) @staticmethod def __get_vertex_component_name(component: PipelineComponent) -> str: diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index ca07d391d..d60d597cd 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -589,7 +589,7 @@ def test_validate_unique_step_names(self): ) def test_validate_loops_on_pipeline(self): - with pytest.raises(ValueError, match="Pipeline contains cycles."): + with pytest.raises(ValueError, match="Pipeline is not a valid DAG."): runner.invoke( app, [ From 1e89223e9151259dda087d8b85148274d7fb8f0c Mon Sep 17 00:00:00 2001 From: Alejandro Jaramillo Date: Mon, 18 Sep 2023 15:36:37 +0200 Subject: [PATCH 40/40] Change to id --- .../components/base_components/pipeline_component.py | 4 ++++ .../streams_bootstrap/streams/streams_app.py | 2 +- kpops/pipeline_generator/pipeline.py | 11 +++-------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kpops/components/base_components/pipeline_component.py b/kpops/components/base_components/pipeline_component.py index 5444f63bc..93096255a 100644 --- a/kpops/components/base_components/pipeline_component.py +++ b/kpops/components/base_components/pipeline_component.py @@ -74,6 +74,10 @@ def get_extra_output_topics(self) -> dict[str, str]: """Get extra output topics list from config.""" return {} + @property + def id(self) -> str: + return f"component-{self.full_name}" + @property def full_name(self) -> str: return self.prefix + self.name diff --git a/kpops/components/streams_bootstrap/streams/streams_app.py b/kpops/components/streams_bootstrap/streams/streams_app.py index 6bc18ee4c..ba0c1ee39 100644 --- a/kpops/components/streams_bootstrap/streams/streams_app.py +++ b/kpops/components/streams_bootstrap/streams/streams_app.py @@ -33,7 +33,7 @@ def get_output_topic(self) -> str | None: return self.app.streams.output_topic @override - def get_extra_output_topics(self) -> dict[str, str] | None: + def get_extra_output_topics(self) -> dict[str, str]: return self.app.streams.extra_output_topics @override diff --git a/kpops/pipeline_generator/pipeline.py b/kpops/pipeline_generator/pipeline.py index 0d3967d52..e23a8c05f 100644 --- a/kpops/pipeline_generator/pipeline.py +++ b/kpops/pipeline_generator/pipeline.py @@ -78,14 +78,13 @@ def validate_unique_names(self) -> None: def generate_graph(self) -> None: for component in self.components: - component_node_name = self.__get_vertex_component_name(component) - self.graph.add_node(component_node_name) + self.graph.add_node(component.id) for input_topic in component.inputs: - self.__add_input(input_topic, component_node_name) + self.__add_input(input_topic, component.id) for output_topic in component.outputs: - self.__add_output(output_topic, component_node_name) + self.__add_output(output_topic, component.id) def __add_output(self, output_topic: str, source: str) -> None: self.graph.add_node(output_topic) @@ -95,10 +94,6 @@ def __add_input(self, input_topic: str, component_node_name: str) -> None: self.graph.add_node(input_topic) self.graph.add_edge(input_topic, component_node_name) - @staticmethod - def __get_vertex_component_name(component: PipelineComponent) -> str: - return f"component-{component.full_name}" - @staticmethod def _populate_component_name(component: PipelineComponent) -> None: # TODO: remove with suppress(