From 4efd5b82b52d760c9ee84b4cd2e3e525b677f88c Mon Sep 17 00:00:00 2001 From: Collin Dutter Date: Fri, 12 Apr 2024 13:39:31 -0700 Subject: [PATCH 1/2] Restructure project, remove old code --- griptape/cli/commands/app.py | 95 ----- griptape/cli/commands/cloud.py | 376 ------------------ griptape/cli/core/app.py | 49 --- griptape/cli/core/app_packager.py | 74 ---- griptape/cli/core/cloud_client.py | 204 ---------- griptape/cli/core/structure_runner.py | 51 --- .../cli/core/templates/app/cookiecutter.json | 6 - .../templates/app/hooks/post_gen_project.py | 15 - .../templates/app/hooks/pre_gen_project.py | 0 .../app/{{cookiecutter.app_name}}/.gitignore | 5 - .../app/{{cookiecutter.app_name}}/README.md | 1 - .../app/{{cookiecutter.app_name}}/app.py | 8 - .../{{cookiecutter.app_name}}/pyproject.toml | 15 - .../requirements.txt | 2 - .../tests/__init__.py | 0 griptape/cli/core/utils/__init__.py | 0 griptape/cli/core/utils/constants.py | 3 - griptape/cli/core/utils/endpoint_utils.py | 8 - griptape/cli/main.py | 16 - {griptape => griptapecli}/__init__.py | 0 .../cli => griptapecli/commands}/__init__.py | 0 .../cli => griptapecli}/commands/server.py | 4 +- .../commands => griptapecli/core}/__init__.py | 0 {griptape/cli => griptapecli}/core/models.py | 0 {griptape/cli => griptapecli}/core/server.py | 0 {griptape/cli => griptapecli}/core/state.py | 0 griptapecli/main.py | 12 + poetry.lock | 163 +------- pyproject.toml | 7 +- {griptape/cli => tests/unit}/core/__init__.py | 0 tests/unit/core/test_app_packager.py | 36 -- tests/unit/core/test_structure_runner.py | 44 -- 32 files changed, 17 insertions(+), 1177 deletions(-) delete mode 100644 griptape/cli/commands/app.py delete mode 100644 griptape/cli/commands/cloud.py delete mode 100644 griptape/cli/core/app.py delete mode 100644 griptape/cli/core/app_packager.py delete mode 100644 griptape/cli/core/cloud_client.py delete mode 100644 griptape/cli/core/structure_runner.py delete mode 100644 griptape/cli/core/templates/app/cookiecutter.json delete mode 100644 griptape/cli/core/templates/app/hooks/post_gen_project.py delete mode 100644 griptape/cli/core/templates/app/hooks/pre_gen_project.py delete mode 100644 griptape/cli/core/templates/app/{{cookiecutter.app_name}}/.gitignore delete mode 100644 griptape/cli/core/templates/app/{{cookiecutter.app_name}}/README.md delete mode 100644 griptape/cli/core/templates/app/{{cookiecutter.app_name}}/app.py delete mode 100644 griptape/cli/core/templates/app/{{cookiecutter.app_name}}/pyproject.toml delete mode 100644 griptape/cli/core/templates/app/{{cookiecutter.app_name}}/requirements.txt delete mode 100644 griptape/cli/core/templates/app/{{cookiecutter.app_name}}/tests/__init__.py delete mode 100644 griptape/cli/core/utils/__init__.py delete mode 100644 griptape/cli/core/utils/constants.py delete mode 100644 griptape/cli/core/utils/endpoint_utils.py delete mode 100644 griptape/cli/main.py rename {griptape => griptapecli}/__init__.py (100%) rename {griptape/cli => griptapecli/commands}/__init__.py (100%) rename {griptape/cli => griptapecli}/commands/server.py (97%) rename {griptape/cli/commands => griptapecli/core}/__init__.py (100%) rename {griptape/cli => griptapecli}/core/models.py (100%) rename {griptape/cli => griptapecli}/core/server.py (100%) rename {griptape/cli => griptapecli}/core/state.py (100%) create mode 100644 griptapecli/main.py rename {griptape/cli => tests/unit}/core/__init__.py (100%) delete mode 100644 tests/unit/core/test_app_packager.py delete mode 100644 tests/unit/core/test_structure_runner.py diff --git a/griptape/cli/commands/app.py b/griptape/cli/commands/app.py deleted file mode 100644 index 43c03be..0000000 --- a/griptape/cli/commands/app.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import click -from click import echo -from griptape.artifacts import TextArtifact -from griptape.cli.core.app import App -from griptape.cli.core.structure_runner import StructureRunner - - -@click.group() -@click.pass_context -def app(ctx): - pass - - -@app.command(name="new") -@click.argument( - "name", - type=str, - required=True, -) -@click.option( - "--package_manager", - "-p", - type=click.Choice(["pip"]), - help="Package manager to use for Griptape app.", - default="pip", - show_default=True, -) -@click.option( - "--directory", - "-d", - type=str, - help="Directory to create a new app in.", - default=".", - show_default=True, -) -@click.option( - "--griptape-version", - "-g", - type=str, - help="Version of griptape to use for the app.", - required=False, -) -def new(name: str, package_manager: str, directory: str, griptape_version: str) -> None: - """ - Create a new Griptape app. - """ - - echo(f"Initializing app {name}") - - App( - name=name, package_manager=package_manager, griptape_version=griptape_version - ).generate(directory) - - -@app.command(name="run") -@click.option( - "--arg", - "-a", - multiple=True, - type=str, - help="Argument to pass to the structure run method (Accepts multiple)", - required=False, -) -@click.option( - "--init-param", - "-i", - "init_params", - type=(str, str), - multiple=True, - help="Initialization parameters for the app in the format 'key value'.", - required=False, -) -@click.option( - "--directory", - "-d", - type=str, - help="Directory where app resides. Defaults to current directory.", - default=os.getcwd(), - show_default=True, -) -def run( - arg: list[str], init_params: list[tuple[str, str]], directory: str -) -> TextArtifact: - """ - Run a Griptape app. - """ - - echo(f"Running app") - params = {k: v for k, v in init_params} - - structure_runner = StructureRunner( - args=arg, init_params=params, app_directory=directory - ) - structure_runner.run() diff --git a/griptape/cli/commands/cloud.py b/griptape/cli/commands/cloud.py deleted file mode 100644 index d48a4fa..0000000 --- a/griptape/cli/commands/cloud.py +++ /dev/null @@ -1,376 +0,0 @@ -import os -from typing import Optional -import click -from click import echo, style -from griptape.cli.core.app_packager import AppPackager -from griptape.cli.core.cloud_client import CloudClient -from griptape.cli.core.utils.constants import DEFAULT_ENDPOINT_URL -from griptape.cli.core.utils.endpoint_utils import is_valid_endpoint -from InquirerPy import inquirer - - -@click.group() -@click.pass_context -def cloud(ctx): - pass - - -@cloud.command(name="configure") -def configure() -> None: - try: - api_key = inquirer.text("Enter your Griptape Cloud API key: ").execute() - - endpoint_choices = [DEFAULT_ENDPOINT_URL, "Other"] - endpoint_url = inquirer.select( - message="Select the endpoint you want to use: ", - choices=endpoint_choices, - ).execute() - if endpoint_url == "Other": - valid_endpoint = False - while not valid_endpoint: - endpoint_url = inquirer.text( - message="Enter the endpoint you want to use: ", - default=DEFAULT_ENDPOINT_URL, - ).execute() - if is_valid_endpoint(endpoint_url): - valid_endpoint = True - else: - echo( - f"Invalid endpoint url detected: {endpoint_url}. \nPlease set a valid endpoint url with the format: https://api.cloud<-stage>.griptape.ai." - ) - - counter = 0 - cloud_client = CloudClient(api_key=api_key, endpoint_url=endpoint_url) - organizations = cloud_client.list_organizations().json()["organizations"] - - org_choices = [ - f"{counter+1}). {org['name']}: {org['organization_id']}" - for org in organizations - ] - org_choice = inquirer.select( - message="Select the organization you want to use:", - choices=org_choices, - ).execute() - - org = organizations[org_choices.index(org_choice)] - - environments = cloud_client.list_environments( - organization_id=org["organization_id"] - ).json()["environments"] - - counter = 0 - environment_choices = [ - f"{counter+1}). {env['name']}: {env['environment_id']}" - for env in environments - ] - - env_choice = inquirer.select( - message="Select the environment you want to use:", - choices=environment_choices, - ).execute() - - env = environments[environment_choices.index(env_choice)] - - profile_name = click.prompt( - "Enter a name for this profile", - type=str, - show_default=True, - default="default", - ) - - cloud_client._write_gt_cloud_profile( - profile_name=profile_name, - api_key=api_key, - organization_id=org["organization_id"], - environment_id=env["environment_id"], - endpoint_url=endpoint_url, - ) - - echo(f"Successfully configured profile {profile_name}!") - - except Exception as e: - echo(f"{e}") - - -@cloud.command(name="list-organizations") -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def list_organizations(profile: str): - """ - List Griptape Cloud Organizations. - """ - - cloud_client = CloudClient(profile=profile) - response = cloud_client.list_organizations() - echo(response.json()) - - -@cloud.command(name="list-environments") -@click.option( - "--organization-id", - type=str, - required=False, - help="Organization ID to list environments for", -) -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def list_environments(organization_id: str, profile: str): - """ - List Griptape Cloud Environments. - """ - - cloud_client = CloudClient(profile=profile) - response = cloud_client.list_environments(organization_id=organization_id) - echo(response.json()) - - -@cloud.command(name="list-apps") -@click.option( - "--environment-id", - type=str, - required=False, - help="Environment ID to list apps for", -) -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def list_apps(environment_id: str, profile: str): - """ - List Griptape Cloud Apps. - """ - - cloud_client = CloudClient(profile=profile) - response = cloud_client.list_apps(environment_id=environment_id) - echo(response.json()) - - -@cloud.command(name="create-app") -@click.option( - "--name", - "-n", - type=str, - help="Griptape Cloud app name", - required=True, -) -@click.option( - "--environment-id", - type=str, - help="Griptape Cloud environment id", - default=None, - required=False, -) -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def create_app( - name: str, environment_id: Optional[str], profile: Optional[str] -) -> None: - """ - Create a Griptape App on the Griptape Cloud. - """ - app_data = { - "name": name, - } - cloud_client = CloudClient(profile=profile) - response = cloud_client.create_app(app_data=app_data, environment_id=environment_id) - echo(response.json()) - - -@cloud.command(name="create-deployment") -@click.option( - "--app-id", - type=str, - help="Griptape Cloud app id", - required=True, -) -@click.option( - "--directory", - "-d", - type=str, - help="Directory where app resides. Defaults to current directory.", - default=os.getcwd(), - show_default=True, -) -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def create_deployment(app_id: str, directory: str, profile: str) -> None: - """ - Deploy a Griptape App to Griptape Cloud. - """ - - cloud_client = CloudClient(profile=profile) - - app_packager = AppPackager( - app_directory=directory, - ) - source = app_packager.get_deployment_source() - - deployment_data = {"source": {"zip_file": {"base64_content": source}}} - - try: - response = cloud_client.create_deployment( - deployment_data=deployment_data, app_id=app_id - ) - echo(response.json()) - except Exception as e: - echo(f"Unable to create deployment: {e}", err=True) - raise e - - -@cloud.command(name="run") -@click.option( - "--app-id", - type=str, - help="Griptape Cloud app id", - required=True, -) -@click.option( - "--deployment-id", - type=str, - help="The targeted deployment id of the app to run", - default=None, - required=False, -) -@click.option( - "--session-id", - type=str, - help="The targeted session id of the app to run", - default=None, - required=False, -) -@click.option( - "--arg", - "-a", - "args", - multiple=True, - type=str, - help="Argument to pass to the structure run method (Accepts multiple)", - required=False, -) -@click.option( - "--init-param", - "-i", - "init_params", - type=(str, str), - multiple=True, - help="Initialization parameter for the app in the format 'key value' (Accepts multiple)", - required=False, -) -@click.option( - "--no-polling", - default=False, - is_flag=True, - type=bool, - help="Disable polling for the run and events", - required=False, - show_default=True, -) -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def run( - app_id: str, - deployment_id: str, - session_id: str, - args: list[str], - init_params: list[tuple[str, str]], - no_polling: bool, - profile: str, -) -> None: - """ - Run a Griptape App on the Cloud. - """ - - cloud_client = CloudClient(profile=profile) - - run_data = {} - - if args: - run_data["args"] = list(args) - if deployment_id: - run_data["deployment_id"] = deployment_id - if session_id: - run_data["session_id"] = session_id - if init_params: - run_data["init_params"] = {k: v for k, v in init_params} - - try: - response = cloud_client.create_run(run_data=run_data, app_id=app_id) - echo(style(response.json(), fg="cyan")) - except Exception as e: - echo(f"Unable to create run: {e}", err=True) - raise e - - if not no_polling: - try: - echo("\nPolling run and events...\n") - cloud_client.poll_run(run_id=response.json()["run_id"]) - except Exception as e: - echo(f"Unable to poll run: {e}", err=True) - raise e - - -@cloud.command(name="get-run") -@click.option( - "--run-id", - type=str, - help="Griptape Cloud run id", - required=True, -) -@click.option( - "--profile", - "-p", - type=str, - help="Griptape Cloud profile name", - default=None, - required=False, -) -def get_run( - run_id: str, - profile: str, -) -> None: - """ - Get a Griptape Run on the Cloud. - """ - - cloud_client = CloudClient(profile=profile) - - try: - response = cloud_client.get_run(run_id=run_id) - echo(response.json()) - except Exception as e: - echo(f"Unable to get run: {e}", err=True) - raise e diff --git a/griptape/cli/core/app.py b/griptape/cli/core/app.py deleted file mode 100644 index 10909c2..0000000 --- a/griptape/cli/core/app.py +++ /dev/null @@ -1,49 +0,0 @@ -import os -from typing import Optional -import stringcase -from attr import define, field -from cookiecutter.main import cookiecutter - -from griptape.cli.core.utils.constants import GRIPTAPE_VERSION - - -@define -class App: - DEFAULT_TEMPLATE_PATH = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "templates", "app" - ) - - name: str = field(kw_only=True) - package_manager: str = field(kw_only=True) - template_path: Optional[str] = field(default=None, kw_only=True) - griptape_version: Optional[str] = field(default=None, kw_only=True) - - def generate(self, directory: str = ".") -> None: - template = ( - self.DEFAULT_TEMPLATE_PATH - if self.template_path is None - else self.template_path - ) - - if not self.griptape_version: - if self.package_manager == "pip": - self.griptape_version = f">={GRIPTAPE_VERSION}" - else: - self.griptape_version = f'"^{GRIPTAPE_VERSION}"' - else: - if self.package_manager == "pip": - self.griptape_version = f"=={self.griptape_version}" - else: - self.griptape_version = f'"{self.griptape_version}"' - - cookiecutter( - template, - no_input=True, - output_dir=directory, - extra_context={ - "app_name": self.name, - "package_name": stringcase.snakecase(self.name), - "package_manager": self.package_manager, - "griptape_version": self.griptape_version, - }, - ) diff --git a/griptape/cli/core/app_packager.py b/griptape/cli/core/app_packager.py deleted file mode 100644 index 3dfe6ab..0000000 --- a/griptape/cli/core/app_packager.py +++ /dev/null @@ -1,74 +0,0 @@ -import base64 -import os -import shutil -from typing import Optional -from attr import define, field -from datetime import datetime -from click import echo - - -@define -class AppPackager: - app_directory: str = field(kw_only=True) - - def __attrs_post_init__(self): - self.app_directory = os.path.abspath(self.app_directory) - - @app_directory.validator - def validate_app_directory(self, _, app_directory: str) -> None: - if not os.path.exists(app_directory) or not os.path.exists( - os.path.join(app_directory, "app.py") - ): - raise ValueError(f"App doesn't exist in directory: {app_directory}") - - def get_deployment_source(self) -> str: - tmp_dir = zip_file = None - - try: - tmp_dir = self._create_deployment_tmp_dir() - zip_file = self._create_deployment_zip_file(tmp_dir) - return self._get_deployment_source(zip_file) - except Exception as e: - echo(f"Unable to create deployment contents: {e}", err=True) - raise e - finally: - self._clean_up_deployment_artifacts(tmp_dir, zip_file) - - def _create_deployment_tmp_dir(self) -> str: - # Copy to new dir to ignore certain patterns - ignore_patterns = [] - if os.path.exists(os.path.join(self.app_directory, ".gitignore")): - with open(os.path.join(self.app_directory, ".gitignore"), "r") as file: - for line in file.readlines(): - if line.endswith("\n"): - line = line[:-1] - ignore_patterns.append(line.strip()) - return shutil.copytree( - self.app_directory, - os.path.join( - self.app_directory, f"zip_tmp_{str(datetime.now().timestamp())}" - ), - ignore=shutil.ignore_patterns(*ignore_patterns), - ) - - def _create_deployment_zip_file(self, tmp_dir: str) -> str: - dir = os.getcwd() - os.chdir(tmp_dir) - zip = shutil.make_archive("artifact", "zip", tmp_dir) - os.chdir(dir) - return os.path.join(tmp_dir, "artifact.zip") - - def _get_deployment_source(self, zip_file: str) -> str: - with open(zip_file, "rb") as file: - file_data = file.read() - - source = base64.b64encode(file_data).decode("utf-8") - return source - - def _clean_up_deployment_artifacts( - self, tmp_dir: Optional[str], zip_file: Optional[str] - ) -> None: - if tmp_dir and os.path.exists(tmp_dir): - shutil.rmtree(tmp_dir) - if zip_file and os.path.exists(zip_file): - os.remove(zip_file) diff --git a/griptape/cli/core/cloud_client.py b/griptape/cli/core/cloud_client.py deleted file mode 100644 index 9724d4d..0000000 --- a/griptape/cli/core/cloud_client.py +++ /dev/null @@ -1,204 +0,0 @@ -import json -import os -import stat -import time -from typing import Optional -from click import echo, style -import requests -from requests import Response -from requests.compat import urljoin -from attr import Factory, define, field - - -@define -class CloudClient: - api_key: Optional[str] = field(kw_only=True, default=None) - endpoint_url: Optional[str] = field(kw_only=True, default=None) - profile: str = field(kw_only=True, default="default") - profile_data: Optional[dict] = field( - kw_only=True, default=Factory(lambda: CloudClient._init_profile_data()) - ) - - def __attrs_post_init__(self): - if not self.profile: - self.profile = "default" - if not self.api_key: - try: - self.api_key = self.profile_data[self.profile]["api_key"] - except Exception: - echo("Unable to determine API key! Try running 'gt cloud configure'") - exit(1) - if not self.endpoint_url: - try: - self.endpoint_url = self.profile_data[self.profile]["endpoint_url"] - except Exception: - echo( - "Unable to determine endpoint URL! Try running 'gt cloud configure'" - ) - exit(1) - - @classmethod - def _init_profile_data(cls) -> dict: - try: - data = cls._extract_profile_data_from_local_storage() - return data - except Exception: - return {} - - @classmethod - def _get_profile_path(cls) -> str: - return os.path.expanduser("~/.gtcloud") - - @classmethod - def _does_profiles_file_exist(cls) -> bool: - return os.path.exists(cls._get_profile_path()) - - @classmethod - def _extract_profile_data_from_local_storage(cls) -> any: - path = cls._get_profile_path() - - with open(path, "r") as file: - data = file.read() - return json.loads(data) - - @staticmethod - def _write_gt_cloud_profile( - profile_name: str, - api_key: str, - organization_id: str, - environment_id: str, - endpoint_url: str, - ) -> None: - path = CloudClient._get_profile_path() - - if CloudClient._does_profiles_file_exist(): - data = CloudClient._extract_profile_data_from_local_storage() - data[f"{profile_name}"] = { - "api_key": api_key, - "endpoint_url": endpoint_url, - "organization_id": organization_id, - "environment_id": environment_id, - } - else: - data = { - f"{profile_name}": { - "api_key": api_key, - "endpoint_url": endpoint_url, - "organization_id": organization_id, - "environment_id": environment_id, - } - } - - with open(path, "w+") as file: - file.write(json.dumps(data)) - os.chmod(CloudClient._get_profile_path(), stat.S_IRUSR | stat.S_IWUSR) - - def _get_authorization_headers(self) -> dict: - return {"Authorization": f"{self.api_key}"} - - def _send_request( - self, method: str, url: str, data: Optional[dict] = None - ) -> Response: - response = None - - if method == "GET": - response = requests.get(url=url, headers=self._get_authorization_headers()) - elif method == "POST": - response = requests.post( - url=url, json=data, headers=self._get_authorization_headers() - ) - elif method == "PUT": - response = requests.put( - url=url, json=data, headers=self._get_authorization_headers() - ) - elif method == "DELETE": - response = requests.delete( - url=url, headers=self._get_authorization_headers() - ) - else: - raise Exception("Invalid method") - - try: - response.raise_for_status() - except Exception as e: - echo(response.json()) - exit(1) - return response - - def list_organizations(self) -> Response: - url = urljoin(self.endpoint_url, "organizations/") - return self._send_request("GET", url) - - def list_environments(self, organization_id: Optional[str]) -> Response: - if not organization_id: - try: - organization_id = self.profile_data[self.profile]["organization_id"] - except Exception: - echo("Organization ID is required") - exit(1) - url = urljoin( - self.endpoint_url, f"organizations/{organization_id}/environments" - ) - return self._send_request("GET", url) - - def list_apps(self, environment_id: str) -> Response: - if not environment_id: - try: - environment_id = self.profile_data[self.profile]["environment_id"] - except Exception: - echo("Environment ID is required") - exit(1) - - url = urljoin(self.endpoint_url, f"environments/{environment_id}/apps") - return self._send_request("GET", url) - - def list_events(self, run_id: str) -> Response: - url = urljoin(self.endpoint_url, f"runs/{run_id}/events") - return self._send_request("GET", url) - - def create_app(self, app_data: dict, environment_id: Optional[str]) -> Response: - if not environment_id: - try: - environment_id = self.profile_data[self.profile]["environment_id"] - except Exception: - echo("Environment ID is required") - exit(1) - - url = urljoin(self.endpoint_url, f"environments/{environment_id}/apps") - return self._send_request("POST", url, app_data) - - def create_deployment(self, deployment_data: dict, app_id: str) -> Response: - url = urljoin(self.endpoint_url, f"apps/{app_id}/deployments") - return self._send_request("POST", url, deployment_data) - - def create_run(self, run_data: dict, app_id: str) -> Response: - url = urljoin(self.endpoint_url, f"apps/{app_id}/runs") - return self._send_request("POST", url, run_data) - - def get_run(self, run_id: str) -> Response: - url = urljoin(self.endpoint_url, f"runs/{run_id}") - return self._send_request("GET", url) - - def poll_run(self, run_id: str) -> None: - """ - Poll a Griptape App Run on the Cloud. - """ - - run = self.get_run(run_id).json() - event_ids = set() - while run["status"] not in ["SUCCEEDED", "FAILED"]: - events_res = self.list_events(run_id).json() - if "events" in events_res and len(events_res["events"]) > 0: - events: [] = events_res["events"] - for event in list(reversed(events)): - if event["event_id"] not in event_ids: - echo(style(event, fg="blue")) - echo("\n") - event_ids.add(event["event_id"]) - run = self.get_run(run_id).json() - time.sleep(2) - - if run["status"] == "FAILED": - echo(style(run["errors"], fg="red")) - else: - echo(style(run["output"], fg="green")) diff --git a/griptape/cli/core/structure_runner.py b/griptape/cli/core/structure_runner.py deleted file mode 100644 index cc455e0..0000000 --- a/griptape/cli/core/structure_runner.py +++ /dev/null @@ -1,51 +0,0 @@ -import os -import subprocess -import sys -from typing import Optional - -from attr import Factory, define, field - - -@define -class StructureRunner: - args: list[str] = field(kw_only=True) - init_params: Optional[dict[str, str]] = field( - kw_only=True, default=Factory(lambda: dict()) - ) - app_directory: Optional[str] = field( - kw_only=True, default=Factory(lambda: os.getcwd()) - ) - - def __attrs_post_init__(self): - self.app_directory = os.path.abspath(self.app_directory) - - def run(self): - try: - os.chdir(self.app_directory) - sys.path.append(self.app_directory) - if not self._install_pip_dependencies(): - self._install_poetry_dependencies() - from app import init_structure - - try: - return init_structure(*self.args, **self.init_params).run(*self.args) - except Exception as e: - raise Exception(f"Error running app: {e}") - except Exception as e: - raise Exception(f"Error importing app: {e}") - - def _install_pip_dependencies(self) -> bool: - requirements_path = os.path.join(self.app_directory, "requirements.txt") - if os.path.exists(requirements_path): - subprocess.check_call( - [sys.executable, "-m", "pip", "install", "-r", requirements_path] - ) - return True - return False - - def _install_poetry_dependencies(self) -> None: - pyproject_path = os.path.join(self.app_directory, "pyproject.toml") - if os.path.exists(pyproject_path): - subprocess.check_call( - ["poetry", "install", "--directory", self.app_directory] - ) diff --git a/griptape/cli/core/templates/app/cookiecutter.json b/griptape/cli/core/templates/app/cookiecutter.json deleted file mode 100644 index 3e81daf..0000000 --- a/griptape/cli/core/templates/app/cookiecutter.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "app_name": "griptape-app", - "package_name": "griptape_app", - "package_manager": "pip", - "griptape_version": "0.21.1" -} diff --git a/griptape/cli/core/templates/app/hooks/post_gen_project.py b/griptape/cli/core/templates/app/hooks/post_gen_project.py deleted file mode 100644 index e72b492..0000000 --- a/griptape/cli/core/templates/app/hooks/post_gen_project.py +++ /dev/null @@ -1,15 +0,0 @@ -import os - -REMOVE_PATHS = [ - '{% if cookiecutter.package_manager != "pip" %}requirements.txt{% endif %}', - '{% if cookiecutter.package_manager != "poetry" %}pyproject.toml{% endif %}', -] - -for path in REMOVE_PATHS: - path = path.strip() - - if path and os.path.exists(path): - if os.path.isdir(path): - os.rmdir(path) - else: - os.unlink(path) diff --git a/griptape/cli/core/templates/app/hooks/pre_gen_project.py b/griptape/cli/core/templates/app/hooks/pre_gen_project.py deleted file mode 100644 index e69de29..0000000 diff --git a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/.gitignore b/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/.gitignore deleted file mode 100644 index ef382b2..0000000 --- a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -venv* -.venv* -__pycache__* -*.pyc -.idea diff --git a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/README.md b/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/README.md deleted file mode 100644 index ea32ac2..0000000 --- a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/README.md +++ /dev/null @@ -1 +0,0 @@ -# {{cookiecutter.app_name}} \ No newline at end of file diff --git a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/app.py b/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/app.py deleted file mode 100644 index bde241c..0000000 --- a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/app.py +++ /dev/null @@ -1,8 +0,0 @@ -from dotenv import load_dotenv -from griptape.structures import Agent, Structure - -load_dotenv() - - -def init_structure(*args, **init_params) -> Structure: - return Agent() diff --git a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/pyproject.toml b/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/pyproject.toml deleted file mode 100644 index 18086cb..0000000 --- a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/pyproject.toml +++ /dev/null @@ -1,15 +0,0 @@ -[tool.poetry] -name = "{{cookiecutter.package_name}}" -version = "0.1.0" -description = "" -authors = [] -readme = "README.md" - -[tool.poetry.dependencies] -python = ">=3.9,<3.12" -griptape = {{cookiecutter.griptape_version}} -python-dotenv = "*" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" diff --git a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/requirements.txt b/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/requirements.txt deleted file mode 100644 index fd1641a..0000000 --- a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -griptape{{cookiecutter.griptape_version}} -python-dotenv \ No newline at end of file diff --git a/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/tests/__init__.py b/griptape/cli/core/templates/app/{{cookiecutter.app_name}}/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/griptape/cli/core/utils/__init__.py b/griptape/cli/core/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/griptape/cli/core/utils/constants.py b/griptape/cli/core/utils/constants.py deleted file mode 100644 index f4fd572..0000000 --- a/griptape/cli/core/utils/constants.py +++ /dev/null @@ -1,3 +0,0 @@ -DEFAULT_ENDPOINT_URL = "https://api.cloud-preview.griptape.ai" - -GRIPTAPE_VERSION = "0.21.1" diff --git a/griptape/cli/core/utils/endpoint_utils.py b/griptape/cli/core/utils/endpoint_utils.py deleted file mode 100644 index b54cb06..0000000 --- a/griptape/cli/core/utils/endpoint_utils.py +++ /dev/null @@ -1,8 +0,0 @@ -import re - - -def is_valid_endpoint(endpoint: str) -> bool: - if re.match(r"^^https:\/\/api\.cloud(?:\-.*)?\.griptape\.ai$", endpoint): - return True - else: - return False diff --git a/griptape/cli/main.py b/griptape/cli/main.py deleted file mode 100644 index 772cafe..0000000 --- a/griptape/cli/main.py +++ /dev/null @@ -1,16 +0,0 @@ -import click - -from griptape.cli.commands.app import app -from griptape.cli.commands.cloud import cloud -from griptape.cli.commands.server import server - - -@click.group() -@click.pass_context -def cli(ctx): - ctx.obj = {} - - -cli.add_command(app) -cli.add_command(cloud) -cli.add_command(server) diff --git a/griptape/__init__.py b/griptapecli/__init__.py similarity index 100% rename from griptape/__init__.py rename to griptapecli/__init__.py diff --git a/griptape/cli/__init__.py b/griptapecli/commands/__init__.py similarity index 100% rename from griptape/cli/__init__.py rename to griptapecli/commands/__init__.py diff --git a/griptape/cli/commands/server.py b/griptapecli/commands/server.py similarity index 97% rename from griptape/cli/commands/server.py rename to griptapecli/commands/server.py index 547954d..7ad9a56 100644 --- a/griptape/cli/commands/server.py +++ b/griptapecli/commands/server.py @@ -80,7 +80,7 @@ def start( """Starts the Griptape server.""" logger.info(f"Server started at http://{host}:{port}") uvicorn.run( - "griptape.cli.core.server:app", + "griptapecli.core.server:app", host=host, port=port, reload=True, @@ -108,7 +108,7 @@ def register( "environment": dict(environment), }, ) - logger.debug(response.json()) + logger.info(response.text) @server.command(name="build") diff --git a/griptape/cli/commands/__init__.py b/griptapecli/core/__init__.py similarity index 100% rename from griptape/cli/commands/__init__.py rename to griptapecli/core/__init__.py diff --git a/griptape/cli/core/models.py b/griptapecli/core/models.py similarity index 100% rename from griptape/cli/core/models.py rename to griptapecli/core/models.py diff --git a/griptape/cli/core/server.py b/griptapecli/core/server.py similarity index 100% rename from griptape/cli/core/server.py rename to griptapecli/core/server.py diff --git a/griptape/cli/core/state.py b/griptapecli/core/state.py similarity index 100% rename from griptape/cli/core/state.py rename to griptapecli/core/state.py diff --git a/griptapecli/main.py b/griptapecli/main.py new file mode 100644 index 0000000..70f2d4e --- /dev/null +++ b/griptapecli/main.py @@ -0,0 +1,12 @@ +import click + +from griptapecli.commands.server import server + + +@click.group() +@click.pass_context +def cli(ctx): + ctx.obj = {} + + +cli.add_command(server) diff --git a/poetry.lock b/poetry.lock index b034845..12d7a3a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -33,25 +33,6 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] -[[package]] -name = "arrow" -version = "1.3.0" -description = "Better dates & times for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"}, - {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"}, -] - -[package.dependencies] -python-dateutil = ">=2.7.0" -types-python-dateutil = ">=2.8.10" - -[package.extras] -doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] -test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] - [[package]] name = "attrs" version = "23.2.0" @@ -71,20 +52,6 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] -[[package]] -name = "binaryornot" -version = "0.4.4" -description = "Ultra-lightweight pure Python package to check if a file is binary or text." -optional = false -python-versions = "*" -files = [ - {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"}, - {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"}, -] - -[package.dependencies] -chardet = ">=3.0.2" - [[package]] name = "black" version = "23.12.1" @@ -142,17 +109,6 @@ files = [ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] -[[package]] -name = "chardet" -version = "5.2.0" -description = "Universal encoding detector for Python 3" -optional = false -python-versions = ">=3.7" -files = [ - {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, - {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, -] - [[package]] name = "charset-normalizer" version = "3.3.2" @@ -288,27 +244,6 @@ files = [ {file = "contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869"}, ] -[[package]] -name = "cookiecutter" -version = "2.6.0" -description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d"}, - {file = "cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c"}, -] - -[package.dependencies] -arrow = "*" -binaryornot = ">=0.4.4" -click = ">=7.0,<9.0.0" -Jinja2 = ">=2.7,<4.0.0" -python-slugify = ">=4.0.0" -pyyaml = ">=5.3.1" -requests = ">=2.23.0" -rich = "*" - [[package]] name = "dateparser" version = "1.2.0" @@ -653,24 +588,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "inquirerpy" -version = "0.3.4" -description = "Python port of Inquirer.js (A collection of common interactive command-line user interfaces)" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "InquirerPy-0.3.4-py3-none-any.whl", hash = "sha256:c65fdfbac1fa00e3ee4fb10679f4d3ed7a012abf4833910e63c295827fe2a7d4"}, - {file = "InquirerPy-0.3.4.tar.gz", hash = "sha256:89d2ada0111f337483cb41ae31073108b2ec1e618a49d7110b0d7ade89fc197e"}, -] - -[package.dependencies] -pfzy = ">=0.3.1,<0.4.0" -prompt-toolkit = ">=3.0.1,<4.0.0" - -[package.extras] -docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17-beta.43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] - [[package]] name = "jinja2" version = "3.1.3" @@ -926,20 +843,6 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] -[[package]] -name = "pfzy" -version = "0.3.4" -description = "Python port of the fzy fuzzy string matching algorithm" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "pfzy-0.3.4-py3-none-any.whl", hash = "sha256:5f50d5b2b3207fa72e7ec0ef08372ef652685470974a107d0d4999fc5a903a96"}, - {file = "pfzy-0.3.4.tar.gz", hash = "sha256:717ea765dd10b63618e7298b2d98efd819e0b30cd5905c9707223dceeb94b3f1"}, -] - -[package.extras] -docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17-beta.43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] - [[package]] name = "platformdirs" version = "4.2.0" @@ -970,20 +873,6 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "prompt-toolkit" -version = "3.0.43" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, -] - -[package.dependencies] -wcwidth = "*" - [[package]] name = "pydantic" version = "2.6.4" @@ -1176,23 +1065,6 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "python-slugify" -version = "8.0.4" -description = "A Python slugify application that also handles Unicode" -optional = false -python-versions = ">=3.7" -files = [ - {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, - {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, -] - -[package.dependencies] -text-unidecode = ">=1.3" - -[package.extras] -unidecode = ["Unidecode (>=1.1.1)"] - [[package]] name = "pytz" version = "2024.1" @@ -1583,17 +1455,6 @@ files = [ [package.extras] doc = ["reno", "sphinx", "tornado (>=4.5)"] -[[package]] -name = "text-unidecode" -version = "1.3" -description = "The most basic Text::Unidecode port" -optional = false -python-versions = "*" -files = [ - {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, - {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, -] - [[package]] name = "tiktoken" version = "0.6.0" @@ -1677,17 +1538,6 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] -[[package]] -name = "types-python-dateutil" -version = "2.9.0.20240316" -description = "Typing stubs for python-dateutil" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, - {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, -] - [[package]] name = "typing-extensions" version = "4.11.0" @@ -1901,17 +1751,6 @@ files = [ [package.dependencies] anyio = ">=3.0.0" -[[package]] -name = "wcwidth" -version = "0.2.13" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = "*" -files = [ - {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, - {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, -] - [[package]] name = "websocket-client" version = "1.7.0" @@ -2012,4 +1851,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "b61e5f6d8883ffa4bb17650ffc95b634f232933643a1d2c57263047038c6eb81" +content-hash = "9c374ae1182b4e4f53906648ed0a440b4904827f837d6e8dacc96336acbc384d" diff --git a/pyproject.toml b/pyproject.toml index 7a7fcb8..5721507 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,17 +8,14 @@ readme = "README.md" repository = "https://github.com/griptape-ai/griptape-cli" packages = [ - {include = "griptape"} + {include = "griptapecli"} ] [tool.poetry.dependencies] python = ">=3.10,<3.12" click = "^8.1.3" griptape = "^0.24.0" -cookiecutter = "^2.1.1" attrs = "^23.1.0" -stringcase = "^1.2.0" -inquirerpy = "^0.3.4" uvicorn = {extras = ["standard"], version = "^0.29.0"} fastapi = "^0.110.1" python-dotenv = "^1.0.1" @@ -35,4 +32,4 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] -gt = "griptape.cli.main:cli" +gt = "griptapecli.main:cli" diff --git a/griptape/cli/core/__init__.py b/tests/unit/core/__init__.py similarity index 100% rename from griptape/cli/core/__init__.py rename to tests/unit/core/__init__.py diff --git a/tests/unit/core/test_app_packager.py b/tests/unit/core/test_app_packager.py deleted file mode 100644 index 4eb1ae0..0000000 --- a/tests/unit/core/test_app_packager.py +++ /dev/null @@ -1,36 +0,0 @@ -import base64 -import os -import shutil -import tempfile -import pytest -from click.testing import CliRunner -from griptape.cli.commands import app -from griptape.cli.core.app_packager import AppPackager - - -class TestAppPackager: - def test_invalid_app_directory(self): - with pytest.raises(ValueError): - AppPackager(app_directory="/tmp") - - def test_deploy(self): - runner = CliRunner() - - with tempfile.TemporaryDirectory() as temp_dir: - runner.invoke(app.new, ["FooBar", "-d", temp_dir]) - - app_deployer = AppPackager(app_directory=os.path.join(temp_dir, "FooBar")) - - app_source = app_deployer.get_deployment_source() - - os.makedirs(os.path.join(temp_dir, "artifact")) - dir = os.path.join(temp_dir, "artifact") - with open(os.path.join(dir, "artifact.zip"), "wb") as f: - f.write(base64.b64decode(app_source)) - - shutil.unpack_archive(os.path.join(dir, "artifact.zip"), dir, "zip") - files = os.listdir(dir) - assert "app.py" in files - assert "requirements.txt" in files - assert "README.md" in files - assert ".gitignore" in files diff --git a/tests/unit/core/test_structure_runner.py b/tests/unit/core/test_structure_runner.py deleted file mode 100644 index 03c2da7..0000000 --- a/tests/unit/core/test_structure_runner.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -import tempfile -import pytest -import unittest -from click.testing import CliRunner -from griptape.tasks import BaseTask -from griptape.cli.commands import app -from griptape.cli.core.structure_runner import StructureRunner - - -class TestStructureRunner: - @pytest.fixture() - def mock_subprocess(self, mocker): - yield mocker.patch( - "griptape.cli.core.structure_runner.subprocess.check_call", return_value=0 - ) - - def test_run(self, mocker, mock_subprocess): - runner = CliRunner() - - with tempfile.TemporaryDirectory() as temp_dir: - runner.invoke(app.new, ["FooBar", "-d", temp_dir]) - - workdir = os.getcwd() - os.chdir(temp_dir) - structure_runner = StructureRunner( - args=["foo", "bar"], app_directory="./FooBar" - ) - os.chdir(workdir) - - # Check for substring due to 'private' folder prefix - assert os.path.join(temp_dir, "FooBar") in structure_runner.app_directory - - mock_task = mocker.Mock(spec=BaseTask) - mock_app = mocker.Mock() - mock_structure = mocker.Mock() - mock_app.init_structure.return_value = mock_structure - mock_structure.run.return_value = mock_task - with unittest.mock.patch.dict("sys.modules", app=mock_app): - result = structure_runner.run() - assert result == mock_task - mock_subprocess.assert_called_once() - args, kwargs = mock_structure.run.call_args - assert args == ("foo", "bar") From 91d25bdacd7fb9d38b9026bceaffaf39b0ed9436 Mon Sep 17 00:00:00 2001 From: Collin Dutter Date: Fri, 12 Apr 2024 13:59:03 -0700 Subject: [PATCH 2/2] Add dumb tests --- tests/unit/core/test_models.py | 15 +++++++++++++++ tests/unit/core/test_state.py | 6 ++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/unit/core/test_models.py create mode 100644 tests/unit/core/test_state.py diff --git a/tests/unit/core/test_models.py b/tests/unit/core/test_models.py new file mode 100644 index 0000000..cc6282e --- /dev/null +++ b/tests/unit/core/test_models.py @@ -0,0 +1,15 @@ +from griptapecli.core.models import Event, Run, Structure + + +class TestModels: + def test_event_model_init(self): + assert Event(value={}) + + def test_run_model_init(self): + assert Run() + + def test_structure_model_init(self): + assert Structure( + directory="directory", + main_file="main_file", + ) diff --git a/tests/unit/core/test_state.py b/tests/unit/core/test_state.py new file mode 100644 index 0000000..06b1c9b --- /dev/null +++ b/tests/unit/core/test_state.py @@ -0,0 +1,6 @@ +from griptapecli.core.state import State + + +class TestState: + def test_init(self): + assert State()