From 75c2872c24e66c80e9ccd77e1a21974ae074f9f1 Mon Sep 17 00:00:00 2001
From: Callum Wells <68609181+swells2020@users.noreply.github.com>
Date: Tue, 1 Aug 2023 10:04:41 +0100
Subject: [PATCH 01/10] [RPD-282] adds stack cli command (#179)
* adds tests and logic for stack and stack set cli commands
* fixes typos
* updated for comments
* addresses comments
---
src/matcha_ml/cli/cli.py | 24 ++++++++++++
src/matcha_ml/core/__init__.py | 2 +
src/matcha_ml/core/core.py | 13 ++++--
tests/test_cli/test_stack.py | 72 ++++++++++++++++++++++++++++++++++
4 files changed, 108 insertions(+), 3 deletions(-)
create mode 100644 tests/test_cli/test_stack.py
diff --git a/src/matcha_ml/cli/cli.py b/src/matcha_ml/cli/cli.py
index 4aacfdce..a1d12fac 100644
--- a/src/matcha_ml/cli/cli.py
+++ b/src/matcha_ml/cli/cli.py
@@ -27,11 +27,17 @@
app = typer.Typer(no_args_is_help=True, pretty_exceptions_show_locals=False)
analytics_app = typer.Typer(no_args_is_help=True, pretty_exceptions_show_locals=False)
+stack_app = typer.Typer(no_args_is_help=True, pretty_exceptions_show_locals=False)
app.add_typer(
analytics_app,
name="analytics",
help="Enable or disable the collection of anonymous usage data (enabled by default).",
)
+app.add_typer(
+ stack_app,
+ name="stack",
+ help="Configure the stack for Matcha to provision.",
+)
def fill_provision_variables(
@@ -242,5 +248,23 @@ def opt_in() -> None:
core.analytics_opt_in()
+@stack_app.command(help="Define the stack for Matcha to provision.")
+def set(stack: str = typer.Argument("default")) -> None:
+ """Define the stack for Matcha to provision.
+
+ Args:
+ stack (str): the name of the stack to provision.
+
+ Raises:
+ Exit: Exit if input is not a defined stack.
+ """
+ try:
+ set_stack = core.stack_set(stack)
+ print_status(build_status(f"Matcha {set_stack} stack has been set."))
+ except MatchaInputError as e:
+ print_error(str(e))
+ raise typer.Exit()
+
+
if __name__ == "__main__":
app()
diff --git a/src/matcha_ml/core/__init__.py b/src/matcha_ml/core/__init__.py
index 86d5244b..97bac49d 100644
--- a/src/matcha_ml/core/__init__.py
+++ b/src/matcha_ml/core/__init__.py
@@ -6,6 +6,7 @@
get,
provision,
remove_state_lock,
+ stack_set,
)
__all__ = [
@@ -15,4 +16,5 @@
"remove_state_lock",
"destroy",
"provision",
+ "stack_set",
]
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index 6c4e6986..6dc606f2 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -15,7 +15,6 @@
from matcha_ml.state.matcha_state import MatchaState
from matcha_ml.templates.azure_template import AzureTemplate
-
MAJOR_MINOR_ZENML_VERSION = "0.36"
@@ -23,13 +22,16 @@ def zenml_version_is_supported() -> None:
"""Check the zenml version of the local environment against the version matcha is expecting."""
try:
import zenml
+
if zenml.__version__[:3] != MAJOR_MINOR_ZENML_VERSION:
warn(
f"Matcha expects ZenML version {MAJOR_MINOR_ZENML_VERSION}.x, but you have version {zenml.__version__}."
)
except:
- warn(f"No local installation of ZenMl found. Defaulting to version {MAJOR_MINOR_ZENML_VERSION} for remote "
- f"resources.")
+ warn(
+ f"No local installation of ZenMl found. Defaulting to version {MAJOR_MINOR_ZENML_VERSION} for remote "
+ f"resources."
+ )
@track(event_name=AnalyticsEvent.GET)
@@ -259,3 +261,8 @@ def provision(
matcha_state_service = MatchaStateService()
return matcha_state_service.fetch_resources_from_state_file()
+
+
+def stack_set(stack: str) -> str:
+ """Placeholder for core matcha stack set functionality."""
+ return stack
diff --git a/tests/test_cli/test_stack.py b/tests/test_cli/test_stack.py
new file mode 100644
index 00000000..a70c8908
--- /dev/null
+++ b/tests/test_cli/test_stack.py
@@ -0,0 +1,72 @@
+"""Test suit to test the stack command and all its subcommands."""
+
+from typer.testing import CliRunner
+
+from matcha_ml.cli.cli import app
+
+INTERNAL_FUNCTION_STUB = "matcha_ml.core"
+
+
+def test_cli_stack_command_help_option(runner: CliRunner) -> None:
+ """Tests the --help option for the cli stack command.
+
+ Args:
+ runner (CliRunner): typer CLI runner
+ """
+ result = runner.invoke(app, ["stack", "--help"])
+
+ assert result.exit_code == 0
+
+ assert "Configure the stack for Matcha to provision." in result.stdout
+
+
+def test_cli_stack_command_defaults_to_help(runner: CliRunner) -> None:
+ """Tests the --help option for the cli stack command.
+
+ Args:
+ runner (CliRunner): typer CLI runner
+ """
+ result = runner.invoke(app, ["stack"])
+
+ assert result.exit_code == 0
+
+ assert "Configure the stack for Matcha to provision." in result.stdout
+
+
+def test_cli_stack_set_command_help_option(runner: CliRunner) -> None:
+ """Tests the --help option for the cli stack set sub-command.
+
+ Args:
+ runner (CliRunner): typer CLI runner
+ """
+ result = runner.invoke(app, ["stack", "set", "--help"])
+
+ assert result.exit_code == 0
+
+ assert "Define the stack for Matcha to provision." in result.stdout
+
+
+def test_cli_stack_set_command_without_args(runner: CliRunner) -> None:
+ """Tests the cli stack set sub-command.
+
+ Args:
+ runner (CliRunner): typer CLI runner
+ """
+ result = runner.invoke(app, ["stack", "set"])
+
+ assert result.exit_code == 0
+
+ assert "Matcha default stack has been set." in result.stdout
+
+
+def test_cli_stack_set_command_with_args(runner: CliRunner) -> None:
+ """Tests the cli stack set sub-command.
+
+ Args:
+ runner (CliRunner): typer CLI runner
+ """
+ result = runner.invoke(app, ["stack", "set", "test_stack"])
+
+ assert result.exit_code == 0
+
+ assert "Matcha test_stack stack has been set." in result.stdout
From 7bf865cdbb990c2a52fe80226f09df6647c92f5f Mon Sep 17 00:00:00 2001
From: Chris <32800386+Christopher-Norman@users.noreply.github.com>
Date: Wed, 2 Aug 2023 15:57:11 +0100
Subject: [PATCH 02/10] [RPD-285] Create LLM stack Terraform files (#182)
* Add initial LLM Terraform files
* Update Terraform Kubernetes Chroma deployment
* Update Terraform docs
* Revert default variables
* Add missing aks module
---
src/matcha_ml/infrastructure/llm/.gitignore | 34 ++
src/matcha_ml/infrastructure/llm/README.md | 76 +++++
.../infrastructure/llm/aks/README.md | 41 +++
src/matcha_ml/infrastructure/llm/aks/main.tf | 19 ++
.../infrastructure/llm/aks/output.tf | 46 +++
.../infrastructure/llm/aks/variables.tf | 14 +
.../llm/azure_container_registry/README.md | 36 ++
.../llm/azure_container_registry/main.tf | 13 +
.../llm/azure_container_registry/output.tf | 10 +
.../llm/azure_container_registry/variables.tf | 19 ++
.../infrastructure/llm/chroma/README.md | 29 ++
.../infrastructure/llm/chroma/main.tf | 99 ++++++
.../infrastructure/llm/configure_kubectl.tf | 12 +
.../data_version_control_storage/README.md | 44 +++
.../llm/data_version_control_storage/main.tf | 22 ++
.../data_version_control_storage/output.tf | 15 +
.../data_version_control_storage/providers.tf | 8 +
.../data_version_control_storage/variables.tf | 14 +
src/matcha_ml/infrastructure/llm/helm.tf | 10 +
.../infrastructure/llm/kubernetes.tf | 30 ++
src/matcha_ml/infrastructure/llm/main.tf | 100 ++++++
.../llm/mlflow_module/README.md | 41 +++
.../llm/mlflow_module/getURI.tf | 8 +
.../infrastructure/llm/mlflow_module/main.tf | 44 +++
.../llm/mlflow_module/output.tf | 4 +
.../llm/mlflow_module/providers.tf | 12 +
.../llm/mlflow_module/variables.tf | 29 ++
.../llm/mlflow_module/zenml_namespace.tf | 5 +
src/matcha_ml/infrastructure/llm/output.tf | 94 ++++++
src/matcha_ml/infrastructure/llm/printf.cmd | 2 +
src/matcha_ml/infrastructure/llm/providers.tf | 46 +++
.../llm/resource_group/README.md | 32 ++
.../infrastructure/llm/resource_group/main.tf | 3 +
.../llm/resource_group/output.tf | 4 +
.../llm/resource_group/variables.tf | 4 +
.../infrastructure/llm/seldon/README.md | 49 +++
.../infrastructure/llm/seldon/istio.tf | 65 ++++
.../infrastructure/llm/seldon/main.tf | 47 +++
.../infrastructure/llm/seldon/outputs.tf | 16 +
.../infrastructure/llm/seldon/permissions.tf | 39 +++
.../infrastructure/llm/seldon/providers.tf | 12 +
.../infrastructure/llm/seldon/variables.tf | 15 +
.../infrastructure/llm/storage/README.md | 44 +++
.../infrastructure/llm/storage/main.tf | 22 ++
.../infrastructure/llm/storage/output.tf | 50 +++
.../infrastructure/llm/storage/providers.tf | 8 +
.../infrastructure/llm/storage/variables.tf | 14 +
src/matcha_ml/infrastructure/llm/variables.tf | 35 ++
.../infrastructure/llm/zen_server/README.md | 69 ++++
.../infrastructure/llm/zen_server/getURL.tf | 10 +
.../infrastructure/llm/zen_server/ingress.tf | 30 ++
.../infrastructure/llm/zen_server/main.tf | 108 ++++++
.../infrastructure/llm/zen_server/outputs.tf | 19 ++
.../llm/zen_server/providers.tf | 16 +
.../infrastructure/llm/zen_server/sql.tf | 57 ++++
.../llm/zen_server/variables.tf | 168 ++++++++++
.../llm/zen_server/zenml_helm/Chart.yaml | 13 +
.../zen_server/zenml_helm/templates/NOTES.txt | 36 ++
.../zenml_helm/templates/_helpers.tpl | 70 ++++
.../zenml_helm/templates/cert-secret.yaml | 45 +++
.../zen_server/zenml_helm/templates/hpa.yaml | 28 ++
.../templates/server-deployment.yaml | 243 ++++++++++++++
.../zenml_helm/templates/server-ingress.yaml | 59 ++++
.../zenml_helm/templates/server-secret.yaml | 70 ++++
.../zenml_helm/templates/server-service.yaml | 15 +
.../zenml_helm/templates/serviceaccount.yaml | 12 +
.../templates/tests/test-connection.yaml | 15 +
.../llm/zen_server/zenml_helm/values.yaml | 311 ++++++++++++++++++
.../llm/zenml_storage/README.md | 45 +++
.../infrastructure/llm/zenml_storage/main.tf | 31 ++
.../llm/zenml_storage/output.tf | 50 +++
.../llm/zenml_storage/variables.tf | 19 ++
72 files changed, 2974 insertions(+)
create mode 100644 src/matcha_ml/infrastructure/llm/.gitignore
create mode 100644 src/matcha_ml/infrastructure/llm/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/aks/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/aks/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/aks/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/aks/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/azure_container_registry/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/azure_container_registry/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/azure_container_registry/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/azure_container_registry/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/configure_kubectl.tf
create mode 100644 src/matcha_ml/infrastructure/llm/data_version_control_storage/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/data_version_control_storage/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/data_version_control_storage/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/data_version_control_storage/providers.tf
create mode 100644 src/matcha_ml/infrastructure/llm/data_version_control_storage/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/helm.tf
create mode 100644 src/matcha_ml/infrastructure/llm/kubernetes.tf
create mode 100644 src/matcha_ml/infrastructure/llm/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/getURI.tf
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/providers.tf
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/mlflow_module/zenml_namespace.tf
create mode 100644 src/matcha_ml/infrastructure/llm/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/printf.cmd
create mode 100644 src/matcha_ml/infrastructure/llm/providers.tf
create mode 100644 src/matcha_ml/infrastructure/llm/resource_group/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/resource_group/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/resource_group/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/resource_group/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/istio.tf
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/outputs.tf
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/permissions.tf
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/providers.tf
create mode 100644 src/matcha_ml/infrastructure/llm/seldon/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/storage/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/storage/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/storage/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/storage/providers.tf
create mode 100644 src/matcha_ml/infrastructure/llm/storage/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/getURL.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/ingress.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/outputs.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/providers.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/sql.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/variables.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/Chart.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/NOTES.txt
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/_helpers.tpl
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/cert-secret.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/hpa.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-deployment.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-ingress.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-secret.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-service.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/serviceaccount.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/tests/test-connection.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/values.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/zenml_storage/README.md
create mode 100644 src/matcha_ml/infrastructure/llm/zenml_storage/main.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zenml_storage/output.tf
create mode 100644 src/matcha_ml/infrastructure/llm/zenml_storage/variables.tf
diff --git a/src/matcha_ml/infrastructure/llm/.gitignore b/src/matcha_ml/infrastructure/llm/.gitignore
new file mode 100644
index 00000000..6304eb3c
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/.gitignore
@@ -0,0 +1,34 @@
+# Local .terraform directories
+**/.terraform/*
+
+# .tfstate files
+*.tfstate
+*.tfstate.*
+
+# Crash log files
+crash.log
+crash.*.log
+
+# Exclude all .tfvars files, which are likely to contain sensitive data, such as
+# password, private keys, and other secrets. These should not be part of version
+# control as they are data points which are potentially sensitive and subject
+# to change depending on the environment.
+*.tfvars
+*.tfvars.json
+
+# Ignore override files as they are usually used to override resources locally and so
+# are not checked in
+override.tf
+override.tf.json
+*_override.tf
+*_override.tf.json
+
+# Include override files you do wish to add to version control using negated pattern
+# !example_override.tf
+
+# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
+# example: *tfplan*
+
+# Ignore CLI configuration files
+.terraformrc
+terraform.rc
diff --git a/src/matcha_ml/infrastructure/llm/README.md b/src/matcha_ml/infrastructure/llm/README.md
new file mode 100644
index 00000000..88361d90
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/README.md
@@ -0,0 +1,76 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.14.8 |
+| [azurerm](#requirement\_azurerm) | >=3.16.0 |
+| [helm](#requirement\_helm) | ~> 2.0.1 |
+| [htpasswd](#requirement\_htpasswd) | 1.0.4 |
+| [kubectl](#requirement\_kubectl) | 1.14.0 |
+| [kubernetes](#requirement\_kubernetes) | ~> 2.11.0 |
+| [local](#requirement\_local) | 2.1.0 |
+| [null](#requirement\_null) | 3.2.1 |
+| [random](#requirement\_random) | 3.1.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [external](#provider\_external) | n/a |
+| [null](#provider\_null) | 3.2.1 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [acr](#module\_acr) | ./azure_container_registry | n/a |
+| [aks](#module\_aks) | ./aks | n/a |
+| [chroma](#module\_chroma) | ./chroma | n/a |
+| [data\_version\_control\_storage](#module\_data\_version\_control\_storage) | ./data_version_control_storage | n/a |
+| [mlflow](#module\_mlflow) | ./mlflow_module | n/a |
+| [resource\_group](#module\_resource\_group) | ./resource_group | n/a |
+| [seldon](#module\_seldon) | ./seldon | n/a |
+| [storage](#module\_storage) | ./storage | n/a |
+| [zenml\_storage](#module\_zenml\_storage) | ./zenml_storage | n/a |
+| [zenserver](#module\_zenserver) | ./zen_server | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [null_resource.configure_local_kubectl](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
+| [external_external.os](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [location](#input\_location) | The Azure Region in which all resources should be provisioned | `string` | `"uksouth"` | no |
+| [password](#input\_password) | Password for ZenServer | `string` | `"default"` | no |
+| [prefix](#input\_prefix) | A prefix used for all resources | `string` | `"christest1"` | no |
+| [seldon\_name](#input\_seldon\_name) | Name of the Seldon deployment | `string` | `"seldon"` | no |
+| [seldon\_namespace](#input\_seldon\_namespace) | Namespace for Seldon resources | `string` | `"seldon-system"` | no |
+| [username](#input\_username) | Username for ZenServer | `string` | `"default"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [cloud\_azure\_location](#output\_cloud\_azure\_location) | The Azure location in which the resources are provisioned |
+| [cloud\_azure\_prefix](#output\_cloud\_azure\_prefix) | The Azure resource group name prefix |
+| [cloud\_azure\_resource\_group\_name](#output\_cloud\_azure\_resource\_group\_name) | Name of the Azure resource group |
+| [container\_registry\_azure\_registry\_name](#output\_container\_registry\_azure\_registry\_name) | The name of the Azure Container Registry |
+| [container\_registry\_azure\_registry\_url](#output\_container\_registry\_azure\_registry\_url) | The URL for the Azure Container Registry |
+| [data\_version\_control\_primary\_connection\_string](#output\_data\_version\_control\_primary\_connection\_string) | The primary connection string for the ZenML Azure Storage Account |
+| [data\_version\_control\_storage\_account\_name](#output\_data\_version\_control\_storage\_account\_name) | The name of the storage account for data version control |
+| [data\_version\_control\_storage\_container\_name](#output\_data\_version\_control\_storage\_container\_name) | The name of the container used for data version control |
+| [experiment\_tracker\_mlflow\_azure\_connection\_string](#output\_experiment\_tracker\_mlflow\_azure\_connection\_string) | The Azure connection string for the MLflow artifact storage |
+| [experiment\_tracker\_mlflow\_tracking\_url](#output\_experiment\_tracker\_mlflow\_tracking\_url) | The URL for the MLflow tracking server |
+| [model\_deployer\_seldon\_base\_url](#output\_model\_deployer\_seldon\_base\_url) | The base URL for the Seldon API server |
+| [model\_deployer\_seldon\_workloads\_namespace](#output\_model\_deployer\_seldon\_workloads\_namespace) | The Kubernetes namespace for Seldon workloads |
+| [orchestrator\_aks\_k8s\_context](#output\_orchestrator\_aks\_k8s\_context) | The name of the Kubernetes context used for deployment |
+| [pipeline\_zenml\_connection\_string](#output\_pipeline\_zenml\_connection\_string) | The primary connection string for the ZenML Azure Storage Account |
+| [pipeline\_zenml\_server\_password](#output\_pipeline\_zenml\_server\_password) | The password for accessing the ZenServer API server |
+| [pipeline\_zenml\_server\_url](#output\_pipeline\_zenml\_server\_url) | The URL for the ZenServer API server |
+| [pipeline\_zenml\_server\_username](#output\_pipeline\_zenml\_server\_username) | The username for accessing the ZenServer API server |
+| [pipeline\_zenml\_storage\_path](#output\_pipeline\_zenml\_storage\_path) | The Azure Blob Storage Container path for storing ZenML artifacts |
diff --git a/src/matcha_ml/infrastructure/llm/aks/README.md b/src/matcha_ml/infrastructure/llm/aks/README.md
new file mode 100644
index 00000000..8b7b77bb
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/aks/README.md
@@ -0,0 +1,41 @@
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_kubernetes_cluster.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [location](#input\_location) | The Azure region where the Kubernetes cluster will be created | `string` | n/a | yes |
+| [prefix](#input\_prefix) | Prefix to be used for all resources in this module | `string` | n/a | yes |
+| [resource\_group\_name](#input\_resource\_group\_name) | The name of the resource group to create the Kubernetes cluster in | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [aks\_cluster\_id](#output\_aks\_cluster\_id) | ID of the created Kubernetes cluster |
+| [aks\_cluster\_name](#output\_aks\_cluster\_name) | Name of the created Kubernetes cluster |
+| [aks\_object\_id](#output\_aks\_object\_id) | Object ID for the Kubernetes cluster |
+| [aks\_principal\_id](#output\_aks\_principal\_id) | Principal ID for the Kubernetes cluster |
+| [client\_certificate](#output\_client\_certificate) | Client certificate for accessing the Kubernetes cluster |
+| [client\_key](#output\_client\_key) | Client key for accessing the Kubernetes cluster |
+| [cluster\_ca\_certificate](#output\_cluster\_ca\_certificate) | Cluster CA certificate for the Kubernetes cluster |
+| [host](#output\_host) | Host address for the Kubernetes cluster |
+| [kube\_config](#output\_kube\_config) | Raw Kubernetes configuration for the created cluster |
diff --git a/src/matcha_ml/infrastructure/llm/aks/main.tf b/src/matcha_ml/infrastructure/llm/aks/main.tf
new file mode 100644
index 00000000..262c24c6
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/aks/main.tf
@@ -0,0 +1,19 @@
+resource "azurerm_kubernetes_cluster" "main" {
+ name = "${var.prefix}-k8s"
+ location = var.location
+ resource_group_name = var.resource_group_name
+ dns_prefix = "${var.prefix}-k8s"
+
+ default_node_pool {
+ name = "default"
+ vm_size = "Standard_DS3_v2"
+
+ enable_auto_scaling = true
+ max_count = 3
+ min_count = 1
+ }
+
+ identity {
+ type = "SystemAssigned"
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/aks/output.tf b/src/matcha_ml/infrastructure/llm/aks/output.tf
new file mode 100644
index 00000000..de131e60
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/aks/output.tf
@@ -0,0 +1,46 @@
+output "kube_config" {
+ description = "Raw Kubernetes configuration for the created cluster"
+ value = azurerm_kubernetes_cluster.main.kube_config_raw
+ sensitive = true
+}
+
+output "client_key" {
+ description = "Client key for accessing the Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.kube_config.0.client_key
+}
+
+output "client_certificate" {
+ description = "Client certificate for accessing the Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.kube_config.0.client_certificate
+ sensitive = true
+}
+
+output "cluster_ca_certificate" {
+ description = "Cluster CA certificate for the Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.kube_config.0.cluster_ca_certificate
+}
+
+output "host" {
+ description = "Host address for the Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.kube_config.0.host
+}
+
+output "aks_cluster_id" {
+ description = "ID of the created Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.id
+}
+
+output "aks_cluster_name" {
+ description = "Name of the created Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.name
+}
+
+output "aks_principal_id" {
+ description = "Principal ID for the Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.identity[0].principal_id
+}
+
+output "aks_object_id" {
+ description = "Object ID for the Kubernetes cluster"
+ value = azurerm_kubernetes_cluster.main.kubelet_identity[0].object_id
+}
diff --git a/src/matcha_ml/infrastructure/llm/aks/variables.tf b/src/matcha_ml/infrastructure/llm/aks/variables.tf
new file mode 100644
index 00000000..f48f6d27
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/aks/variables.tf
@@ -0,0 +1,14 @@
+variable "prefix" {
+ description = "Prefix to be used for all resources in this module"
+ type = string
+}
+
+variable "location" {
+ description = "The Azure region where the Kubernetes cluster will be created"
+ type = string
+}
+
+variable "resource_group_name" {
+ description = "The name of the resource group to create the Kubernetes cluster in"
+ type = string
+}
diff --git a/src/matcha_ml/infrastructure/llm/azure_container_registry/README.md b/src/matcha_ml/infrastructure/llm/azure_container_registry/README.md
new file mode 100644
index 00000000..70af6ba7
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/azure_container_registry/README.md
@@ -0,0 +1,36 @@
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_container_registry.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_registry) | resource |
+| [azurerm_role_assignment.aks_acr_access](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [aks\_object\_id](#input\_aks\_object\_id) | Object id for aks cluster | `string` | n/a | yes |
+| [location](#input\_location) | The Azure region in which this resources should be created. | `string` | n/a | yes |
+| [prefix](#input\_prefix) | A prefix used for all resources | `string` | n/a | yes |
+| [resource\_group\_name](#input\_resource\_group\_name) | The resource group name which is used to create the resource group | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [container\_registry\_name](#output\_container\_registry\_name) | The name of the container registry |
+| [container\_registry\_url](#output\_container\_registry\_url) | The URL used to log into the container registry |
diff --git a/src/matcha_ml/infrastructure/llm/azure_container_registry/main.tf b/src/matcha_ml/infrastructure/llm/azure_container_registry/main.tf
new file mode 100644
index 00000000..9c7ec142
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/azure_container_registry/main.tf
@@ -0,0 +1,13 @@
+resource "azurerm_container_registry" "main" {
+ name = "cr${var.prefix}"
+ resource_group_name = var.resource_group_name
+ location = var.location
+ sku = "Standard"
+}
+
+resource "azurerm_role_assignment" "aks_acr_access" {
+ scope = azurerm_container_registry.main.id
+ role_definition_name = "AcrPull"
+ principal_id = var.aks_object_id
+ skip_service_principal_aad_check = true
+}
diff --git a/src/matcha_ml/infrastructure/llm/azure_container_registry/output.tf b/src/matcha_ml/infrastructure/llm/azure_container_registry/output.tf
new file mode 100644
index 00000000..a2069133
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/azure_container_registry/output.tf
@@ -0,0 +1,10 @@
+# output for container registry
+output "container_registry_url" {
+ description = "The URL used to log into the container registry"
+ value = azurerm_container_registry.main.login_server
+}
+
+output "container_registry_name" {
+ description = "The name of the container registry"
+ value = azurerm_container_registry.main.name
+}
diff --git a/src/matcha_ml/infrastructure/llm/azure_container_registry/variables.tf b/src/matcha_ml/infrastructure/llm/azure_container_registry/variables.tf
new file mode 100644
index 00000000..513a9768
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/azure_container_registry/variables.tf
@@ -0,0 +1,19 @@
+variable "prefix" {
+ description = "A prefix used for all resources"
+ type = string
+}
+
+variable "resource_group_name" {
+ description = "The resource group name which is used to create the resource group"
+ type = string
+}
+
+variable "location" {
+ description = "The Azure region in which this resources should be created."
+ type = string
+}
+
+variable "aks_object_id" {
+ description = "Object id for aks cluster"
+ type = string
+}
diff --git a/src/matcha_ml/infrastructure/llm/chroma/README.md b/src/matcha_ml/infrastructure/llm/chroma/README.md
new file mode 100644
index 00000000..2a8396f1
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/README.md
@@ -0,0 +1,29 @@
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [kubernetes](#provider\_kubernetes) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [kubernetes_deployment.chroma-server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
+| [kubernetes_persistent_volume_claim.pvc](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
+| [kubernetes_service.chroma-service](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
+
+## Inputs
+
+No inputs.
+
+## Outputs
+
+No outputs.
diff --git a/src/matcha_ml/infrastructure/llm/chroma/main.tf b/src/matcha_ml/infrastructure/llm/chroma/main.tf
new file mode 100644
index 00000000..9d5f3d37
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/main.tf
@@ -0,0 +1,99 @@
+resource "kubernetes_deployment" "chroma-server" {
+ metadata {
+ name = "chroma-server"
+ }
+
+ spec {
+ selector {
+ match_labels = {
+ app = "chroma-server"
+ }
+ }
+
+ template {
+ metadata {
+ labels = {
+ app = "chroma-server"
+ }
+ }
+
+ spec {
+ container {
+ name = "chroma-server"
+ image = "ghcr.io/chroma-core/chroma:0.4.3"
+ port {
+ container_port = 8000
+ }
+ resources {
+ requests = {
+ memory = "256Mi"
+ cpu = "256m"
+ }
+ limits = {
+ memory = "2Gi"
+ cpu = "2"
+ }
+ }
+ volume_mount {
+ mount_path = "/index_data"
+ name = "chroma-server-index"
+ }
+ }
+
+ restart_policy = "Always"
+
+ volume {
+ name = "chroma-server-index"
+ persistent_volume_claim {
+ claim_name = "chroma-server-index"
+ }
+ }
+ }
+ }
+ }
+}
+
+resource "kubernetes_persistent_volume_claim" "pvc" {
+ metadata {
+ name = "chroma-server-index"
+ }
+
+ spec {
+ access_modes = ["ReadWriteOnce"]
+ storage_class_name = "default"
+ resources {
+ requests = {
+ storage = "100Mi"
+ }
+ }
+ }
+}
+
+resource "kubernetes_service" "chroma-service" {
+ metadata {
+ name = "chroma-service"
+ }
+
+ spec {
+ selector = {"app": "chroma-server"}
+
+ port {
+ name = "8123"
+ port = 8123
+ target_port = 8123
+ }
+
+ port {
+ name = "9000"
+ port = 9000
+ target_port = 9000
+ }
+
+ port {
+ name = "8000"
+ port = 8000
+ target_port = 8000
+ }
+
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/configure_kubectl.tf b/src/matcha_ml/infrastructure/llm/configure_kubectl.tf
new file mode 100644
index 00000000..6e69e9de
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/configure_kubectl.tf
@@ -0,0 +1,12 @@
+# Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/aws-minimal/configure_kubectl.tf
+
+# set up local kubectl client to access the newly created cluster
+resource "null_resource" "configure_local_kubectl" {
+ provisioner "local-exec" {
+ command = "az aks get-credentials --resource-group ${module.resource_group.name} --name ${module.aks.aks_cluster_name} --context ${local.kubectl_context} --overwrite-existing"
+ }
+}
+
+locals {
+ kubectl_context = "terraform-${module.aks.aks_cluster_name}-${replace(substr(timestamp(), 0, 16), ":", "_")}"
+}
diff --git a/src/matcha_ml/infrastructure/llm/data_version_control_storage/README.md b/src/matcha_ml/infrastructure/llm/data_version_control_storage/README.md
new file mode 100644
index 00000000..cae1bfe3
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/data_version_control_storage/README.md
@@ -0,0 +1,44 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [azurerm](#requirement\_azurerm) | 3.48.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | 3.48.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_storage_account.storageaccount](https://registry.terraform.io/providers/hashicorp/azurerm/3.48.0/docs/resources/storage_account) | resource |
+| [azurerm_storage_container.storagecontainer](https://registry.terraform.io/providers/hashicorp/azurerm/3.48.0/docs/resources/storage_container) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [location](#input\_location) | The Azure Region in which this resources should be created. | `string` | n/a | yes |
+| [prefix](#input\_prefix) | The prefix which should be used for naming storage account ({prefix}storageacc) and container ({prefix}storagecontainer) | `string` | n/a | yes |
+| [resource\_group\_name](#input\_resource\_group\_name) | The resource group name which is used to create the resource group | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [blobstorage\_container\_path](#output\_blobstorage\_container\_path) | The Azure Blob Storage Container path for storing your artifacts |
+| [primary\_access\_key](#output\_primary\_access\_key) | Azure Storage Account - Primary access key |
+| [primary\_blob\_connection\_string](#output\_primary\_blob\_connection\_string) | Azure Storage Account - Primary Blob service connection string |
+| [primary\_connection\_string](#output\_primary\_connection\_string) | Azure Storage Account - Primary connection string |
+| [secondary\_access\_key](#output\_secondary\_access\_key) | Azure Storage Account - Secondary access key |
+| [secondary\_blob\_connection\_string](#output\_secondary\_blob\_connection\_string) | Azure Storage Account - Secondary Blob service connection string |
+| [secondary\_connection\_string](#output\_secondary\_connection\_string) | Azure Storage Account - Secondary connection string |
+| [storage\_account\_name](#output\_storage\_account\_name) | The name of the Azure Storage Account. |
+| [storage\_container\_name](#output\_storage\_container\_name) | The name of the Azure Storage Container. |
diff --git a/src/matcha_ml/infrastructure/llm/data_version_control_storage/main.tf b/src/matcha_ml/infrastructure/llm/data_version_control_storage/main.tf
new file mode 100644
index 00000000..72b26b18
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/data_version_control_storage/main.tf
@@ -0,0 +1,22 @@
+# Reference: https://github.com/hashicorp/terraform-provider-azurerm/tree/main/examples/storage/storage-container
+
+# create a storage account
+resource "azurerm_storage_account" "storageaccount" {
+ name = "${var.prefix}dvcacc"
+ resource_group_name = var.resource_group_name
+ location = var.location
+
+ account_tier = "Standard"
+ account_kind = "StorageV2"
+ account_replication_type = "LRS"
+ enable_https_traffic_only = true
+ access_tier = "Hot"
+ allow_nested_items_to_be_public = true
+}
+
+# create a storage container inside created storage account
+resource "azurerm_storage_container" "storagecontainer" {
+ name = "${var.prefix}dvcstore"
+ storage_account_name = azurerm_storage_account.storageaccount.name
+ container_access_type = "container"
+}
diff --git a/src/matcha_ml/infrastructure/llm/data_version_control_storage/output.tf b/src/matcha_ml/infrastructure/llm/data_version_control_storage/output.tf
new file mode 100644
index 00000000..45a5f5ce
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/data_version_control_storage/output.tf
@@ -0,0 +1,15 @@
+output "storage_container_name" {
+ description = "The name of the Azure Storage Container."
+ value = azurerm_storage_container.storagecontainer.name
+}
+
+output "storage_account_name" {
+ description = "The name of the Azure Storage Account."
+ value = azurerm_storage_account.storageaccount.name
+}
+
+output "primary_connection_string" {
+ description = "Azure Storage Account - Primary connection string"
+ value = azurerm_storage_account.storageaccount.primary_connection_string
+ sensitive = true
+}
diff --git a/src/matcha_ml/infrastructure/llm/data_version_control_storage/providers.tf b/src/matcha_ml/infrastructure/llm/data_version_control_storage/providers.tf
new file mode 100644
index 00000000..e2d7507d
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/data_version_control_storage/providers.tf
@@ -0,0 +1,8 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "3.48.0"
+ }
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/data_version_control_storage/variables.tf b/src/matcha_ml/infrastructure/llm/data_version_control_storage/variables.tf
new file mode 100644
index 00000000..8a3fab49
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/data_version_control_storage/variables.tf
@@ -0,0 +1,14 @@
+variable "resource_group_name" {
+ description = "The resource group name which is used to create the resource group"
+ type = string
+}
+
+variable "prefix" {
+ description = "The prefix which should be used for naming storage account ({prefix}dvcacc) and container ({prefix}dvcstore)"
+ type = string
+}
+
+variable "location" {
+ description = "The Azure Region in which this resources should be created."
+ type = string
+}
diff --git a/src/matcha_ml/infrastructure/llm/helm.tf b/src/matcha_ml/infrastructure/llm/helm.tf
new file mode 100644
index 00000000..dac70cd9
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/helm.tf
@@ -0,0 +1,10 @@
+provider "helm" {
+ kubernetes {
+ host = module.aks.host
+
+ client_certificate = base64decode(module.aks.client_certificate)
+ client_key = base64decode(module.aks.client_key)
+ cluster_ca_certificate = base64decode(module.aks.cluster_ca_certificate)
+ config_path = local.kubectl_config_path
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/kubernetes.tf b/src/matcha_ml/infrastructure/llm/kubernetes.tf
new file mode 100644
index 00000000..304dcc5e
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/kubernetes.tf
@@ -0,0 +1,30 @@
+# Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/aws-minimal/kubernetes.tf
+
+# check if the host OS is Linux or Windows
+data "external" "os" {
+ working_dir = path.module
+ program = ["printf", "{\"os\": \"Linux\"}"]
+}
+
+locals {
+ os = data.external.os.result.os
+ kubectl_config_path = local.os == "Windows" ? "%USERPROFILE%\\.kube\\config" : "~/.kube/config"
+}
+
+# a default (non-aliased) provider configuration for "kubernetes"
+provider "kubernetes" {
+ host = module.aks.host
+
+ client_certificate = base64decode(module.aks.client_certificate)
+ client_key = base64decode(module.aks.client_key)
+ cluster_ca_certificate = base64decode(module.aks.cluster_ca_certificate)
+ config_path = local.kubectl_config_path
+}
+
+provider "kubectl" {
+ host = module.aks.host
+
+ client_certificate = base64decode(module.aks.client_certificate)
+ client_key = base64decode(module.aks.client_key)
+ cluster_ca_certificate = base64decode(module.aks.cluster_ca_certificate)
+}
diff --git a/src/matcha_ml/infrastructure/llm/main.tf b/src/matcha_ml/infrastructure/llm/main.tf
new file mode 100644
index 00000000..8070aa07
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/main.tf
@@ -0,0 +1,100 @@
+provider "azurerm" {
+ features {
+ resource_group {
+ prevent_deletion_if_contains_resources = false
+ }
+ }
+}
+
+module "resource_group" {
+ source = "./resource_group"
+
+ prefix = var.prefix
+}
+
+module "storage" {
+ source = "./storage"
+
+ resource_group_name = module.resource_group.name
+ prefix = var.prefix
+ location = var.location
+}
+
+module "zenml_storage" {
+ source = "./zenml_storage"
+
+ prefix = var.prefix
+ resource_group_name = module.resource_group.name
+ location = var.location
+ aks_principal_id = module.aks.aks_principal_id
+}
+
+module "data_version_control_storage" {
+ source = "./data_version_control_storage"
+
+ resource_group_name = module.resource_group.name
+ prefix = var.prefix
+ location = var.location
+}
+
+module "aks" {
+ source = "./aks"
+
+ prefix = var.prefix
+ location = var.location
+ resource_group_name = module.resource_group.name
+}
+
+module "acr" {
+ source = "./azure_container_registry"
+
+ prefix = var.prefix
+ resource_group_name = module.resource_group.name
+ location = var.location
+ aks_object_id = module.aks.aks_object_id
+}
+
+module "mlflow" {
+ source = "./mlflow_module"
+
+ depends_on = [null_resource.configure_local_kubectl]
+
+ # storage variables
+ storage_account_name = module.storage.storage_account_name
+ storage_container_name = module.storage.storage_container_name
+ artifact_azure_access_key = module.storage.primary_access_key
+}
+
+
+module "zenserver" {
+ source = "./zen_server"
+
+ depends_on = [null_resource.configure_local_kubectl]
+
+ # resource group variables
+ resource_group_name = module.resource_group.name
+ location = var.location
+ prefix = var.prefix
+
+ # ZenServer credentials
+ username = var.username
+ password = var.password
+}
+
+
+module "seldon" {
+ source = "./seldon"
+
+ depends_on = [null_resource.configure_local_kubectl]
+
+ # details about the seldon deployment
+ seldon_name = var.seldon_name
+ seldon_namespace = var.seldon_namespace
+
+}
+
+module "chroma" {
+ source = "./chroma"
+
+ depends_on = [null_resource.configure_local_kubectl]
+}
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/README.md b/src/matcha_ml/infrastructure/llm/mlflow_module/README.md
new file mode 100644
index 00000000..a06e695c
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/README.md
@@ -0,0 +1,41 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.14.8 |
+| [htpasswd](#requirement\_htpasswd) | 1.0.4 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [helm](#provider\_helm) | n/a |
+| [kubernetes](#provider\_kubernetes) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [helm_release.mlflow-tracking](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [kubernetes_namespace.k8s_ns](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
+| [kubernetes_service.mlflow_tracking](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/data-sources/service) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [artifact\_azure](#input\_artifact\_azure) | Boolean to indicate if we are using Azure Blob Storage as storage for MLFlow | `bool` | `true` | no |
+| [artifact\_azure\_access\_key](#input\_artifact\_azure\_access\_key) | Access Key for Azure Blob Storage | `string` | `""` | no |
+| [artifact\_proxied\_access](#input\_artifact\_proxied\_access) | Boolean to indicate if we are using proxied artifact storage | `bool` | `false` | no |
+| [storage\_account\_name](#input\_storage\_account\_name) | Name of Azure Storage Container already created inside Azure Blob Storage | `string` | n/a | yes |
+| [storage\_container\_name](#input\_storage\_container\_name) | Name of container to create inside Azure Storage Account to store artifacts | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [mlflow\_tracking\_url](#output\_mlflow\_tracking\_url) | The tracking URL for MLFlow dashboard |
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/getURI.tf b/src/matcha_ml/infrastructure/llm/mlflow_module/getURI.tf
new file mode 100644
index 00000000..e4a6890c
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/getURI.tf
@@ -0,0 +1,8 @@
+# Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/azure-minimal/get_URIs.tf
+
+# get URI for MLflow tracking server
+data "kubernetes_service" "mlflow_tracking" {
+ metadata {
+ name = helm_release.mlflow_tracking.name
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/main.tf b/src/matcha_ml/infrastructure/llm/mlflow_module/main.tf
new file mode 100644
index 00000000..eb97dfaa
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/main.tf
@@ -0,0 +1,44 @@
+# create the mlflow tracking server deployment using mlflow helm charts
+# Reference: https://github.com/community-charts/helm-charts/blob/main/charts/mlflow/values.yaml
+resource "helm_release" "mlflow_tracking" {
+
+ name = "mlflow-tracking"
+ repository = "https://community-charts.github.io/helm-charts"
+ chart = "mlflow"
+
+ # Change type from "ClusterIP" to "LoadBalancer"
+ set {
+ name = "service.type"
+ value = "LoadBalancer"
+ }
+ # set proxied access to artifact storage
+ set {
+ name = "artifactRoot.proxiedArtifactStorage"
+ value = var.artifact_proxied_access
+ type = "auto"
+ }
+
+ # Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/aws-minimal/mlflow-module/mlflow.tf#L39
+ # set values for Azure Blob Storage
+ set {
+ name = "artifactRoot.azureBlob.enabled"
+ value = var.artifact_azure
+ type = "auto"
+ }
+ set {
+ name = "artifactRoot.azureBlob.storageAccount"
+ value = var.storage_account_name
+ type = "string"
+ }
+ set {
+ name = "artifactRoot.azureBlob.container"
+ value = var.storage_container_name
+ type = "string"
+ }
+ set_sensitive {
+ name = "artifactRoot.azureBlob.accessKey"
+ value = var.artifact_azure_access_key
+ type = "string"
+ }
+
+}
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/output.tf b/src/matcha_ml/infrastructure/llm/mlflow_module/output.tf
new file mode 100644
index 00000000..d73628a7
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/output.tf
@@ -0,0 +1,4 @@
+output "mlflow_tracking_url" {
+ description = "The tracking URL for MLFlow dashboard"
+ value = "http://${data.kubernetes_service.mlflow_tracking.status.0.load_balancer.0.ingress.0.ip}:${data.kubernetes_service.mlflow_tracking.spec.0.port.0.port}"
+}
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/providers.tf b/src/matcha_ml/infrastructure/llm/mlflow_module/providers.tf
new file mode 100644
index 00000000..f46344cb
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/providers.tf
@@ -0,0 +1,12 @@
+# Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/aws-minimal/mlflow-module/providers.tf
+
+# defining the providers required by the mlflow module
+terraform {
+ required_providers {
+ htpasswd = {
+ source = "loafoe/htpasswd"
+ version = "1.0.4"
+ }
+ }
+ required_version = ">= 0.14.8"
+}
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/variables.tf b/src/matcha_ml/infrastructure/llm/mlflow_module/variables.tf
new file mode 100644
index 00000000..058a5057
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/variables.tf
@@ -0,0 +1,29 @@
+# artifact storage variables
+variable "artifact_proxied_access" {
+ description = "Boolean to indicate if we are using proxied artifact storage"
+ type = bool
+ default = false
+}
+
+variable "storage_account_name" {
+ description = "Name of Azure Storage Container already created inside Azure Blob Storage"
+ type = string
+}
+
+variable "storage_container_name" {
+ description = "Name of container to create inside Azure Storage Account to store artifacts"
+ type = string
+}
+
+variable "artifact_azure" {
+ description = "Boolean to indicate if we are using Azure Blob Storage as storage for MLFlow"
+ type = bool
+ default = true
+}
+
+
+variable "artifact_azure_access_key" {
+ description = "Access Key for Azure Blob Storage"
+ type = string
+ default = ""
+}
diff --git a/src/matcha_ml/infrastructure/llm/mlflow_module/zenml_namespace.tf b/src/matcha_ml/infrastructure/llm/mlflow_module/zenml_namespace.tf
new file mode 100644
index 00000000..c0705a8a
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/mlflow_module/zenml_namespace.tf
@@ -0,0 +1,5 @@
+resource "kubernetes_namespace" "k8s_ns" {
+ metadata {
+ name = "zenml"
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/output.tf b/src/matcha_ml/infrastructure/llm/output.tf
new file mode 100644
index 00000000..f62fd806
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/output.tf
@@ -0,0 +1,94 @@
+output "experiment_tracker_mlflow_tracking_url" {
+ description = "The URL for the MLflow tracking server"
+ value = module.mlflow.mlflow_tracking_url
+}
+
+output "experiment_tracker_mlflow_azure_connection_string" {
+ description = "The Azure connection string for the MLflow artifact storage"
+ value = module.storage.primary_connection_string
+ sensitive = true
+}
+
+output "pipeline_zenml_storage_path" {
+ description = "The Azure Blob Storage Container path for storing ZenML artifacts"
+ value = module.zenml_storage.zenml_blobstorage_container_path
+}
+
+
+output "pipeline_zenml_connection_string" {
+ description = "The primary connection string for the ZenML Azure Storage Account"
+ value = module.zenml_storage.zenml_primary_connection_string
+ sensitive = true
+}
+
+output "orchestrator_aks_k8s_context" {
+ description = "The name of the Kubernetes context used for deployment"
+ value = local.kubectl_context
+}
+
+output "pipeline_zenml_server_url" {
+ description = "The URL for the ZenServer API server"
+ value = module.zenserver.zenserver_url
+}
+
+output "pipeline_zenml_server_username" {
+ description = "The username for accessing the ZenServer API server"
+ value = module.zenserver.zenserver_username
+}
+
+output "pipeline_zenml_server_password" {
+ description = "The password for accessing the ZenServer API server"
+ value = module.zenserver.zenserver_password
+ sensitive = true
+}
+
+output "container_registry_azure_registry_url" {
+ description = "The URL for the Azure Container Registry"
+ value = module.acr.container_registry_url
+}
+
+output "container_registry_azure_registry_name" {
+ description = "The name of the Azure Container Registry"
+ value = module.acr.container_registry_name
+}
+
+output "model_deployer_seldon_workloads_namespace" {
+ description = "The Kubernetes namespace for Seldon workloads"
+ value = module.seldon.workloads_namespace
+}
+
+output "model_deployer_seldon_base_url" {
+ description = "The base URL for the Seldon API server"
+ value = module.seldon.base_url
+}
+
+output "cloud_azure_resource_group_name" {
+ description = "Name of the Azure resource group"
+ value = module.resource_group.name
+}
+
+output "cloud_azure_prefix"{
+ description = "The Azure resource group name prefix"
+ value = var.prefix
+}
+
+output "cloud_azure_location"{
+ description = "The Azure location in which the resources are provisioned"
+ value = var.location
+}
+
+output "data_version_control_primary_connection_string"{
+ description = "The primary connection string for the ZenML Azure Storage Account"
+ value = module.data_version_control_storage.primary_connection_string
+ sensitive = true
+}
+
+output "data_version_control_storage_container_name"{
+ description = "The name of the container used for data version control"
+ value = module.data_version_control_storage.storage_container_name
+}
+
+output "data_version_control_storage_account_name"{
+ description = "The name of the storage account for data version control"
+ value = module.data_version_control_storage.storage_account_name
+}
diff --git a/src/matcha_ml/infrastructure/llm/printf.cmd b/src/matcha_ml/infrastructure/llm/printf.cmd
new file mode 100644
index 00000000..07e225fa
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/printf.cmd
@@ -0,0 +1,2 @@
+@echo off
+echo {"os": "Windows"}
diff --git a/src/matcha_ml/infrastructure/llm/providers.tf b/src/matcha_ml/infrastructure/llm/providers.tf
new file mode 100644
index 00000000..b3876b23
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/providers.tf
@@ -0,0 +1,46 @@
+# defining the providers for the all module
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = ">=3.16.0"
+ }
+
+ random = {
+ source = "hashicorp/random"
+ version = "3.1.0"
+ }
+
+ helm = {
+ source = "hashicorp/helm"
+ version = "~> 2.0.1"
+ }
+
+ local = {
+ source = "hashicorp/local"
+ version = "2.1.0"
+ }
+
+ null = {
+ source = "hashicorp/null"
+ version = "3.2.1"
+ }
+
+ kubernetes = {
+ source = "hashicorp/kubernetes"
+ version = "~> 2.11.0"
+ }
+
+ kubectl = {
+ source = "gavinbunney/kubectl"
+ version = "1.14.0"
+ }
+
+ htpasswd = {
+ source = "loafoe/htpasswd"
+ version = "1.0.4"
+ }
+ }
+
+ required_version = ">= 0.14.8"
+}
diff --git a/src/matcha_ml/infrastructure/llm/resource_group/README.md b/src/matcha_ml/infrastructure/llm/resource_group/README.md
new file mode 100644
index 00000000..72624d2e
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/resource_group/README.md
@@ -0,0 +1,32 @@
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_resource_group.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [location](#input\_location) | The Azure region in which resource group should be provisioned | `string` | n/a | yes |
+| [prefix](#input\_prefix) | A prefix used for all resources | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [name](#output\_name) | Name of the resource group |
diff --git a/src/matcha_ml/infrastructure/llm/resource_group/main.tf b/src/matcha_ml/infrastructure/llm/resource_group/main.tf
new file mode 100644
index 00000000..6afb0a9e
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/resource_group/main.tf
@@ -0,0 +1,3 @@
+data "azurerm_resource_group" "main" {
+ name = "${var.prefix}-resources"
+}
diff --git a/src/matcha_ml/infrastructure/llm/resource_group/output.tf b/src/matcha_ml/infrastructure/llm/resource_group/output.tf
new file mode 100644
index 00000000..55f05726
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/resource_group/output.tf
@@ -0,0 +1,4 @@
+output "name" {
+ description = "Name of the resource group"
+ value = data.azurerm_resource_group.main.name
+}
diff --git a/src/matcha_ml/infrastructure/llm/resource_group/variables.tf b/src/matcha_ml/infrastructure/llm/resource_group/variables.tf
new file mode 100644
index 00000000..0325a60e
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/resource_group/variables.tf
@@ -0,0 +1,4 @@
+variable "prefix" {
+ description = "A prefix used for all resources"
+ type = string
+}
diff --git a/src/matcha_ml/infrastructure/llm/seldon/README.md b/src/matcha_ml/infrastructure/llm/seldon/README.md
new file mode 100644
index 00000000..9ceb938e
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/seldon/README.md
@@ -0,0 +1,49 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.14.8 |
+| [kubectl](#requirement\_kubectl) | 1.14.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [helm](#provider\_helm) | n/a |
+| [kubectl](#provider\_kubectl) | 1.14.0 |
+| [kubernetes](#provider\_kubernetes) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [helm_release.istio_base](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [helm_release.istio_ingress](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [helm_release.istiod](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [helm_release.seldon](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [kubectl_manifest.gateway](https://registry.terraform.io/providers/gavinbunney/kubectl/1.14.0/docs/resources/manifest) | resource |
+| [kubernetes_cluster_role_binding_v1.seldon_machinelearning-permission_binding](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/cluster_role_binding_v1) | resource |
+| [kubernetes_cluster_role_v1.seldon-machinelearning_permission](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/cluster_role_v1) | resource |
+| [kubernetes_namespace.istio_ns](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
+| [kubernetes_namespace.seldon_ns](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
+| [kubernetes_namespace.seldon_workloads](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
+| [kubernetes_service.seldon_ingress](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/data-sources/service) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [seldon\_name](#input\_seldon\_name) | Seldon Helm deployment name | `string` | n/a | yes |
+| [seldon\_namespace](#input\_seldon\_namespace) | Seldon system namespace | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [base\_url](#output\_base\_url) | The base URL of the Seldon deployment |
+| [ingress\_gateway\_spec](#output\_ingress\_gateway\_spec) | The YAML specification for the Istio ingress gateway |
+| [workloads\_namespace](#output\_workloads\_namespace) | The namespace for Seldon workloads |
diff --git a/src/matcha_ml/infrastructure/llm/seldon/istio.tf b/src/matcha_ml/infrastructure/llm/seldon/istio.tf
new file mode 100644
index 00000000..7c4d9a9a
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/seldon/istio.tf
@@ -0,0 +1,65 @@
+# Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/aws-minimal/seldon/istio.tf
+
+# create a namespace for istio resources
+resource "kubernetes_namespace" "istio_ns" {
+ metadata {
+ name = "istio-system"
+ labels = {
+ istio-injection = "enabled"
+ }
+ }
+}
+
+# istio-base creates the istio definitions that will be used going forward
+resource "helm_release" "istio_base" {
+ name = "istio-base-seldon"
+ repository = "https://istio-release.storage.googleapis.com/charts"
+ chart = "base"
+
+ # adding a dependency on the istio-namespace
+ namespace = kubernetes_namespace.istio_ns.metadata[0].name
+}
+
+# the istio daemon
+resource "helm_release" "istiod" {
+ name = "istiod-seldon"
+ repository = helm_release.istio_base.repository # dependency on istio-base
+ chart = "istiod"
+
+ namespace = kubernetes_namespace.istio_ns.metadata[0].name
+}
+
+# the istio ingress gateway
+# cannot use kubernetes_manifest resource since it practically
+# doesn't support CRDs. Going with kubectl instead.
+resource "kubectl_manifest" "gateway" {
+ yaml_body = < [azurerm](#requirement\_azurerm) | 3.48.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | 3.48.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_storage_account.storageaccount](https://registry.terraform.io/providers/hashicorp/azurerm/3.48.0/docs/resources/storage_account) | resource |
+| [azurerm_storage_container.storagecontainer](https://registry.terraform.io/providers/hashicorp/azurerm/3.48.0/docs/resources/storage_container) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [location](#input\_location) | The Azure Region in which this resources should be created. | `string` | n/a | yes |
+| [prefix](#input\_prefix) | The prefix which should be used for naming storage account ({prefix}storageacc) and container ({prefix}storagecontainer) | `string` | n/a | yes |
+| [resource\_group\_name](#input\_resource\_group\_name) | The resource group name which is used to create the resource group | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [blobstorage\_container\_path](#output\_blobstorage\_container\_path) | The Azure Blob Storage Container path for storing your artifacts |
+| [primary\_access\_key](#output\_primary\_access\_key) | Azure Storage Account - Primary access key |
+| [primary\_blob\_connection\_string](#output\_primary\_blob\_connection\_string) | Azure Storage Account - Primary Blob service connection string |
+| [primary\_connection\_string](#output\_primary\_connection\_string) | Azure Storage Account - Primary connection string |
+| [secondary\_access\_key](#output\_secondary\_access\_key) | Azure Storage Account - Secondary access key |
+| [secondary\_blob\_connection\_string](#output\_secondary\_blob\_connection\_string) | Azure Storage Account - Secondary Blob service connection string |
+| [secondary\_connection\_string](#output\_secondary\_connection\_string) | Azure Storage Account - Secondary connection string |
+| [storage\_account\_name](#output\_storage\_account\_name) | The name of the Azure Storage Account. |
+| [storage\_container\_name](#output\_storage\_container\_name) | The name of the Azure Storage Container. |
diff --git a/src/matcha_ml/infrastructure/llm/storage/main.tf b/src/matcha_ml/infrastructure/llm/storage/main.tf
new file mode 100644
index 00000000..b448a625
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/storage/main.tf
@@ -0,0 +1,22 @@
+# Reference: https://github.com/hashicorp/terraform-provider-azurerm/tree/main/examples/storage/storage-container
+
+# create a storage account
+resource "azurerm_storage_account" "storageaccount" {
+ name = "st${var.prefix}acc"
+ resource_group_name = var.resource_group_name
+ location = var.location
+
+ account_tier = "Standard"
+ account_kind = "StorageV2"
+ account_replication_type = "LRS"
+ enable_https_traffic_only = true
+ access_tier = "Hot"
+ allow_nested_items_to_be_public = true
+}
+
+# create a storage container inside created storage account
+resource "azurerm_storage_container" "storagecontainer" {
+ name = "${var.prefix}store"
+ storage_account_name = azurerm_storage_account.storageaccount.name
+ container_access_type = "container"
+}
diff --git a/src/matcha_ml/infrastructure/llm/storage/output.tf b/src/matcha_ml/infrastructure/llm/storage/output.tf
new file mode 100644
index 00000000..ef9a9916
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/storage/output.tf
@@ -0,0 +1,50 @@
+output "storage_container_name" {
+ description = "The name of the Azure Storage Container."
+ value = azurerm_storage_container.storagecontainer.name
+}
+
+output "blobstorage_container_path" {
+ description = "The Azure Blob Storage Container path for storing your artifacts"
+ value = "az://${azurerm_storage_container.storagecontainer.name}"
+}
+
+output "storage_account_name" {
+ description = "The name of the Azure Storage Account."
+ value = azurerm_storage_account.storageaccount.name
+}
+
+output "primary_access_key" {
+ description = "Azure Storage Account - Primary access key"
+ value = azurerm_storage_account.storageaccount.primary_access_key
+ sensitive = true
+}
+
+output "secondary_access_key" {
+ description = "Azure Storage Account - Secondary access key"
+ value = azurerm_storage_account.storageaccount.secondary_access_key
+ sensitive = true
+}
+
+output "primary_connection_string" {
+ description = "Azure Storage Account - Primary connection string"
+ value = azurerm_storage_account.storageaccount.primary_connection_string
+ sensitive = true
+}
+
+output "secondary_connection_string" {
+ description = "Azure Storage Account - Secondary connection string"
+ value = azurerm_storage_account.storageaccount.secondary_connection_string
+ sensitive = true
+}
+
+output "primary_blob_connection_string" {
+ description = "Azure Storage Account - Primary Blob service connection string"
+ value = azurerm_storage_account.storageaccount.primary_blob_connection_string
+ sensitive = true
+}
+
+output "secondary_blob_connection_string" {
+ description = "Azure Storage Account - Secondary Blob service connection string"
+ value = azurerm_storage_account.storageaccount.secondary_blob_connection_string
+ sensitive = true
+}
diff --git a/src/matcha_ml/infrastructure/llm/storage/providers.tf b/src/matcha_ml/infrastructure/llm/storage/providers.tf
new file mode 100644
index 00000000..e2d7507d
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/storage/providers.tf
@@ -0,0 +1,8 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "3.48.0"
+ }
+ }
+}
diff --git a/src/matcha_ml/infrastructure/llm/storage/variables.tf b/src/matcha_ml/infrastructure/llm/storage/variables.tf
new file mode 100644
index 00000000..23388ac3
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/storage/variables.tf
@@ -0,0 +1,14 @@
+variable "resource_group_name" {
+ description = "The resource group name which is used to create the resource group"
+ type = string
+}
+
+variable "prefix" {
+ description = "The prefix which should be used for naming storage account ({prefix}storageacc) and container ({prefix}storagecontainer)"
+ type = string
+}
+
+variable "location" {
+ description = "The Azure Region in which this resources should be created."
+ type = string
+}
diff --git a/src/matcha_ml/infrastructure/llm/variables.tf b/src/matcha_ml/infrastructure/llm/variables.tf
new file mode 100644
index 00000000..501c1a11
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/variables.tf
@@ -0,0 +1,35 @@
+variable "prefix" {
+ description = "A prefix used for all resources"
+ type = string
+ default = "matcha"
+}
+
+variable "location" {
+ description = "The Azure Region in which all resources should be provisioned"
+ type = string
+}
+
+variable "username" {
+ description = "Username for ZenServer"
+ type = string
+ default = "default"
+}
+
+variable "password" {
+ description = "Password for ZenServer"
+ type = string
+ sensitive = true
+}
+
+# seldon variables
+variable "seldon_name" {
+ description = "Name of the Seldon deployment"
+ type = string
+ default = "seldon"
+}
+
+variable "seldon_namespace" {
+ description = "Namespace for Seldon resources"
+ type = string
+ default = "seldon-system"
+}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/README.md b/src/matcha_ml/infrastructure/llm/zen_server/README.md
new file mode 100644
index 00000000..8b7759f2
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/README.md
@@ -0,0 +1,69 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.14.8 |
+| [htpasswd](#requirement\_htpasswd) | 1.0.4 |
+| [kubectl](#requirement\_kubectl) | 1.14.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | n/a |
+| [helm](#provider\_helm) | n/a |
+| [kubernetes](#provider\_kubernetes) | n/a |
+| [random](#provider\_random) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_mysql_flexible_database.db](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mysql_flexible_database) | resource |
+| [azurerm_mysql_flexible_server.mysql](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mysql_flexible_server) | resource |
+| [azurerm_mysql_flexible_server_configuration.require_ssl](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mysql_flexible_server_configuration) | resource |
+| [azurerm_mysql_flexible_server_firewall_rule.allow_IPs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mysql_flexible_server_firewall_rule) | resource |
+| [helm_release.zen_server](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [kubernetes_namespace.zen_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
+| [random_password.mysql_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
+| [kubernetes_service.zen_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/data-sources/service) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [analytics\_opt\_in](#input\_analytics\_opt\_in) | The flag to enable/disable analytics | `bool` | `false` | no |
+| [database\_password](#input\_database\_password) | The password for the CloudSQL store | `string` | `""` | no |
+| [database\_ssl\_ca](#input\_database\_ssl\_ca) | The server ca for the Flexible MySQL instance | `string` | `""` | no |
+| [database\_ssl\_cert](#input\_database\_ssl\_cert) | The client cert for the Flexible MySQL instance | `string` | `""` | no |
+| [database\_ssl\_key](#input\_database\_ssl\_key) | The client key for the Flexible MySQL instance | `string` | `""` | no |
+| [database\_ssl\_verify\_server\_cert](#input\_database\_ssl\_verify\_server\_cert) | Should SSL be verified? | `bool` | `false` | no |
+| [database\_url](#input\_database\_url) | The URL for the Flexible MySQL instance | `string` | `""` | no |
+| [database\_username](#input\_database\_username) | The username for the CloudSQL store | `string` | `"user"` | no |
+| [db\_disk\_size](#input\_db\_disk\_size) | The allocated storage in gigabytes | `number` | `20` | no |
+| [db\_instance\_name](#input\_db\_instance\_name) | The name for the Flexible MySQL store | `string` | `"zenmlserver"` | no |
+| [db\_name](#input\_db\_name) | The name for the database | `string` | `"zendb"` | no |
+| [db\_sku\_name](#input\_db\_sku\_name) | The sku\_name for the database resource | `string` | `"B_Standard_B1s"` | no |
+| [db\_version](#input\_db\_version) | The version of MySQL to use | `string` | `"5.7"` | no |
+| [deploy\_db](#input\_deploy\_db) | Should a Flexible MySQL instance be created? | `bool` | `true` | no |
+| [kubectl\_config\_path](#input\_kubectl\_config\_path) | The path to the kube config | `string` | `""` | no |
+| [location](#input\_location) | The location for your Azure resources | `string` | n/a | yes |
+| [namespace](#input\_namespace) | The namespace to install the ZenML server Helm chart in | `string` | `"terraform-server"` | no |
+| [password](#input\_password) | Password for the default ZenML server account | `string` | n/a | yes |
+| [prefix](#input\_prefix) | A prefix used for all resources | `string` | n/a | yes |
+| [resource\_group\_name](#input\_resource\_group\_name) | The resource group in Azure that you want to deploy ZenML to | `string` | n/a | yes |
+| [username](#input\_username) | Username for the default ZenML server account | `string` | `"default"` | no |
+| [zenmlserver\_image\_repo](#input\_zenmlserver\_image\_repo) | The repository to use for the zenmlserver docker image. | `string` | `"zenmldocker/zenml-server"` | no |
+| [zenmlserver\_image\_tag](#input\_zenmlserver\_image\_tag) | The tag to use for the zenmlserver docker image. | `string` | `"latest"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [zenserver\_password](#output\_zenserver\_password) | The password used to access the ZenML server |
+| [zenserver\_url](#output\_zenserver\_url) | The URL for the ZenML server |
+| [zenserver\_username](#output\_zenserver\_username) | The username used to access the ZenML server |
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/getURL.tf b/src/matcha_ml/infrastructure/llm/zen_server/getURL.tf
new file mode 100644
index 00000000..a45aff5b
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/getURL.tf
@@ -0,0 +1,10 @@
+data "kubernetes_service" "zen_server" {
+ metadata {
+ name = "${helm_release.zen_server.name}-zenml"
+ namespace = helm_release.zen_server.namespace
+ }
+
+ depends_on = [
+ helm_release.zen_server
+ ]
+}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/ingress.tf b/src/matcha_ml/infrastructure/llm/zen_server/ingress.tf
new file mode 100644
index 00000000..257498df
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/ingress.tf
@@ -0,0 +1,30 @@
+# # set up the nginx ingress controller
+# resource "kubernetes_namespace" "nginx-ns" {
+# count = var.create_ingress_controller ? 1 : 0
+# metadata {
+# name = "${var.name}-ingress"
+# }
+# }
+
+# resource "helm_release" "nginx-controller" {
+# name = "zenml"
+# count = var.create_ingress_controller ? 1 : 0
+# repository = "https://kubernetes.github.io/ingress-nginx"
+# chart = "ingress-nginx"
+# # dependency on nginx-ns
+# namespace = var.create_ingress_controller ? kubernetes_namespace.nginx-ns[0].metadata[0].name : ""
+# depends_on = [
+# resource.kubernetes_namespace.nginx-ns
+# ]
+# }
+
+# data "kubernetes_service" "ingress-controller" {
+# count = var.create_ingress_controller ? 1 : 0
+# metadata {
+# name = "zenml-ingress-nginx-controller"
+# namespace = var.create_ingress_controller ? kubernetes_namespace.nginx-ns[0].metadata[0].name : ""
+# }
+# depends_on = [
+# resource.helm_release.nginx-controller
+# ]
+# }
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/main.tf b/src/matcha_ml/infrastructure/llm/zen_server/main.tf
new file mode 100644
index 00000000..9e78107a
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/main.tf
@@ -0,0 +1,108 @@
+# Derived from ZenML's stack recipes; source: https://github.com/zenml-io/mlops-stacks/blob/8eb06596bf836d3a3dd2634fbc7f2b5687421811/modules/zenml-module/zen_server.tf
+
+# create the ZenServer deployment
+resource "kubernetes_namespace" "zen_server" {
+ metadata {
+ name = "${var.prefix}-${var.namespace}"
+ }
+}
+
+resource "helm_release" "zen_server" {
+
+ name = "${var.prefix}-zenserver"
+ chart = "${path.module}/zenml_helm"
+ namespace = kubernetes_namespace.zen_server.metadata[0].name
+
+ set {
+ name = "zenml.image.repository"
+ value = var.zenmlserver_image_repo
+ }
+
+ set {
+ name = "zenml.defaultUsername"
+ value = var.username
+ }
+ set {
+ name = "zenml.defaultPassword"
+ value = var.password
+ }
+ set {
+ name = "zenml.deploymentType"
+ value = "azure"
+ }
+ set {
+ name = "zenml.analyticsOptIn"
+ value = var.analytics_opt_in
+ }
+
+ # # Ingress set up
+ # set {
+ # name = "zenml.rootUrlPath"
+ # value = var.ingress_path != "" ? "/${var.ingress_path}" : ""
+ # }
+ # set {
+ # name = "zenml.ingress.path"
+ # value = var.ingress_path != "" ? "/${var.ingress_path}/?(.*)" : "/"
+ # }
+ # set {
+ # name = "zenml.ingress.annotations.nginx\\.ingress\\.kubernetes\\.io/rewrite-target"
+ # value = var.ingress_path != "" ? "/$1" : ""
+ # }
+ # set {
+ # name = "zenml.ingress.host"
+ # value = var.create_ingress_controller ? "${data.kubernetes_service.ingress-controller[0].status.0.load_balancer.0.ingress.0.ip}.nip.io" : "${var.ingress_controller_hostname}.nip.io"
+ # }
+ # set {
+ # name = "zenml.ingress.tls.enabled"
+ # value = var.ingress_tls
+ # }
+ # set {
+ # name = "zenml.ingress.tls.generateCerts"
+ # value = var.ingress_tls_generate_certs
+ # }
+ # set {
+ # name = "zenml.ingress.tls.secretName"
+ # value = "${var.prefix}-${var.ingress_tls_secret_name}"
+ # }
+
+ # set parameters for the mysql database
+ set {
+ name = "zenml.database.url"
+ value = var.deploy_db ? "mysql://${var.database_username}:${azurerm_mysql_flexible_server.mysql[0].administrator_password}@${azurerm_mysql_flexible_server.mysql[0].name}.mysql.database.azure.com:3306/${var.db_name}" : var.database_url
+ }
+ set {
+ name = "zenml.database.sslCa"
+ value = var.deploy_db ? "" : var.database_ssl_ca
+ }
+ set {
+ name = "zenml.database.sslCert"
+ value = var.deploy_db ? "" : var.database_ssl_cert
+ }
+ set {
+ name = "zenml.database.sslKey"
+ value = var.deploy_db ? "" : var.database_ssl_key
+ }
+ set {
+ name = "zenml.database.sslVerifyServerCert"
+ value = var.deploy_db ? false : var.database_ssl_verify_server_cert
+ }
+ depends_on = [
+ resource.kubernetes_namespace.zen_server
+ ]
+}
+
+# data "kubernetes_secret" "certificates" {
+# metadata {
+# name = "${var.prefix}-${var.ingress_tls_secret_name}"
+# namespace = "${var.prefix}-${var.namespace}"
+# }
+# binary_data = {
+# "tls.crt" = ""
+# "tls.key" = ""
+# "ca.crt" = ""
+# }
+
+# depends_on = [
+# helm_release.zen-server
+# ]
+# }
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/outputs.tf b/src/matcha_ml/infrastructure/llm/zen_server/outputs.tf
new file mode 100644
index 00000000..8d986559
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/outputs.tf
@@ -0,0 +1,19 @@
+output "zenserver_url" {
+ description = "The URL for the ZenML server"
+ value = "http://${data.kubernetes_service.zen_server.status.0.load_balancer.0.ingress.0.ip}"
+}
+
+output "zenserver_username" {
+ description = "The username used to access the ZenML server"
+ value = var.username
+}
+
+output "zenserver_password" {
+ description = "The password used to access the ZenML server"
+ value = var.password
+ sensitive = true
+}
+
+# output "zenserver_url" {
+# value = var.create_ingress_controller ? "https://${data.kubernetes_service.ingress-controller[0].status.0.load_balancer.0.ingress.0.ip}.nip.io/${var.ingress_path}" : "https://${var.ingress_controller_hostname}.nip.io/${var.ingress_path}"
+# }
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/providers.tf b/src/matcha_ml/infrastructure/llm/zen_server/providers.tf
new file mode 100644
index 00000000..a418423b
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/providers.tf
@@ -0,0 +1,16 @@
+# defining the providers for the zenserver module
+terraform {
+ required_providers {
+ kubectl = {
+ source = "gavinbunney/kubectl"
+ version = "1.14.0"
+ }
+
+ htpasswd = {
+ source = "loafoe/htpasswd"
+ version = "1.0.4"
+ }
+ }
+
+ required_version = ">= 0.14.8"
+}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/sql.tf b/src/matcha_ml/infrastructure/llm/zen_server/sql.tf
new file mode 100644
index 00000000..4e87117e
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/sql.tf
@@ -0,0 +1,57 @@
+resource "azurerm_mysql_flexible_server" "mysql" {
+ count = var.deploy_db ? 1 : 0
+ name = "${var.prefix}${var.db_instance_name}"
+ resource_group_name = var.resource_group_name
+ location = var.location
+ administrator_login = var.database_username
+ administrator_password = var.database_password == "" ? random_password.mysql_password.result : var.database_password
+ version = var.db_version
+ storage {
+ size_gb = var.db_disk_size
+ }
+ sku_name = var.db_sku_name
+}
+
+resource "azurerm_mysql_flexible_database" "db" {
+ count = var.deploy_db ? 1 : 0
+ name = "${var.prefix}${var.db_name}"
+ resource_group_name = var.resource_group_name
+ server_name = azurerm_mysql_flexible_server.mysql[0].name
+ charset = "utf8"
+ collation = "utf8_unicode_ci"
+}
+
+resource "azurerm_mysql_flexible_server_firewall_rule" "allow_IPs" {
+ count = var.deploy_db ? 1 : 0
+ name = "all_traffic"
+ resource_group_name = var.resource_group_name
+ server_name = azurerm_mysql_flexible_server.mysql[0].name
+ start_ip_address = "0.0.0.0"
+ end_ip_address = "255.255.255.255"
+}
+
+resource "azurerm_mysql_flexible_server_configuration" "require_ssl" {
+ count = var.deploy_db ? 1 : 0
+ name = "require_secure_transport"
+ resource_group_name = var.resource_group_name
+ server_name = azurerm_mysql_flexible_server.mysql[0].name
+ value = "OFF"
+}
+
+resource "random_password" "mysql_password" {
+ length = 12
+ special = false
+ min_lower = 1
+ min_numeric = 1
+ min_upper = 1
+}
+
+# # download SSL certificate
+# resource "null_resource" "download-SSL-certificate" {
+# count = var.deploy_db ? 1 : 0
+
+# provisioner "local-exec" {
+# command = "wget https://dl.cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem"
+# }
+
+# }
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/variables.tf b/src/matcha_ml/infrastructure/llm/zen_server/variables.tf
new file mode 100644
index 00000000..9c969b01
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/variables.tf
@@ -0,0 +1,168 @@
+variable "prefix" {
+ description = "A prefix used for all resources"
+ type = string
+}
+
+variable "resource_group_name" {
+ description = "The resource group in Azure that you want to deploy ZenML to"
+ type = string
+}
+
+variable "location" {
+ description = "The location for your Azure resources"
+ type = string
+}
+
+# ZenServer credentials
+variable "username" {
+ description = "Username for the default ZenML server account"
+ default = "default"
+ type = string
+}
+
+variable "password" {
+ description = "Password for the default ZenML server account"
+ type = string
+}
+
+variable "namespace" {
+ description = "The namespace to install the ZenML server Helm chart in"
+ default = "terraform-server"
+ type = string
+}
+
+variable "kubectl_config_path" {
+ description = "The path to the kube config"
+ default = ""
+ type = string
+}
+
+variable "analytics_opt_in" {
+ description = "The flag to enable/disable analytics"
+ default = false
+ type = bool
+}
+
+# If you want a new Flexible Server, choose a name and a password. If you already
+# have an instance, provide the name and the password here too.
+variable "database_username" {
+ description = "The username for the CloudSQL store"
+ default = "user"
+ type = string
+}
+variable "database_password" {
+ description = "The password for the CloudSQL store"
+ default = ""
+ type = string
+}
+
+# if you enable the deploy_db option, this will
+# create a new Flexible MySQL instance and then use it for this
+# ZenServer. If disabled, you have to supply connection details
+# in the section below.
+variable "deploy_db" {
+ description = "Should a Flexible MySQL instance be created?"
+ default = true
+ type = bool
+}
+variable "db_instance_name" {
+ description = "The name for the Flexible MySQL store"
+ default = "zenmlserver"
+ type = string
+}
+variable "db_name" {
+ description = "The name for the database"
+ default = "zendb"
+ type = string
+}
+variable "db_version" {
+ description = "The version of MySQL to use"
+ default = "5.7"
+}
+variable "db_sku_name" {
+ description = "The sku_name for the database resource"
+ default = "B_Standard_B1s"
+ type = string
+}
+variable "db_disk_size" {
+ description = "The allocated storage in gigabytes"
+ default = 20
+ type = number
+}
+
+# If you haven't enabled the deploy_db option, provide
+# the following value in addition to setting the username and
+# password in the values.tfvars.json file.
+variable "database_url" {
+ description = "The URL for the Flexible MySQL instance"
+ default = ""
+ type = string
+}
+variable "database_ssl_ca" {
+ description = "The server ca for the Flexible MySQL instance"
+ default = ""
+ type = string
+}
+variable "database_ssl_cert" {
+ description = "The client cert for the Flexible MySQL instance"
+ default = ""
+ type = string
+}
+variable "database_ssl_key" {
+ description = "The client key for the Flexible MySQL instance"
+ default = ""
+ type = string
+}
+variable "database_ssl_verify_server_cert" {
+ description = "Should SSL be verified?"
+ default = false
+ type = bool
+}
+
+# # Ingress variables
+# variable "ingress_path" {
+# description = "The path on the Ingress URL to expose ZenML at"
+# default = "zenml"
+# type = string
+# }
+
+# # set to true if you don't already have an nginx ingress
+# # controller in your cluster
+# variable "create_ingress_controller" {
+# description = "set to true if you want to create an ingress controller in your cluster"
+# default = true
+# type = bool
+# }
+
+# # if you already have an ingress controller, supply it's URL
+# variable "ingress_controller_hostname" {
+# description = "The hostname for the ingress controller on your cluster"
+# default = ""
+# type = string
+# }
+# variable "ingress_tls" {
+# description = "Whether to enable tls on the ingress or not"
+# default = true
+# type = bool
+# }
+# variable "ingress_tls_generate_certs" {
+# description = "Whether to enable tls certificates or not"
+# default = true
+# type = bool
+# }
+# variable "ingress_tls_secret_name" {
+# description = "Name for the Kubernetes secret that stores certificates"
+# default = "zenml-tls-certs"
+# type = string
+# }
+
+variable "zenmlserver_image_repo" {
+ description = "The repository to use for the zenmlserver docker image."
+ default = "zenmldocker/zenml-server"
+ type = string
+}
+variable "zenmlserver_image_tag" {
+ description = "The tag to use for the zenmlserver docker image."
+ default = "latest"
+ type = string
+}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/Chart.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/Chart.yaml
new file mode 100644
index 00000000..ce568663
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/Chart.yaml
@@ -0,0 +1,13 @@
+apiVersion: v2
+name: zenml
+version: "1.0"
+description: Open source MLOps framework for portable production ready ML pipelines
+keywords:
+- mlops
+- zenml
+- server
+home: https://zenml.io
+sources:
+- https://github.com/zenml-io/zenml
+icon: https://raw.githubusercontent.com/zenml-io/zenml/main/docs/book/assets/zenml_logo.png
+appVersion: "0.36.1"
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/NOTES.txt b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/NOTES.txt
new file mode 100644
index 00000000..a4de5753
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/NOTES.txt
@@ -0,0 +1,36 @@
+{{- if .Values.zenml.ingress.enabled }}
+{{- if .Values.zenml.ingress.host }}
+You can access the ZenML server at:
+
+ http{{ if $.Values.zenml.ingress.tls.enabled }}s{{ end }}://{{ .Values.zenml.ingress.host }}{{ .Values.zenml.ingress.path }}
+
+with the following credentials:
+
+ username: {{ .Values.zenml.defaultUsername }}
+ password: {{ .Values.zenml.defaultPassword }}
+
+{{- else }}
+
+
+{{- end }}
+{{- else }}
+
+You can get the ZenML server URL by running these commands:
+
+{{- if contains "NodePort" .Values.zenml.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "zenml.fullname" . }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.zenml.service.type }}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "zenml.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "zenml.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+ echo http://$SERVICE_IP:{{ .Values.zenml.service.port }}
+{{- else if contains "ClusterIP" .Values.zenml.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "zenml.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+ echo "Visit http://127.0.0.1:8080 to use your application"
+ kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
+
+{{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/_helpers.tpl b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/_helpers.tpl
new file mode 100644
index 00000000..6732baae
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/_helpers.tpl
@@ -0,0 +1,70 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "zenml.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "zenml.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "zenml.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "zenml.labels" -}}
+helm.sh/chart: {{ include "zenml.chart" . }}
+{{ include "zenml.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+{{- define "zenml.metadataLabels" -}}
+helm.sh/chart: {{ include "zenml.chart" . }}
+{{ include "zenml.metadataSelectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "zenml.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "zenml.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "zenml.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "zenml.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/cert-secret.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/cert-secret.yaml
new file mode 100644
index 00000000..c10854db
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/cert-secret.yaml
@@ -0,0 +1,45 @@
+{{- if and .Values.zenml.ingress.enabled .Values.zenml.ingress.tls.enabled .Values.zenml.ingress.tls.generateCerts -}}
+
+{{- $certSubjectName := .Values.zenml.ingress.host -}}
+
+{{- $prevServerSecret := (lookup "v1" "Secret" .Release.Namespace .Values.zenml.ingress.tls.secretName) -}}
+{{- if or .Release.IsInstall (not $prevServerSecret) }}
+{{- $_ := set . "regenerateCerts" true -}}
+{{- else if eq (index $prevServerSecret.metadata.annotations "zenml.certs/subject-name") $certSubjectName }}
+{{- $_ := set . "regenerateCerts" false -}}
+{{- else }}
+{{- $_ := set . "regenerateCerts" true -}}
+{{- end }}
+
+{{- if .regenerateCerts }}
+
+{{- $caCert := genCA "zenml-ca" 365 -}}
+{{- $serverCert := genSignedCert $certSubjectName nil (list $certSubjectName) 365 $caCert -}}
+
+{{- $_ := set . "caCert" $caCert.Cert -}}
+{{- $_ := set . "serverCert" $serverCert.Cert -}}
+{{- $_ := set . "serverKey" $serverCert.Key -}}
+
+{{- else }}
+
+{{- $_ := set . "caCert" (index $prevServerSecret.data "ca.crt" | b64dec) -}}
+{{- $_ := set . "serverCert" (index $prevServerSecret.data "tls.crt" | b64dec) -}}
+{{- $_ := set . "serverKey" (index $prevServerSecret.data "tls.key" | b64dec) -}}
+
+{{- end }}
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ .Values.zenml.ingress.tls.secretName }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+ annotations:
+ zenml.certs/subject-name: {{ $certSubjectName}}
+type: kubernetes.io/tls
+data:
+ tls.crt: {{ .serverCert | b64enc | quote }}
+ tls.key: {{ .serverKey | b64enc | quote }}
+ ca.crt: {{ .caCert | b64enc | quote }}
+
+{{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/hpa.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/hpa.yaml
new file mode 100644
index 00000000..da913c40
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/hpa.yaml
@@ -0,0 +1,28 @@
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: {{ include "zenml.fullname" . }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ include "zenml.fullname" . }}
+ minReplicas: {{ .Values.autoscaling.minReplicas }}
+ maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+ metrics:
+ {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: cpu
+ targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+ {{- end }}
+ {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: memory
+ targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ {{- end }}
+{{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-deployment.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-deployment.yaml
new file mode 100644
index 00000000..faa2df8b
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-deployment.yaml
@@ -0,0 +1,243 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "zenml.fullname" . }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+spec:
+ {{- if .Values.zenml.database.url }}
+ {{- if not .Values.autoscaling.enabled }}
+ replicas: {{ .Values.zenml.replicaCount }}
+ {{- end }}
+ {{- else }}
+ replicas: 1
+ {{- end }}
+ selector:
+ matchLabels:
+ {{- include "zenml.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ annotations:
+ checksum/secret: {{ include (print $.Template.BasePath "/server-secret.yaml") . | sha256sum }}
+ {{- with .Values.podAnnotations }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "zenml.selectorLabels" . | nindent 8 }}
+ spec:
+ {{- with .Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ serviceAccountName: {{ include "zenml.serviceAccountName" . }}
+ securityContext:
+ {{- toYaml .Values.podSecurityContext | nindent 8 }}
+ {{- if and (eq .Values.zenml.secretsStore.type "gcp") .Values.zenml.secretsStore.gcp.google_application_credentials }}
+ volumes:
+ - name: gcp-credentials
+ secret:
+ secretName: {{ include "zenml.fullname" . }}
+ items:
+ - key: GOOGLE_APPLICATION_CREDENTIALS_FILE
+ path: credentials.json
+ {{- end }}
+ {{- if .Values.zenml.database.url }}
+ initContainers:
+ - name: {{ .Chart.Name }}-db-init
+ securityContext:
+ {{- toYaml .Values.securityContext | nindent 12 }}
+ image: "{{ .Values.zenml.image.repository }}:{{ .Values.zenml.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: {{ .Values.zenml.image.pullPolicy }}
+ args: ["status"]
+ command: ['zenml']
+ env:
+ {{- if .Values.zenml.debug }}
+ - name: ZENML_LOGGING_VERBOSITY
+ value: "DEBUG"
+ {{- end }}
+ {{- if .Values.zenml.analyticsOptIn }}
+ - name: ZENML_ANALYTICS_OPT_IN
+ value: "True"
+ {{- else if not .Values.zenml.analyticsOptIn }}
+ - name: ZENML_ANALYTICS_OPT_IN
+ value: "False"
+ {{- end }}
+ - name: ZENML_DEFAULT_PROJECT_NAME
+ value: {{ .Values.zenml.defaultProject | quote }}
+ - name: ZENML_DEFAULT_USER_NAME
+ value: {{ .Values.zenml.defaultUsername | quote }}
+ {{- if .Values.zenml.database.url }}
+ - name: ZENML_STORE_TYPE
+ value: sql
+ - name: ZENML_STORE_SSL_VERIFY_SERVER_CERT
+ value: {{ .Values.zenml.database.sslVerifyServerCert | default "false" | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.enabled }}
+ - name: ZENML_SECRETS_STORE_TYPE
+ value: {{ .Values.zenml.secretsStore.type | quote }}
+ {{- if eq .Values.zenml.secretsStore.type "aws" }}
+ - name: ZENML_SECRETS_STORE_REGION_NAME
+ value: {{ .Values.zenml.secretsStore.aws.region_name | quote }}
+ - name: ZENML_SECRETS_STORE_SECRET_LIST_REFRESH_TIMEOUT
+ value: {{ .Values.zenml.secretsStore.aws.secret_list_refresh_timeout | quote }}
+ {{- else if eq .Values.zenml.secretsStore.type "gcp" }}
+ - name: ZENML_SECRETS_STORE_PROJECT_ID
+ value: {{ .Values.zenml.secretsStore.gcp.project_id | quote }}
+ {{- if .Values.zenml.secretsStore.gcp.google_application_credentials }}
+ - name: GOOGLE_APPLICATION_CREDENTIALS
+ value: /gcp-credentials/credentials.json
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "azure" }}
+ - name: ZENML_SECRETS_STORE_KEY_VAULT_NAME
+ value: {{ .Values.zenml.secretsStore.azure.key_vault_name | quote }}
+ {{- else if eq .Values.zenml.secretsStore.type "hashicorp" }}
+ - name: ZENML_SECRETS_STORE_VAULT_ADDR
+ value: {{ .Values.zenml.secretsStore.hashicorp.vault_addr | quote }}
+ {{- if .Values.zenml.secretsStore.hashicorp.vault_namespace }}
+ - name: ZENML_SECRETS_STORE_VAULT_NAMESPACE
+ value: {{ .Values.zenml.secretsStore.hashicorp.vault_namespace | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.hashicorp.max_versions }}
+ - name: ZENML_SECRETS_STORE_MAX_VERSIONS
+ value: {{ .Values.zenml.secretsStore.hashicorp.max_versions | quote }}
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "custom" }}
+ - name: ZENML_SECRETS_STORE_CLASS_PATH
+ value: {{ .Values.zenml.secretsStore.custom.class_path | quote }}
+ {{- end }}
+ {{- else }}
+ - name: ZENML_SECRETS_STORE_TYPE
+ value: none
+ {{- end }}
+ {{- if .Values.zenml.environment }}
+ {{- range $key, $value := .Values.zenml.environment }}
+ - name: {{ $key }}
+ value: {{ $value | quote }}
+ {{- end }}
+ {{- end }}
+ envFrom:
+ - secretRef:
+ name: {{ include "zenml.fullname" . }}
+ {{- if and (eq .Values.zenml.secretsStore.type "gcp") .Values.zenml.secretsStore.gcp.google_application_credentials }}
+ volumeMounts:
+ - name: gcp-credentials
+ mountPath: /gcp-credentials
+ readOnly: true
+ {{- end }}
+ {{- end }}
+ containers:
+ - name: {{ .Chart.Name }}
+ securityContext:
+ {{- toYaml .Values.securityContext | nindent 12 }}
+ image: "{{ .Values.zenml.image.repository }}:{{ .Values.zenml.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: {{ .Values.zenml.image.pullPolicy }}
+ env:
+ {{- if .Values.zenml.debug }}
+ - name: ZENML_LOGGING_VERBOSITY
+ value: "DEBUG"
+ {{- end }}
+ {{- if .Values.zenml.analyticsOptIn }}
+ - name: ZENML_ANALYTICS_OPT_IN
+ value: "True"
+ {{- else if not .Values.zenml.analyticsOptIn }}
+ - name: ZENML_ANALYTICS_OPT_IN
+ value: "False"
+ {{- end }}
+ - name: ZENML_AUTH_TYPE
+ value: {{ .Values.zenml.authType | quote }}
+ {{- if .Values.zenml.rootUrlPath }}
+ - name: ZENML_SERVER_ROOT_URL_PATH
+ value: {{ .Values.zenml.rootUrlPath | quote }}
+ {{- end }}
+ - name: ZENML_DEFAULT_PROJECT_NAME
+ value: {{ .Values.zenml.defaultProject | quote }}
+ - name: ZENML_DEFAULT_USER_NAME
+ value: {{ .Values.zenml.defaultUsername | quote }}
+ {{- if .Values.zenml.database.url }}
+ - name: ZENML_STORE_TYPE
+ value: sql
+ - name: DISABLE_DATABASE_MIGRATION
+ value: "True"
+ - name: ZENML_STORE_SSL_VERIFY_SERVER_CERT
+ value: {{ .Values.zenml.database.sslVerifyServerCert | default "false" | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.enabled }}
+ - name: ZENML_SECRETS_STORE_TYPE
+ value: {{ .Values.zenml.secretsStore.type | quote }}
+ {{- if eq .Values.zenml.secretsStore.type "aws" }}
+ - name: ZENML_SECRETS_STORE_REGION_NAME
+ value: {{ .Values.zenml.secretsStore.aws.region_name | quote }}
+ - name: ZENML_SECRETS_STORE_SECRET_LIST_REFRESH_TIMEOUT
+ value: {{ .Values.zenml.secretsStore.aws.secret_list_refresh_timeout | quote }}
+ {{- else if eq .Values.zenml.secretsStore.type "gcp" }}
+ - name: ZENML_SECRETS_STORE_PROJECT_ID
+ value: {{ .Values.zenml.secretsStore.gcp.project_id | quote }}
+ {{- if .Values.zenml.secretsStore.gcp.google_application_credentials }}
+ - name: GOOGLE_APPLICATION_CREDENTIALS
+ value: /gcp-credentials/credentials.json
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "azure" }}
+ - name: ZENML_SECRETS_STORE_KEY_VAULT_NAME
+ value: {{ .Values.zenml.secretsStore.azure.key_vault_name | quote }}
+ {{- else if eq .Values.zenml.secretsStore.type "hashicorp" }}
+ - name: ZENML_SECRETS_STORE_VAULT_ADDR
+ value: {{ .Values.zenml.secretsStore.hashicorp.vault_addr | quote }}
+ {{- if .Values.zenml.secretsStore.hashicorp.vault_namespace }}
+ - name: ZENML_SECRETS_STORE_VAULT_NAMESPACE
+ value: {{ .Values.zenml.secretsStore.hashicorp.vault_namespace | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.hashicorp.max_versions }}
+ - name: ZENML_SECRETS_STORE_MAX_VERSIONS
+ value: {{ .Values.zenml.secretsStore.hashicorp.max_versions | quote }}
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "custom" }}
+ - name: ZENML_SECRETS_STORE_CLASS_PATH
+ value: {{ .Values.zenml.secretsStore.custom.class_path | quote }}
+ {{- end }}
+ {{- else }}
+ - name: ZENML_SECRETS_STORE_TYPE
+ value: none
+ {{- end }}
+ - name: ZENML_SERVER_DEPLOYMENT_TYPE
+ value: {{ .Values.zenml.deploymentType | default "kubernetes" }}
+ {{- if .Values.zenml.environment }}
+ {{- range $key, $value := .Values.zenml.environment }}
+ - name: {{ $key }}
+ value: {{ $value | quote }}
+ {{- end }}
+ {{- end }}
+ envFrom:
+ - secretRef:
+ name: {{ include "zenml.fullname" . }}
+ {{- if and (eq .Values.zenml.secretsStore.type "gcp") .Values.zenml.secretsStore.gcp.google_application_credentials }}
+ volumeMounts:
+ - name: gcp-credentials
+ mountPath: /gcp-credentials
+ readOnly: true
+ {{- end }}
+ ports:
+ - name: http
+ containerPort: 8080
+ protocol: TCP
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: http
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: http
+ resources:
+ {{- toYaml .Values.resources | nindent 12 }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-ingress.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-ingress.yaml
new file mode 100644
index 00000000..91de1992
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-ingress.yaml
@@ -0,0 +1,59 @@
+{{- if .Values.zenml.ingress.enabled -}}
+{{- $fullName := include "zenml.fullname" . -}}
+{{- $svcPort := .Values.zenml.service.port -}}
+{{- if and .Values.zenml.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
+ {{- if not (hasKey .Values.zenml.ingress.annotations "kubernetes.io/ingress.class") }}
+ {{- $_ := set .Values.zenml.ingress.annotations "kubernetes.io/ingress.class" .Values.zenml.ingress.className}}
+ {{- end }}
+{{- end }}
+{{- if $.Values.zenml.ingress.tls.enabled }}
+ {{- $_ := set .Values.zenml.ingress.annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true"}}
+{{- end }}
+
+{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+ name: {{ $fullName }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+ {{- with .Values.zenml.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- if and .Values.zenml.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
+ ingressClassName: {{ .Values.zenml.ingress.className }}
+ {{- end }}
+ {{- if .Values.zenml.ingress.tls.enabled }}
+ tls:
+ - hosts:
+ - {{ .Values.zenml.ingress.host | quote }}
+ secretName: {{ .Values.zenml.ingress.tls.secretName }}
+ {{- end }}
+ rules:
+ - http:
+ paths:
+ - path: {{ .Values.zenml.ingress.path }}
+ {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
+ pathType: Prefix
+ {{- end }}
+ backend:
+ {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $svcPort }}
+ {{- else }}
+ serviceName: {{ $fullName }}
+ servicePort: {{ $svcPort }}
+ {{- end }}
+ {{- if .Values.zenml.ingress.host }}
+ host: {{ .Values.zenml.ingress.host | quote }}
+ {{- end }}
+{{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-secret.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-secret.yaml
new file mode 100644
index 00000000..45f8fd11
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-secret.yaml
@@ -0,0 +1,70 @@
+apiVersion: v1
+kind: Secret
+type: Opaque
+metadata:
+ name: {{ include "zenml.fullname" . }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+data:
+ ZENML_DEFAULT_USER_PASSWORD: {{ .Values.zenml.defaultPassword | b64enc | quote }}
+ {{- if .Values.zenml.jwtSecretKey }}
+ ZENML_JWT_SECRET_KEY: {{ .Values.zenml.jwtSecretKey | b64enc | quote }}
+ {{- else if .Release.IsInstall }}
+ ZENML_JWT_SECRET_KEY: {{ randAlphaNum 32 | b64enc | quote }}
+ {{- else }}
+ ZENML_JWT_SECRET_KEY: {{ (lookup "v1" "Secret" .Release.Namespace (include "zenml.fullname" .)).data.ZENML_JWT_SECRET_KEY | default (randAlphaNum 32 | b64enc | quote) }}
+ {{- end }}
+ {{- if .Values.zenml.database.url }}
+ ZENML_STORE_URL: {{ .Values.zenml.database.url | b64enc | quote }}
+ {{- if .Values.zenml.database.sslCa }}
+ ZENML_STORE_SSL_CA: {{ .Files.Get .Values.zenml.database.sslCa | b64enc }}
+ {{- end }}
+ {{- if .Values.zenml.database.sslCert }}
+ ZENML_STORE_SSL_CERT: {{ .Files.Get .Values.zenml.database.sslCert | b64enc }}
+ {{- end }}
+ {{- if .Values.zenml.database.sslKey }}
+ ZENML_STORE_SSL_KEY: {{ .Files.Get .Values.zenml.database.sslKey | b64enc }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.enabled }}
+ {{- if eq .Values.zenml.secretsStore.type "sql" }}
+ {{- if .Values.zenml.secretsStore.sql.encryptionKey }}
+ ZENML_SECRETS_STORE_ENCRYPTION_KEY: {{ .Values.zenml.secretsStore.sql.encryptionKey | b64enc | quote }}
+ {{- else if .Values.zenml.secretsStore.encryptionKey }}
+ ZENML_SECRETS_STORE_ENCRYPTION_KEY: {{ .Values.zenml.secretsStore.encryptionKey | b64enc | quote }}
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "aws" }}
+ {{- if .Values.zenml.secretsStore.aws.aws_access_key_id }}
+ ZENML_SECRETS_STORE_AWS_ACCESS_KEY_ID: {{ .Values.zenml.secretsStore.aws.aws_access_key_id | b64enc | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.aws.aws_secret_access_key }}
+ ZENML_SECRETS_STORE_AWS_SECRET_ACCESS_KEY: {{ .Values.zenml.secretsStore.aws.aws_secret_access_key | b64enc | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.aws.aws_session_token }}
+ ZENML_SECRETS_STORE_AWS_SESSION_TOKEN: {{ .Values.zenml.secretsStore.aws.aws_session_token | b64enc | quote }}
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "azure" }}
+ {{- if .Values.zenml.secretsStore.azure.azure_client_id }}
+ ZENML_SECRETS_STORE_AZURE_CLIENT_ID: {{ .Values.zenml.secretsStore.azure.azure_client_id | b64enc | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.azure.azure_client_secret }}
+ ZENML_SECRETS_STORE_AZURE_CLIENT_SECRET: {{ .Values.zenml.secretsStore.azure.azure_client_secret | b64enc | quote }}
+ {{- end }}
+ {{- if .Values.zenml.secretsStore.azure.azure_tenant_id }}
+ ZENML_SECRETS_STORE_AZURE_TENANT_ID: {{ .Values.zenml.secretsStore.azure.azure_tenant_id | b64enc | quote }}
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "gcp" }}
+ {{- if .Values.zenml.secretsStore.gcp.google_application_credentials }}
+ GOOGLE_APPLICATION_CREDENTIALS_FILE: {{ .Files.Get .Values.zenml.secretsStore.gcp.google_application_credentials | b64enc | quote }}
+ {{- end }}
+ {{- else if eq .Values.zenml.secretsStore.type "hashicorp" }}
+ {{- if .Values.zenml.secretsStore.hashicorp.vault_token }}
+ ZENML_SECRETS_STORE_VAULT_TOKEN: {{ .Values.zenml.secretsStore.hashicorp.vault_token | b64enc | quote }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.zenml.environment }}
+ {{- range $key, $value := .Values.zenml.environment }}
+ {{ $key }}: {{ $value | b64enc | quote }}
+ {{- end }}
+ {{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-service.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-service.yaml
new file mode 100644
index 00000000..74d00f3a
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/server-service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "zenml.fullname" . }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+spec:
+ type: {{ .Values.zenml.service.type }}
+ ports:
+ - port: {{ .Values.zenml.service.port }}
+ targetPort: 8080
+ protocol: TCP
+ name: http
+ selector:
+ {{- include "zenml.selectorLabels" . | nindent 4 }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/serviceaccount.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/serviceaccount.yaml
new file mode 100644
index 00000000..79eacbc8
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/serviceaccount.yaml
@@ -0,0 +1,12 @@
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "zenml.serviceAccountName" . }}
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- end }}
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/tests/test-connection.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/tests/test-connection.yaml
new file mode 100644
index 00000000..1ff5a91f
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/templates/tests/test-connection.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: "{{ include "zenml.fullname" . }}-test-connection"
+ labels:
+ {{- include "zenml.labels" . | nindent 4 }}
+ annotations:
+ "helm.sh/hook": test
+spec:
+ containers:
+ - name: wget
+ image: busybox
+ command: ['wget']
+ args: ['{{ include "zenml.fullname" . }}:{{ .Values.zenml.service.port }}']
+ restartPolicy: Never
diff --git a/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/values.yaml b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/values.yaml
new file mode 100644
index 00000000..53c34b24
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zen_server/zenml_helm/values.yaml
@@ -0,0 +1,311 @@
+# Default values for zenml.
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+# ZenML server related options.
+zenml:
+ replicaCount: 1
+
+ image:
+ repository: zenmldocker/zenml-server
+ pullPolicy: Always
+ # Overrides the image tag whose default is the chart appVersion.
+ tag:
+
+ debug: true
+
+ # Flag to enable/disable the tracking process of the analytics
+ analyticsOptIn: true
+
+ # ZenML server deployment type. This field is used for telemetry purposes.
+ # Example values are "local", "kubernetes", "aws", "gcp", "azure".
+ deploymentType:
+
+ # The ZenML authentication scheme. Use one of:
+ #
+ # NO_AUTH - No authentication
+ # HTTP_BASIC - HTTP Basic authentication
+ # OAUTH2_PASSWORD_BEARER - OAuth2 password bearer with JWT tokens
+ authType: OAUTH2_PASSWORD_BEARER
+
+ # The secret key used to sign JWT tokens. Only relevant if the
+ # OAUTH2_PASSWORD_BEARER authentication scheme is used. This should be set to
+ # a random string with a recommended length of at least 32 characters, e.g.:
+ #
+ # ```python
+ # from secrets import token_hex
+ # token_hex(32)
+ # ```
+ #
+ # or:
+ #
+ # ```shell
+ # openssl rand -hex 32
+ # ```
+ #
+ # If not explicitly set, a random key will be generated when the helm
+ # chart is installed and reused for all subsequent upgrades.
+ jwtSecretKey:
+
+ # The root URL path to use when behind a proxy. This is useful when the
+ # `rewrite-target` annotation is used in the ingress controller, e.g.:
+ #
+ # ```yaml
+ # rootUrlPath: /zenml
+ #
+ # ingress:
+ # enabled: true
+ # className: "nginx"
+ # annotations:
+ # nginx.ingress.kubernetes.io/rewrite-target: /$1
+ # host:
+ # path: /zenml/?(.*)
+ # ```
+ rootUrlPath:
+
+ defaultProject: default
+ defaultUsername: default
+ # Use your own password here
+ defaultPassword: zenml
+
+ # MySQL database configuration. If not set, a local sqlite database will be
+ # used, which will not be persisted across pod restarts.
+ # NOTE: the certificate files need to be copied in the helm chart folder and
+ # the paths configured here need to be relative to the root of the helm chart.
+ database:
+ {}
+ # url: "mysql://admin:password@zenml-mysql:3306/database"
+ # sslCa: /path/to/ca.pem
+ # sslCert: /path/to/client-cert.pem
+ # sslKey: /path/to/client-key.pem
+ # sslVerifyServerCert: True
+
+ # Secrets store settings. This is used to store centralized secrets.
+ secretsStore:
+ # Set to false to disable the secrets store.
+ enabled: true
+
+ # The type of secrets store to use. Use one of:
+ #
+ # sql - Use the same SQL database as the ZenML server
+ # aws - Use the AWS Secrets Manager as a secrets store
+ # gcp - Use the GCP Secrets Manager as a secrets store
+ # azure - Use the Azure Key Vault as a secrets store
+ # hashicorp - Use the HashiCorp Vault as a secrets store
+ # custom - Use a custom secrets store implementation (needs a custom
+ # ZenML server image with the custom secrets store implementation
+ # installed)
+ #
+ # Depending on the type, additional configuration options may be required
+ # under the respective sections.
+ #
+ type: sql
+
+ # SQL secrets store configuration. Only relevant if the `sql` secrets store
+ # type is configured.
+ sql:
+ # The secret key used to encrypt secrets in the SQL database. Only relevant
+ # if the SQL secrets store type is used. This should be set to a random
+ # string with a recommended length of at least 32 characters, e.g.:
+ #
+ # ```python
+ # from secrets import token_hex
+ # token_hex(32)
+ # ```
+ #
+ # or:
+ #
+ # ```shell
+ # openssl rand -hex 32
+ # ```
+ #
+ # If not set, database secret encryption will be disabled.
+ #
+ # IMPORTANT: If you configure encryption for your SQL database secrets
+ # store, you should keep this value somewhere safe and secure, as it will be
+ # required to decrypt the secrets in the database. If you lose the
+ # encryption key, you will not be able to decrypt the secrets in the
+ # database and will have to reset them. You should not change this value
+ # after you have already configured encryption for your SQL database
+ # secrets store.
+ encryptionKey:
+
+ # AWS secrets store configuration. Only relevant if the `aws` secrets store
+ # type is configured.
+ aws:
+ # The AWS region to use. This must be set to the region where the AWS
+ # Secrets Manager service that you want to use is located.
+ region_name: us-east-1
+
+ # The AWS credentials to use to authenticate with the AWS Secrets
+ # Manager instance. You can omit these if you are running the ZenML server
+ # in an AWS EKS cluster that has an IAM role attached to it that has
+ # permissions to access the AWS Secrets Manager instance.
+ # NOTE: setting this is the same as setting the AWS_ACCESS_KEY_ID,
+ # AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables
+ # in the zenml.secretEnvironment variable.
+ aws_access_key_id:
+ aws_secret_access_key:
+ aws_session_token:
+
+ # The AWS Secrets Manager has a known issue where it does not immediately
+ # reflect new and updated secrets in the `list_secrets` results. To work
+ # around this issue, you can set this value to a non-zero value to
+ # get the ZenML server to wait after creating or updating an AWS secret
+ # until the changes are reflected in the secrets returned by
+ # `list_secrets` or the number of seconds specified by this value has
+ # elapsed. Should not be set to a high value as it may cause thread
+ # starvation in the ZenML server on high load.
+ secret_list_refresh_timeout: 0
+
+ # GCP secrets store configuration. Only relevant if the `gcp` secrets store
+ # type is configured.
+ gcp:
+ # The GCP project ID to use. This must be set to the project ID where the
+ # GCP Secrets Manager service that you want to use is located.
+ project_id: my-gcp-project
+
+ # Path to the GCP credentials file to use to authenticate with the GCP Secrets
+ # Manager instance. You can omit this if you are running the ZenML server
+ # in a GCP GKE cluster that uses workload identity to authenticate with
+ # GCP services without the need for credentials.
+ # NOTE: the credentials file needs to be copied in the helm chart folder
+ # and the path configured here needs to be relative to the root of the
+ # helm chart.
+ google_application_credentials:
+
+ # AWS Key Vault secrets store configuration. Only relevant if the `azure`
+ # secrets store type is configured.
+ azure:
+ # The name of the Azure Key Vault. This must be set to point to the Azure
+ # Key Vault instance that you want to use.
+ key_vault_name:
+
+ # The Azure application service principal credentials to use to
+ # authenticate with the Azure Key Vault API. You can omit these if you are
+ # running the ZenML server hosted in Azure and are using a managed
+ # identity to access the Azure Key Vault service.
+ # NOTE: setting this is the same as setting the AZURE_CLIENT_ID,
+ # AZURE_CLIENT_SECRET, and AZURE_TENANT_ID environment variables
+ # in the zenml.secretEnvironment variable.
+ azure_client_id:
+ azure_client_secret:
+ azure_tenant_id:
+
+ # HashiCorp Vault secrets store configuration. Only relevant if the `hashicorp`
+ # secrets store type is configured
+ hashicorp:
+ # The url of the HashiCorp Vault server
+ vault_addr: https://vault.example.com
+ # The token used to authenticate with the Vault server
+ vault_token:
+ # The Vault Enterprise namespace. Not required for Vault OSS.
+ vault_namespace:
+ # The maximum number of secret versions to keep. If not set, the default
+ # value of 1 will be used (only the latest version will be kept).
+ max_versions:
+
+ # Custom secrets store configuration. Only relevant if the `custom` secrets
+ # store type is configured.
+ custom:
+ # The class path of the custom secrets store implementation. This should
+ # point to a full Python class that extends the
+ # `zenml.zen_stores.secrets_stores.base_secrets_store.BaseSecretsStore`
+ # base class. The class should be importable from the container image
+ # that you are using for the ZenML server.
+ #
+ # Any additional configuration options for the custom secrets store
+ # implementation should be passed through the `environment` and the
+ # `secretEnvironment` variables and using the `ZENML_SECRETS_STORE_`
+ # environment variable naming convention. For example, if the custom
+ # secrets store implementation expects an `aws_access_key_id` option, you
+ # should set the `ZENML_SECRETS_STORE_AWS_ACCESS_KEY_ID` environment
+ # variable in the `zenml.secretEnvironment` variable.
+ class_path: my.custom.secrets.store.MyCustomSecretsStore
+
+ # Extra environment variables to set in the ZenML server container.
+ environment: {}
+
+ # Extra environment variables to set in the ZenML server container that
+ # should be kept secret. These will be set as Kubernetes secrets and
+ # mounted as environment variables in the ZenML server container.
+ secretEnvironment: {}
+
+ service:
+ type: LoadBalancer # Changed from ClusterIP
+ port: 80
+
+ ingress:
+ enabled: false # Changed from true
+ className: "nginx"
+ annotations:
+ nginx.ingress.kubernetes.io/ssl-redirect: "true"
+ # nginx.ingress.kubernetes.io/rewrite-target: /$1
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ # cert-manager.io/cluster-issuer: "letsencrypt"
+
+ # hint: you can use a service like nip.io to get a wildcard DNS for your
+ # ingress IP address. For example, if your ingress IP is 192.168.0.1, you
+ # can use a host name like zenml.192.168.0.1.nip.io. This allows you to
+ # reuse the same ingress for multiple deployments and/or services.
+ host:
+ path: /
+ tls:
+ enabled: false
+ # NOTE: if enabled, this will generate self-signed certificates during
+ # installation. This also requires that the ingress host be set to the
+ # domain name or IP address used to access the ZenML server from outside
+ # the cluster.
+ generateCerts: false
+ secretName: zenml-tls-certs
+
+serviceAccount:
+ # Specifies whether a service account should be created
+ create: true
+ # Annotations to add to the service account
+ annotations: {}
+ # The name of the service account to use.
+ # If not set and create is true, a name is generated using the fullname template
+ name: "zenml"
+
+podAnnotations: {}
+
+podSecurityContext:
+ {}
+ # fsGroup: 2000
+
+securityContext:
+ runAsNonRoot: true
+ runAsUser: 1000
+ # capabilities:
+ # drop:
+ # - ALL
+
+resources:
+ {}
+ # We usually recommend not to specify default resources and to leave this as a conscious
+ # choice for the user. This also increases chances charts run on environments with little
+ # resources, such as Minikube. If you do want to specify resources, uncomment the following
+ # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+ # limits:
+ # cpu: 100m
+ # memory: 128Mi
+ # requests:
+ # cpu: 100m
+ # memory: 128Mi
+
+autoscaling:
+ enabled: false
+ minReplicas: 1
+ maxReplicas: 100
+ targetCPUUtilizationPercentage: 80
+ # targetMemoryUtilizationPercentage: 80
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/src/matcha_ml/infrastructure/llm/zenml_storage/README.md b/src/matcha_ml/infrastructure/llm/zenml_storage/README.md
new file mode 100644
index 00000000..3787ccea
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zenml_storage/README.md
@@ -0,0 +1,45 @@
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | n/a |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_role_assignment.zenmlstorage](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
+| [azurerm_storage_account.zenmlaccount](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource |
+| [azurerm_storage_container.zenmlstoragecontainer](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
+| [azurerm_storage_account.zenmlaccount](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/storage_account) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [aks\_principal\_id](#input\_aks\_principal\_id) | Principal id for aks cluster | `string` | n/a | yes |
+| [location](#input\_location) | The Azure Region in which this resources should be created. | `string` | n/a | yes |
+| [prefix](#input\_prefix) | A prefix used for all resources | `string` | n/a | yes |
+| [resource\_group\_name](#input\_resource\_group\_name) | The resource group name which is used to create the resource group | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [zenml\_blobstorage\_container\_path](#output\_zenml\_blobstorage\_container\_path) | The Azure Blob Storage Container path for storing zenml artifacts |
+| [zenml\_primary\_access\_key](#output\_zenml\_primary\_access\_key) | ZenML Azure Storage Account - Primary access key |
+| [zenml\_primary\_blob\_connection\_string](#output\_zenml\_primary\_blob\_connection\_string) | ZenML Azure Storage Account - Primary Blob service connection string |
+| [zenml\_primary\_connection\_string](#output\_zenml\_primary\_connection\_string) | ZenML Azure Storage Account - Primary connection string |
+| [zenml\_secondary\_access\_key](#output\_zenml\_secondary\_access\_key) | ZenML Azure Storage Account - Secondary access key |
+| [zenml\_secondary\_blob\_connection\_string](#output\_zenml\_secondary\_blob\_connection\_string) | ZenML Azure Storage Account - Secondary Blob service connection string |
+| [zenml\_secondary\_connection\_string](#output\_zenml\_secondary\_connection\_string) | ZenML Azure Storage Account - Secondary connection string |
+| [zenml\_storage\_account\_name](#output\_zenml\_storage\_account\_name) | The name of the Azure Storage Account used to store ZenML artifacts. |
+| [zenml\_storage\_container\_name](#output\_zenml\_storage\_container\_name) | The name of the Azure Storage container used to store ZenML artifacts. |
diff --git a/src/matcha_ml/infrastructure/llm/zenml_storage/main.tf b/src/matcha_ml/infrastructure/llm/zenml_storage/main.tf
new file mode 100644
index 00000000..8a37cb74
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zenml_storage/main.tf
@@ -0,0 +1,31 @@
+# Reference: https://github.com/hashicorp/terraform-provider-azurerm/tree/main/examples/storage/storage-container
+
+# create a storage account
+resource "azurerm_storage_account" "zenmlaccount" {
+ name = "${var.prefix}zenmlacc"
+ resource_group_name = var.resource_group_name
+ location = var.location
+
+ account_tier = "Standard"
+ account_kind = "StorageV2"
+ account_replication_type = "LRS"
+}
+
+# create a storage container inside created storage account
+resource "azurerm_storage_container" "zenmlstoragecontainer" {
+ name = "${var.prefix}artifactstore"
+ storage_account_name = azurerm_storage_account.zenmlaccount.name
+ container_access_type = "private"
+}
+
+
+data "azurerm_storage_account" "zenmlaccount" {
+ name = azurerm_storage_account.zenmlaccount.name
+ resource_group_name = var.resource_group_name
+}
+
+resource "azurerm_role_assignment" "zenmlstorage" {
+ scope = azurerm_storage_account.zenmlaccount.id
+ role_definition_name = "Contributor"
+ principal_id = var.aks_principal_id
+}
diff --git a/src/matcha_ml/infrastructure/llm/zenml_storage/output.tf b/src/matcha_ml/infrastructure/llm/zenml_storage/output.tf
new file mode 100644
index 00000000..84226fbf
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zenml_storage/output.tf
@@ -0,0 +1,50 @@
+output "zenml_storage_container_name" {
+ description = "The name of the Azure Storage container used to store ZenML artifacts."
+ value = azurerm_storage_container.zenmlstoragecontainer.name
+}
+
+output "zenml_blobstorage_container_path" {
+ description = "The Azure Blob Storage Container path for storing zenml artifacts"
+ value = "az://${azurerm_storage_container.zenmlstoragecontainer.name}"
+}
+
+output "zenml_storage_account_name" {
+ description = "The name of the Azure Storage Account used to store ZenML artifacts."
+ value = azurerm_storage_account.zenmlaccount.name
+}
+
+output "zenml_primary_access_key" {
+ description = "ZenML Azure Storage Account - Primary access key"
+ value = azurerm_storage_account.zenmlaccount.primary_access_key
+ sensitive = true
+}
+
+output "zenml_secondary_access_key" {
+ description = "ZenML Azure Storage Account - Secondary access key"
+ value = azurerm_storage_account.zenmlaccount.secondary_access_key
+ sensitive = true
+}
+
+output "zenml_primary_connection_string" {
+ description = "ZenML Azure Storage Account - Primary connection string"
+ value = azurerm_storage_account.zenmlaccount.primary_connection_string
+ sensitive = true
+}
+
+output "zenml_secondary_connection_string" {
+ description = "ZenML Azure Storage Account - Secondary connection string"
+ value = azurerm_storage_account.zenmlaccount.secondary_connection_string
+ sensitive = true
+}
+
+output "zenml_primary_blob_connection_string" {
+ description = "ZenML Azure Storage Account - Primary Blob service connection string"
+ value = azurerm_storage_account.zenmlaccount.primary_blob_connection_string
+ sensitive = true
+}
+
+output "zenml_secondary_blob_connection_string" {
+ description = "ZenML Azure Storage Account - Secondary Blob service connection string"
+ value = azurerm_storage_account.zenmlaccount.secondary_blob_connection_string
+ sensitive = true
+}
diff --git a/src/matcha_ml/infrastructure/llm/zenml_storage/variables.tf b/src/matcha_ml/infrastructure/llm/zenml_storage/variables.tf
new file mode 100644
index 00000000..c41ea739
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/zenml_storage/variables.tf
@@ -0,0 +1,19 @@
+variable "prefix" {
+ description = "A prefix used for all resources"
+ type = string
+}
+
+variable "resource_group_name" {
+ description = "The resource group name which is used to create the resource group"
+ type = string
+}
+
+variable "location" {
+ description = "The Azure Region in which this resources should be created."
+ type = string
+}
+
+variable "aks_principal_id" {
+ description = "Principal id for aks cluster"
+ type = string
+}
From 7d082066453e1afc5333d8c487340095e8878fc1 Mon Sep 17 00:00:00 2001
From: KirsoppJ <40233184+KirsoppJ@users.noreply.github.com>
Date: Wed, 9 Aug 2023 15:58:35 +0100
Subject: [PATCH 03/10] [RPD-283] add core function for updating stack type
(#185)
* [RPD-287] ZenML version inference for zenserver (#180)
* various changes
* change variable names to make things more clear
* shubham's comment
* test for latest
* update existing tests
* update existing tests
* shubham latest comment
* add gitflow notation branches to ci (#183)
* remove old, commented out code
* [RPD-260] Add an object to handle the `matcha.config.json` file. (#184)
* adds logic and tests for matcha config module
* updates docstrings
* adds tests and implements config object throughout matcha
* updated for pr comments
* updates docstring
* fixes ci
* updates for comments
* enum and metaclass
* enum and metaclass
* bug removal
* docstring stack_set
* docstring file exists
* fix current tests
* add a couple tests, move logic for updating to configservice
* lowercase-ify arg to enum
* american spelling
* american spelling
* chris' comment re overwriting
* friendlier api
* Runtime error if not recognised arg type fpor update()
* Runtime error if not recognised arg type fpor update()
* update provision to use new update() API
* update stack name
* tests
* tests
* tests
* quote marks
* type version, mypy
* various review comments
* test for update() function
* update tests to include quotes.
* fixing tests
* tidy tests, test error if resources provisioned
* clearer error handling
* remove unnecessary context
* update test to new error type
---------
Co-authored-by: Callum Wells <68609181+swells2020@users.noreply.github.com>
---
.github/workflows/ci.yml | 5 +-
poetry.lock | 924 +++++++++---------
src/matcha_ml/cli/cli.py | 10 +-
src/matcha_ml/config/__init__.py | 16 +
src/matcha_ml/config/matcha_config.py | 206 ++++
src/matcha_ml/core/core.py | 94 +-
.../resources/.terraform.lock.hcl | 11 +-
.../infrastructure/resources/main.tf | 2 +
.../infrastructure/resources/variables.tf | 6 +
.../resources/zen_server/main.tf | 4 +
.../resources/zen_server/variables.tf | 3 +-
.../zen_server/zenml_helm/Chart.yaml | 4 +-
.../templates/server-deployment.yaml | 9 +-
.../zenml_helm/templates/server-ingress.yaml | 2 +-
.../zen_server/zenml_helm/values.yaml | 37 +-
src/matcha_ml/state/remote_state_manager.py | 145 ++-
tests/conftest.py | 90 +-
tests/test_cli/test_provision.py | 4 +
tests/test_cli/test_stack.py | 89 +-
tests/test_config/test_matcha_config.py | 230 +++++
tests/test_core/test_core_provision.py | 10 +-
tests/test_core/test_stack_set.py | 84 ++
tests/test_state/test_remote_state_manager.py | 107 +-
23 files changed, 1413 insertions(+), 679 deletions(-)
create mode 100644 src/matcha_ml/config/__init__.py
create mode 100644 src/matcha_ml/config/matcha_config.py
create mode 100644 tests/test_config/test_matcha_config.py
create mode 100644 tests/test_core/test_stack_set.py
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e9e35ff4..47c5cc39 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,7 +6,10 @@ on:
branches:
- main
- develop
- - '**feature**'
+ - 'feature/*'
+ - 'hotfix/*'
+ - 'release/*'
+ - 'fixes/*'
push:
branches:
- main
diff --git a/poetry.lock b/poetry.lock
index b79044e2..10e4cfc6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -13,13 +13,13 @@ files = [
[[package]]
name = "azure-core"
-version = "1.26.4"
+version = "1.28.0"
description = "Microsoft Azure Core Library for Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "azure-core-1.26.4.zip", hash = "sha256:075fe06b74c3007950dd93d49440c2f3430fd9b4a5a2756ec8c79454afc989c6"},
- {file = "azure_core-1.26.4-py3-none-any.whl", hash = "sha256:d9664b4bc2675d72fba461a285ac43ae33abb2967014a955bf136d9703a2ab3c"},
+ {file = "azure-core-1.28.0.zip", hash = "sha256:e9eefc66fc1fde56dab6f04d4e5d12c60754d5a9fa49bdcfd8534fc96ed936bd"},
+ {file = "azure_core-1.28.0-py3-none-any.whl", hash = "sha256:dec36dfc8eb0b052a853f30c07437effec2f9e3e1fc8f703d9bdaa5cfc0043d9"},
]
[package.dependencies]
@@ -144,23 +144,23 @@ msrest = ">=0.7.1"
[[package]]
name = "azure-storage-blob"
-version = "12.16.0"
+version = "12.17.0"
description = "Microsoft Azure Blob Storage Client Library for Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "azure-storage-blob-12.16.0.zip", hash = "sha256:43b45f19a518a5c6895632f263b3825ebc23574f25cc84b66e1630a6160e466f"},
- {file = "azure_storage_blob-12.16.0-py3-none-any.whl", hash = "sha256:91bb192b2a97939c4259c72373bac0f41e30810bbc853d5184f0f45904eacafd"},
+ {file = "azure-storage-blob-12.17.0.zip", hash = "sha256:c14b785a17050b30fc326a315bdae6bc4a078855f4f94a4c303ad74a48dc8c63"},
+ {file = "azure_storage_blob-12.17.0-py3-none-any.whl", hash = "sha256:0016e0c549a80282d7b4920c03f2f4ba35c53e6e3c7dbcd2a4a8c8eb3882c1e7"},
]
[package.dependencies]
-azure-core = ">=1.26.0,<2.0.0"
+azure-core = ">=1.28.0,<2.0.0"
cryptography = ">=2.1.4"
isodate = ">=0.6.1"
-typing-extensions = ">=4.0.1"
+typing-extensions = ">=4.3.0"
[package.extras]
-aio = ["azure-core[aio] (>=1.26.0,<2.0.0)"]
+aio = ["azure-core[aio] (>=1.28.0,<2.0.0)"]
[[package]]
name = "backoff"
@@ -175,13 +175,13 @@ files = [
[[package]]
name = "certifi"
-version = "2023.5.7"
+version = "2023.7.22"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
files = [
- {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"},
- {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"},
+ {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
+ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
]
[[package]]
@@ -273,97 +273,97 @@ files = [
[[package]]
name = "charset-normalizer"
-version = "3.1.0"
+version = "3.2.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
files = [
- {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"},
- {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"},
+ {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
+ {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
]
[[package]]
name = "click"
-version = "8.1.3"
+version = "8.1.6"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
- {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
- {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
+ {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"},
+ {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"},
]
[package.dependencies]
@@ -396,62 +396,71 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
[[package]]
name = "coverage"
-version = "7.2.5"
+version = "7.2.7"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "coverage-7.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c"},
- {file = "coverage-7.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a"},
- {file = "coverage-7.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f"},
- {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a"},
- {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a"},
- {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11"},
- {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5"},
- {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c"},
- {file = "coverage-7.2.5-cp310-cp310-win32.whl", hash = "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5"},
- {file = "coverage-7.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c"},
- {file = "coverage-7.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce"},
- {file = "coverage-7.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88"},
- {file = "coverage-7.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e"},
- {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2"},
- {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139"},
- {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8"},
- {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed"},
- {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6"},
- {file = "coverage-7.2.5-cp311-cp311-win32.whl", hash = "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b"},
- {file = "coverage-7.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068"},
- {file = "coverage-7.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1"},
- {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33"},
- {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade"},
- {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5"},
- {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47"},
- {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd"},
- {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969"},
- {file = "coverage-7.2.5-cp37-cp37m-win32.whl", hash = "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718"},
- {file = "coverage-7.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0"},
- {file = "coverage-7.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84"},
- {file = "coverage-7.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790"},
- {file = "coverage-7.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771"},
- {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045"},
- {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614"},
- {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3"},
- {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd"},
- {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1"},
- {file = "coverage-7.2.5-cp38-cp38-win32.whl", hash = "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813"},
- {file = "coverage-7.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212"},
- {file = "coverage-7.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b"},
- {file = "coverage-7.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200"},
- {file = "coverage-7.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5"},
- {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e"},
- {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303"},
- {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3"},
- {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a"},
- {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1"},
- {file = "coverage-7.2.5-cp39-cp39-win32.whl", hash = "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31"},
- {file = "coverage-7.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252"},
- {file = "coverage-7.2.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3"},
- {file = "coverage-7.2.5.tar.gz", hash = "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"},
+ {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"},
+ {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"},
+ {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"},
+ {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"},
+ {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"},
+ {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"},
+ {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"},
+ {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"},
+ {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"},
+ {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"},
+ {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"},
+ {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"},
+ {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"},
+ {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"},
+ {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"},
+ {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"},
+ {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"},
+ {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"},
+ {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"},
+ {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"},
+ {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"},
+ {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"},
+ {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"},
+ {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"},
+ {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"},
+ {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"},
+ {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"},
+ {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"},
+ {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"},
+ {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"},
+ {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"},
+ {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"},
+ {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"},
+ {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"},
+ {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"},
+ {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"},
+ {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"},
+ {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"},
+ {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"},
+ {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"},
+ {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"},
+ {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"},
+ {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"},
+ {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"},
+ {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"},
+ {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"},
+ {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"},
+ {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"},
+ {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"},
+ {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"},
+ {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"},
+ {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"},
+ {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"},
+ {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"},
+ {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"},
+ {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"},
+ {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"},
+ {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"},
+ {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"},
+ {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"},
]
[package.dependencies]
@@ -462,30 +471,34 @@ toml = ["tomli"]
[[package]]
name = "cryptography"
-version = "40.0.2"
+version = "41.0.3"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:8f79b5ff5ad9d3218afb1e7e20ea74da5f76943ee5edb7f76e56ec5161ec782b"},
- {file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440"},
- {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df2af28d7bedc84fe45bd49bc35d710aede676e2a4cb7fc6d103a2adc8afe4d"},
- {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288"},
- {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a04386fb7bc85fab9cd51b6308633a3c271e3d0d3eae917eebab2fac6219b6d2"},
- {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:adc0d980fd2760c9e5de537c28935cc32b9353baaf28e0814df417619c6c8c3b"},
- {file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d5a1bd0e9e2031465761dfa920c16b0065ad77321d8a8c1f5ee331021fda65e9"},
- {file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a95f4802d49faa6a674242e25bfeea6fc2acd915b5e5e29ac90a32b1139cae1c"},
- {file = "cryptography-40.0.2-cp36-abi3-win32.whl", hash = "sha256:aecbb1592b0188e030cb01f82d12556cf72e218280f621deed7d806afd2113f9"},
- {file = "cryptography-40.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:b12794f01d4cacfbd3177b9042198f3af1c856eedd0a98f10f141385c809a14b"},
- {file = "cryptography-40.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:142bae539ef28a1c76794cca7f49729e7c54423f615cfd9b0b1fa90ebe53244b"},
- {file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:956ba8701b4ffe91ba59665ed170a2ebbdc6fc0e40de5f6059195d9f2b33ca0e"},
- {file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f01c9863da784558165f5d4d916093737a75203a5c5286fde60e503e4276c7a"},
- {file = "cryptography-40.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3daf9b114213f8ba460b829a02896789751626a2a4e7a43a28ee77c04b5e4958"},
- {file = "cryptography-40.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48f388d0d153350f378c7f7b41497a54ff1513c816bcbbcafe5b829e59b9ce5b"},
- {file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c0764e72b36a3dc065c155e5b22f93df465da9c39af65516fe04ed3c68c92636"},
- {file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cbaba590180cba88cb99a5f76f90808a624f18b169b90a4abb40c1fd8c19420e"},
- {file = "cryptography-40.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a38250f433cd41df7fcb763caa3ee9362777fdb4dc642b9a349721d2bf47404"},
- {file = "cryptography-40.0.2.tar.gz", hash = "sha256:c33c0d32b8594fa647d2e01dbccc303478e16fdd7cf98652d5b3ed11aa5e5c99"},
+ {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"},
+ {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"},
+ {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"},
+ {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd"},
+ {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47"},
+ {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116"},
+ {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c"},
+ {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae"},
+ {file = "cryptography-41.0.3-cp37-abi3-win32.whl", hash = "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306"},
+ {file = "cryptography-41.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574"},
+ {file = "cryptography-41.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087"},
+ {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858"},
+ {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906"},
+ {file = "cryptography-41.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e"},
+ {file = "cryptography-41.0.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd"},
+ {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207"},
+ {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84"},
+ {file = "cryptography-41.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7"},
+ {file = "cryptography-41.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d"},
+ {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de"},
+ {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"},
+ {file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"},
+ {file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"},
]
[package.dependencies]
@@ -494,22 +507,22 @@ cffi = ">=1.12"
[package.extras]
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
-pep8test = ["black", "check-manifest", "mypy", "ruff"]
-sdist = ["setuptools-rust (>=0.11.4)"]
+nox = ["nox"]
+pep8test = ["black", "check-sdist", "mypy", "ruff"]
+sdist = ["build"]
ssh = ["bcrypt (>=3.1.5)"]
-test = ["iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist"]
+test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
test-randomorder = ["pytest-randomly"]
-tox = ["tox"]
[[package]]
name = "dataclasses-json"
-version = "0.5.7"
+version = "0.5.9"
description = "Easily serialize dataclasses to and from JSON"
optional = false
python-versions = ">=3.6"
files = [
- {file = "dataclasses-json-0.5.7.tar.gz", hash = "sha256:c2c11bc8214fbf709ffc369d11446ff6945254a7f09128154a7620613d8fda90"},
- {file = "dataclasses_json-0.5.7-py3-none-any.whl", hash = "sha256:bc285b5f892094c3a53d558858a88553dd6a61a11ab1a8128a0e554385dcc5dd"},
+ {file = "dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e"},
+ {file = "dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c"},
]
[package.dependencies]
@@ -518,28 +531,28 @@ marshmallow-enum = ">=1.5.1,<2.0.0"
typing-inspect = ">=0.4.0"
[package.extras]
-dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=6.2.3)", "simplejson", "types-dataclasses"]
+dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "setuptools", "simplejson", "twine", "types-dataclasses", "wheel"]
[[package]]
name = "distlib"
-version = "0.3.6"
+version = "0.3.7"
description = "Distribution utilities"
optional = false
python-versions = "*"
files = [
- {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"},
- {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
+ {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"},
+ {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"},
]
[[package]]
name = "exceptiongroup"
-version = "1.1.1"
+version = "1.1.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
files = [
- {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
- {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
+ {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
+ {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
]
[package.extras]
@@ -547,18 +560,18 @@ test = ["pytest (>=6)"]
[[package]]
name = "filelock"
-version = "3.12.0"
+version = "3.12.2"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.7"
files = [
- {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"},
- {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"},
+ {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
+ {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
]
[package.extras]
-docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
+docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
[[package]]
name = "ghp-import"
@@ -579,13 +592,13 @@ dev = ["flake8", "markdown", "twine", "wheel"]
[[package]]
name = "griffe"
-version = "0.29.0"
+version = "0.32.3"
description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "griffe-0.29.0-py3-none-any.whl", hash = "sha256:e62ff34b04630c2382e2e277301cb2c29221fb09c04028e62ef35afccc64344b"},
- {file = "griffe-0.29.0.tar.gz", hash = "sha256:6fc892aaa251b3761e3a8d2f5893758e1850ec5d81d4605c4557be0666202a0b"},
+ {file = "griffe-0.32.3-py3-none-any.whl", hash = "sha256:d9471934225818bf8f309822f70451cc6abb4b24e59e0bb27402a45f9412510f"},
+ {file = "griffe-0.32.3.tar.gz", hash = "sha256:14983896ad581f59d5ad7b6c9261ff12bdaa905acccc1129341d13e545da8521"},
]
[package.dependencies]
@@ -593,13 +606,13 @@ colorama = ">=0.4"
[[package]]
name = "identify"
-version = "2.5.24"
+version = "2.5.26"
description = "File identification library for Python"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"},
- {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"},
+ {file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"},
+ {file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"},
]
[package.extras]
@@ -618,13 +631,13 @@ files = [
[[package]]
name = "importlib-metadata"
-version = "6.6.0"
+version = "6.8.0"
description = "Read metadata from Python packages"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
- {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
+ {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
+ {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
]
[package.dependencies]
@@ -633,7 +646,7 @@ zipp = ">=0.5"
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
perf = ["ipython"]
-testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
+testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
[[package]]
name = "iniconfig"
@@ -679,98 +692,99 @@ i18n = ["Babel (>=2.7)"]
[[package]]
name = "markdown"
-version = "3.3.7"
-description = "Python implementation of Markdown."
+version = "3.4.4"
+description = "Python implementation of John Gruber's Markdown."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"},
- {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"},
+ {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"},
+ {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"},
]
[package.dependencies]
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
[package.extras]
+docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"]
testing = ["coverage", "pyyaml"]
[[package]]
name = "markupsafe"
-version = "2.1.2"
+version = "2.1.3"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.7"
files = [
- {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"},
- {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"},
- {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"},
- {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"},
- {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"},
- {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"},
- {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
+ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
]
[[package]]
name = "marshmallow"
-version = "3.19.0"
+version = "3.20.1"
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"},
- {file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"},
+ {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"},
+ {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"},
]
[package.dependencies]
packaging = ">=17.0"
[package.extras]
-dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"]
-docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"]
-lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"]
+dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"]
+docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"]
+lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"]
tests = ["pytest", "pytz", "simplejson"]
[[package]]
@@ -800,13 +814,13 @@ files = [
[[package]]
name = "mkdocs"
-version = "1.4.3"
+version = "1.5.2"
description = "Project documentation with Markdown."
optional = false
python-versions = ">=3.7"
files = [
- {file = "mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd"},
- {file = "mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57"},
+ {file = "mkdocs-1.5.2-py3-none-any.whl", hash = "sha256:60a62538519c2e96fe8426654a67ee177350451616118a41596ae7c876bb7eac"},
+ {file = "mkdocs-1.5.2.tar.gz", hash = "sha256:70d0da09c26cff288852471be03c23f0f521fc15cf16ac89c7a3bfb9ae8d24f9"},
]
[package.dependencies]
@@ -815,26 +829,29 @@ colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""}
ghp-import = ">=1.0"
importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""}
jinja2 = ">=2.11.1"
-markdown = ">=3.2.1,<3.4"
+markdown = ">=3.2.1"
+markupsafe = ">=2.0.1"
mergedeep = ">=1.3.4"
packaging = ">=20.5"
+pathspec = ">=0.11.1"
+platformdirs = ">=2.2.0"
pyyaml = ">=5.1"
pyyaml-env-tag = ">=0.1"
watchdog = ">=2.0"
[package.extras]
i18n = ["babel (>=2.9.0)"]
-min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"]
+min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"]
[[package]]
name = "mkdocs-autorefs"
-version = "0.4.1"
+version = "0.5.0"
description = "Automatically link across pages in MkDocs."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"},
- {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"},
+ {file = "mkdocs_autorefs-0.5.0-py3-none-any.whl", hash = "sha256:7930fcb8ac1249f10e683967aeaddc0af49d90702af111a5e390e8b20b3d97ff"},
+ {file = "mkdocs_autorefs-0.5.0.tar.gz", hash = "sha256:9a5054a94c08d28855cfab967ada10ed5be76e2bfad642302a610b252c3274c0"},
]
[package.dependencies]
@@ -854,20 +871,20 @@ files = [
[[package]]
name = "mkdocs-material"
-version = "9.1.14"
+version = "9.1.21"
description = "Documentation that simply works"
optional = false
python-versions = ">=3.7"
files = [
- {file = "mkdocs_material-9.1.14-py3-none-any.whl", hash = "sha256:b56a9f955ed32d38333715cbbf68ce38f683bf38610c65094fa4ef2db9f08bcd"},
- {file = "mkdocs_material-9.1.14.tar.gz", hash = "sha256:1ae74cc5464ef2f64574d4884512efed7f4db386fb9bc6af20fd427d7a702f49"},
+ {file = "mkdocs_material-9.1.21-py3-none-any.whl", hash = "sha256:58bb2f11ef240632e176d6f0f7d1cff06be1d11c696a5a1b553b808b4280ed47"},
+ {file = "mkdocs_material-9.1.21.tar.gz", hash = "sha256:71940cdfca84ab296b6362889c25395b1621273fb16c93deda257adb7ff44ec8"},
]
[package.dependencies]
colorama = ">=0.4"
jinja2 = ">=3.0"
markdown = ">=3.2"
-mkdocs = ">=1.4.2"
+mkdocs = ">=1.5.0"
mkdocs-material-extensions = ">=1.1"
pygments = ">=2.14"
pymdown-extensions = ">=9.9.1"
@@ -939,17 +956,17 @@ files = [
[[package]]
name = "msal"
-version = "1.22.0"
+version = "1.23.0"
description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect."
optional = false
python-versions = "*"
files = [
- {file = "msal-1.22.0-py2.py3-none-any.whl", hash = "sha256:9120b7eafdf061c92f7b3d744e5f325fca35873445fa8ffebb40b1086a13dd58"},
- {file = "msal-1.22.0.tar.gz", hash = "sha256:8a82f5375642c1625c89058018430294c109440dce42ea667d466c2cab520acd"},
+ {file = "msal-1.23.0-py2.py3-none-any.whl", hash = "sha256:3342e0837a047007f9d479e814b559c3219767453d57920dc40a31986862048b"},
+ {file = "msal-1.23.0.tar.gz", hash = "sha256:25c9a33acf84301f93d1fdbe9f1a9c60cd38af0d5fffdbfa378138fc7bc1e86b"},
]
[package.dependencies]
-cryptography = ">=0.6,<43"
+cryptography = ">=0.6,<44"
PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]}
requests = ">=2.0.0,<3"
@@ -997,43 +1014,43 @@ async = ["aiodns", "aiohttp (>=3.0)"]
[[package]]
name = "mypy"
-version = "1.3.0"
+version = "1.4.1"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "mypy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eb485cea53f4f5284e5baf92902cd0088b24984f4209e25981cc359d64448d"},
- {file = "mypy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c99c3ecf223cf2952638da9cd82793d8f3c0c5fa8b6ae2b2d9ed1e1ff51ba85"},
- {file = "mypy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:550a8b3a19bb6589679a7c3c31f64312e7ff482a816c96e0cecec9ad3a7564dd"},
- {file = "mypy-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cbc07246253b9e3d7d74c9ff948cd0fd7a71afcc2b77c7f0a59c26e9395cb152"},
- {file = "mypy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:a22435632710a4fcf8acf86cbd0d69f68ac389a3892cb23fbad176d1cddaf228"},
- {file = "mypy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e33bb8b2613614a33dff70565f4c803f889ebd2f859466e42b46e1df76018dd"},
- {file = "mypy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d23370d2a6b7a71dc65d1266f9a34e4cde9e8e21511322415db4b26f46f6b8c"},
- {file = "mypy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:658fe7b674769a0770d4b26cb4d6f005e88a442fe82446f020be8e5f5efb2fae"},
- {file = "mypy-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d29e324cdda61daaec2336c42512e59c7c375340bd202efa1fe0f7b8f8ca"},
- {file = "mypy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:d0b6c62206e04061e27009481cb0ec966f7d6172b5b936f3ead3d74f29fe3dcf"},
- {file = "mypy-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:76ec771e2342f1b558c36d49900dfe81d140361dd0d2df6cd71b3db1be155409"},
- {file = "mypy-1.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc95f8386314272bbc817026f8ce8f4f0d2ef7ae44f947c4664efac9adec929"},
- {file = "mypy-1.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:faff86aa10c1aa4a10e1a301de160f3d8fc8703b88c7e98de46b531ff1276a9a"},
- {file = "mypy-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8c5979d0deb27e0f4479bee18ea0f83732a893e81b78e62e2dda3e7e518c92ee"},
- {file = "mypy-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c5d2cc54175bab47011b09688b418db71403aefad07cbcd62d44010543fc143f"},
- {file = "mypy-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87df44954c31d86df96c8bd6e80dfcd773473e877ac6176a8e29898bfb3501cb"},
- {file = "mypy-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:473117e310febe632ddf10e745a355714e771ffe534f06db40702775056614c4"},
- {file = "mypy-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:74bc9b6e0e79808bf8678d7678b2ae3736ea72d56eede3820bd3849823e7f305"},
- {file = "mypy-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:44797d031a41516fcf5cbfa652265bb994e53e51994c1bd649ffcd0c3a7eccbf"},
- {file = "mypy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ddae0f39ca146972ff6bb4399f3b2943884a774b8771ea0a8f50e971f5ea5ba8"},
- {file = "mypy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c4c42c60a8103ead4c1c060ac3cdd3ff01e18fddce6f1016e08939647a0e703"},
- {file = "mypy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e86c2c6852f62f8f2b24cb7a613ebe8e0c7dc1402c61d36a609174f63e0ff017"},
- {file = "mypy-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f9dca1e257d4cc129517779226753dbefb4f2266c4eaad610fc15c6a7e14283e"},
- {file = "mypy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:95d8d31a7713510685b05fbb18d6ac287a56c8f6554d88c19e73f724a445448a"},
- {file = "mypy-1.3.0-py3-none-any.whl", hash = "sha256:a8763e72d5d9574d45ce5881962bc8e9046bf7b375b0abf031f3e6811732a897"},
- {file = "mypy-1.3.0.tar.gz", hash = "sha256:e1f4d16e296f5135624b34e8fb741eb0eadedca90862405b1f1fde2040b9bd11"},
+ {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"},
+ {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"},
+ {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"},
+ {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"},
+ {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"},
+ {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"},
+ {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"},
+ {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"},
+ {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"},
+ {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"},
+ {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"},
+ {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"},
+ {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"},
+ {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"},
+ {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"},
+ {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"},
+ {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"},
+ {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"},
+ {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"},
+ {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"},
+ {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"},
+ {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"},
+ {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"},
+ {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"},
+ {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"},
+ {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"},
]
[package.dependencies]
mypy-extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = ">=3.10"
+typing-extensions = ">=4.1.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
@@ -1093,30 +1110,41 @@ files = [
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]
+[[package]]
+name = "pathspec"
+version = "0.11.2"
+description = "Utility library for gitignore style pattern matching of file paths."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
+ {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
+]
+
[[package]]
name = "platformdirs"
-version = "3.5.1"
+version = "3.10.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false
python-versions = ">=3.7"
files = [
- {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"},
- {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"},
+ {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
+ {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
]
[package.extras]
-docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
[[package]]
name = "pluggy"
-version = "1.0.0"
+version = "1.2.0"
description = "plugin and hook calling mechanisms for python"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
- {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
+ {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
+ {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
]
[package.extras]
@@ -1144,13 +1172,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p
[[package]]
name = "pre-commit"
-version = "3.3.2"
+version = "3.3.3"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false
python-versions = ">=3.8"
files = [
- {file = "pre_commit-3.3.2-py2.py3-none-any.whl", hash = "sha256:8056bc52181efadf4aac792b1f4f255dfd2fb5a350ded7335d251a68561e8cb6"},
- {file = "pre_commit-3.3.2.tar.gz", hash = "sha256:66e37bec2d882de1f17f88075047ef8962581f83c234ac08da21a0c58953d1f0"},
+ {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"},
+ {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"},
]
[package.dependencies]
@@ -1187,13 +1215,13 @@ plugins = ["importlib-metadata"]
[[package]]
name = "pyjwt"
-version = "2.7.0"
+version = "2.8.0"
description = "JSON Web Token implementation in Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "PyJWT-2.7.0-py3-none-any.whl", hash = "sha256:ba2b425b15ad5ef12f200dc67dd56af4e26de2331f965c5439994dad075876e1"},
- {file = "PyJWT-2.7.0.tar.gz", hash = "sha256:bd6ca4a3c4285c1a2d4349e5a035fdf8fb94e04ccd0fcbe6ba289dae9cc3e074"},
+ {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"},
+ {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"},
]
[package.dependencies]
@@ -1222,13 +1250,13 @@ pyyaml = "*"
[[package]]
name = "pytest"
-version = "7.3.1"
+version = "7.4.0"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"},
- {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"},
+ {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
+ {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
]
[package.dependencies]
@@ -1240,17 +1268,17 @@ pluggy = ">=0.12,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
-testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
+testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "pytest-cov"
-version = "4.0.0"
+version = "4.1.0"
description = "Pytest plugin for measuring coverage."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"},
- {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"},
+ {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"},
+ {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"},
]
[package.dependencies]
@@ -1372,99 +1400,99 @@ pyyaml = "*"
[[package]]
name = "regex"
-version = "2023.5.5"
+version = "2023.6.3"
description = "Alternative regular expression module, to replace re."
optional = false
python-versions = ">=3.6"
files = [
- {file = "regex-2023.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:48c9ec56579d4ba1c88f42302194b8ae2350265cb60c64b7b9a88dcb7fbde309"},
- {file = "regex-2023.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f4541550459c08fdd6f97aa4e24c6f1932eec780d58a2faa2068253df7d6ff"},
- {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e22e4460f0245b468ee645156a4f84d0fc35a12d9ba79bd7d79bdcd2f9629d"},
- {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b870b6f632fc74941cadc2a0f3064ed8409e6f8ee226cdfd2a85ae50473aa94"},
- {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:171c52e320fe29260da550d81c6b99f6f8402450dc7777ef5ced2e848f3b6f8f"},
- {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad5524c2aedaf9aa14ef1bc9327f8abd915699dea457d339bebbe2f0d218f86"},
- {file = "regex-2023.5.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a0f874ee8c0bc820e649c900243c6d1e6dc435b81da1492046716f14f1a2a96"},
- {file = "regex-2023.5.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e645c757183ee0e13f0bbe56508598e2d9cd42b8abc6c0599d53b0d0b8dd1479"},
- {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a4c5da39bca4f7979eefcbb36efea04471cd68db2d38fcbb4ee2c6d440699833"},
- {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5e3f4468b8c6fd2fd33c218bbd0a1559e6a6fcf185af8bb0cc43f3b5bfb7d636"},
- {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:59e4b729eae1a0919f9e4c0fc635fbcc9db59c74ad98d684f4877be3d2607dd6"},
- {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ba73a14e9c8f9ac409863543cde3290dba39098fc261f717dc337ea72d3ebad2"},
- {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0bbd5dcb19603ab8d2781fac60114fb89aee8494f4505ae7ad141a3314abb1f9"},
- {file = "regex-2023.5.5-cp310-cp310-win32.whl", hash = "sha256:40005cbd383438aecf715a7b47fe1e3dcbc889a36461ed416bdec07e0ef1db66"},
- {file = "regex-2023.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:59597cd6315d3439ed4b074febe84a439c33928dd34396941b4d377692eca810"},
- {file = "regex-2023.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f08276466fedb9e36e5193a96cb944928301152879ec20c2d723d1031cd4ddd"},
- {file = "regex-2023.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cd46f30e758629c3ee91713529cfbe107ac50d27110fdcc326a42ce2acf4dafc"},
- {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2910502f718828cecc8beff004917dcf577fc5f8f5dd40ffb1ea7612124547b"},
- {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:445d6f4fc3bd9fc2bf0416164454f90acab8858cd5a041403d7a11e3356980e8"},
- {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18196c16a584619c7c1d843497c069955d7629ad4a3fdee240eb347f4a2c9dbe"},
- {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33d430a23b661629661f1fe8395be2004006bc792bb9fc7c53911d661b69dd7e"},
- {file = "regex-2023.5.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72a28979cc667e5f82ef433db009184e7ac277844eea0f7f4d254b789517941d"},
- {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f764e4dfafa288e2eba21231f455d209f4709436baeebb05bdecfb5d8ddc3d35"},
- {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23d86ad2121b3c4fc78c58f95e19173790e22ac05996df69b84e12da5816cb17"},
- {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:690a17db524ee6ac4a27efc5406530dd90e7a7a69d8360235323d0e5dafb8f5b"},
- {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:1ecf3dcff71f0c0fe3e555201cbe749fa66aae8d18f80d2cc4de8e66df37390a"},
- {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:811040d7f3dd9c55eb0d8b00b5dcb7fd9ae1761c454f444fd9f37fe5ec57143a"},
- {file = "regex-2023.5.5-cp311-cp311-win32.whl", hash = "sha256:c8c143a65ce3ca42e54d8e6fcaf465b6b672ed1c6c90022794a802fb93105d22"},
- {file = "regex-2023.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:586a011f77f8a2da4b888774174cd266e69e917a67ba072c7fc0e91878178a80"},
- {file = "regex-2023.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b6365703e8cf1644b82104cdd05270d1a9f043119a168d66c55684b1b557d008"},
- {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a56c18f21ac98209da9c54ae3ebb3b6f6e772038681d6cb43b8d53da3b09ee81"},
- {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8b942d8b3ce765dbc3b1dad0a944712a89b5de290ce8f72681e22b3c55f3cc8"},
- {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:844671c9c1150fcdac46d43198364034b961bd520f2c4fdaabfc7c7d7138a2dd"},
- {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2ce65bdeaf0a386bb3b533a28de3994e8e13b464ac15e1e67e4603dd88787fa"},
- {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fee0016cc35a8a91e8cc9312ab26a6fe638d484131a7afa79e1ce6165328a135"},
- {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:18f05d14f14a812fe9723f13afafefe6b74ca042d99f8884e62dbd34dcccf3e2"},
- {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:941b3f1b2392f0bcd6abf1bc7a322787d6db4e7457be6d1ffd3a693426a755f2"},
- {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:921473a93bcea4d00295799ab929522fc650e85c6b9f27ae1e6bb32a790ea7d3"},
- {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:e2205a81f815b5bb17e46e74cc946c575b484e5f0acfcb805fb252d67e22938d"},
- {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:385992d5ecf1a93cb85adff2f73e0402dd9ac29b71b7006d342cc920816e6f32"},
- {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:890a09cb0a62198bff92eda98b2b507305dd3abf974778bae3287f98b48907d3"},
- {file = "regex-2023.5.5-cp36-cp36m-win32.whl", hash = "sha256:821a88b878b6589c5068f4cc2cfeb2c64e343a196bc9d7ac68ea8c2a776acd46"},
- {file = "regex-2023.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:7918a1b83dd70dc04ab5ed24c78ae833ae8ea228cef84e08597c408286edc926"},
- {file = "regex-2023.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:338994d3d4ca4cf12f09822e025731a5bdd3a37aaa571fa52659e85ca793fb67"},
- {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a69cf0c00c4d4a929c6c7717fd918414cab0d6132a49a6d8fc3ded1988ed2ea"},
- {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f5e06df94fff8c4c85f98c6487f6636848e1dc85ce17ab7d1931df4a081f657"},
- {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8906669b03c63266b6a7693d1f487b02647beb12adea20f8840c1a087e2dfb5"},
- {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fda3e50abad8d0f48df621cf75adc73c63f7243cbe0e3b2171392b445401550"},
- {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ac2b7d341dc1bd102be849d6dd33b09701223a851105b2754339e390be0627a"},
- {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fb2b495dd94b02de8215625948132cc2ea360ae84fe6634cd19b6567709c8ae2"},
- {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aa7d032c1d84726aa9edeb6accf079b4caa87151ca9fabacef31fa028186c66d"},
- {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d45864693351c15531f7e76f545ec35000d50848daa833cead96edae1665559"},
- {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21e90a288e6ba4bf44c25c6a946cb9b0f00b73044d74308b5e0afd190338297c"},
- {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:10250a093741ec7bf74bcd2039e697f519b028518f605ff2aa7ac1e9c9f97423"},
- {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6b8d0c153f07a953636b9cdb3011b733cadd4178123ef728ccc4d5969e67f3c2"},
- {file = "regex-2023.5.5-cp37-cp37m-win32.whl", hash = "sha256:10374c84ee58c44575b667310d5bbfa89fb2e64e52349720a0182c0017512f6c"},
- {file = "regex-2023.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9b320677521aabf666cdd6e99baee4fb5ac3996349c3b7f8e7c4eee1c00dfe3a"},
- {file = "regex-2023.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:afb1c70ec1e594a547f38ad6bf5e3d60304ce7539e677c1429eebab115bce56e"},
- {file = "regex-2023.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cf123225945aa58b3057d0fba67e8061c62d14cc8a4202630f8057df70189051"},
- {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99757ad7fe5c8a2bb44829fc57ced11253e10f462233c1255fe03888e06bc19"},
- {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a623564d810e7a953ff1357f7799c14bc9beeab699aacc8b7ab7822da1e952b8"},
- {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced02e3bd55e16e89c08bbc8128cff0884d96e7f7a5633d3dc366b6d95fcd1d6"},
- {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cbe6b5be3b9b698d8cc4ee4dee7e017ad655e83361cd0ea8e653d65e469468"},
- {file = "regex-2023.5.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a6e4b0e0531223f53bad07ddf733af490ba2b8367f62342b92b39b29f72735a"},
- {file = "regex-2023.5.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e9c4f778514a560a9c9aa8e5538bee759b55f6c1dcd35613ad72523fd9175b8"},
- {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:256f7f4c6ba145f62f7a441a003c94b8b1af78cee2cccacfc1e835f93bc09426"},
- {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd7b68fd2e79d59d86dcbc1ccd6e2ca09c505343445daaa4e07f43c8a9cc34da"},
- {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4a5059bd585e9e9504ef9c07e4bc15b0a621ba20504388875d66b8b30a5c4d18"},
- {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:6893544e06bae009916a5658ce7207e26ed17385149f35a3125f5259951f1bbe"},
- {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c64d5abe91a3dfe5ff250c6bb267ef00dbc01501518225b45a5f9def458f31fb"},
- {file = "regex-2023.5.5-cp38-cp38-win32.whl", hash = "sha256:7923470d6056a9590247ff729c05e8e0f06bbd4efa6569c916943cb2d9b68b91"},
- {file = "regex-2023.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:4035d6945cb961c90c3e1c1ca2feb526175bcfed44dfb1cc77db4fdced060d3e"},
- {file = "regex-2023.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:50fd2d9b36938d4dcecbd684777dd12a407add4f9f934f235c66372e630772b0"},
- {file = "regex-2023.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d19e57f888b00cd04fc38f5e18d0efbd91ccba2d45039453ab2236e6eec48d4d"},
- {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd966475e963122ee0a7118ec9024388c602d12ac72860f6eea119a3928be053"},
- {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db09e6c18977a33fea26fe67b7a842f706c67cf8bda1450974d0ae0dd63570df"},
- {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6164d4e2a82f9ebd7752a06bd6c504791bedc6418c0196cd0a23afb7f3e12b2d"},
- {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84397d3f750d153ebd7f958efaa92b45fea170200e2df5e0e1fd4d85b7e3f58a"},
- {file = "regex-2023.5.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c3efee9bb53cbe7b285760c81f28ac80dc15fa48b5fe7e58b52752e642553f1"},
- {file = "regex-2023.5.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:144b5b017646b5a9392a5554a1e5db0000ae637be4971c9747566775fc96e1b2"},
- {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1189fbbb21e2c117fda5303653b61905aeeeea23de4a94d400b0487eb16d2d60"},
- {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f83fe9e10f9d0b6cf580564d4d23845b9d692e4c91bd8be57733958e4c602956"},
- {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:72aa4746993a28c841e05889f3f1b1e5d14df8d3daa157d6001a34c98102b393"},
- {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:de2f780c3242ea114dd01f84848655356af4dd561501896c751d7b885ea6d3a1"},
- {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:290fd35219486dfbc00b0de72f455ecdd63e59b528991a6aec9fdfc0ce85672e"},
- {file = "regex-2023.5.5-cp39-cp39-win32.whl", hash = "sha256:732176f5427e72fa2325b05c58ad0b45af341c459910d766f814b0584ac1f9ac"},
- {file = "regex-2023.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:1307aa4daa1cbb23823d8238e1f61292fd07e4e5d8d38a6efff00b67a7cdb764"},
- {file = "regex-2023.5.5.tar.gz", hash = "sha256:7d76a8a1fc9da08296462a18f16620ba73bcbf5909e42383b253ef34d9d5141e"},
+ {file = "regex-2023.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:824bf3ac11001849aec3fa1d69abcb67aac3e150a933963fb12bda5151fe1bfd"},
+ {file = "regex-2023.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05ed27acdf4465c95826962528f9e8d41dbf9b1aa8531a387dee6ed215a3e9ef"},
+ {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b49c764f88a79160fa64f9a7b425620e87c9f46095ef9c9920542ab2495c8bc"},
+ {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e3f1316c2293e5469f8f09dc2d76efb6c3982d3da91ba95061a7e69489a14ef"},
+ {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43e1dd9d12df9004246bacb79a0e5886b3b6071b32e41f83b0acbf293f820ee8"},
+ {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959e8bcbfda5146477d21c3a8ad81b185cd252f3d0d6e4724a5ef11c012fb06"},
+ {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af4dd387354dc83a3bff67127a124c21116feb0d2ef536805c454721c5d7993d"},
+ {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2239d95d8e243658b8dbb36b12bd10c33ad6e6933a54d36ff053713f129aa536"},
+ {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:890e5a11c97cf0d0c550eb661b937a1e45431ffa79803b942a057c4fb12a2da2"},
+ {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a8105e9af3b029f243ab11ad47c19b566482c150c754e4c717900a798806b222"},
+ {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:25be746a8ec7bc7b082783216de8e9473803706723b3f6bef34b3d0ed03d57e2"},
+ {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3676f1dd082be28b1266c93f618ee07741b704ab7b68501a173ce7d8d0d0ca18"},
+ {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:10cb847aeb1728412c666ab2e2000ba6f174f25b2bdc7292e7dd71b16db07568"},
+ {file = "regex-2023.6.3-cp310-cp310-win32.whl", hash = "sha256:dbbbfce33cd98f97f6bffb17801b0576e653f4fdb1d399b2ea89638bc8d08ae1"},
+ {file = "regex-2023.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:c5f8037000eb21e4823aa485149f2299eb589f8d1fe4b448036d230c3f4e68e0"},
+ {file = "regex-2023.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c123f662be8ec5ab4ea72ea300359023a5d1df095b7ead76fedcd8babbedf969"},
+ {file = "regex-2023.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9edcbad1f8a407e450fbac88d89e04e0b99a08473f666a3f3de0fd292badb6aa"},
+ {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcba6dae7de533c876255317c11f3abe4907ba7d9aa15d13e3d9710d4315ec0e"},
+ {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29cdd471ebf9e0f2fb3cac165efedc3c58db841d83a518b082077e612d3ee5df"},
+ {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b74fbbf6cbbf9dbce20eb9b5879469e97aeeaa874145517563cca4029db65c"},
+ {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c29ca1bd61b16b67be247be87390ef1d1ef702800f91fbd1991f5c4421ebae8"},
+ {file = "regex-2023.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77f09bc4b55d4bf7cc5eba785d87001d6757b7c9eec237fe2af57aba1a071d9"},
+ {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ea353ecb6ab5f7e7d2f4372b1e779796ebd7b37352d290096978fea83c4dba0c"},
+ {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:10590510780b7541969287512d1b43f19f965c2ece6c9b1c00fc367b29d8dce7"},
+ {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e2fbd6236aae3b7f9d514312cdb58e6494ee1c76a9948adde6eba33eb1c4264f"},
+ {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:6b2675068c8b56f6bfd5a2bda55b8accbb96c02fd563704732fd1c95e2083461"},
+ {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74419d2b50ecb98360cfaa2974da8689cb3b45b9deff0dcf489c0d333bcc1477"},
+ {file = "regex-2023.6.3-cp311-cp311-win32.whl", hash = "sha256:fb5ec16523dc573a4b277663a2b5a364e2099902d3944c9419a40ebd56a118f9"},
+ {file = "regex-2023.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:09e4a1a6acc39294a36b7338819b10baceb227f7f7dbbea0506d419b5a1dd8af"},
+ {file = "regex-2023.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0654bca0cdf28a5956c83839162692725159f4cda8d63e0911a2c0dc76166525"},
+ {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:463b6a3ceb5ca952e66550a4532cef94c9a0c80dc156c4cc343041951aec1697"},
+ {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87b2a5bb5e78ee0ad1de71c664d6eb536dc3947a46a69182a90f4410f5e3f7dd"},
+ {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6343c6928282c1f6a9db41f5fd551662310e8774c0e5ebccb767002fcf663ca9"},
+ {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6192d5af2ccd2a38877bfef086d35e6659566a335b1492786ff254c168b1693"},
+ {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74390d18c75054947e4194019077e243c06fbb62e541d8817a0fa822ea310c14"},
+ {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:742e19a90d9bb2f4a6cf2862b8b06dea5e09b96c9f2df1779e53432d7275331f"},
+ {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8abbc5d54ea0ee80e37fef009e3cec5dafd722ed3c829126253d3e22f3846f1e"},
+ {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c2b867c17a7a7ae44c43ebbeb1b5ff406b3e8d5b3e14662683e5e66e6cc868d3"},
+ {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d831c2f8ff278179705ca59f7e8524069c1a989e716a1874d6d1aab6119d91d1"},
+ {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ee2d1a9a253b1729bb2de27d41f696ae893507c7db224436abe83ee25356f5c1"},
+ {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:61474f0b41fe1a80e8dfa70f70ea1e047387b7cd01c85ec88fa44f5d7561d787"},
+ {file = "regex-2023.6.3-cp36-cp36m-win32.whl", hash = "sha256:0b71e63226e393b534105fcbdd8740410dc6b0854c2bfa39bbda6b0d40e59a54"},
+ {file = "regex-2023.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bbb02fd4462f37060122e5acacec78e49c0fbb303c30dd49c7f493cf21fc5b27"},
+ {file = "regex-2023.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b862c2b9d5ae38a68b92e215b93f98d4c5e9454fa36aae4450f61dd33ff48487"},
+ {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:976d7a304b59ede34ca2921305b57356694f9e6879db323fd90a80f865d355a3"},
+ {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:83320a09188e0e6c39088355d423aa9d056ad57a0b6c6381b300ec1a04ec3d16"},
+ {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9427a399501818a7564f8c90eced1e9e20709ece36be701f394ada99890ea4b3"},
+ {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178bbc1b2ec40eaca599d13c092079bf529679bf0371c602edaa555e10b41c3"},
+ {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:837328d14cde912af625d5f303ec29f7e28cdab588674897baafaf505341f2fc"},
+ {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d44dc13229905ae96dd2ae2dd7cebf824ee92bc52e8cf03dcead37d926da019"},
+ {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d54af539295392611e7efbe94e827311eb8b29668e2b3f4cadcfe6f46df9c777"},
+ {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7117d10690c38a622e54c432dfbbd3cbd92f09401d622902c32f6d377e2300ee"},
+ {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bb60b503ec8a6e4e3e03a681072fa3a5adcbfa5479fa2d898ae2b4a8e24c4591"},
+ {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:65ba8603753cec91c71de423a943ba506363b0e5c3fdb913ef8f9caa14b2c7e0"},
+ {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:271f0bdba3c70b58e6f500b205d10a36fb4b58bd06ac61381b68de66442efddb"},
+ {file = "regex-2023.6.3-cp37-cp37m-win32.whl", hash = "sha256:9beb322958aaca059f34975b0df135181f2e5d7a13b84d3e0e45434749cb20f7"},
+ {file = "regex-2023.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fea75c3710d4f31389eed3c02f62d0b66a9da282521075061ce875eb5300cf23"},
+ {file = "regex-2023.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f56fcb7ff7bf7404becdfc60b1e81a6d0561807051fd2f1860b0d0348156a07"},
+ {file = "regex-2023.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d2da3abc88711bce7557412310dfa50327d5769a31d1c894b58eb256459dc289"},
+ {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99b50300df5add73d307cf66abea093304a07eb017bce94f01e795090dea87c"},
+ {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5708089ed5b40a7b2dc561e0c8baa9535b77771b64a8330b684823cfd5116036"},
+ {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:687ea9d78a4b1cf82f8479cab23678aff723108df3edeac098e5b2498879f4a7"},
+ {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3850beab9f527f06ccc94b446c864059c57651b3f911fddb8d9d3ec1d1b25d"},
+ {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8915cc96abeb8983cea1df3c939e3c6e1ac778340c17732eb63bb96247b91d2"},
+ {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:841d6e0e5663d4c7b4c8099c9997be748677d46cbf43f9f471150e560791f7ff"},
+ {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9edce5281f965cf135e19840f4d93d55b3835122aa76ccacfd389e880ba4cf82"},
+ {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b956231ebdc45f5b7a2e1f90f66a12be9610ce775fe1b1d50414aac1e9206c06"},
+ {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:36efeba71c6539d23c4643be88295ce8c82c88bbd7c65e8a24081d2ca123da3f"},
+ {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:cf67ca618b4fd34aee78740bea954d7c69fdda419eb208c2c0c7060bb822d747"},
+ {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b4598b1897837067a57b08147a68ac026c1e73b31ef6e36deeeb1fa60b2933c9"},
+ {file = "regex-2023.6.3-cp38-cp38-win32.whl", hash = "sha256:f415f802fbcafed5dcc694c13b1292f07fe0befdb94aa8a52905bd115ff41e88"},
+ {file = "regex-2023.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:d4f03bb71d482f979bda92e1427f3ec9b220e62a7dd337af0aa6b47bf4498f72"},
+ {file = "regex-2023.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccf91346b7bd20c790310c4147eee6ed495a54ddb6737162a36ce9dbef3e4751"},
+ {file = "regex-2023.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b28f5024a3a041009eb4c333863d7894d191215b39576535c6734cd88b0fcb68"},
+ {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0bb18053dfcfed432cc3ac632b5e5e5c5b7e55fb3f8090e867bfd9b054dbcbf"},
+ {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5bfb3004f2144a084a16ce19ca56b8ac46e6fd0651f54269fc9e230edb5e4a"},
+ {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c6b48d0fa50d8f4df3daf451be7f9689c2bde1a52b1225c5926e3f54b6a9ed1"},
+ {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051da80e6eeb6e239e394ae60704d2b566aa6a7aed6f2890a7967307267a5dc6"},
+ {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4c3b7fa4cdaa69268748665a1a6ff70c014d39bb69c50fda64b396c9116cf77"},
+ {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:457b6cce21bee41ac292d6753d5e94dcbc5c9e3e3a834da285b0bde7aa4a11e9"},
+ {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aad51907d74fc183033ad796dd4c2e080d1adcc4fd3c0fd4fd499f30c03011cd"},
+ {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0385e73da22363778ef2324950e08b689abdf0b108a7d8decb403ad7f5191938"},
+ {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c6a57b742133830eec44d9b2290daf5cbe0a2f1d6acee1b3c7b1c7b2f3606df7"},
+ {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3e5219bf9e75993d73ab3d25985c857c77e614525fac9ae02b1bebd92f7cecac"},
+ {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e5087a3c59eef624a4591ef9eaa6e9a8d8a94c779dade95d27c0bc24650261cd"},
+ {file = "regex-2023.6.3-cp39-cp39-win32.whl", hash = "sha256:20326216cc2afe69b6e98528160b225d72f85ab080cbdf0b11528cbbaba2248f"},
+ {file = "regex-2023.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:bdff5eab10e59cf26bc479f565e25ed71a7d041d1ded04ccf9aee1d9f208487a"},
+ {file = "regex-2023.6.3.tar.gz", hash = "sha256:72d1a25bf36d2050ceb35b517afe13864865268dfb45910e2e17a84be6cbfeb0"},
]
[[package]]
@@ -1527,13 +1555,13 @@ jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
[[package]]
name = "segment-analytics-python"
-version = "2.2.2"
+version = "2.2.3"
description = "The hassle-free way to integrate analytics into any python application."
optional = false
python-versions = ">=3.6.0"
files = [
- {file = "segment-analytics-python-2.2.2.tar.gz", hash = "sha256:10ef6ee42b9e504b9db76b44c893e6a44c3ebc51cd01f475ac76f0e80a8fff09"},
- {file = "segment_analytics_python-2.2.2-py2.py3-none-any.whl", hash = "sha256:363ea1679d14adb13c582eac1edd78c0d397d5dcc17fcea6376b66ba04032663"},
+ {file = "segment-analytics-python-2.2.3.tar.gz", hash = "sha256:0df5908e3df74b4482f33392fdd450df4c8351bf54974376fbe6bf33b0700865"},
+ {file = "segment_analytics_python-2.2.3-py2.py3-none-any.whl", hash = "sha256:06cc3d8e79103f02c3878ec66cb66152415473d0d2a142b98a0ee18da972e109"},
]
[package.dependencies]
@@ -1547,13 +1575,13 @@ test = ["flake8 (==3.7.9)", "mock (==2.0.0)", "pylint (==2.8.0)"]
[[package]]
name = "setuptools"
-version = "67.8.0"
+version = "68.0.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.7"
files = [
- {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"},
- {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"},
+ {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"},
+ {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"},
]
[package.extras]
@@ -1619,46 +1647,46 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.
[[package]]
name = "types-pyyaml"
-version = "6.0.12.9"
+version = "6.0.12.11"
description = "Typing stubs for PyYAML"
optional = false
python-versions = "*"
files = [
- {file = "types-PyYAML-6.0.12.9.tar.gz", hash = "sha256:c51b1bd6d99ddf0aa2884a7a328810ebf70a4262c292195d3f4f9a0005f9eeb6"},
- {file = "types_PyYAML-6.0.12.9-py3-none-any.whl", hash = "sha256:5aed5aa66bd2d2e158f75dda22b059570ede988559f030cf294871d3b647e3e8"},
+ {file = "types-PyYAML-6.0.12.11.tar.gz", hash = "sha256:7d340b19ca28cddfdba438ee638cd4084bde213e501a3978738543e27094775b"},
+ {file = "types_PyYAML-6.0.12.11-py3-none-any.whl", hash = "sha256:a461508f3096d1d5810ec5ab95d7eeecb651f3a15b71959999988942063bf01d"},
]
[[package]]
name = "types-urllib3"
-version = "1.26.25.13"
+version = "1.26.25.14"
description = "Typing stubs for urllib3"
optional = false
python-versions = "*"
files = [
- {file = "types-urllib3-1.26.25.13.tar.gz", hash = "sha256:3300538c9dc11dad32eae4827ac313f5d986b8b21494801f1bf97a1ac6c03ae5"},
- {file = "types_urllib3-1.26.25.13-py3-none-any.whl", hash = "sha256:5dbd1d2bef14efee43f5318b5d36d805a489f6600252bb53626d4bfafd95e27c"},
+ {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"},
+ {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"},
]
[[package]]
name = "typing-extensions"
-version = "4.5.0"
+version = "4.7.1"
description = "Backported and Experimental Type Hints for Python 3.7+"
optional = false
python-versions = ">=3.7"
files = [
- {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
- {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
+ {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
+ {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
]
[[package]]
name = "typing-inspect"
-version = "0.8.0"
+version = "0.9.0"
description = "Runtime inspection utilities for typing module."
optional = false
python-versions = "*"
files = [
- {file = "typing_inspect-0.8.0-py3-none-any.whl", hash = "sha256:5fbf9c1e65d4fa01e701fe12a5bca6c6e08a4ffd5bc60bfac028253a447c5188"},
- {file = "typing_inspect-0.8.0.tar.gz", hash = "sha256:8b1ff0c400943b6145df8119c41c244ca8207f1f10c9c057aeed1560e4806e3d"},
+ {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
+ {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
]
[package.dependencies]
@@ -1683,23 +1711,23 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "virtualenv"
-version = "20.23.0"
+version = "20.24.2"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.7"
files = [
- {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"},
- {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"},
+ {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"},
+ {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"},
]
[package.dependencies]
-distlib = ">=0.3.6,<1"
-filelock = ">=3.11,<4"
-platformdirs = ">=3.2,<4"
+distlib = ">=0.3.7,<1"
+filelock = ">=3.12.2,<4"
+platformdirs = ">=3.9.1,<4"
[package.extras]
-docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"]
-test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"]
+docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
[[package]]
name = "watchdog"
@@ -1742,18 +1770,18 @@ watchmedo = ["PyYAML (>=3.10)"]
[[package]]
name = "zipp"
-version = "3.15.0"
+version = "3.16.2"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"},
- {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"},
+ {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"},
+ {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"},
]
[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
-testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
[metadata]
lock-version = "2.0"
diff --git a/src/matcha_ml/cli/cli.py b/src/matcha_ml/cli/cli.py
index a1d12fac..2bfaa837 100644
--- a/src/matcha_ml/cli/cli.py
+++ b/src/matcha_ml/cli/cli.py
@@ -254,16 +254,16 @@ def set(stack: str = typer.Argument("default")) -> None:
Args:
stack (str): the name of the stack to provision.
-
- Raises:
- Exit: Exit if input is not a defined stack.
"""
try:
- set_stack = core.stack_set(stack)
- print_status(build_status(f"Matcha {set_stack} stack has been set."))
+ core.stack_set(stack)
+ print_status(build_status(f"Matcha '{stack}' stack has been set."))
except MatchaInputError as e:
print_error(str(e))
raise typer.Exit()
+ except MatchaError as e:
+ print_error(str(e))
+ raise typer.Exit()
if __name__ == "__main__":
diff --git a/src/matcha_ml/config/__init__.py b/src/matcha_ml/config/__init__.py
new file mode 100644
index 00000000..0d0bad86
--- /dev/null
+++ b/src/matcha_ml/config/__init__.py
@@ -0,0 +1,16 @@
+"""Matcha state sub-module."""
+from .matcha_config import (
+ DEFAULT_CONFIG_NAME,
+ MatchaConfig,
+ MatchaConfigComponent,
+ MatchaConfigComponentProperty,
+ MatchaConfigService,
+)
+
+__all__ = [
+ "MatchaConfigService",
+ "MatchaConfig",
+ "MatchaConfigComponentProperty",
+ "MatchaConfigComponent",
+ "DEFAULT_CONFIG_NAME",
+]
diff --git a/src/matcha_ml/config/matcha_config.py b/src/matcha_ml/config/matcha_config.py
new file mode 100644
index 00000000..696b837b
--- /dev/null
+++ b/src/matcha_ml/config/matcha_config.py
@@ -0,0 +1,206 @@
+"""The matcha.config.json file interface."""
+import json
+import os
+from dataclasses import dataclass
+from typing import Dict, List, Union
+
+from matcha_ml.errors import MatchaError
+
+DEFAULT_CONFIG_NAME = "matcha.config.json"
+
+
+@dataclass
+class MatchaConfigComponentProperty:
+ """A class to represent Matcha config properties."""
+
+ name: str
+ value: str
+
+
+@dataclass
+class MatchaConfigComponent:
+ """A class to represent Matcha config components."""
+
+ name: str
+ properties: List[MatchaConfigComponentProperty]
+
+ def find_property(self, property_name: str) -> MatchaConfigComponentProperty:
+ """Given a property name, find the property that matches it.
+
+ Note: this only works under the assumption of none-duplicated properties.
+
+ Args:
+ property_name (str): the name of the property.
+
+ Raises:
+ MatchaError: if the property could not be found.
+
+ Returns:
+ MatchaConfigComponentProperty: the property that matches the property_name parameter.
+ """
+ property = next(
+ filter(lambda property: property.name == property_name, self.properties),
+ None,
+ )
+
+ if property is None:
+ raise MatchaError(
+ f"The property with the name '{property_name}' could not be found."
+ )
+
+ return property
+
+
+@dataclass
+class MatchaConfig:
+ """A class to represent the Matcha config file."""
+
+ components: List[MatchaConfigComponent]
+
+ def find_component(self, component_name: str) -> MatchaConfigComponent:
+ """Given a component name, find the component that matches it.
+
+ Note: this only works under the assumption of none-duplicated properties.
+
+ Args:
+ component_name (str): the name of the component.
+
+ Raises:
+ MatchaError: if the component could not be found.
+
+ Returns:
+ MatchaConfigComponent: the component that matches the component_name parameter.
+ """
+ component = next(
+ filter(lambda component: component.name == component_name, self.components),
+ None,
+ )
+
+ if component is None:
+ raise MatchaError(
+ f"The component with the name '{component_name}' could not be found."
+ )
+
+ return component
+
+ def to_dict(self) -> Dict[str, Dict[str, str]]:
+ """A function to convert the MatchaConfig class into a dictionary.
+
+ Returns:
+ Dict[str, Dict[str, str]]: the MatchaState as a dictionary.
+ """
+ state_dictionary = {}
+ for config_component in self.components:
+ state_dictionary[config_component.name] = {
+ property.name: property.value
+ for property in config_component.properties
+ }
+
+ return state_dictionary
+
+ @staticmethod
+ def from_dict(state_dict: Dict[str, Dict[str, str]]) -> "MatchaConfig":
+ """A function to convert a dictionary representation of the Matcha config file into a MatchaConfig instance.
+
+ Args:
+ state_dict (Dict[str, Dict[str, str]]): the dictionary representation of the Matcha config file.
+
+ Returns:
+ MatchaConfig: the MatchaConfig representation of the MatchaConfig instance.
+ """
+ components: List[MatchaConfigComponent] = []
+ for resource, properties in state_dict.items():
+ components.append(
+ MatchaConfigComponent(
+ name=resource,
+ properties=[
+ MatchaConfigComponentProperty(name=key, value=value)
+ for key, value in properties.items()
+ ],
+ )
+ )
+
+ return MatchaConfig(components=components)
+
+
+class MatchaConfigService:
+ """A service for handling the Matcha config file."""
+
+ @staticmethod
+ def write_matcha_config(matcha_config: MatchaConfig) -> None:
+ """A function for writing the local Matcha config file.
+
+ Args:
+ matcha_config (MatchaConfig): the MatchaConfig representation of the MatchaConfig instance.
+ """
+ local_config_file = os.path.join(os.getcwd(), DEFAULT_CONFIG_NAME)
+
+ with open(local_config_file, "w") as file:
+ json.dump(matcha_config.to_dict(), file)
+
+ @staticmethod
+ def read_matcha_config() -> MatchaConfig:
+ """A function for reading the Matcha config file into a MatchaConfig object.
+
+ Returns:
+ MatchaConfig: the MatchaConfig representation of the MatchaConfig instance.
+
+ Raises:
+ MatchaError: raises a MatchaError if the local config file could not be read.
+ """
+ local_config_file = os.path.join(os.getcwd(), DEFAULT_CONFIG_NAME)
+
+ if os.path.exists(local_config_file):
+ with open(local_config_file) as config:
+ local_config = json.load(config)
+
+ return MatchaConfig.from_dict(local_config)
+ else:
+ raise MatchaError(
+ f"No '{DEFAULT_CONFIG_NAME}' file found, please generate one by running 'matcha provision', or add an existing ''{DEFAULT_CONFIG_NAME}'' file to the root project directory."
+ )
+
+ @staticmethod
+ def config_file_exists() -> bool:
+ """A convencience function which checks for the existence of the matcha.config.json file.
+
+ Returns:
+ True if the matcha.config.json file exists, False otherwise.
+ """
+ return os.path.exists(os.path.join(os.getcwd(), DEFAULT_CONFIG_NAME))
+
+ @staticmethod
+ def update(components: Union[MatchaConfigComponent, List[MatchaConfigComponent]]) -> None:
+ """A function which updates the matcha config file.
+
+ If no config file exists, this function will create one.
+
+ Args:
+ components (dict): A list of, or single MatchaConfigComponent object(s).
+ """
+ if isinstance(components, MatchaConfigComponent):
+ components = [components]
+
+ if MatchaConfigService.config_file_exists():
+ config = MatchaConfigService.read_matcha_config()
+ config.components += components
+ else:
+ config = MatchaConfig(components)
+
+ MatchaConfigService.write_matcha_config(config)
+
+ @staticmethod
+ def delete_matcha_config() -> None:
+ """A function for deleting the local Matcha config file.
+
+ Raises:
+ MatchaError: raises a MatchaError if the local config file could not be removed.
+ """
+ local_config_file = os.path.join(os.getcwd(), DEFAULT_CONFIG_NAME)
+
+ try:
+ os.remove(local_config_file)
+ except Exception:
+ raise MatchaError(
+ f"Local config file at path:{local_config_file} could not be removed."
+ )
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index 6dc606f2..1a48e033 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -1,11 +1,16 @@
"""The core functionality for Matcha API."""
import os
+from enum import Enum, EnumMeta
from typing import Optional
-from warnings import warn
from matcha_ml.cli._validation import get_command_validation
from matcha_ml.cli.ui.print_messages import print_status
from matcha_ml.cli.ui.status_message_builders import build_warning_status
+from matcha_ml.config import (
+ MatchaConfigComponent,
+ MatchaConfigComponentProperty,
+ MatchaConfigService,
+)
from matcha_ml.core._validation import is_valid_prefix, is_valid_region
from matcha_ml.errors import MatchaError, MatchaInputError
from matcha_ml.runners import AzureRunner
@@ -15,23 +20,53 @@
from matcha_ml.state.matcha_state import MatchaState
from matcha_ml.templates.azure_template import AzureTemplate
-MAJOR_MINOR_ZENML_VERSION = "0.36"
+class StackTypeMeta(
+ EnumMeta
+): # this is probably overkill, but we might need it if we'll support custom stacks later.
+ """Metaclass for the StackType Enum."""
-def zenml_version_is_supported() -> None:
+ def __contains__(self, item: str) -> bool: # type: ignore
+ """Dunder method for checking if an item is a member of the enum.
+
+ Args:
+ item (str): the quantity to check for in the Enum.
+
+ Returns:
+ True if item is a member of the Enum, False otherwise.
+ """
+ try:
+ self(item)
+ except ValueError:
+ return False
+ else:
+ return True
+
+
+class StackType(Enum, metaclass=StackTypeMeta):
+ """Enum defining matcha stack types."""
+
+ DEFAULT = "default"
+ LLM = "llm"
+
+
+def infer_zenml_version() -> str:
"""Check the zenml version of the local environment against the version matcha is expecting."""
try:
- import zenml
+ import zenml # type: ignore
- if zenml.__version__[:3] != MAJOR_MINOR_ZENML_VERSION:
- warn(
- f"Matcha expects ZenML version {MAJOR_MINOR_ZENML_VERSION}.x, but you have version {zenml.__version__}."
- )
- except:
- warn(
- f"No local installation of ZenMl found. Defaulting to version {MAJOR_MINOR_ZENML_VERSION} for remote "
- f"resources."
+ version = str(zenml.__version__)
+ print(
+ f"\nMatcha detected zenml version {version}, so will use the same version on the remote resources."
)
+ except ImportError:
+ version = "latest"
+ print(
+ "\nMatcha didn't find a zenml installation locally, so will install the latest release of zenml on the "
+ "remote resources."
+ )
+
+ return version
@track(event_name=AnalyticsEvent.GET)
@@ -205,7 +240,6 @@ def provision(
MatchaError: If prefix is not valid.
MatchaError: If region is not valid.
"""
- zenml_version_is_supported()
remote_state_manager = RemoteStateManager()
template_runner = AzureRunner()
@@ -221,7 +255,7 @@ def provision(
"Matcha has detected a stale state file. This means that your local configuration is out of sync with the remote state, the resource group may have been removed. Deleting existing state config."
)
)
- remote_state_manager.remove_matcha_config()
+ MatchaConfigService.delete_matcha_config()
template_runner.remove_matcha_dir()
if remote_state_manager.is_state_provisioned():
@@ -251,8 +285,12 @@ def provision(
azure_template = AzureTemplate()
+ zenml_version = infer_zenml_version()
config = azure_template.build_template_configuration(
- location=location, prefix=prefix, password=password
+ location=location,
+ prefix=prefix,
+ password=password,
+ zenmlserver_version=zenml_version,
)
azure_template.build_template(config, template, destination, verbose)
@@ -263,6 +301,26 @@ def provision(
return matcha_state_service.fetch_resources_from_state_file()
-def stack_set(stack: str) -> str:
- """Placeholder for core matcha stack set functionality."""
- return stack
+def stack_set(stack_name: str) -> None:
+ """A function for updating the stack type in the local matcha.config.json file.
+
+ Args:
+ stack_name (str): the name of the type of stack to be specified in the config file.
+ """
+ if RemoteStateManager().is_state_provisioned():
+ raise MatchaError(
+ "The remote resources are already provisioned. Changing the stack now will not "
+ "change the remote state."
+ )
+
+ if stack_name.lower() not in StackType:
+ raise MatchaInputError(f"{stack_name} is not a valid stack type.")
+
+ stack_enum = StackType(stack_name.lower())
+
+ stack = MatchaConfigComponent(
+ name="stack",
+ properties=[MatchaConfigComponentProperty(name="name", value=stack_enum.name)],
+ )
+
+ MatchaConfigService.update(stack)
diff --git a/src/matcha_ml/infrastructure/resources/.terraform.lock.hcl b/src/matcha_ml/infrastructure/resources/.terraform.lock.hcl
index 96270233..ecf35119 100644
--- a/src/matcha_ml/infrastructure/resources/.terraform.lock.hcl
+++ b/src/matcha_ml/infrastructure/resources/.terraform.lock.hcl
@@ -6,6 +6,7 @@ provider "registry.terraform.io/gavinbunney/kubectl" {
constraints = "1.14.0"
hashes = [
"h1:gLFn+RvP37sVzp9qnFCwngRjjFV649r6apjxvJ1E/SE=",
+ "h1:mX2AOFIMIxJmW5kM8DT51gloIOKCr9iT6W8yodnUyfs=",
"zh:0350f3122ff711984bbc36f6093c1fe19043173fad5a904bce27f86afe3cc858",
"zh:07ca36c7aa7533e8325b38232c77c04d6ef1081cb0bac9d56e8ccd51f12f2030",
"zh:0c351afd91d9e994a71fe64bbd1662d0024006b3493bb61d46c23ea3e42a7cf5",
@@ -20,9 +21,10 @@ provider "registry.terraform.io/gavinbunney/kubectl" {
provider "registry.terraform.io/hashicorp/azurerm" {
version = "3.48.0"
- constraints = "3.48.0"
+ constraints = ">= 3.16.0, 3.48.0"
hashes = [
"h1:5sGcXKelc4o4MnPZfKKs9pd8w969TtlCV+0IZvW58Cs=",
+ "h1:RSUCtxgd6hD9J11YZGOA4yffeu5P8YmQnP5SRNl6+d8=",
"zh:01bd328009f2803ebc18ac27535e7d1548c735bb5bd02460e471acc835e5dd19",
"zh:070b0bdd5ff27232eec7ef9128fc9bd17e6bdae503ddcc450c944449f3a8d216",
"zh:0a0a0e81f7ab8757aa83876fffbc57328843664900923d8b3c577e7596884726",
@@ -41,6 +43,7 @@ provider "registry.terraform.io/hashicorp/azurerm" {
provider "registry.terraform.io/hashicorp/external" {
version = "2.3.1"
hashes = [
+ "h1:9rJggijNdRdFk//ViQPGZdK0xu9XU/9qBDijNsZJMg0=",
"h1:bROCw6g5D/3fFnWeJ01L4IrdnJl1ILU8DGDgXCtYzaY=",
"zh:001e2886dc81fc98cf17cf34c0d53cb2dae1e869464792576e11b0f34ee92f54",
"zh:2eeac58dd75b1abdf91945ac4284c9ccb2bfb17fa9bdb5f5d408148ff553b3ee",
@@ -61,6 +64,7 @@ provider "registry.terraform.io/hashicorp/helm" {
version = "2.0.3"
constraints = "~> 2.0.1"
hashes = [
+ "h1:FRSVqY+1/AUO/j/lVxHHsLudfSA9gDc7Dsu+YxcJSEY=",
"h1:eUr4dHyxlcLmLja0wBgJC7t5bfHzbtACyuumKPuDrGs=",
"zh:154e0aa489e474e2eeb3de94be7666133faf6fd950712a640425b2bf3a81ee95",
"zh:16a2be6c4b61d0c5205c63816148c7ab0c8f56a75c05e8d897fa4d5cac0c029a",
@@ -80,6 +84,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" {
version = "2.11.0"
constraints = "~> 2.11.0"
hashes = [
+ "h1:T65SZhN/tQgsAsHe/G5PCgpjofi+aTKPZ+nZg6WOJpc=",
"h1:pJiAJwZKUaoAJ4x+3ONJkwEVkjrwGROCGFgj7noPO58=",
"zh:143a19dd0ea3b07fc5e3d9231f3c2d01f92894385c98a67327de74c76c715843",
"zh:1fc757d209e09c3cf7848e4274daa32408c07743698fbed10ee52a4a479b62b6",
@@ -101,6 +106,7 @@ provider "registry.terraform.io/hashicorp/local" {
constraints = "2.1.0"
hashes = [
"h1:EYZdckuGU3n6APs97nS2LxZm3dDtGqyM4qaIvsmac8o=",
+ "h1:KfieWtVyGWwplSoLIB5usKAUnrIkDQBkWaR5TI+4WYg=",
"zh:0f1ec65101fa35050978d483d6e8916664b7556800348456ff3d09454ac1eae2",
"zh:36e42ac19f5d68467aacf07e6adcf83c7486f2e5b5f4339e9671f68525fc87ab",
"zh:6db9db2a1819e77b1642ec3b5e95042b202aee8151a0256d289f2e141bf3ceb3",
@@ -120,6 +126,7 @@ provider "registry.terraform.io/hashicorp/null" {
constraints = "3.2.1"
hashes = [
"h1:FbGfc+muBsC17Ohy5g806iuI1hQc4SIexpYCrQHQd8w=",
+ "h1:tSj1mL6OQ8ILGqR2mDu7OYYYWf+hoir0pf9KAQ8IzO8=",
"zh:58ed64389620cc7b82f01332e27723856422820cfd302e304b5f6c3436fb9840",
"zh:62a5cc82c3b2ddef7ef3a6f2fedb7b9b3deff4ab7b414938b08e51d6e8be87cb",
"zh:63cff4de03af983175a7e37e52d4bd89d990be256b16b5c7f919aff5ad485aa5",
@@ -140,6 +147,7 @@ provider "registry.terraform.io/hashicorp/random" {
constraints = "3.1.0"
hashes = [
"h1:BZMEPucF+pbu9gsPk0G0BHx7YP04+tKdq2MrRDF1EDM=",
+ "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
"zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
"zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
"zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff",
@@ -158,6 +166,7 @@ provider "registry.terraform.io/loafoe/htpasswd" {
version = "1.0.4"
constraints = "1.0.4"
hashes = [
+ "h1:/OCwJ2uB9PfESHNn4bDwdHnMOp8x5D/aNvvUl8XNFA4=",
"h1:v/EZlkxlFBRlLIK2rmgbksuhbxOwenP3TQvreUhCAtE=",
"zh:1f17ffcb8ab2f19de1242a6980f78334fc81efeaddfa85545435048f54045e4a",
"zh:6265fd9bbb718d55655120044b4969c80aa938ecfb17a0fd7541ff7de8c54e1e",
diff --git a/src/matcha_ml/infrastructure/resources/main.tf b/src/matcha_ml/infrastructure/resources/main.tf
index d2230403..55d761e7 100644
--- a/src/matcha_ml/infrastructure/resources/main.tf
+++ b/src/matcha_ml/infrastructure/resources/main.tf
@@ -79,6 +79,8 @@ module "zenserver" {
# ZenServer credentials
username = var.username
password = var.password
+
+ zenmlserver_version = var.zenmlserver_version
}
diff --git a/src/matcha_ml/infrastructure/resources/variables.tf b/src/matcha_ml/infrastructure/resources/variables.tf
index 2d2d79ef..15202b4e 100644
--- a/src/matcha_ml/infrastructure/resources/variables.tf
+++ b/src/matcha_ml/infrastructure/resources/variables.tf
@@ -21,6 +21,12 @@ variable "password" {
sensitive = true
}
+variable "zenmlserver_version" {
+ description = "The tag to use for the zenmlserver docker image."
+ default = "latest"
+ type = string
+}
+
# seldon variables
variable "seldon_name" {
description = "Name of the Seldon deployment"
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/main.tf b/src/matcha_ml/infrastructure/resources/zen_server/main.tf
index 9e78107a..d4026cac 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/main.tf
+++ b/src/matcha_ml/infrastructure/resources/zen_server/main.tf
@@ -86,6 +86,10 @@ resource "helm_release" "zen_server" {
name = "zenml.database.sslVerifyServerCert"
value = var.deploy_db ? false : var.database_ssl_verify_server_cert
}
+ set {
+ name = "zenml.image.tag"
+ value = var.zenmlserver_version
+ }
depends_on = [
resource.kubernetes_namespace.zen_server
]
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/variables.tf b/src/matcha_ml/infrastructure/resources/zen_server/variables.tf
index 9c969b01..ae4a8d66 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/variables.tf
+++ b/src/matcha_ml/infrastructure/resources/zen_server/variables.tf
@@ -161,8 +161,7 @@ variable "zenmlserver_image_repo" {
default = "zenmldocker/zenml-server"
type = string
}
-variable "zenmlserver_image_tag" {
+variable "zenmlserver_version" {
description = "The tag to use for the zenmlserver docker image."
- default = "latest"
type = string
}
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/Chart.yaml b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/Chart.yaml
index ce568663..51fbb0fe 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/Chart.yaml
+++ b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/Chart.yaml
@@ -9,5 +9,5 @@ keywords:
home: https://zenml.io
sources:
- https://github.com/zenml-io/zenml
-icon: https://raw.githubusercontent.com/zenml-io/zenml/main/docs/book/assets/zenml_logo.png
-appVersion: "0.36.1"
+icon: https://raw.githubusercontent.com/zenml-io/zenml/main/docs/book/.gitbook/assets/zenml_logo.png
+appVersion: "0.42.1"
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-deployment.yaml b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-deployment.yaml
index faa2df8b..6e28098f 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-deployment.yaml
+++ b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-deployment.yaml
@@ -55,13 +55,8 @@ spec:
- name: ZENML_LOGGING_VERBOSITY
value: "DEBUG"
{{- end }}
- {{- if .Values.zenml.analyticsOptIn }}
- - name: ZENML_ANALYTICS_OPT_IN
- value: "True"
- {{- else if not .Values.zenml.analyticsOptIn }}
- name: ZENML_ANALYTICS_OPT_IN
value: "False"
- {{- end }}
- name: ZENML_DEFAULT_PROJECT_NAME
value: {{ .Values.zenml.defaultProject | quote }}
- name: ZENML_DEFAULT_USER_NAME
@@ -153,6 +148,10 @@ spec:
value: {{ .Values.zenml.defaultProject | quote }}
- name: ZENML_DEFAULT_USER_NAME
value: {{ .Values.zenml.defaultUsername | quote }}
+ {{- if .Values.zenml.enableImplicitAuthMethods }}
+ - name: ZENML_ENABLE_IMPLICIT_AUTH_METHODS
+ value: "True"
+ {{- end }}
{{- if .Values.zenml.database.url }}
- name: ZENML_STORE_TYPE
value: sql
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-ingress.yaml b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-ingress.yaml
index 91de1992..d2e0423e 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-ingress.yaml
+++ b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-ingress.yaml
@@ -6,7 +6,7 @@
{{- $_ := set .Values.zenml.ingress.annotations "kubernetes.io/ingress.class" .Values.zenml.ingress.className}}
{{- end }}
{{- end }}
-{{- if $.Values.zenml.ingress.tls.enabled }}
+{{- if and $.Values.zenml.ingress.tls.enabled (eq .Values.zenml.ingress.className "nginx") }}
{{- $_ := set .Values.zenml.ingress.annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true"}}
{{- end }}
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml
index 53c34b24..f0c35dae 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml
+++ b/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml
@@ -4,8 +4,10 @@ imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
+
# ZenML server related options.
zenml:
+
replicaCount: 1
image:
@@ -24,7 +26,7 @@ zenml:
deploymentType:
# The ZenML authentication scheme. Use one of:
- #
+ #
# NO_AUTH - No authentication
# HTTP_BASIC - HTTP Basic authentication
# OAUTH2_PASSWORD_BEARER - OAuth2 password bearer with JWT tokens
@@ -38,7 +40,7 @@ zenml:
# from secrets import token_hex
# token_hex(32)
# ```
- #
+ #
# or:
#
# ```shell
@@ -70,20 +72,27 @@ zenml:
# Use your own password here
defaultPassword: zenml
+ # Implicit authentication methods featured by service connectors that support
+ # them are disabled by default, for security reasons. This is because they
+ # allow users to authenticate to the cloud provider where ZenML is running
+ # without having to provide any credentials.
+ enableImplicitAuthMethods: false
+
# MySQL database configuration. If not set, a local sqlite database will be
# used, which will not be persisted across pod restarts.
# NOTE: the certificate files need to be copied in the helm chart folder and
# the paths configured here need to be relative to the root of the helm chart.
- database:
- {}
+ database: {}
# url: "mysql://admin:password@zenml-mysql:3306/database"
# sslCa: /path/to/ca.pem
# sslCert: /path/to/client-cert.pem
# sslKey: /path/to/client-key.pem
# sslVerifyServerCert: True
+
# Secrets store settings. This is used to store centralized secrets.
secretsStore:
+
# Set to false to disable the secrets store.
enabled: true
@@ -106,6 +115,7 @@ zenml:
# SQL secrets store configuration. Only relevant if the `sql` secrets store
# type is configured.
sql:
+
# The secret key used to encrypt secrets in the SQL database. Only relevant
# if the SQL secrets store type is used. This should be set to a random
# string with a recommended length of at least 32 characters, e.g.:
@@ -114,7 +124,7 @@ zenml:
# from secrets import token_hex
# token_hex(32)
# ```
- #
+ #
# or:
#
# ```shell
@@ -135,6 +145,7 @@ zenml:
# AWS secrets store configuration. Only relevant if the `aws` secrets store
# type is configured.
aws:
+
# The AWS region to use. This must be set to the region where the AWS
# Secrets Manager service that you want to use is located.
region_name: us-east-1
@@ -160,9 +171,11 @@ zenml:
# starvation in the ZenML server on high load.
secret_list_refresh_timeout: 0
+
# GCP secrets store configuration. Only relevant if the `gcp` secrets store
# type is configured.
gcp:
+
# The GCP project ID to use. This must be set to the project ID where the
# GCP Secrets Manager service that you want to use is located.
project_id: my-gcp-project
@@ -179,6 +192,7 @@ zenml:
# AWS Key Vault secrets store configuration. Only relevant if the `azure`
# secrets store type is configured.
azure:
+
# The name of the Azure Key Vault. This must be set to point to the Azure
# Key Vault instance that you want to use.
key_vault_name:
@@ -197,6 +211,7 @@ zenml:
# HashiCorp Vault secrets store configuration. Only relevant if the `hashicorp`
# secrets store type is configured
hashicorp:
+
# The url of the HashiCorp Vault server
vault_addr: https://vault.example.com
# The token used to authenticate with the Vault server
@@ -210,6 +225,7 @@ zenml:
# Custom secrets store configuration. Only relevant if the `custom` secrets
# store type is configured.
custom:
+
# The class path of the custom secrets store implementation. This should
# point to a full Python class that extends the
# `zenml.zen_stores.secrets_stores.base_secrets_store.BaseSecretsStore`
@@ -234,11 +250,11 @@ zenml:
secretEnvironment: {}
service:
- type: LoadBalancer # Changed from ClusterIP
+ type: LoadBalancer # changed from ClusterIP
port: 80
ingress:
- enabled: false # Changed from true
+ enabled: false # changed from true
className: "nginx"
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
@@ -262,6 +278,7 @@ zenml:
generateCerts: false
secretName: zenml-tls-certs
+
serviceAccount:
# Specifies whether a service account should be created
create: true
@@ -273,8 +290,7 @@ serviceAccount:
podAnnotations: {}
-podSecurityContext:
- {}
+podSecurityContext: {}
# fsGroup: 2000
securityContext:
@@ -284,8 +300,7 @@ securityContext:
# drop:
# - ALL
-resources:
- {}
+resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
diff --git a/src/matcha_ml/state/remote_state_manager.py b/src/matcha_ml/state/remote_state_manager.py
index 8b3b94b1..59b50f3a 100644
--- a/src/matcha_ml/state/remote_state_manager.py
+++ b/src/matcha_ml/state/remote_state_manager.py
@@ -1,51 +1,34 @@
"""Remote state manager module."""
import contextlib
-import dataclasses
import os
from typing import Iterator, Optional
from azure.core.exceptions import ResourceExistsError
-from dataclasses_json import DataClassJsonMixin
-from matcha_ml.cli.ui.print_messages import print_error, print_status
+from matcha_ml.cli.ui.print_messages import print_status
from matcha_ml.cli.ui.status_message_builders import (
build_step_success_status,
build_warning_status,
)
+from matcha_ml.config import (
+ DEFAULT_CONFIG_NAME,
+ MatchaConfig,
+ MatchaConfigComponent,
+ MatchaConfigComponentProperty,
+ MatchaConfigService,
+)
from matcha_ml.constants import LOCK_FILE_NAME
from matcha_ml.errors import MatchaError
from matcha_ml.runners.remote_state_runner import RemoteStateRunner
from matcha_ml.storage import AzureStorage
from matcha_ml.templates import RemoteStateTemplate
-DEFAULT_CONFIG_NAME = "matcha.config.json"
ALREADY_LOCKED_MESSAGE = (
"Remote state is already locked, maybe someone else is using matcha?"
" If you think this is a mistake, you can unlock the state by running 'matcha force-unlock'."
)
-@dataclasses.dataclass
-class RemoteStateBucketConfig(DataClassJsonMixin):
- """Dataclass to store state bucket configuration."""
-
- # Azure storage account name
- account_name: str
-
- # Azure storage container name
- container_name: str
-
- # Azure resource group name
- resource_group_name: str
-
-
-@dataclasses.dataclass
-class RemoteStateConfig(DataClassJsonMixin):
- """Dataclass to store remote state configuration."""
-
- remote_state_bucket: RemoteStateBucketConfig
-
-
class RemoteStateManager:
"""Remote State Manager class.
@@ -75,27 +58,18 @@ def _configuration_file_exists(self) -> bool:
"""
return os.path.exists(self.config_path)
- def _load_configuration(self) -> RemoteStateConfig:
- """Load configuration file.
-
- Returns:
- RemoteStateConfig: remote state configuration
- """
- with open(self.config_path) as f:
- return RemoteStateConfig.from_json(f.read())
-
@property
- def configuration(self) -> RemoteStateConfig:
+ def configuration(self) -> MatchaConfig:
"""Configuration property.
Returns:
- RemoteStateConfig: configuration read from the file system
+ MatchaConfig: configuration read from the file system
Raises:
MatchaError: if configuration file failed to load.
"""
try:
- return self._load_configuration()
+ return MatchaConfigService.read_matcha_config()
except Exception as e:
raise MatchaError(f"Error while loading state configuration: {e}")
@@ -114,8 +88,16 @@ def azure_storage(self) -> AzureStorage:
if self._azure_storage is None:
try:
self._azure_storage = AzureStorage(
- account_name=self.configuration.remote_state_bucket.account_name,
- resource_group_name=self.configuration.remote_state_bucket.resource_group_name,
+ account_name=self.configuration.find_component(
+ "remote_state_bucket"
+ )
+ .find_property("account_name")
+ .value,
+ resource_group_name=self.configuration.find_component(
+ "remote_state_bucket"
+ )
+ .find_property("resource_group_name")
+ .value,
)
except Exception as e:
raise MatchaError(f"Error while creating Azure Storage client: {e}")
@@ -151,7 +133,10 @@ def get_hash_remote_state(self, remote_path: str) -> str:
str: Hash content of file on remote storage in hexadecimal string
"""
return self.azure_storage.get_hash_remote_state(
- self.configuration.remote_state_bucket.container_name, remote_path
+ self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value,
+ remote_path,
)
def is_state_provisioned(self) -> bool:
@@ -167,7 +152,9 @@ def is_state_provisioned(self) -> bool:
return False
if not self._bucket_exists(
- self.configuration.remote_state_bucket.container_name
+ self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value
):
return False
@@ -213,13 +200,23 @@ def provision_remote_state(
state_storage_template.build_template(config, template, destination, verbose)
account_name, container_name, resource_group_name = template_runner.provision()
- self._write_matcha_config(account_name, container_name, resource_group_name)
+ properties = [
+ MatchaConfigComponentProperty(name="account_name", value=account_name),
+ MatchaConfigComponentProperty(name="container_name", value=container_name),
+ MatchaConfigComponentProperty(
+ name="resource_group_name", value=resource_group_name
+ ),
+ ]
+ remote_state_bucket_component = MatchaConfigComponent(
+ name="remote_state_bucket", properties=properties
+ )
+ matcha_config = MatchaConfig(components=[remote_state_bucket_component])
+ MatchaConfigService.update(matcha_config.components)
print_status(
build_step_success_status(
"Provisioning Matcha resource group and remote state is complete!"
)
)
- print()
def deprovision_remote_state(self) -> None:
"""Destroy the state bucket provisioned."""
@@ -227,47 +224,7 @@ def deprovision_remote_state(self) -> None:
template_runner = RemoteStateRunner()
template_runner.deprovision()
- self.remove_matcha_config()
-
- def _write_matcha_config(
- self, account_name: str, container_name: str, resource_group_name: str
- ) -> None:
- """Write the outputs of the Terraform deployed state storage to a bucket config file.
-
- Args:
- account_name (str): the storage account name of the remote state storage provisioned.
- container_name (str): the container name of the remote state storage provisioned.
- resource_group_name (str): Azure client ID.
- """
- remote_state_bucket_config = RemoteStateBucketConfig(
- account_name=account_name,
- container_name=container_name,
- resource_group_name=resource_group_name,
- )
- remote_state_config = RemoteStateConfig(
- remote_state_bucket=remote_state_bucket_config
- )
-
- matcha_config = remote_state_config.to_json(indent=4)
-
- with open(self.config_path, "w") as f:
- f.write(matcha_config)
-
- print_status(
- build_step_success_status(
- f"The matcha configuration is written to {self.config_path}"
- )
- )
-
- def remove_matcha_config(self) -> None:
- """Remove the matcha.config.json file."""
- try:
- os.remove(self.config_path)
- self._azure_storage = None
- except FileNotFoundError:
- print_error(
- f"Failed to remove the matcha.config.json file at {self.config_path}, file not found."
- )
+ MatchaConfigService.delete_matcha_config()
def download(self, dest_folder_path: str) -> None:
"""Download the remote state into the local matcha state directory.
@@ -276,7 +233,9 @@ def download(self, dest_folder_path: str) -> None:
dest_folder_path (str): Path to local matcha state directory
"""
self.azure_storage.download_folder(
- container_name=self.configuration.remote_state_bucket.container_name,
+ container_name=self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value,
dest_folder_path=dest_folder_path,
)
@@ -287,7 +246,9 @@ def upload(self, local_folder_path: str) -> None:
local_folder_path (str): Path to local matcha state directory
"""
self.azure_storage.upload_folder(
- container_name=self.configuration.remote_state_bucket.container_name,
+ container_name=self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value,
src_folder_path=local_folder_path,
)
@@ -316,7 +277,9 @@ def lock(self) -> None:
"""
try:
self.azure_storage.create_empty(
- container_name=self.configuration.remote_state_bucket.container_name,
+ container_name=self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value,
blob_name=LOCK_FILE_NAME,
)
except ResourceExistsError:
@@ -325,7 +288,9 @@ def lock(self) -> None:
def unlock(self) -> None:
"""Unlock remote state."""
if not self.azure_storage.blob_exists(
- container_name=self.configuration.remote_state_bucket.container_name,
+ container_name=self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value,
blob_name=LOCK_FILE_NAME,
):
print_status(
@@ -334,7 +299,9 @@ def unlock(self) -> None:
return
else:
self.azure_storage.delete_blob(
- container_name=self.configuration.remote_state_bucket.container_name,
+ container_name=self.configuration.find_component("remote_state_bucket")
+ .find_property("container_name")
+ .value,
blob_name=LOCK_FILE_NAME,
)
diff --git a/tests/conftest.py b/tests/conftest.py
index a64b327d..c643ea2e 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -5,7 +5,7 @@
import tempfile
import uuid
from pathlib import Path
-from typing import Iterator
+from typing import Dict, Iterator
from unittest.mock import PropertyMock, patch
import pytest
@@ -14,6 +14,12 @@
)
from typer.testing import CliRunner
+from matcha_ml.config import (
+ MatchaConfig,
+ MatchaConfigComponent,
+ MatchaConfigComponentProperty,
+ MatchaConfigService,
+)
from matcha_ml.services import AzureClient
from matcha_ml.services.azure_service import ROLE_ID_MAPPING
from matcha_ml.services.terraform_service import TerraformConfig
@@ -241,3 +247,85 @@ def state_file_as_object(uuid_for_testing: uuid.UUID) -> MatchaState:
),
]
)
+
+
+@pytest.fixture
+def mocked_matcha_config_json_object() -> Dict[str, Dict[str, str]]:
+ """A fixture returning a dictionary representation of the matcha.config.json file.
+
+ Returns:
+ matcha_config (Dict[str, Dict[str, str]]): a dictionary representation of the matcha.config.json file
+ """
+ matcha_config = {
+ "remote_state_bucket": {
+ "account_name": "test-account",
+ "container_name": "test-container",
+ "resource_group_name": "test-rg",
+ }
+ }
+
+ return matcha_config
+
+
+@pytest.fixture
+def mocked_matcha_config_component_property() -> MatchaConfigComponentProperty:
+ """A fixture returning a mocked MatchaConfigComponentProperty instance.
+
+ Returns:
+ (MatchaConfigComponentProperty): a mocked MatchaConfigComponentProperty instance.
+ """
+ return MatchaConfigComponentProperty(name="account_name", value="test_account_name")
+
+
+@pytest.fixture
+def mocked_matcha_config_component(mocked_matcha_config_json_object):
+ """A fixture returning a mocked MatchaConfigComponentProperty instance.
+
+ Args:
+ mocked_matcha_config_json_object (Dict[str, Dict[str, str]]): a dictionary representation of the matcha.config.json file
+
+ Returns:
+ (MatchaConfigComponentProperty): a mocked MatchaConfigComponentProperty instance.
+ """
+ properties = []
+ for key, value in mocked_matcha_config_json_object["remote_state_bucket"].items():
+ properties.append(MatchaConfigComponentProperty(name=key, value=value))
+
+ return MatchaConfigComponent(name="remote_state_bucket", properties=properties)
+
+
+@pytest.fixture
+def mocked_matcha_config(mocked_matcha_config_component):
+ """A fixture returning a mocked MatchaConfig instance.
+
+ Args:
+ mocked_matcha_config_component (MatchaConfigComponent): a mocked MatchaConfigComponent instance.
+
+ Returns:
+ (MatchaConfig): a mocked MatchaConfig instance.
+ """
+ return MatchaConfig([mocked_matcha_config_component])
+
+
+@pytest.fixture
+def mocked_matcha_config_service():
+ """A fixture representing a mocked MatchaConfigService.
+
+ Returns:
+ (MatchaConfigService): a mocked MatchaConfigService instance.
+ """
+ return MatchaConfigService()
+
+
+@pytest.fixture
+def mocked_remote_state_manager_is_state_provisioned_false():
+ """A fixture for providing context within which RemoteStateManager.is_state_provisioned always returns false.
+
+ Yields:
+ A mocked RemoteStateManager object with a patched is_state_provisioned method.
+ """
+ with patch(
+ "matcha_ml.state.remote_state_manager.RemoteStateManager.is_state_provisioned"
+ ) as is_state_provisioned:
+ is_state_provisioned.return_value = False
+ yield is_state_provisioned
diff --git a/tests/test_cli/test_provision.py b/tests/test_cli/test_provision.py
index c878cb0b..c5313d51 100644
--- a/tests/test_cli/test_provision.py
+++ b/tests/test_cli/test_provision.py
@@ -143,6 +143,7 @@ def test_cli_provision_command(
"location": "uksouth",
"prefix": "matcha",
"password": "default",
+ "zenmlserver_version": "latest"
}
assert_infrastructure(
@@ -199,6 +200,7 @@ def test_cli_provision_command_with_args(
"location": "uksouth",
"prefix": "matcha",
"password": "ninja",
+ "zenmlserver_version": "latest"
}
assert_infrastructure(
@@ -245,6 +247,7 @@ def test_cli_provision_command_with_prefix(
"location": "uksouth",
"prefix": "coffee",
"password": "default",
+ "zenmlserver_version": "latest"
}
assert_infrastructure(
@@ -289,6 +292,7 @@ def test_cli_provision_command_with_default_prefix(
"location": "uksouth",
"prefix": "matcha",
"password": "default",
+ "zenmlserver_version": "latest"
}
assert_infrastructure(
diff --git a/tests/test_cli/test_stack.py b/tests/test_cli/test_stack.py
index a70c8908..3beae607 100644
--- a/tests/test_cli/test_stack.py
+++ b/tests/test_cli/test_stack.py
@@ -1,8 +1,11 @@
"""Test suit to test the stack command and all its subcommands."""
+import os
+
from typer.testing import CliRunner
from matcha_ml.cli.cli import app
+from matcha_ml.config import MatchaConfig, MatchaConfigService
INTERNAL_FUNCTION_STUB = "matcha_ml.core"
@@ -46,27 +49,103 @@ def test_cli_stack_set_command_help_option(runner: CliRunner) -> None:
assert "Define the stack for Matcha to provision." in result.stdout
-def test_cli_stack_set_command_without_args(runner: CliRunner) -> None:
+def test_cli_stack_set_command_without_args(
+ runner: CliRunner, mocked_remote_state_manager_is_state_provisioned_false
+) -> None:
"""Tests the cli stack set sub-command.
Args:
runner (CliRunner): typer CLI runner
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked RemoteStateManager object
"""
result = runner.invoke(app, ["stack", "set"])
assert result.exit_code == 0
- assert "Matcha default stack has been set." in result.stdout
+ assert "Matcha 'default' stack has been set." in result.stdout
-def test_cli_stack_set_command_with_args(runner: CliRunner) -> None:
+def test_cli_stack_set_command_with_args(
+ runner: CliRunner, mocked_remote_state_manager_is_state_provisioned_false
+) -> None:
"""Tests the cli stack set sub-command.
Args:
runner (CliRunner): typer CLI runner
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
"""
- result = runner.invoke(app, ["stack", "set", "test_stack"])
+ result = runner.invoke(app, ["stack", "set", "default"])
assert result.exit_code == 0
- assert "Matcha test_stack stack has been set." in result.stdout
+ assert "Matcha 'default' stack has been set." in result.stdout
+
+
+def test_stack_set_stack_not_recognized(
+ runner: CliRunner, mocked_remote_state_manager_is_state_provisioned_false
+) -> None:
+ """Tests the cli stack set sub-command behavior when an unrecognized stack name is passed.
+
+ Args:
+ runner (CliRunner): typer CLI runner
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
+ """
+ result = runner.invoke(app, ["stack", "set", "random"])
+
+ assert result.exit_code == 0
+ assert "random is not a valid stack type" in result.stdout
+
+
+def test_stack_set_file_created(
+ matcha_testing_directory: str,
+ runner: CliRunner,
+ mocked_remote_state_manager_is_state_provisioned_false,
+) -> None:
+ """Test that stack_set cli command creates a config file if one doesn't exist.
+
+ Args:
+ matcha_testing_directory (str): a temporary working directory.
+ runner (CliRunner): terminal emulator
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
+ """
+ os.chdir(matcha_testing_directory)
+
+ result = runner.invoke(app, ["stack", "set", "llm"])
+
+ assert result.exit_code == 0
+
+ config = MatchaConfigService.read_matcha_config()
+ assert config.to_dict() == {"stack": {"name": "LLM"}}
+
+
+def test_stack_set_file_modified(
+ matcha_testing_directory,
+ mocked_matcha_config_json_object,
+ runner: CliRunner,
+ mocked_remote_state_manager_is_state_provisioned_false,
+) -> None:
+ """Test that if a config file exists, stack set cli command modifies the file.
+
+ Args:
+ matcha_testing_directory (str): temporary working directory.
+ mocked_matcha_config_json_object (dict): A dictionary representation of the matcha config json file.
+ runner (CliRunner): terminal emulator.
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
+ """
+ os.chdir(matcha_testing_directory)
+
+ config = MatchaConfig.from_dict(mocked_matcha_config_json_object)
+ config_dict = config.to_dict()
+ MatchaConfigService.write_matcha_config(config)
+
+ result = runner.invoke(app, ["stack", "set", "llm"])
+ assert result.exit_code == 0
+
+ new_config = MatchaConfigService.read_matcha_config()
+
+ new_config_dict = new_config.to_dict()
+
+ assert len(new_config_dict) == len(config_dict) + 1
+ assert "stack" in new_config_dict
+ assert new_config_dict["stack"]["name"] == "LLM"
+ assert config_dict.items() <= new_config_dict.items()
diff --git a/tests/test_config/test_matcha_config.py b/tests/test_config/test_matcha_config.py
new file mode 100644
index 00000000..3f508e11
--- /dev/null
+++ b/tests/test_config/test_matcha_config.py
@@ -0,0 +1,230 @@
+"""Tests for Matcha Config module."""
+
+import json
+import os
+from typing import Dict, Iterator
+
+import pytest
+
+from matcha_ml.config.matcha_config import (
+ DEFAULT_CONFIG_NAME,
+ MatchaConfig,
+ MatchaConfigComponent,
+ MatchaConfigComponentProperty,
+ MatchaConfigService,
+)
+from matcha_ml.errors import MatchaError
+
+
+def test_matcha_config_to_dict(
+ mocked_matcha_config_json_object: Dict[str, Dict[str, str]],
+ mocked_matcha_config: MatchaConfig,
+):
+ """Tests the to_dict method of the MatchaConfig class.
+
+ The test compares the output of the MatchaConfig to_dict method with a dictionary representation of the matcha.config.json file.
+
+ Args:
+ mocked_matcha_config_json_object (Dict[str, Dict[str, str]]): a dictionary representation of the matcha.config.json file
+ mocked_matcha_config (MatchaConfig): a mocked MatchaConfig instance.
+ """
+ assert mocked_matcha_config_json_object == mocked_matcha_config.to_dict()
+
+
+def test_matcha_config_from_dict(
+ mocked_matcha_config_json_object: Dict[str, Dict[str, str]],
+ mocked_matcha_config: MatchaConfig,
+):
+ """Tests the from_dict method of the MatchaConfig class.
+
+ The test compares the output of the MatchaConfig from_dict method with a mocked MatchaConfig instance.
+
+ Args:
+ mocked_matcha_config_json_object (Dict[str, Dict[str, str]]): a dictionary representation of the matcha.config.json file
+ mocked_matcha_config (MatchaConfig): a mocked MatchaConfig instance.
+ """
+ assert (
+ mocked_matcha_config.from_dict(mocked_matcha_config_json_object)
+ == mocked_matcha_config
+ )
+
+
+def test_matcha_config_service_write_matcha_config(
+ matcha_testing_directory: Iterator[str],
+ mocked_matcha_config_service: MatchaConfigService,
+ mocked_matcha_config: MatchaConfig,
+):
+ """Tests the write_matcha_config method of the MatchaConfigService.
+
+ The test creates a testing directory and a mock matcha.config.json file to test the read_matcha_config method.
+
+ Args:
+ matcha_testing_directory (Iterator[str]): a fixture for creating and removing temporary test directory for storing and moving files
+ mocked_matcha_config_service (MatchaConfigService): a mocked MatchaConfigService instance
+ mocked_matcha_config (MatchaConfig): a mocked MatchaConfig instance
+ """
+ matcha_config_file_path = os.path.join(
+ matcha_testing_directory, DEFAULT_CONFIG_NAME
+ )
+
+ assert not os.path.isfile(matcha_config_file_path)
+
+ os.chdir(matcha_testing_directory)
+
+ mocked_matcha_config_service.write_matcha_config(mocked_matcha_config)
+
+ assert mocked_matcha_config_service.read_matcha_config() == mocked_matcha_config
+
+
+def test_matcha_config_service_read_matcha_config(
+ matcha_testing_directory: Iterator[str],
+ mocked_matcha_config_service: MatchaConfigService,
+ mocked_matcha_config: MatchaConfig,
+ mocked_matcha_config_json_object: Dict[str, Dict[str, str]],
+):
+ """Tests the read_matcha_config method of the MatchaConfigService.
+
+ The test creates a testing directory and a mock matcha.config.json file to test the read_matcha_config method.
+
+ Args:
+ matcha_testing_directory (Iterator[str]): a fixture for creating and removing temporary test directory for storing and moving files
+ mocked_matcha_config_service (MatchaConfigService): a mocked MatchaConfigService instance
+ mocked_matcha_config_json_object (Dict[str, Dict[str, str]]): a dictionary representation of the matcha.config.json file
+ mocked_matcha_config (MatchaConfig): a mocked MatchaConfig instance
+ """
+ matcha_config_file_path = os.path.join(
+ matcha_testing_directory, DEFAULT_CONFIG_NAME
+ )
+
+ with open(matcha_config_file_path, "w") as file:
+ json.dump(mocked_matcha_config_json_object, file)
+
+ os.chdir(matcha_testing_directory)
+
+ assert mocked_matcha_config_service.read_matcha_config() == mocked_matcha_config
+
+
+def test_matcha_config_service_read_matcha_config_with_no_config(
+ matcha_testing_directory: Iterator[str],
+):
+ """Tests the error handling of the read_matcha_config method of the MatchaConfigService.
+
+ This test expects a MatchaError to be thrown if the config rile cannot be read.
+
+ Args:
+ matcha_testing_directory (Iterator[str]): a fixture for creating and removing temporary test directory for storing and moving files
+ """
+ os.chdir(matcha_testing_directory)
+
+ with pytest.raises(MatchaError):
+ _ = MatchaConfigService.read_matcha_config()
+
+
+def test_matcha_config_service_delete_matcha_config(
+ matcha_testing_directory: Iterator[str],
+ mocked_matcha_config_service: MatchaConfigService,
+ mocked_matcha_config_json_object: Dict[str, Dict[str, str]],
+):
+ """Tests the delete_matcha_config method of the MatchaConfigService.
+
+ The test creates a testing directory and a mock matcha.config.json file to then destroy, testing the delete_matcha_config method.
+
+ Args:
+ matcha_testing_directory (Iterator[str]): a fixture for creating and removing temporary test directory for storing and moving files
+ mocked_matcha_config_service (MatchaConfigService): a mocked MatchaConfigService instance
+ mocked_matcha_config_json_object (Dict[str, Dict[str, str]]): a dictionary representation of the matcha.config.json file
+ """
+ matcha_config_file_path = os.path.join(
+ matcha_testing_directory, DEFAULT_CONFIG_NAME
+ )
+
+ with open(matcha_config_file_path, "w") as file:
+ json.dump(mocked_matcha_config_json_object, file)
+
+ assert os.path.isfile(matcha_config_file_path)
+
+ os.chdir(matcha_testing_directory)
+
+ mocked_matcha_config_service.delete_matcha_config()
+
+ assert not os.path.isfile(matcha_config_file_path)
+
+
+def test_matcha_config_service_delete_matcha_config_error_handling(
+ matcha_testing_directory: Iterator[str],
+ mocked_matcha_config_service: MatchaConfigService,
+):
+ """Tests the error handling of the delete_matcha_config method of the MatchaConfigService.
+
+ The test asserts that no file exist and then attempts to destroy the non-existent file.
+
+ Args:
+ matcha_testing_directory (Iterator[str]): a fixture for creating and removing temporary test directory for storing and moving files
+ mocked_matcha_config_service (MatchaConfigService): a mocked MatchaConfigService instance
+ """
+ matcha_config_file_path = os.path.join(
+ matcha_testing_directory, DEFAULT_CONFIG_NAME
+ )
+
+ assert not os.path.isfile(matcha_config_file_path)
+
+ os.chdir(matcha_testing_directory)
+
+ with pytest.raises(MatchaError):
+ mocked_matcha_config_service.delete_matcha_config()
+
+
+def test_matcha_config_service_update(
+ matcha_testing_directory, mocked_matcha_config_json_object
+) -> None:
+ """Test that the update function in MatchaConfigService creates the desired changes in config file.
+
+ Args:
+ matcha_testing_directory (str): A temporary working directory.
+ mocked_matcha_config_json_object (dict): A dictionary representation of a matcha config json file.
+ """
+ os.chdir(matcha_testing_directory)
+ config = MatchaConfig.from_dict(mocked_matcha_config_json_object)
+ config_dict = config.to_dict()
+
+ MatchaConfigService.write_matcha_config(config)
+
+ component = MatchaConfigComponent(
+ name="test",
+ properties=[MatchaConfigComponentProperty(name="name", value="passed")],
+ )
+
+ MatchaConfigService.update(component)
+
+ updated_config = MatchaConfigService.read_matcha_config()
+ updated_config_dict = updated_config.to_dict()
+
+ assert len(updated_config_dict) - 1 == len(config_dict)
+ assert config_dict.items() <= updated_config_dict.items()
+ assert updated_config_dict["test"]["name"] == "passed"
+
+ MatchaConfigService.delete_matcha_config()
+ MatchaConfigService.write_matcha_config(config)
+
+ components = [
+ MatchaConfigComponent(
+ name="test",
+ properties=[MatchaConfigComponentProperty(name="name", value="passed")],
+ ),
+ MatchaConfigComponent(
+ name="test2",
+ properties=[
+ MatchaConfigComponentProperty(name="name", value="passed_again")
+ ],
+ ),
+ ]
+
+ MatchaConfigService.update(components)
+
+ updated_config = MatchaConfigService.read_matcha_config()
+ updated_config_dict = updated_config.to_dict()
+
+ assert len(updated_config_dict) - 2 == len(config_dict)
+ assert config_dict.items() <= updated_config_dict.items()
+ assert updated_config_dict["test"]["name"] == "passed"
+ assert updated_config_dict["test2"]["name"] == "passed_again"
diff --git a/tests/test_core/test_core_provision.py b/tests/test_core/test_core_provision.py
index 43496b72..5addf8f8 100644
--- a/tests/test_core/test_core_provision.py
+++ b/tests/test_core/test_core_provision.py
@@ -6,11 +6,12 @@
from pathlib import Path
from typing import Dict, Iterator, Union
from unittest import mock
-from unittest.mock import MagicMock
+from unittest.mock import MagicMock, patch
import pytest
from matcha_ml.core import provision
+from matcha_ml.core.core import infer_zenml_version
from matcha_ml.core._validation import LONGEST_RESOURCE_NAME, MAXIMUM_RESOURCE_NAME_LEN
from matcha_ml.errors import MatchaError, MatchaInputError
from matcha_ml.services.global_parameters_service import GlobalParameters
@@ -209,6 +210,7 @@ def test_provision_copies_infrastructure_templates_with_specified_values(
"location": "uksouth",
"prefix": "coffee",
"password": "default",
+ "zenmlserver_version": "latest"
}
assert_infrastructure(
@@ -334,3 +336,9 @@ def test_stale_remote_state_file_is_removed(matcha_testing_directory: str):
config_file_contents = json.load(f)
assert expected_config_file_contents == config_file_contents
+
+
+def test_version_inference_latest():
+ """Test checking when zenml isn't installed, the latest version is returned."""
+ assert infer_zenml_version() == "latest"
+
diff --git a/tests/test_core/test_stack_set.py b/tests/test_core/test_stack_set.py
new file mode 100644
index 00000000..249271b5
--- /dev/null
+++ b/tests/test_core/test_stack_set.py
@@ -0,0 +1,84 @@
+"""Test suite to test the stack set functionality in matcha."""
+import os
+from unittest.mock import patch
+
+import pytest
+
+from matcha_ml.config import MatchaConfig, MatchaConfigService
+from matcha_ml.core import stack_set
+from matcha_ml.errors import MatchaError, MatchaInputError
+
+
+def test_stack_set_valid_no_existing_file(
+ matcha_testing_directory, mocked_remote_state_manager_is_state_provisioned_false
+):
+ """Test that stack_set creates a config file if one doesn't exist and that it can be read properly.
+
+ Args:
+ matcha_testing_directory (str): temporary working directory
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
+ """
+ os.chdir(matcha_testing_directory)
+
+ stack_set(stack_name="llm")
+
+ config = MatchaConfigService.read_matcha_config()
+ assert config.to_dict() == {"stack": {"name": "LLM"}}
+
+ MatchaConfigService.delete_matcha_config()
+
+ stack_set(stack_name="default")
+
+ config = MatchaConfigService.read_matcha_config()
+ assert config.to_dict() == {"stack": {"name": "DEFAULT"}}
+
+
+def test_stack_set_invalid(
+ matcha_testing_directory, mocked_remote_state_manager_is_state_provisioned_false
+):
+ """Test stack_set raises an error if an invalid name is passed.
+
+ Args:
+ matcha_testing_directory (str): temporary working directory
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
+ """
+ with pytest.raises(MatchaInputError):
+ stack_set("nonsense")
+
+
+def test_stack_set_existing_file(
+ mocked_matcha_config_json_object,
+ matcha_testing_directory,
+ mocked_remote_state_manager_is_state_provisioned_false,
+):
+ """Test that if there's an existing file, the stack set command does not remove existing configuration information.
+
+ Args:
+ mocked_matcha_config_json_object (dict): a dictionary representation of the matcha.config.json file
+ matcha_testing_directory (str): temporary working directory
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager.
+ """
+ os.chdir(matcha_testing_directory)
+
+ config = MatchaConfig.from_dict(mocked_matcha_config_json_object)
+ config_dict = config.to_dict()
+ MatchaConfigService.write_matcha_config(config)
+
+ stack_set("llm")
+
+ new_config = MatchaConfigService.read_matcha_config()
+ new_config_dict = new_config.to_dict()
+
+ assert len(new_config_dict) == len(config_dict) + 1
+ assert "stack" in new_config_dict
+ assert new_config_dict["stack"]["name"] == "LLM"
+ assert config_dict.items() <= new_config_dict.items()
+
+
+def test_stack_set_resources_already_provisioned():
+ """Test that an error is raised if resources are provisioned when stack_set() is called."""
+ with patch(
+ "matcha_ml.state.remote_state_manager.RemoteStateManager.is_state_provisioned"
+ ) as is_state_provisioned, pytest.raises(MatchaError):
+ is_state_provisioned.return_value = True
+ stack_set("LLM")
diff --git a/tests/test_state/test_remote_state_manager.py b/tests/test_state/test_remote_state_manager.py
index 9cc3eea0..8dfe7260 100644
--- a/tests/test_state/test_remote_state_manager.py
+++ b/tests/test_state/test_remote_state_manager.py
@@ -6,20 +6,21 @@
from unittest.mock import MagicMock, PropertyMock, patch
import pytest
-from _pytest.capture import SysCapture
from azure.mgmt.confluent.models._confluent_management_client_enums import ( # type: ignore [import]
ProvisionState,
)
+from matcha_ml.config import (
+ DEFAULT_CONFIG_NAME,
+ MatchaConfig,
+ MatchaConfigService,
+)
from matcha_ml.errors import MatchaError
from matcha_ml.runners.remote_state_runner import RemoteStateRunner
from matcha_ml.state import RemoteStateManager
from matcha_ml.state.remote_state_manager import (
ALREADY_LOCKED_MESSAGE,
- DEFAULT_CONFIG_NAME,
LOCK_FILE_NAME,
- RemoteStateBucketConfig,
- RemoteStateConfig,
)
from matcha_ml.templates.remote_state_template import SUBMODULE_NAMES
@@ -29,39 +30,6 @@
)
-@pytest.fixture
-def remote_state_config() -> RemoteStateConfig:
- """Fixture for a remote state configuration.
-
- Returns:
- RemoteStateConfig: valid config
- """
- return RemoteStateConfig(
- remote_state_bucket=RemoteStateBucketConfig(
- account_name="test-account",
- container_name="test-container",
- resource_group_name="test-rg",
- )
- )
-
-
-@pytest.fixture
-def expected_matcha_config() -> Dict[str, Dict[str, str]]:
- """A fixture for the expected json configuration for testing whether configs are generated as expected.
-
- Returns:
- Dict[str, Dict[str, str]]: the expected matcha configuration.
- """
- config = {
- "remote_state_bucket": {
- "account_name": "test-account",
- "container_name": "test-container",
- "resource_group_name": "test-rg",
- }
- }
- return config
-
-
@pytest.fixture
def broken_config_testing_directory(matcha_testing_directory: str) -> str:
"""Fixture for broken configuration file in temp working directory.
@@ -81,21 +49,20 @@ def broken_config_testing_directory(matcha_testing_directory: str) -> str:
@pytest.fixture
def valid_config_testing_directory(
- matcha_testing_directory: str, remote_state_config: RemoteStateConfig
+ matcha_testing_directory: str, mocked_matcha_config: MatchaConfig
) -> str:
"""Fixture for a valid configuration file in temp working directory.
Args:
matcha_testing_directory (str): temporary working directory path
- remote_state_config (RemoteStateConfig): configuration to write to the config file
+ mocked_matcha_config (RemoteStateConfig): configuration to write to the config file
Returns:
str: temporary working directory path that the configuration was written to
"""
- config_path = os.path.join(matcha_testing_directory, DEFAULT_CONFIG_NAME)
+ os.chdir(matcha_testing_directory)
- with open(config_path, "w") as f:
- f.write(remote_state_config.to_json())
+ MatchaConfigService.write_matcha_config(mocked_matcha_config)
return matcha_testing_directory
@@ -170,7 +137,9 @@ def assert_matcha_config(
def test_provision_remote_state(
- matcha_testing_directory: str, expected_matcha_config: Dict[str, Dict[str, str]]
+ matcha_testing_directory: str,
+ mocked_matcha_config_json_object: Dict[str, Dict[str, str]],
+ valid_config_testing_directory: str,
):
"""Test that provision_state_storage behaves as expected.
@@ -179,7 +148,8 @@ def test_provision_remote_state(
Args:
matcha_testing_directory (str): temporary working directory for tests.
- expected_matcha_config (Dict[str, Dict[str, str]]): the expected matcha config.
+ mocked_matcha_config_json_object (Dict[str, Dict[str, str]]): the expected matcha config.
+ valid_config_testing_directory (str): a testing directory containing a test config file.
"""
os.chdir(matcha_testing_directory)
@@ -202,7 +172,9 @@ def test_provision_remote_state(
state_storage_destination_path, state_storage_expected_tf_vars
)
- assert_matcha_config(matcha_testing_directory, expected_matcha_config)
+ assert matcha_testing_directory == valid_config_testing_directory
+
+ assert_matcha_config(matcha_testing_directory, mocked_matcha_config_json_object)
def test_deprovision_remote_state(matcha_testing_directory: str) -> None:
@@ -211,6 +183,7 @@ def test_deprovision_remote_state(matcha_testing_directory: str) -> None:
Args:
matcha_testing_directory (str): temporary working directory for tests.
"""
+ os.chdir(matcha_testing_directory)
with patch(
"matcha_ml.runners.remote_state_runner.RemoteStateRunner.deprovision"
) as destroy:
@@ -230,27 +203,6 @@ def test_deprovision_remote_state(matcha_testing_directory: str) -> None:
template_runner.deprovision.assert_called()
-def test_write_matcha_config(
- matcha_testing_directory: str, expected_matcha_config: Dict[str, Dict[str, str]]
-):
- """Test whether the write_matcha_config() function is able to write the expected config to the expected destination.
-
- Args:
- matcha_testing_directory (str): temporary working directory for tests.
- expected_matcha_config (Dict[str, Dict[str, str]]): the expected matcha config.
- """
- os.chdir(matcha_testing_directory)
- remote_state_manager = RemoteStateManager(
- os.path.join(matcha_testing_directory, DEFAULT_CONFIG_NAME)
- )
-
- remote_state_manager._write_matcha_config(
- "test-account", "test-container", "test-rg"
- )
-
- assert_matcha_config(matcha_testing_directory, expected_matcha_config)
-
-
def test_is_state_provisioned_true(
valid_config_testing_directory: str, mock_azure_storage_instance: MagicMock
):
@@ -500,29 +452,6 @@ def test_is_state_provisioned_returns_false_when_resource_group_does_not_exist(
mock_azure_storage_instance.container_exists.assert_not_called()
-def test_remove_matcha_config(capsys: SysCapture):
- """Test the functionality of the `remove_matcha_config` function by verifying if it correctly catches the "File not found" error and throws the expected error message.
-
- Args:
- capsys (SysCapture): fixture to capture stdout and stderr
- """
- remote_state_manager = RemoteStateManager()
-
- mock_non_exist_path = "not_exist"
- # Verify path do not exists
- assert not os.path.exists(mock_non_exist_path)
-
- remote_state_manager.config_path = mock_non_exist_path
-
- remote_state_manager.remove_matcha_config()
-
- captured = capsys.readouterr()
-
- expected_output = f"Failed to remove the matcha.config.json file at {mock_non_exist_path}, file not found."
-
- assert expected_output in captured.err
-
-
def test_is_state_stale_false(valid_config_testing_directory: str):
"""Test is_state_stale method returns False, when the user has a state file which has a resource group and container provisioned.
From 639881d1e0824b6f8630bfac8a6b14a600db73bb Mon Sep 17 00:00:00 2001
From: Chris <32800386+Christopher-Norman@users.noreply.github.com>
Date: Fri, 11 Aug 2023 10:21:06 +0100
Subject: [PATCH 04/10] [RPD-286] Add documentation on "stacks" and the new LLM
stack (#189)
* Initial version of docs
* Add motivation to stacks docs
* Various docs updates based on reviews
---
docs/resource-stacks.md | 52 +++++++++++++++++++++++++++++++++++++++++
mkdocs.yml | 1 +
2 files changed, 53 insertions(+)
create mode 100644 docs/resource-stacks.md
diff --git a/docs/resource-stacks.md b/docs/resource-stacks.md
new file mode 100644
index 00000000..64e1618c
--- /dev/null
+++ b/docs/resource-stacks.md
@@ -0,0 +1,52 @@
+# Resource Stacks 📚
+
+Machine Learning projects often vary in their size, from small-scale experimentation to large deployments, meaning that the infrastructure requirements also change and scale. For example, the infrastructure stack needed for deploying an LLM may require a GPU or vector database, which aren't usually needed in more general machine learning use-cases.
+
+Matcha accommodates both of these requirements, and currently offers two infrastructure stacks which we'll discuss in more detail here and show how you can get started with either.
+
+> Note: These stacks must be set before provisioning any resources and cannot be change whilst a Matcha deployment exists.
+
+## Available stacks
+
+### DEFAULT
+
+The `DEFAULT` stack. This stack is ideal for generic machine learning training and deployments and a good starting point. It includes:
+ * [Azure Kubernetes Service](https://azure.microsoft.com/en-gb/products/kubernetes-service)
+ * [ZenML](https://www.zenml.io/home)
+ * [Seldon Core](https://www.seldon.io/solutions/open-source-projects/core) (deployment)
+ * [MLflow](https://mlflow.org/) (experiment tracking)
+ * Data version control storage bucket
+
+This is the stack used in the [getting started page](getting-started.md). Follow the link for more information.
+
+### LLM
+
+The `LLM` stack: This includes everything found within the `DEFAULT` stack with the addition of a vector database - Chroma DB. This stack is modified for the training and deployment of Large Language Models (LLMs).
+
+ * [Azure Kubernetes Service](https://azure.microsoft.com/en-gb/products/kubernetes-service)
+ * [ZenML](https://www.zenml.io/home)
+ * [Seldon Core](https://www.seldon.io/solutions/open-source-projects/core) (deployment)
+ * [MLflow](https://mlflow.org/) (experiment tracking)
+ * Data version control storage bucket
+ * [Chroma DB](https://www.trychroma.com/) (vector database for document retrieval)
+
+
+We use this stack for [MindGPT](https://github.com/fuzzylabs/MindGPT), our large language model for mental health question answering.
+
+## How to switch your stack
+
+To switch your stack to the 'DEFAULT' stack, run the following command:
+
+```bash
+$ matcha stack set default
+```
+
+or for the 'LLM' stack:
+
+```bash
+$ matcha stack set llm
+```
+
+If no stack is set Matcha will use the 'default' stack.
+
+See the [API documentation](references.md) for more information.
diff --git a/mkdocs.yml b/mkdocs.yml
index 3746e0ee..a4196092 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -14,6 +14,7 @@ nav:
- Azure Costs: 'costings.md'
- Inside Matcha:
- How does Matcha work: 'inside-matcha.md'
+ - Resource stacks: 'resource-stacks.md'
- Why we collect usage data: 'privacy.md'
- Tools:
- Data Version Control: 'data-version-control.md'
From 407be1ccf2c29c5abbcb4e587b185baf40470756 Mon Sep 17 00:00:00 2001
From: Chris <32800386+Christopher-Norman@users.noreply.github.com>
Date: Mon, 14 Aug 2023 11:47:05 +0100
Subject: [PATCH 05/10] [RPD-284] Update AzureRunner to select the Terraform
files corresponding to the stack name in the config file (#187)
* [RPD-287] ZenML version inference for zenserver (#180)
* various changes
* change variable names to make things more clear
* shubham's comment
* test for latest
* update existing tests
* update existing tests
* shubham latest comment
* add gitflow notation branches to ci (#183)
* remove old, commented out code
* [RPD-260] Add an object to handle the `matcha.config.json` file. (#184)
* adds logic and tests for matcha config module
* updates docstrings
* adds tests and implements config object throughout matcha
* updated for pr comments
* updates docstring
* fixes ci
* updates for comments
* enum and metaclass
* enum and metaclass
* bug removal
* docstring stack_set
* docstring file exists
* fix current tests
* add a couple tests, move logic for updating to configservice
* lowercase-ify arg to enum
* american spelling
* american spelling
* chris' comment re overwriting
* friendlier api
* Runtime error if not recognised arg type fpor update()
* Runtime error if not recognised arg type fpor update()
* update provision to use new update() API
* update stack name
* tests
* tests
* tests
* Move files for selection
* Clean up file
* Remove a test that no longer describes the expected functionality
* Remove a test that no longer describes the expected functionality
* Fix tests
* Stop creation of config file in local directory when running tests
* Update check to use MatchaConfig object instead of to dict
* Add get current stack name function to MatchaConfigService
* Update get stack function
* Fix test
* Remove unnecessary lower casing
* Fix tests
---
src/matcha_ml/config/matcha_config.py | 24 ++-
src/matcha_ml/core/core.py | 15 +-
.../{resources => default}/.gitignore | 0
.../.terraform.lock.hcl | 0
.../{resources => default}/README.md | 0
.../{resources => default}/aks/README.md | 0
.../{resources => default}/aks/main.tf | 0
.../{resources => default}/aks/output.tf | 0
.../{resources => default}/aks/variables.tf | 0
.../azure_container_registry/README.md | 0
.../azure_container_registry/main.tf | 0
.../azure_container_registry/output.tf | 0
.../azure_container_registry/variables.tf | 0
.../configure_kubectl.tf | 0
.../data_version_control_storage/README.md | 0
.../data_version_control_storage/main.tf | 0
.../data_version_control_storage/output.tf | 2 +-
.../data_version_control_storage/providers.tf | 0
.../data_version_control_storage/variables.tf | 0
.../{resources => default}/helm.tf | 0
.../{resources => default}/kubernetes.tf | 0
.../{resources => default}/main.tf | 0
.../mlflow_module/README.md | 0
.../mlflow_module/getURI.tf | 0
.../mlflow_module/main.tf | 0
.../mlflow_module/output.tf | 0
.../mlflow_module/providers.tf | 0
.../mlflow_module/variables.tf | 0
.../mlflow_module/zenml_namespace.tf | 0
.../{resources => default}/output.tf | 2 +-
.../{resources => default}/printf.cmd | 0
.../{resources => default}/providers.tf | 0
.../resource_group/README.md | 0
.../resource_group/main.tf | 0
.../resource_group/output.tf | 0
.../resource_group/variables.tf | 0
.../{resources => default}/seldon/README.md | 0
.../{resources => default}/seldon/istio.tf | 0
.../{resources => default}/seldon/main.tf | 0
.../{resources => default}/seldon/outputs.tf | 0
.../seldon/permissions.tf | 0
.../seldon/providers.tf | 0
.../seldon/variables.tf | 0
.../{resources => default}/storage/README.md | 0
.../{resources => default}/storage/main.tf | 0
.../{resources => default}/storage/output.tf | 0
.../storage/providers.tf | 0
.../storage/variables.tf | 0
.../{resources => default}/variables.tf | 0
.../zen_server/README.md | 0
.../zen_server/getURL.tf | 0
.../zen_server/ingress.tf | 0
.../{resources => default}/zen_server/main.tf | 0
.../zen_server/outputs.tf | 0
.../zen_server/providers.tf | 0
.../{resources => default}/zen_server/sql.tf | 0
.../zen_server/variables.tf | 0
.../zen_server/zenml_helm/Chart.yaml | 0
.../zen_server/zenml_helm/templates/NOTES.txt | 0
.../zenml_helm/templates/_helpers.tpl | 0
.../zenml_helm/templates/cert-secret.yaml | 0
.../zen_server/zenml_helm/templates/hpa.yaml | 0
.../templates/server-deployment.yaml | 0
.../zenml_helm/templates/server-ingress.yaml | 0
.../zenml_helm/templates/server-secret.yaml | 0
.../zenml_helm/templates/server-service.yaml | 0
.../zenml_helm/templates/serviceaccount.yaml | 0
.../templates/tests/test-connection.yaml | 0
.../zen_server/zenml_helm/values.yaml | 6 +-
.../zenml_storage/README.md | 0
.../zenml_storage/main.tf | 0
.../zenml_storage/output.tf | 0
.../zenml_storage/variables.tf | 0
.../infrastructure/llm/.terraform.lock.hcl | 174 ++++++++++++++++++
src/matcha_ml/services/analytics_service.py | 9 +-
src/matcha_ml/state/remote_state_manager.py | 45 +++--
src/matcha_ml/templates/azure_template.py | 1 +
src/matcha_ml/templates/base_template.py | 1 -
tests/test_cli/test_stack.py | 31 ++--
tests/test_core/test_core_provision.py | 10 +-
tests/test_core/test_stack_set.py | 6 +-
tests/test_state/test_remote_state_manager.py | 47 ++---
82 files changed, 291 insertions(+), 82 deletions(-)
rename src/matcha_ml/infrastructure/{resources => default}/.gitignore (100%)
rename src/matcha_ml/infrastructure/{resources => default}/.terraform.lock.hcl (100%)
rename src/matcha_ml/infrastructure/{resources => default}/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/aks/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/aks/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/aks/output.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/aks/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/azure_container_registry/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/azure_container_registry/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/azure_container_registry/output.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/azure_container_registry/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/configure_kubectl.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/data_version_control_storage/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/data_version_control_storage/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/data_version_control_storage/output.tf (99%)
rename src/matcha_ml/infrastructure/{resources => default}/data_version_control_storage/providers.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/data_version_control_storage/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/helm.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/kubernetes.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/getURI.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/output.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/providers.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/mlflow_module/zenml_namespace.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/output.tf (99%)
rename src/matcha_ml/infrastructure/{resources => default}/printf.cmd (100%)
rename src/matcha_ml/infrastructure/{resources => default}/providers.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/resource_group/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/resource_group/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/resource_group/output.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/resource_group/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/istio.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/outputs.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/permissions.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/providers.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/seldon/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/storage/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/storage/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/storage/output.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/storage/providers.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/storage/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/getURL.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/ingress.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/outputs.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/providers.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/sql.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/variables.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/Chart.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/NOTES.txt (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/_helpers.tpl (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/cert-secret.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/hpa.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/server-deployment.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/server-ingress.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/server-secret.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/server-service.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/serviceaccount.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/templates/tests/test-connection.yaml (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zen_server/zenml_helm/values.yaml (99%)
rename src/matcha_ml/infrastructure/{resources => default}/zenml_storage/README.md (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zenml_storage/main.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zenml_storage/output.tf (100%)
rename src/matcha_ml/infrastructure/{resources => default}/zenml_storage/variables.tf (100%)
create mode 100644 src/matcha_ml/infrastructure/llm/.terraform.lock.hcl
diff --git a/src/matcha_ml/config/matcha_config.py b/src/matcha_ml/config/matcha_config.py
index 696b837b..80a6a53b 100644
--- a/src/matcha_ml/config/matcha_config.py
+++ b/src/matcha_ml/config/matcha_config.py
@@ -2,7 +2,7 @@
import json
import os
from dataclasses import dataclass
-from typing import Dict, List, Union
+from typing import Dict, List, Optional, Union
from matcha_ml.errors import MatchaError
@@ -126,6 +126,24 @@ def from_dict(state_dict: Dict[str, Dict[str, str]]) -> "MatchaConfig":
class MatchaConfigService:
"""A service for handling the Matcha config file."""
+ @staticmethod
+ def get_stack() -> Optional[MatchaConfigComponentProperty]:
+ """Gets the current stack name from the Matcha Config if it exists.
+
+ Returns:
+ Optional[MatchaConfigComponentProperty]: The name of the current stack being used as a config component object.
+ """
+ try:
+ stack = (
+ MatchaConfigService.read_matcha_config()
+ .find_component("stack")
+ .find_property("name")
+ )
+ except MatchaError:
+ stack = None
+
+ return stack
+
@staticmethod
def write_matcha_config(matcha_config: MatchaConfig) -> None:
"""A function for writing the local Matcha config file.
@@ -170,7 +188,9 @@ def config_file_exists() -> bool:
return os.path.exists(os.path.join(os.getcwd(), DEFAULT_CONFIG_NAME))
@staticmethod
- def update(components: Union[MatchaConfigComponent, List[MatchaConfigComponent]]) -> None:
+ def update(
+ components: Union[MatchaConfigComponent, List[MatchaConfigComponent]]
+ ) -> None:
"""A function which updates the matcha config file.
If no config file exists, this function will create one.
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index 1a48e033..b5d5d021 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -271,6 +271,9 @@ def provision(
except MatchaInputError as e:
raise e
+ if MatchaConfigService.get_stack() is None:
+ stack_set("default")
+
# Provision resource group and remote state storage
remote_state_manager.provision_remote_state(location, prefix)
@@ -279,8 +282,16 @@ def provision(
destination = os.path.join(
project_directory, ".matcha", "infrastructure", "resources"
)
+
+ stack = MatchaConfigService.get_stack()
+ if stack is not None:
+ stack_name = stack.value
+
template = os.path.join(
- os.path.dirname(__file__), os.pardir, "infrastructure", "resources"
+ os.path.dirname(__file__),
+ os.pardir,
+ "infrastructure",
+ stack_name,
)
azure_template = AzureTemplate()
@@ -320,7 +331,7 @@ def stack_set(stack_name: str) -> None:
stack = MatchaConfigComponent(
name="stack",
- properties=[MatchaConfigComponentProperty(name="name", value=stack_enum.name)],
+ properties=[MatchaConfigComponentProperty(name="name", value=stack_enum.value)],
)
MatchaConfigService.update(stack)
diff --git a/src/matcha_ml/infrastructure/resources/.gitignore b/src/matcha_ml/infrastructure/default/.gitignore
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/.gitignore
rename to src/matcha_ml/infrastructure/default/.gitignore
diff --git a/src/matcha_ml/infrastructure/resources/.terraform.lock.hcl b/src/matcha_ml/infrastructure/default/.terraform.lock.hcl
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/.terraform.lock.hcl
rename to src/matcha_ml/infrastructure/default/.terraform.lock.hcl
diff --git a/src/matcha_ml/infrastructure/resources/README.md b/src/matcha_ml/infrastructure/default/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/README.md
rename to src/matcha_ml/infrastructure/default/README.md
diff --git a/src/matcha_ml/infrastructure/resources/aks/README.md b/src/matcha_ml/infrastructure/default/aks/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/aks/README.md
rename to src/matcha_ml/infrastructure/default/aks/README.md
diff --git a/src/matcha_ml/infrastructure/resources/aks/main.tf b/src/matcha_ml/infrastructure/default/aks/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/aks/main.tf
rename to src/matcha_ml/infrastructure/default/aks/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/aks/output.tf b/src/matcha_ml/infrastructure/default/aks/output.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/aks/output.tf
rename to src/matcha_ml/infrastructure/default/aks/output.tf
diff --git a/src/matcha_ml/infrastructure/resources/aks/variables.tf b/src/matcha_ml/infrastructure/default/aks/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/aks/variables.tf
rename to src/matcha_ml/infrastructure/default/aks/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/azure_container_registry/README.md b/src/matcha_ml/infrastructure/default/azure_container_registry/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/azure_container_registry/README.md
rename to src/matcha_ml/infrastructure/default/azure_container_registry/README.md
diff --git a/src/matcha_ml/infrastructure/resources/azure_container_registry/main.tf b/src/matcha_ml/infrastructure/default/azure_container_registry/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/azure_container_registry/main.tf
rename to src/matcha_ml/infrastructure/default/azure_container_registry/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/azure_container_registry/output.tf b/src/matcha_ml/infrastructure/default/azure_container_registry/output.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/azure_container_registry/output.tf
rename to src/matcha_ml/infrastructure/default/azure_container_registry/output.tf
diff --git a/src/matcha_ml/infrastructure/resources/azure_container_registry/variables.tf b/src/matcha_ml/infrastructure/default/azure_container_registry/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/azure_container_registry/variables.tf
rename to src/matcha_ml/infrastructure/default/azure_container_registry/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/configure_kubectl.tf b/src/matcha_ml/infrastructure/default/configure_kubectl.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/configure_kubectl.tf
rename to src/matcha_ml/infrastructure/default/configure_kubectl.tf
diff --git a/src/matcha_ml/infrastructure/resources/data_version_control_storage/README.md b/src/matcha_ml/infrastructure/default/data_version_control_storage/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/data_version_control_storage/README.md
rename to src/matcha_ml/infrastructure/default/data_version_control_storage/README.md
diff --git a/src/matcha_ml/infrastructure/resources/data_version_control_storage/main.tf b/src/matcha_ml/infrastructure/default/data_version_control_storage/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/data_version_control_storage/main.tf
rename to src/matcha_ml/infrastructure/default/data_version_control_storage/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/data_version_control_storage/output.tf b/src/matcha_ml/infrastructure/default/data_version_control_storage/output.tf
similarity index 99%
rename from src/matcha_ml/infrastructure/resources/data_version_control_storage/output.tf
rename to src/matcha_ml/infrastructure/default/data_version_control_storage/output.tf
index 7fd8d508..45a5f5ce 100644
--- a/src/matcha_ml/infrastructure/resources/data_version_control_storage/output.tf
+++ b/src/matcha_ml/infrastructure/default/data_version_control_storage/output.tf
@@ -12,4 +12,4 @@ output "primary_connection_string" {
description = "Azure Storage Account - Primary connection string"
value = azurerm_storage_account.storageaccount.primary_connection_string
sensitive = true
-}
\ No newline at end of file
+}
diff --git a/src/matcha_ml/infrastructure/resources/data_version_control_storage/providers.tf b/src/matcha_ml/infrastructure/default/data_version_control_storage/providers.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/data_version_control_storage/providers.tf
rename to src/matcha_ml/infrastructure/default/data_version_control_storage/providers.tf
diff --git a/src/matcha_ml/infrastructure/resources/data_version_control_storage/variables.tf b/src/matcha_ml/infrastructure/default/data_version_control_storage/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/data_version_control_storage/variables.tf
rename to src/matcha_ml/infrastructure/default/data_version_control_storage/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/helm.tf b/src/matcha_ml/infrastructure/default/helm.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/helm.tf
rename to src/matcha_ml/infrastructure/default/helm.tf
diff --git a/src/matcha_ml/infrastructure/resources/kubernetes.tf b/src/matcha_ml/infrastructure/default/kubernetes.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/kubernetes.tf
rename to src/matcha_ml/infrastructure/default/kubernetes.tf
diff --git a/src/matcha_ml/infrastructure/resources/main.tf b/src/matcha_ml/infrastructure/default/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/main.tf
rename to src/matcha_ml/infrastructure/default/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/README.md b/src/matcha_ml/infrastructure/default/mlflow_module/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/README.md
rename to src/matcha_ml/infrastructure/default/mlflow_module/README.md
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/getURI.tf b/src/matcha_ml/infrastructure/default/mlflow_module/getURI.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/getURI.tf
rename to src/matcha_ml/infrastructure/default/mlflow_module/getURI.tf
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/main.tf b/src/matcha_ml/infrastructure/default/mlflow_module/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/main.tf
rename to src/matcha_ml/infrastructure/default/mlflow_module/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/output.tf b/src/matcha_ml/infrastructure/default/mlflow_module/output.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/output.tf
rename to src/matcha_ml/infrastructure/default/mlflow_module/output.tf
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/providers.tf b/src/matcha_ml/infrastructure/default/mlflow_module/providers.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/providers.tf
rename to src/matcha_ml/infrastructure/default/mlflow_module/providers.tf
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/variables.tf b/src/matcha_ml/infrastructure/default/mlflow_module/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/variables.tf
rename to src/matcha_ml/infrastructure/default/mlflow_module/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/mlflow_module/zenml_namespace.tf b/src/matcha_ml/infrastructure/default/mlflow_module/zenml_namespace.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/mlflow_module/zenml_namespace.tf
rename to src/matcha_ml/infrastructure/default/mlflow_module/zenml_namespace.tf
diff --git a/src/matcha_ml/infrastructure/resources/output.tf b/src/matcha_ml/infrastructure/default/output.tf
similarity index 99%
rename from src/matcha_ml/infrastructure/resources/output.tf
rename to src/matcha_ml/infrastructure/default/output.tf
index 53f47f65..f62fd806 100644
--- a/src/matcha_ml/infrastructure/resources/output.tf
+++ b/src/matcha_ml/infrastructure/default/output.tf
@@ -91,4 +91,4 @@ output "data_version_control_storage_container_name"{
output "data_version_control_storage_account_name"{
description = "The name of the storage account for data version control"
value = module.data_version_control_storage.storage_account_name
-}
\ No newline at end of file
+}
diff --git a/src/matcha_ml/infrastructure/resources/printf.cmd b/src/matcha_ml/infrastructure/default/printf.cmd
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/printf.cmd
rename to src/matcha_ml/infrastructure/default/printf.cmd
diff --git a/src/matcha_ml/infrastructure/resources/providers.tf b/src/matcha_ml/infrastructure/default/providers.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/providers.tf
rename to src/matcha_ml/infrastructure/default/providers.tf
diff --git a/src/matcha_ml/infrastructure/resources/resource_group/README.md b/src/matcha_ml/infrastructure/default/resource_group/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/resource_group/README.md
rename to src/matcha_ml/infrastructure/default/resource_group/README.md
diff --git a/src/matcha_ml/infrastructure/resources/resource_group/main.tf b/src/matcha_ml/infrastructure/default/resource_group/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/resource_group/main.tf
rename to src/matcha_ml/infrastructure/default/resource_group/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/resource_group/output.tf b/src/matcha_ml/infrastructure/default/resource_group/output.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/resource_group/output.tf
rename to src/matcha_ml/infrastructure/default/resource_group/output.tf
diff --git a/src/matcha_ml/infrastructure/resources/resource_group/variables.tf b/src/matcha_ml/infrastructure/default/resource_group/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/resource_group/variables.tf
rename to src/matcha_ml/infrastructure/default/resource_group/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/seldon/README.md b/src/matcha_ml/infrastructure/default/seldon/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/README.md
rename to src/matcha_ml/infrastructure/default/seldon/README.md
diff --git a/src/matcha_ml/infrastructure/resources/seldon/istio.tf b/src/matcha_ml/infrastructure/default/seldon/istio.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/istio.tf
rename to src/matcha_ml/infrastructure/default/seldon/istio.tf
diff --git a/src/matcha_ml/infrastructure/resources/seldon/main.tf b/src/matcha_ml/infrastructure/default/seldon/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/main.tf
rename to src/matcha_ml/infrastructure/default/seldon/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/seldon/outputs.tf b/src/matcha_ml/infrastructure/default/seldon/outputs.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/outputs.tf
rename to src/matcha_ml/infrastructure/default/seldon/outputs.tf
diff --git a/src/matcha_ml/infrastructure/resources/seldon/permissions.tf b/src/matcha_ml/infrastructure/default/seldon/permissions.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/permissions.tf
rename to src/matcha_ml/infrastructure/default/seldon/permissions.tf
diff --git a/src/matcha_ml/infrastructure/resources/seldon/providers.tf b/src/matcha_ml/infrastructure/default/seldon/providers.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/providers.tf
rename to src/matcha_ml/infrastructure/default/seldon/providers.tf
diff --git a/src/matcha_ml/infrastructure/resources/seldon/variables.tf b/src/matcha_ml/infrastructure/default/seldon/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/seldon/variables.tf
rename to src/matcha_ml/infrastructure/default/seldon/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/storage/README.md b/src/matcha_ml/infrastructure/default/storage/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/storage/README.md
rename to src/matcha_ml/infrastructure/default/storage/README.md
diff --git a/src/matcha_ml/infrastructure/resources/storage/main.tf b/src/matcha_ml/infrastructure/default/storage/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/storage/main.tf
rename to src/matcha_ml/infrastructure/default/storage/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/storage/output.tf b/src/matcha_ml/infrastructure/default/storage/output.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/storage/output.tf
rename to src/matcha_ml/infrastructure/default/storage/output.tf
diff --git a/src/matcha_ml/infrastructure/resources/storage/providers.tf b/src/matcha_ml/infrastructure/default/storage/providers.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/storage/providers.tf
rename to src/matcha_ml/infrastructure/default/storage/providers.tf
diff --git a/src/matcha_ml/infrastructure/resources/storage/variables.tf b/src/matcha_ml/infrastructure/default/storage/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/storage/variables.tf
rename to src/matcha_ml/infrastructure/default/storage/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/variables.tf b/src/matcha_ml/infrastructure/default/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/variables.tf
rename to src/matcha_ml/infrastructure/default/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/README.md b/src/matcha_ml/infrastructure/default/zen_server/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/README.md
rename to src/matcha_ml/infrastructure/default/zen_server/README.md
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/getURL.tf b/src/matcha_ml/infrastructure/default/zen_server/getURL.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/getURL.tf
rename to src/matcha_ml/infrastructure/default/zen_server/getURL.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/ingress.tf b/src/matcha_ml/infrastructure/default/zen_server/ingress.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/ingress.tf
rename to src/matcha_ml/infrastructure/default/zen_server/ingress.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/main.tf b/src/matcha_ml/infrastructure/default/zen_server/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/main.tf
rename to src/matcha_ml/infrastructure/default/zen_server/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/outputs.tf b/src/matcha_ml/infrastructure/default/zen_server/outputs.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/outputs.tf
rename to src/matcha_ml/infrastructure/default/zen_server/outputs.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/providers.tf b/src/matcha_ml/infrastructure/default/zen_server/providers.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/providers.tf
rename to src/matcha_ml/infrastructure/default/zen_server/providers.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/sql.tf b/src/matcha_ml/infrastructure/default/zen_server/sql.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/sql.tf
rename to src/matcha_ml/infrastructure/default/zen_server/sql.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/variables.tf b/src/matcha_ml/infrastructure/default/zen_server/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/variables.tf
rename to src/matcha_ml/infrastructure/default/zen_server/variables.tf
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/Chart.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/Chart.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/Chart.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/Chart.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/NOTES.txt b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/NOTES.txt
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/NOTES.txt
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/NOTES.txt
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/_helpers.tpl b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/_helpers.tpl
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/_helpers.tpl
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/_helpers.tpl
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/cert-secret.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/cert-secret.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/cert-secret.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/cert-secret.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/hpa.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/hpa.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/hpa.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/hpa.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-deployment.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-deployment.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-deployment.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-deployment.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-ingress.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-ingress.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-ingress.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-ingress.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-secret.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-secret.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-secret.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-secret.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-service.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-service.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/server-service.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/server-service.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/serviceaccount.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/serviceaccount.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/serviceaccount.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/serviceaccount.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/tests/test-connection.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/tests/test-connection.yaml
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/templates/tests/test-connection.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/templates/tests/test-connection.yaml
diff --git a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/values.yaml
similarity index 99%
rename from src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml
rename to src/matcha_ml/infrastructure/default/zen_server/zenml_helm/values.yaml
index f0c35dae..e03a5cd7 100644
--- a/src/matcha_ml/infrastructure/resources/zen_server/zenml_helm/values.yaml
+++ b/src/matcha_ml/infrastructure/default/zen_server/zenml_helm/values.yaml
@@ -26,7 +26,7 @@ zenml:
deploymentType:
# The ZenML authentication scheme. Use one of:
- #
+ #
# NO_AUTH - No authentication
# HTTP_BASIC - HTTP Basic authentication
# OAUTH2_PASSWORD_BEARER - OAuth2 password bearer with JWT tokens
@@ -40,7 +40,7 @@ zenml:
# from secrets import token_hex
# token_hex(32)
# ```
- #
+ #
# or:
#
# ```shell
@@ -124,7 +124,7 @@ zenml:
# from secrets import token_hex
# token_hex(32)
# ```
- #
+ #
# or:
#
# ```shell
diff --git a/src/matcha_ml/infrastructure/resources/zenml_storage/README.md b/src/matcha_ml/infrastructure/default/zenml_storage/README.md
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zenml_storage/README.md
rename to src/matcha_ml/infrastructure/default/zenml_storage/README.md
diff --git a/src/matcha_ml/infrastructure/resources/zenml_storage/main.tf b/src/matcha_ml/infrastructure/default/zenml_storage/main.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zenml_storage/main.tf
rename to src/matcha_ml/infrastructure/default/zenml_storage/main.tf
diff --git a/src/matcha_ml/infrastructure/resources/zenml_storage/output.tf b/src/matcha_ml/infrastructure/default/zenml_storage/output.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zenml_storage/output.tf
rename to src/matcha_ml/infrastructure/default/zenml_storage/output.tf
diff --git a/src/matcha_ml/infrastructure/resources/zenml_storage/variables.tf b/src/matcha_ml/infrastructure/default/zenml_storage/variables.tf
similarity index 100%
rename from src/matcha_ml/infrastructure/resources/zenml_storage/variables.tf
rename to src/matcha_ml/infrastructure/default/zenml_storage/variables.tf
diff --git a/src/matcha_ml/infrastructure/llm/.terraform.lock.hcl b/src/matcha_ml/infrastructure/llm/.terraform.lock.hcl
new file mode 100644
index 00000000..81956fc8
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/.terraform.lock.hcl
@@ -0,0 +1,174 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/gavinbunney/kubectl" {
+ version = "1.14.0"
+ constraints = "1.14.0"
+ hashes = [
+ "h1:mX2AOFIMIxJmW5kM8DT51gloIOKCr9iT6W8yodnUyfs=",
+ "zh:0350f3122ff711984bbc36f6093c1fe19043173fad5a904bce27f86afe3cc858",
+ "zh:07ca36c7aa7533e8325b38232c77c04d6ef1081cb0bac9d56e8ccd51f12f2030",
+ "zh:0c351afd91d9e994a71fe64bbd1662d0024006b3493bb61d46c23ea3e42a7cf5",
+ "zh:39f1a0aa1d589a7e815b62b5aa11041040903b061672c4cfc7de38622866cbc4",
+ "zh:428d3a321043b78e23c91a8d641f2d08d6b97f74c195c654f04d2c455e017de5",
+ "zh:4baf5b1de2dfe9968cc0f57fd4be5a741deb5b34ee0989519267697af5f3eee5",
+ "zh:6131a927f9dffa014ab5ca5364ac965fe9b19830d2bbf916a5b2865b956fdfcf",
+ "zh:c62e0c9fd052cbf68c5c2612af4f6408c61c7e37b615dc347918d2442dd05e93",
+ "zh:f0beffd7ce78f49ead612e4b1aefb7cb6a461d040428f514f4f9cc4e5698ac65",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.48.0"
+ constraints = ">= 3.16.0, 3.48.0"
+ hashes = [
+ "h1:RSUCtxgd6hD9J11YZGOA4yffeu5P8YmQnP5SRNl6+d8=",
+ "zh:01bd328009f2803ebc18ac27535e7d1548c735bb5bd02460e471acc835e5dd19",
+ "zh:070b0bdd5ff27232eec7ef9128fc9bd17e6bdae503ddcc450c944449f3a8d216",
+ "zh:0a0a0e81f7ab8757aa83876fffbc57328843664900923d8b3c577e7596884726",
+ "zh:30994e6988c92d90a71b88bff0bbc4fa8f3b48034d18eb068bd5281888304579",
+ "zh:54dfdbae2bf79f8104ae73e5c6cd94a69d1e6de4345322f6c8eb6affb04a66c5",
+ "zh:55ba99b32346237435d7212b3f2521952ee67934dd5ee942a51642357b0ad4fc",
+ "zh:881bc29857511f7eedc3d359a0f2dcca6b526a48f6d54887cafdb25647abd1fd",
+ "zh:892bfa34b95b6b4b2ced24dc2989edf512b193bd9e5cf121ae47bb9d9e6d0b94",
+ "zh:c7d2c778b0f251990874ee859b9093fbb4beb9b3968858137da6c5167c797ea9",
+ "zh:db558aa70b163af44a73fcb1306d0e4dcafcafe585bedb90ef69f063fa9766a3",
+ "zh:e0ae252b7bea560e05fde09fe632f012430fb91ff9063fce560d997ecdb1cf75",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/external" {
+ version = "2.3.1"
+ hashes = [
+ "h1:9rJggijNdRdFk//ViQPGZdK0xu9XU/9qBDijNsZJMg0=",
+ "zh:001e2886dc81fc98cf17cf34c0d53cb2dae1e869464792576e11b0f34ee92f54",
+ "zh:2eeac58dd75b1abdf91945ac4284c9ccb2bfb17fa9bdb5f5d408148ff553b3ee",
+ "zh:2fc39079ba61411a737df2908942e6970cb67ed2f4fb19090cd44ce2082903dd",
+ "zh:472a71c624952cff7aa98a7b967f6c7bb53153dbd2b8f356ceb286e6743bb4e2",
+ "zh:4cff06d31272aac8bc35e9b7faec42cf4554cbcbae1092eaab6ab7f643c215d9",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:7ed16ccd2049fa089616b98c0bd57219f407958f318f3c697843e2397ddf70df",
+ "zh:842696362c92bf2645eb85c739410fd51376be6c488733efae44f4ce688da50e",
+ "zh:8985129f2eccfd7f1841ce06f3bf2bbede6352ec9e9f926fbaa6b1a05313b326",
+ "zh:a5f0602d8ec991a5411ef42f872aa90f6347e93886ce67905c53cfea37278e05",
+ "zh:bf4ab82cbe5256dcef16949973bf6aa1a98c2c73a98d6a44ee7bc40809d002b8",
+ "zh:e70770be62aa70198fa899526d671643ff99eecf265bf1a50e798fc3480bd417",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/helm" {
+ version = "2.0.3"
+ constraints = "~> 2.0.1"
+ hashes = [
+ "h1:FRSVqY+1/AUO/j/lVxHHsLudfSA9gDc7Dsu+YxcJSEY=",
+ "zh:154e0aa489e474e2eeb3de94be7666133faf6fd950712a640425b2bf3a81ee95",
+ "zh:16a2be6c4b61d0c5205c63816148c7ab0c8f56a75c05e8d897fa4d5cac0c029a",
+ "zh:189e47bc723f8c29bcfe2c1638d43b8148f614ea86e642f4b50b2acb4b760224",
+ "zh:3763901d3630213002cb8c70bb24c628cd29738ff6591585250ea8636264abd6",
+ "zh:4822f85e4700ea049384523d98de0ef7d83549844b13e94bbd544cec05557a9a",
+ "zh:62c5b87b09e0051bab0b712e3ad465fd53e66f9619dbe76ee23519d1087d8a05",
+ "zh:a0a6a842b11190dd1841e98bbb74961074e7ffb95984be5cc392df9f532d803e",
+ "zh:beac4e6806e77447e1018f3404a5fbf782d20d82a0d9b4a31e9bfc7d2bbecab6",
+ "zh:e1bbaa09bf4f4a91ec7606f84d2e0200a02e7b24d045e8b5daebd87d7a75b7ce",
+ "zh:ed1e05c50212d4f57435ccdd68cfb98d8395927c316df76d1dd6509566d3aeaa",
+ "zh:fdc687e16a964bb652ddb670f6832fdead25235eca551796cfed70ec07d94931",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/kubernetes" {
+ version = "2.11.0"
+ constraints = "~> 2.11.0"
+ hashes = [
+ "h1:T65SZhN/tQgsAsHe/G5PCgpjofi+aTKPZ+nZg6WOJpc=",
+ "zh:143a19dd0ea3b07fc5e3d9231f3c2d01f92894385c98a67327de74c76c715843",
+ "zh:1fc757d209e09c3cf7848e4274daa32408c07743698fbed10ee52a4a479b62b6",
+ "zh:22dfebd0685749c51a8f765d51a1090a259778960ac1cd4f32021a325b2b9b72",
+ "zh:3039b3b76e870cd8fc404cf75a29c66b171c6ba9b6182e131b6ae2ca648ec7c0",
+ "zh:3af0a15562fcab4b5684b18802e0239371b2b8ff9197ed069ff4827f795a002b",
+ "zh:50aaf20336d1296a73315adb66f7687f75bd5c6b1f93a894b95c75cc142810ec",
+ "zh:682064fabff895ec351860b4fe0321290bbbb17c2a410b62c9bea0039400650e",
+ "zh:70ac914d5830b3371a2679d8f77cc20c419a6e12925145afae6c977c8eb90934",
+ "zh:710aa02cccf7b0f3fb50880d6d2a7a8b8c9435248666616844ba71f74648cddc",
+ "zh:88e418118cd5afbdec4984944c7ab36950bf48e8d3e09e090232e55eecfb470b",
+ "zh:9cef159377bf23fa331f8724fdc6ce27ad39a217a4bae6df3b1ca408fc643da6",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+ version = "2.1.0"
+ constraints = "2.1.0"
+ hashes = [
+ "h1:KfieWtVyGWwplSoLIB5usKAUnrIkDQBkWaR5TI+4WYg=",
+ "zh:0f1ec65101fa35050978d483d6e8916664b7556800348456ff3d09454ac1eae2",
+ "zh:36e42ac19f5d68467aacf07e6adcf83c7486f2e5b5f4339e9671f68525fc87ab",
+ "zh:6db9db2a1819e77b1642ec3b5e95042b202aee8151a0256d289f2e141bf3ceb3",
+ "zh:719dfd97bb9ddce99f7d741260b8ece2682b363735c764cac83303f02386075a",
+ "zh:7598bb86e0378fd97eaa04638c1a4c75f960f62f69d3662e6d80ffa5a89847fe",
+ "zh:ad0a188b52517fec9eca393f1e2c9daea362b33ae2eb38a857b6b09949a727c1",
+ "zh:c46846c8df66a13fee6eff7dc5d528a7f868ae0dcf92d79deaac73cc297ed20c",
+ "zh:dc1a20a2eec12095d04bf6da5321f535351a594a636912361db20eb2a707ccc4",
+ "zh:e57ab4771a9d999401f6badd8b018558357d3cbdf3d33cc0c4f83e818ca8e94b",
+ "zh:ebdcde208072b4b0f8d305ebf2bfdc62c926e0717599dcf8ec2fd8c5845031c3",
+ "zh:ef34c52b68933bedd0868a13ccfd59ff1c820f299760b3c02e008dc95e2ece91",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/null" {
+ version = "3.2.1"
+ constraints = "3.2.1"
+ hashes = [
+ "h1:tSj1mL6OQ8ILGqR2mDu7OYYYWf+hoir0pf9KAQ8IzO8=",
+ "zh:58ed64389620cc7b82f01332e27723856422820cfd302e304b5f6c3436fb9840",
+ "zh:62a5cc82c3b2ddef7ef3a6f2fedb7b9b3deff4ab7b414938b08e51d6e8be87cb",
+ "zh:63cff4de03af983175a7e37e52d4bd89d990be256b16b5c7f919aff5ad485aa5",
+ "zh:74cb22c6700e48486b7cabefa10b33b801dfcab56f1a6ac9b6624531f3d36ea3",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:79e553aff77f1cfa9012a2218b8238dd672ea5e1b2924775ac9ac24d2a75c238",
+ "zh:a1e06ddda0b5ac48f7e7c7d59e1ab5a4073bbcf876c73c0299e4610ed53859dc",
+ "zh:c37a97090f1a82222925d45d84483b2aa702ef7ab66532af6cbcfb567818b970",
+ "zh:e4453fbebf90c53ca3323a92e7ca0f9961427d2f0ce0d2b65523cc04d5d999c2",
+ "zh:e80a746921946d8b6761e77305b752ad188da60688cfd2059322875d363be5f5",
+ "zh:fbdb892d9822ed0e4cb60f2fedbdbb556e4da0d88d3b942ae963ed6ff091e48f",
+ "zh:fca01a623d90d0cad0843102f9b8b9fe0d3ff8244593bd817f126582b52dd694",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+ version = "3.1.0"
+ constraints = "3.1.0"
+ hashes = [
+ "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
+ "zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
+ "zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
+ "zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff",
+ "zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2",
+ "zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992",
+ "zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427",
+ "zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc",
+ "zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f",
+ "zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b",
+ "zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7",
+ "zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a",
+ ]
+}
+
+provider "registry.terraform.io/loafoe/htpasswd" {
+ version = "1.0.4"
+ constraints = "1.0.4"
+ hashes = [
+ "h1:/OCwJ2uB9PfESHNn4bDwdHnMOp8x5D/aNvvUl8XNFA4=",
+ "zh:1f17ffcb8ab2f19de1242a6980f78334fc81efeaddfa85545435048f54045e4a",
+ "zh:6265fd9bbb718d55655120044b4969c80aa938ecfb17a0fd7541ff7de8c54e1e",
+ "zh:79b7a6e3260b084530f6bdaba13536843fa55fc28569965a69cbdcb5d5c208a5",
+ "zh:827991bd4481b9c0f33a922f5168146d0e68f627c8c71f1c18da27df05386502",
+ "zh:898a54254123718828d07ca54fba9626f6c706e4849c1d5bfd93d16df4463a6f",
+ "zh:b42f93565c8e5ab902d12a44dc34efa7207f5a568c7588f957732be3d9cd3997",
+ "zh:d43a78148ae10aac214c7abef7c131d78b7173d28ab679354ac67c11ff979f8e",
+ "zh:ddb702db1b27df028dab0364fbd90a1f5d97244e41765a7e66a8afc1a85d8371",
+ "zh:df22dd80e4639c14ec428d345cdf21851e807890cfe72908759d037cfaed68b7",
+ "zh:f6c7dfbc72ad83727c1fcfc064adb0362d947b66a2f5ba185742d5668c598c96",
+ "zh:f7e1feafd63a1987f5e39f9c75ac05dc153ffde2c9dd669847c19ad318bbebe7",
+ ]
+}
diff --git a/src/matcha_ml/services/analytics_service.py b/src/matcha_ml/services/analytics_service.py
index e659f402..d963efb9 100644
--- a/src/matcha_ml/services/analytics_service.py
+++ b/src/matcha_ml/services/analytics_service.py
@@ -90,15 +90,10 @@ def inner(*args: Any, **kwargs: Any) -> Any:
result, error_code = execute_analytics_event(func, *args, **kwargs)
te = perf_counter()
- try:
- matcha_state_service = MatchaStateService()
- except Exception as e:
- matcha_state_service = None
- error_code = e
-
# Get the matcha.state UUID if it exists
matcha_state_uuid: Optional[str] = None
- if matcha_state_service and matcha_state_service.state_exists():
+ if MatchaStateService.state_exists():
+ matcha_state_service = MatchaStateService()
try:
state_id_component = matcha_state_service.get_component("id")
except MatchaError:
diff --git a/src/matcha_ml/state/remote_state_manager.py b/src/matcha_ml/state/remote_state_manager.py
index 59b50f3a..3c34bd2c 100644
--- a/src/matcha_ml/state/remote_state_manager.py
+++ b/src/matcha_ml/state/remote_state_manager.py
@@ -43,7 +43,7 @@ def __init__(self, config_path: Optional[str] = None) -> None:
"""Initialize Remote State Manager.
Args:
- config_path (Optional[str]): optional configuration file path
+ config_path (Optional[str]): optional configuration file path.
"""
if config_path is not None:
self.config_path = config_path
@@ -63,7 +63,7 @@ def configuration(self) -> MatchaConfig:
"""Configuration property.
Returns:
- MatchaConfig: configuration read from the file system
+ MatchaConfig: configuration read from the file system.
Raises:
MatchaError: if configuration file failed to load.
@@ -77,13 +77,13 @@ def configuration(self) -> MatchaConfig:
def azure_storage(self) -> AzureStorage:
"""Azure Storage property.
- If it was not initialized before, it will be initialized
+ If it was not initialized before, it will be initialized.
Returns:
- AzureStorage: to interact with blob storage on Azure
+ AzureStorage: to interact with blob storage on Azure.
Raises:
- MatchaError: if Azure Storage client failed to create
+ MatchaError: if Azure Storage client failed to create.
"""
if self._azure_storage is None:
try:
@@ -119,7 +119,7 @@ def _resource_group_exists(self) -> bool:
"""Check if an Azure resource group already exists.
Returns:
- bool: True, if the resource group exists
+ bool: True, if the resource group exists.
"""
return self.azure_storage.resource_group_exists
@@ -127,10 +127,10 @@ def get_hash_remote_state(self, remote_path: str) -> str:
"""Get the hash of remote matcha state file.
Args:
- remote_path (str) : Path to file on remote storage
+ remote_path (str) : Path to file on remote storage.
Returns:
- str: Hash content of file on remote storage in hexadecimal string
+ str: Hash content of file on remote storage in hexadecimal string.
"""
return self.azure_storage.get_hash_remote_state(
self.configuration.find_component("remote_state_bucket")
@@ -143,11 +143,18 @@ def is_state_provisioned(self) -> bool:
"""Check if remote state has already been provisioned.
Returns:
- bool: is state provisioned
+ bool: is state provisioned.
"""
if not self._configuration_file_exists():
return False
+ try:
+ MatchaConfigService.read_matcha_config().find_component(
+ "remote_state_bucket"
+ )
+ except MatchaError:
+ return False
+
if not self._resource_group_exists():
return False
@@ -164,11 +171,19 @@ def is_state_stale(self) -> bool:
"""Check if remote state has been destroyed.
Returns:
- bool: True, if state is stale
+ bool: True, if state is stale.
"""
- return bool(
- self._configuration_file_exists() and not self._resource_group_exists()
- )
+ if not self._configuration_file_exists():
+ return False
+
+ try:
+ MatchaConfigService.read_matcha_config().find_component(
+ "remote_state_bucket"
+ )
+ except MatchaError:
+ return False
+
+ return not self._resource_group_exists()
def provision_remote_state(
self, location: str, prefix: str, verbose: Optional[bool] = False
@@ -176,7 +191,7 @@ def provision_remote_state(
"""Provision the state bucket using templates.
Args:
- location (str): location of where this bucket will be provisioned
+ location (str): location of where this bucket will be provisioned.
prefix (str): Prefix used for all resources, or empty string to fill in.
verbose (Optional[bool], optional): additional output is show when True. Defaults to False.
"""
@@ -230,7 +245,7 @@ def download(self, dest_folder_path: str) -> None:
"""Download the remote state into the local matcha state directory.
Args:
- dest_folder_path (str): Path to local matcha state directory
+ dest_folder_path (str): Path to local matcha state directory.
"""
self.azure_storage.download_folder(
container_name=self.configuration.find_component("remote_state_bucket")
diff --git a/src/matcha_ml/templates/azure_template.py b/src/matcha_ml/templates/azure_template.py
index 16e97ce7..10688077 100644
--- a/src/matcha_ml/templates/azure_template.py
+++ b/src/matcha_ml/templates/azure_template.py
@@ -16,6 +16,7 @@
"zen_server/zenml_helm",
"zen_server/zenml_helm/templates",
"data_version_control_storage",
+ "chroma",
]
diff --git a/src/matcha_ml/templates/base_template.py b/src/matcha_ml/templates/base_template.py
index e66cb6fd..a36b2c15 100644
--- a/src/matcha_ml/templates/base_template.py
+++ b/src/matcha_ml/templates/base_template.py
@@ -70,7 +70,6 @@ def copy_files(
if sub_folder_path
else destination
)
-
for source_path in files:
filename = os.path.basename(source_path)
destination_path = os.path.join(destination_folder, filename)
diff --git a/tests/test_cli/test_stack.py b/tests/test_cli/test_stack.py
index 3beae607..29f763cb 100644
--- a/tests/test_cli/test_stack.py
+++ b/tests/test_cli/test_stack.py
@@ -6,6 +6,7 @@
from matcha_ml.cli.cli import app
from matcha_ml.config import MatchaConfig, MatchaConfigService
+from matcha_ml.state.remote_state_manager import RemoteStateManager
INTERNAL_FUNCTION_STUB = "matcha_ml.core"
@@ -14,7 +15,7 @@ def test_cli_stack_command_help_option(runner: CliRunner) -> None:
"""Tests the --help option for the cli stack command.
Args:
- runner (CliRunner): typer CLI runner
+ runner (CliRunner): typer CLI runner.
"""
result = runner.invoke(app, ["stack", "--help"])
@@ -27,7 +28,7 @@ def test_cli_stack_command_defaults_to_help(runner: CliRunner) -> None:
"""Tests the --help option for the cli stack command.
Args:
- runner (CliRunner): typer CLI runner
+ runner (CliRunner): typer CLI runner.
"""
result = runner.invoke(app, ["stack"])
@@ -40,7 +41,7 @@ def test_cli_stack_set_command_help_option(runner: CliRunner) -> None:
"""Tests the --help option for the cli stack set sub-command.
Args:
- runner (CliRunner): typer CLI runner
+ runner (CliRunner): typer CLI runner.
"""
result = runner.invoke(app, ["stack", "set", "--help"])
@@ -50,14 +51,18 @@ def test_cli_stack_set_command_help_option(runner: CliRunner) -> None:
def test_cli_stack_set_command_without_args(
- runner: CliRunner, mocked_remote_state_manager_is_state_provisioned_false
+ matcha_testing_directory: str,
+ runner: CliRunner,
+ mocked_remote_state_manager_is_state_provisioned_false: RemoteStateManager,
) -> None:
"""Tests the cli stack set sub-command.
Args:
- runner (CliRunner): typer CLI runner
- mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked RemoteStateManager object
+ matcha_testing_directory (str): a temporary working directory.
+ runner (CliRunner): typer CLI runner.
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked RemoteStateManager object.
"""
+ os.chdir(matcha_testing_directory)
result = runner.invoke(app, ["stack", "set"])
assert result.exit_code == 0
@@ -66,14 +71,18 @@ def test_cli_stack_set_command_without_args(
def test_cli_stack_set_command_with_args(
- runner: CliRunner, mocked_remote_state_manager_is_state_provisioned_false
+ matcha_testing_directory: str,
+ runner: CliRunner,
+ mocked_remote_state_manager_is_state_provisioned_false,
) -> None:
"""Tests the cli stack set sub-command.
Args:
- runner (CliRunner): typer CLI runner
- mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager
+ matcha_testing_directory (str): a temporary working directory.
+ runner (CliRunner): typer CLI runner.
+ mocked_remote_state_manager_is_state_provisioned_false (RemoteStateManager): A mocked remote state manager.
"""
+ os.chdir(matcha_testing_directory)
result = runner.invoke(app, ["stack", "set", "default"])
assert result.exit_code == 0
@@ -115,7 +124,7 @@ def test_stack_set_file_created(
assert result.exit_code == 0
config = MatchaConfigService.read_matcha_config()
- assert config.to_dict() == {"stack": {"name": "LLM"}}
+ assert config.to_dict() == {"stack": {"name": "llm"}}
def test_stack_set_file_modified(
@@ -147,5 +156,5 @@ def test_stack_set_file_modified(
assert len(new_config_dict) == len(config_dict) + 1
assert "stack" in new_config_dict
- assert new_config_dict["stack"]["name"] == "LLM"
+ assert new_config_dict["stack"]["name"] == "llm"
assert config_dict.items() <= new_config_dict.items()
diff --git a/tests/test_core/test_core_provision.py b/tests/test_core/test_core_provision.py
index 5addf8f8..90a42c3a 100644
--- a/tests/test_core/test_core_provision.py
+++ b/tests/test_core/test_core_provision.py
@@ -6,13 +6,13 @@
from pathlib import Path
from typing import Dict, Iterator, Union
from unittest import mock
-from unittest.mock import MagicMock, patch
+from unittest.mock import MagicMock
import pytest
from matcha_ml.core import provision
-from matcha_ml.core.core import infer_zenml_version
from matcha_ml.core._validation import LONGEST_RESOURCE_NAME, MAXIMUM_RESOURCE_NAME_LEN
+from matcha_ml.core.core import infer_zenml_version
from matcha_ml.errors import MatchaError, MatchaInputError
from matcha_ml.services.global_parameters_service import GlobalParameters
from matcha_ml.state.matcha_state import (
@@ -210,7 +210,7 @@ def test_provision_copies_infrastructure_templates_with_specified_values(
"location": "uksouth",
"prefix": "coffee",
"password": "default",
- "zenmlserver_version": "latest"
+ "zenmlserver_version": "latest",
}
assert_infrastructure(
@@ -323,7 +323,8 @@ def test_stale_remote_state_file_is_removed(matcha_testing_directory: str):
"account_name": "test-account",
"container_name": "test-container",
"resource_group_name": "test-rg",
- }
+ },
+ "stack": {"name": "default"},
}
with mock.patch(
@@ -341,4 +342,3 @@ def test_stale_remote_state_file_is_removed(matcha_testing_directory: str):
def test_version_inference_latest():
"""Test checking when zenml isn't installed, the latest version is returned."""
assert infer_zenml_version() == "latest"
-
diff --git a/tests/test_core/test_stack_set.py b/tests/test_core/test_stack_set.py
index 249271b5..8a38df08 100644
--- a/tests/test_core/test_stack_set.py
+++ b/tests/test_core/test_stack_set.py
@@ -23,14 +23,14 @@ def test_stack_set_valid_no_existing_file(
stack_set(stack_name="llm")
config = MatchaConfigService.read_matcha_config()
- assert config.to_dict() == {"stack": {"name": "LLM"}}
+ assert config.to_dict() == {"stack": {"name": "llm"}}
MatchaConfigService.delete_matcha_config()
stack_set(stack_name="default")
config = MatchaConfigService.read_matcha_config()
- assert config.to_dict() == {"stack": {"name": "DEFAULT"}}
+ assert config.to_dict() == {"stack": {"name": "default"}}
def test_stack_set_invalid(
@@ -71,7 +71,7 @@ def test_stack_set_existing_file(
assert len(new_config_dict) == len(config_dict) + 1
assert "stack" in new_config_dict
- assert new_config_dict["stack"]["name"] == "LLM"
+ assert new_config_dict["stack"]["name"] == "llm"
assert config_dict.items() <= new_config_dict.items()
diff --git a/tests/test_state/test_remote_state_manager.py b/tests/test_state/test_remote_state_manager.py
index 8dfe7260..e398f048 100644
--- a/tests/test_state/test_remote_state_manager.py
+++ b/tests/test_state/test_remote_state_manager.py
@@ -15,6 +15,7 @@
MatchaConfig,
MatchaConfigService,
)
+from matcha_ml.config.matcha_config import MatchaConfigComponent
from matcha_ml.errors import MatchaError
from matcha_ml.runners.remote_state_runner import RemoteStateRunner
from matcha_ml.state import RemoteStateManager
@@ -30,23 +31,6 @@
)
-@pytest.fixture
-def broken_config_testing_directory(matcha_testing_directory: str) -> str:
- """Fixture for broken configuration file in temp working directory.
-
- Args:
- matcha_testing_directory (str): temporary working directory path
-
- Returns:
- str: temporary working directory path that the configuration was written to
- """
- config_path = os.path.join(matcha_testing_directory, DEFAULT_CONFIG_NAME)
- content = {}
- with open(config_path, "w") as f:
- json.dump(content, f)
- return matcha_testing_directory
-
-
@pytest.fixture
def valid_config_testing_directory(
matcha_testing_directory: str, mocked_matcha_config: MatchaConfig
@@ -233,18 +217,6 @@ def test_is_state_provisioned_no_config(matcha_testing_directory: str):
assert not remote_state.is_state_provisioned()
-def test_is_state_provisioned_broken_config(broken_config_testing_directory: str):
- """Test is_state_provisioned method returns False, when the configuration file is broken.
-
- Args:
- broken_config_testing_directory (str): temporary working directory path, with broken config file
- """
- os.chdir(broken_config_testing_directory) # move to temporary working directory
- remote_state = RemoteStateManager()
- with pytest.raises(MatchaError):
- assert not remote_state.is_state_provisioned()
-
-
def test_is_state_provisioned_broken_no_bucket(
valid_config_testing_directory: str, mock_azure_storage_instance: MagicMock
):
@@ -464,9 +436,13 @@ def test_is_state_stale_false(valid_config_testing_directory: str):
"matcha_ml.state.remote_state_manager.RemoteStateManager._configuration_file_exists"
) as config_file_exists, patch(
"matcha_ml.state.remote_state_manager.RemoteStateManager._resource_group_exists"
- ) as resource_group_exists:
+ ) as resource_group_exists, patch(
+ "matcha_ml.state.remote_state_manager.MatchaConfigService.read_matcha_config"
+ ) as matcha_config:
config_file_exists.return_value = True
resource_group_exists.return_value = True
+ matcha_config.return_value = MatchaConfig([])
+
remote_state = RemoteStateManager()
assert not remote_state.is_state_stale()
@@ -483,8 +459,17 @@ def test_is_state_stale_no_resource_group(matcha_testing_directory: str):
"matcha_ml.state.remote_state_manager.RemoteStateManager._configuration_file_exists"
) as config_file_exists, patch(
"matcha_ml.state.remote_state_manager.RemoteStateManager._resource_group_exists"
- ) as resource_group_exists:
+ ) as resource_group_exists, patch(
+ "matcha_ml.state.remote_state_manager.MatchaConfigService.read_matcha_config"
+ ) as matcha_config, patch(
+ "matcha_ml.state.remote_state_manager.MatchaConfig.find_component"
+ ) as matcha_config_get_component:
config_file_exists.return_value = True
resource_group_exists.return_value = False
+ matcha_config.return_value = MatchaConfig([])
+ matcha_config_get_component.return_value = MatchaConfigComponent(
+ name="remote_state_bucket", properties=[]
+ )
+
remote_state = RemoteStateManager()
assert remote_state.is_state_stale()
From b42b31dc7d95977d1333701cbd2f9d6deaf96ee6 Mon Sep 17 00:00:00 2001
From: Callum Wells <68609181+swells2020@users.noreply.github.com>
Date: Tue, 15 Aug 2023 08:29:25 +0100
Subject: [PATCH 06/10] updates stack handling
---
src/matcha_ml/core/core.py | 8 ++++++--
src/matcha_ml/templates/azure_template.py | 10 +++++-----
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index b5d5d021..cf47cf53 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -18,7 +18,7 @@
from matcha_ml.services.global_parameters_service import GlobalParameters
from matcha_ml.state import MatchaStateService, RemoteStateManager
from matcha_ml.state.matcha_state import MatchaState
-from matcha_ml.templates.azure_template import AzureTemplate
+from matcha_ml.templates.azure_template import DEFAULT_STACK, LLM_STACK, AzureTemplate
class StackTypeMeta(
@@ -293,8 +293,12 @@ def provision(
"infrastructure",
stack_name,
)
+ if stack_name == "llm":
+ submodule_names = DEFAULT_STACK + LLM_STACK
+ else:
+ submodule_names = DEFAULT_STACK
- azure_template = AzureTemplate()
+ azure_template = AzureTemplate(submodule_names)
zenml_version = infer_zenml_version()
config = azure_template.build_template_configuration(
diff --git a/src/matcha_ml/templates/azure_template.py b/src/matcha_ml/templates/azure_template.py
index 10688077..a36affe7 100644
--- a/src/matcha_ml/templates/azure_template.py
+++ b/src/matcha_ml/templates/azure_template.py
@@ -1,10 +1,10 @@
"""Build a template for provisioning resources on Azure using terraform files."""
-from typing import Optional
+from typing import List, Optional
from matcha_ml.state import MatchaState, MatchaStateService
from matcha_ml.templates.base_template import BaseTemplate, TemplateVariables
-SUBMODULE_NAMES = [
+DEFAULT_STACK = [
"aks",
"resource_group",
"mlflow_module",
@@ -16,8 +16,8 @@
"zen_server/zenml_helm",
"zen_server/zenml_helm/templates",
"data_version_control_storage",
- "chroma",
]
+LLM_STACK = ["chroma"]
class AzureTemplate(BaseTemplate):
@@ -27,13 +27,13 @@ class AzureTemplate(BaseTemplate):
BaseTemplate: The base template class.
"""
- def __init__(self) -> None:
+ def __init__(self, submodule_names: List[str]) -> None:
"""Initialize the StateStorageTemplate with the submodule names.
Args:
submodule_names (List[str]): A list of submodule names.
"""
- super().__init__(SUBMODULE_NAMES)
+ super().__init__(submodule_names)
def build_template(
self,
From fdab96f00fce5f1d90f090c31171a4424306958e Mon Sep 17 00:00:00 2001
From: Callum Wells <68609181+swells2020@users.noreply.github.com>
Date: Tue, 15 Aug 2023 08:32:47 +0100
Subject: [PATCH 07/10] Revert "updates stack handling"
This reverts commit b42b31dc7d95977d1333701cbd2f9d6deaf96ee6.
---
src/matcha_ml/core/core.py | 8 ++------
src/matcha_ml/templates/azure_template.py | 10 +++++-----
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index cf47cf53..b5d5d021 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -18,7 +18,7 @@
from matcha_ml.services.global_parameters_service import GlobalParameters
from matcha_ml.state import MatchaStateService, RemoteStateManager
from matcha_ml.state.matcha_state import MatchaState
-from matcha_ml.templates.azure_template import DEFAULT_STACK, LLM_STACK, AzureTemplate
+from matcha_ml.templates.azure_template import AzureTemplate
class StackTypeMeta(
@@ -293,12 +293,8 @@ def provision(
"infrastructure",
stack_name,
)
- if stack_name == "llm":
- submodule_names = DEFAULT_STACK + LLM_STACK
- else:
- submodule_names = DEFAULT_STACK
- azure_template = AzureTemplate(submodule_names)
+ azure_template = AzureTemplate()
zenml_version = infer_zenml_version()
config = azure_template.build_template_configuration(
diff --git a/src/matcha_ml/templates/azure_template.py b/src/matcha_ml/templates/azure_template.py
index a36affe7..10688077 100644
--- a/src/matcha_ml/templates/azure_template.py
+++ b/src/matcha_ml/templates/azure_template.py
@@ -1,10 +1,10 @@
"""Build a template for provisioning resources on Azure using terraform files."""
-from typing import List, Optional
+from typing import Optional
from matcha_ml.state import MatchaState, MatchaStateService
from matcha_ml.templates.base_template import BaseTemplate, TemplateVariables
-DEFAULT_STACK = [
+SUBMODULE_NAMES = [
"aks",
"resource_group",
"mlflow_module",
@@ -16,8 +16,8 @@
"zen_server/zenml_helm",
"zen_server/zenml_helm/templates",
"data_version_control_storage",
+ "chroma",
]
-LLM_STACK = ["chroma"]
class AzureTemplate(BaseTemplate):
@@ -27,13 +27,13 @@ class AzureTemplate(BaseTemplate):
BaseTemplate: The base template class.
"""
- def __init__(self, submodule_names: List[str]) -> None:
+ def __init__(self) -> None:
"""Initialize the StateStorageTemplate with the submodule names.
Args:
submodule_names (List[str]): A list of submodule names.
"""
- super().__init__(submodule_names)
+ super().__init__(SUBMODULE_NAMES)
def build_template(
self,
From c3ec8cd0bbcf004e8c656f82acdeb5a17dadc48c Mon Sep 17 00:00:00 2001
From: Chris <32800386+Christopher-Norman@users.noreply.github.com>
Date: Tue, 15 Aug 2023 09:53:15 +0100
Subject: [PATCH 08/10] [RPD-289] Update the Chroma Terraform within the LLM
stack to use Helm #194
---
.../infrastructure/llm/chroma/README.md | 8 +-
.../llm/chroma/chroma_helm/Chart.yaml | 4 +
.../chroma_helm/templates/deployment.yaml | 29 +++++
.../llm/chroma/chroma_helm/templates/pvc.yaml | 12 +++
.../chroma/chroma_helm/templates/service.yaml | 18 ++++
.../llm/chroma/chroma_helm/values.yaml | 18 ++++
.../infrastructure/llm/chroma/main.tf | 102 +-----------------
src/matcha_ml/templates/azure_template.py | 2 +
8 files changed, 92 insertions(+), 101 deletions(-)
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/chroma_helm/Chart.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/deployment.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/pvc.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/service.yaml
create mode 100644 src/matcha_ml/infrastructure/llm/chroma/chroma_helm/values.yaml
diff --git a/src/matcha_ml/infrastructure/llm/chroma/README.md b/src/matcha_ml/infrastructure/llm/chroma/README.md
index 2a8396f1..52f1fcc3 100644
--- a/src/matcha_ml/infrastructure/llm/chroma/README.md
+++ b/src/matcha_ml/infrastructure/llm/chroma/README.md
@@ -1,3 +1,4 @@
+
## Requirements
No requirements.
@@ -6,7 +7,7 @@ No requirements.
| Name | Version |
|------|---------|
-| [kubernetes](#provider\_kubernetes) | n/a |
+| [helm](#provider\_helm) | n/a |
## Modules
@@ -16,9 +17,7 @@ No modules.
| Name | Type |
|------|------|
-| [kubernetes_deployment.chroma-server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
-| [kubernetes_persistent_volume_claim.pvc](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
-| [kubernetes_service.chroma-service](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
+| [helm_release.chroma](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
## Inputs
@@ -27,3 +26,4 @@ No inputs.
## Outputs
No outputs.
+
diff --git a/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/Chart.yaml b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/Chart.yaml
new file mode 100644
index 00000000..3932fbba
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/Chart.yaml
@@ -0,0 +1,4 @@
+apiVersion: v2
+name: chroma
+description: Chroma Server Helm Chart
+version: 0.1.0
diff --git a/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/deployment.yaml b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/deployment.yaml
new file mode 100644
index 00000000..fedc6444
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/deployment.yaml
@@ -0,0 +1,29 @@
+# templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .Release.Name }}-server
+spec:
+ selector:
+ matchLabels:
+ app: {{ .Release.Name }}-server
+ template:
+ metadata:
+ labels:
+ app: {{ .Release.Name }}-server
+ spec:
+ containers:
+ - name: {{ .Release.Name }}-server
+ image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+ ports:
+ - containerPort: 8000
+ resources:
+{{ toYaml .Values.resources | indent 12 }}
+ volumeMounts:
+ - mountPath: /index_data
+ name: {{ .Release.Name }}-server-index
+ restartPolicy: Always
+ volumes:
+ - name: {{ .Release.Name }}-server-index
+ persistentVolumeClaim:
+ claimName: {{ .Release.Name }}-server-index
diff --git a/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/pvc.yaml b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/pvc.yaml
new file mode 100644
index 00000000..56d3b0fe
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/pvc.yaml
@@ -0,0 +1,12 @@
+# templates/pvc.yaml
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ .Release.Name }}-server-index
+spec:
+ accessModes:
+ - ReadWriteOnce
+ storageClassName: {{ .Values.pvc.storageClassName }}
+ resources:
+ requests:
+ storage: {{ .Values.pvc.requestsStorage }}
diff --git a/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/service.yaml b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/service.yaml
new file mode 100644
index 00000000..9ce103d6
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/templates/service.yaml
@@ -0,0 +1,18 @@
+# templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Release.Name }}-service
+spec:
+ selector:
+ app: {{ .Release.Name }}-server
+ ports:
+ - name: "8123"
+ port: 8123
+ targetPort: 8123
+ - name: "9000"
+ port: 9000
+ targetPort: 9000
+ - name: "8000"
+ port: 8000
+ targetPort: 8000
diff --git a/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/values.yaml b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/values.yaml
new file mode 100644
index 00000000..c38d484a
--- /dev/null
+++ b/src/matcha_ml/infrastructure/llm/chroma/chroma_helm/values.yaml
@@ -0,0 +1,18 @@
+# values.yaml
+image:
+ repository: ghcr.io/chroma-core/chroma
+ tag: 0.4.3
+
+resources:
+ requests:
+ memory: "256Mi"
+ cpu: "256m"
+ limits:
+ memory: "2Gi"
+ cpu: "2"
+
+pvc:
+ accessModes:
+ - ReadWriteOnce
+ storageClassName: default
+ requestsStorage: "100Mi"
diff --git a/src/matcha_ml/infrastructure/llm/chroma/main.tf b/src/matcha_ml/infrastructure/llm/chroma/main.tf
index 9d5f3d37..d91003fb 100644
--- a/src/matcha_ml/infrastructure/llm/chroma/main.tf
+++ b/src/matcha_ml/infrastructure/llm/chroma/main.tf
@@ -1,99 +1,7 @@
-resource "kubernetes_deployment" "chroma-server" {
- metadata {
- name = "chroma-server"
- }
+resource "helm_release" "chroma" {
+ name = "chroma"
+ chart = "${path.module}/chroma_helm"
+ namespace = "default"
- spec {
- selector {
- match_labels = {
- app = "chroma-server"
- }
- }
-
- template {
- metadata {
- labels = {
- app = "chroma-server"
- }
- }
-
- spec {
- container {
- name = "chroma-server"
- image = "ghcr.io/chroma-core/chroma:0.4.3"
- port {
- container_port = 8000
- }
- resources {
- requests = {
- memory = "256Mi"
- cpu = "256m"
- }
- limits = {
- memory = "2Gi"
- cpu = "2"
- }
- }
- volume_mount {
- mount_path = "/index_data"
- name = "chroma-server-index"
- }
- }
-
- restart_policy = "Always"
-
- volume {
- name = "chroma-server-index"
- persistent_volume_claim {
- claim_name = "chroma-server-index"
- }
- }
- }
- }
- }
-}
-
-resource "kubernetes_persistent_volume_claim" "pvc" {
- metadata {
- name = "chroma-server-index"
- }
-
- spec {
- access_modes = ["ReadWriteOnce"]
- storage_class_name = "default"
- resources {
- requests = {
- storage = "100Mi"
- }
- }
- }
-}
-
-resource "kubernetes_service" "chroma-service" {
- metadata {
- name = "chroma-service"
- }
-
- spec {
- selector = {"app": "chroma-server"}
-
- port {
- name = "8123"
- port = 8123
- target_port = 8123
- }
-
- port {
- name = "9000"
- port = 9000
- target_port = 9000
- }
-
- port {
- name = "8000"
- port = 8000
- target_port = 8000
- }
-
- }
+ values = [file("${path.module}/chroma_helm/values.yaml")]
}
diff --git a/src/matcha_ml/templates/azure_template.py b/src/matcha_ml/templates/azure_template.py
index 10688077..2fa0988b 100644
--- a/src/matcha_ml/templates/azure_template.py
+++ b/src/matcha_ml/templates/azure_template.py
@@ -17,6 +17,8 @@
"zen_server/zenml_helm/templates",
"data_version_control_storage",
"chroma",
+ "chroma/chroma_helm",
+ "chroma/chroma_helm/templates",
]
From a7809be76802cd149a5897ca4e915e202771fda6 Mon Sep 17 00:00:00 2001
From: Callum Wells <68609181+swells2020@users.noreply.github.com>
Date: Tue, 15 Aug 2023 10:32:39 +0100
Subject: [PATCH 09/10] [RPD-292] [BUG] Update AzureTemplate to not create
redundant folders during provisioning (#195)
* splits default stack
* updates llm stack
---
src/matcha_ml/core/core.py | 6 ++++--
src/matcha_ml/templates/azure_template.py | 10 ++++++----
tests/test_cli/test_provision.py | 12 ++++++------
tests/test_core/test_core_provision.py | 4 ++--
4 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index b5d5d021..254923ca 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -18,7 +18,7 @@
from matcha_ml.services.global_parameters_service import GlobalParameters
from matcha_ml.state import MatchaStateService, RemoteStateManager
from matcha_ml.state.matcha_state import MatchaState
-from matcha_ml.templates.azure_template import AzureTemplate
+from matcha_ml.templates.azure_template import DEFAULT_STACK, LLM_STACK, AzureTemplate
class StackTypeMeta(
@@ -294,7 +294,9 @@ def provision(
stack_name,
)
- azure_template = AzureTemplate()
+ azure_template = AzureTemplate(
+ LLM_STACK if stack_name == StackType.LLM.value else DEFAULT_STACK
+ )
zenml_version = infer_zenml_version()
config = azure_template.build_template_configuration(
diff --git a/src/matcha_ml/templates/azure_template.py b/src/matcha_ml/templates/azure_template.py
index 2fa0988b..f8ff3510 100644
--- a/src/matcha_ml/templates/azure_template.py
+++ b/src/matcha_ml/templates/azure_template.py
@@ -1,10 +1,10 @@
"""Build a template for provisioning resources on Azure using terraform files."""
-from typing import Optional
+from typing import List, Optional
from matcha_ml.state import MatchaState, MatchaStateService
from matcha_ml.templates.base_template import BaseTemplate, TemplateVariables
-SUBMODULE_NAMES = [
+DEFAULT_STACK = [
"aks",
"resource_group",
"mlflow_module",
@@ -16,6 +16,8 @@
"zen_server/zenml_helm",
"zen_server/zenml_helm/templates",
"data_version_control_storage",
+]
+LLM_STACK = DEFAULT_STACK + [
"chroma",
"chroma/chroma_helm",
"chroma/chroma_helm/templates",
@@ -29,13 +31,13 @@ class AzureTemplate(BaseTemplate):
BaseTemplate: The base template class.
"""
- def __init__(self) -> None:
+ def __init__(self, submodule_names: List[str]) -> None:
"""Initialize the StateStorageTemplate with the submodule names.
Args:
submodule_names (List[str]): A list of submodule names.
"""
- super().__init__(SUBMODULE_NAMES)
+ super().__init__(submodule_names)
def build_template(
self,
diff --git a/tests/test_cli/test_provision.py b/tests/test_cli/test_provision.py
index c5313d51..de912e78 100644
--- a/tests/test_cli/test_provision.py
+++ b/tests/test_cli/test_provision.py
@@ -9,7 +9,7 @@
from typer.testing import CliRunner
from matcha_ml.cli.cli import app
-from matcha_ml.templates.azure_template import SUBMODULE_NAMES
+from matcha_ml.templates.azure_template import DEFAULT_STACK
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TEMPLATE_DIR = os.path.join(
@@ -66,7 +66,7 @@ def assert_infrastructure(
module_file_path = os.path.join(destination_path, module_file_name)
assert os.path.exists(module_file_path)
- for module_name in SUBMODULE_NAMES:
+ for module_name in DEFAULT_STACK:
for module_file_name in glob.glob(
os.path.join(TEMPLATE_DIR, module_name, "*.tf")
):
@@ -143,7 +143,7 @@ def test_cli_provision_command(
"location": "uksouth",
"prefix": "matcha",
"password": "default",
- "zenmlserver_version": "latest"
+ "zenmlserver_version": "latest",
}
assert_infrastructure(
@@ -200,7 +200,7 @@ def test_cli_provision_command_with_args(
"location": "uksouth",
"prefix": "matcha",
"password": "ninja",
- "zenmlserver_version": "latest"
+ "zenmlserver_version": "latest",
}
assert_infrastructure(
@@ -247,7 +247,7 @@ def test_cli_provision_command_with_prefix(
"location": "uksouth",
"prefix": "coffee",
"password": "default",
- "zenmlserver_version": "latest"
+ "zenmlserver_version": "latest",
}
assert_infrastructure(
@@ -292,7 +292,7 @@ def test_cli_provision_command_with_default_prefix(
"location": "uksouth",
"prefix": "matcha",
"password": "default",
- "zenmlserver_version": "latest"
+ "zenmlserver_version": "latest",
}
assert_infrastructure(
diff --git a/tests/test_core/test_core_provision.py b/tests/test_core/test_core_provision.py
index 90a42c3a..a6368e83 100644
--- a/tests/test_core/test_core_provision.py
+++ b/tests/test_core/test_core_provision.py
@@ -18,7 +18,7 @@
from matcha_ml.state.matcha_state import (
MatchaState,
)
-from matcha_ml.templates.azure_template import SUBMODULE_NAMES
+from matcha_ml.templates.azure_template import DEFAULT_STACK
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -149,7 +149,7 @@ def assert_infrastructure(
module_file_path = os.path.join(destination_path, module_file_name)
assert os.path.exists(module_file_path)
- for module_name in SUBMODULE_NAMES:
+ for module_name in DEFAULT_STACK:
for module_file_name in glob.glob(
os.path.join(TEMPLATE_DIR, module_name, "*.tf")
):
From 12dcd553809c46bd299829b90d28ea0994769aca Mon Sep 17 00:00:00 2001
From: Jonathan Carlton
Date: Tue, 15 Aug 2023 10:43:05 +0100
Subject: [PATCH 10/10] [RPD-303] Update stack_set docstring to include example
and raises (#196)
---
src/matcha_ml/core/core.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/matcha_ml/core/core.py b/src/matcha_ml/core/core.py
index 254923ca..591ad5e5 100644
--- a/src/matcha_ml/core/core.py
+++ b/src/matcha_ml/core/core.py
@@ -317,8 +317,17 @@ def provision(
def stack_set(stack_name: str) -> None:
"""A function for updating the stack type in the local matcha.config.json file.
+ Note: This cannot be run once there are provisioned resources.
+
+ Examples:
+ >>> stack_set(stack_name='default')
+
Args:
stack_name (str): the name of the type of stack to be specified in the config file.
+
+ Raises:
+ MatchaInputError: if the stack_name is not a valid stack type
+ MatchaError: if there are already resources provisioned.
"""
if RemoteStateManager().is_state_provisioned():
raise MatchaError(