diff --git a/agentstack/cli/cli.py b/agentstack/cli/cli.py index 15b61676..bc5648c6 100644 --- a/agentstack/cli/cli.py +++ b/agentstack/cli/cli.py @@ -13,6 +13,8 @@ import os import importlib.resources from cookiecutter.main import cookiecutter +from dotenv import load_dotenv +import subprocess from .agentstack_data import ( FrameworkData, @@ -184,8 +186,9 @@ def run_project(framework: str, path: str = ''): print(e) sys.exit(1) + load_dotenv(_path / '.env') # explicitly load the project's .env file entrypoint = _path / frameworks.get_entrypoint_path(framework) - os.system(f'python {entrypoint}') + subprocess.run(['python', entrypoint], env=os.environ) def ask_framework() -> str: diff --git a/agentstack/templates/crewai/{{cookiecutter.project_metadata.project_slug}}/src/main.py b/agentstack/templates/crewai/{{cookiecutter.project_metadata.project_slug}}/src/main.py index bba6c84f..291a6177 100644 --- a/agentstack/templates/crewai/{{cookiecutter.project_metadata.project_slug}}/src/main.py +++ b/agentstack/templates/crewai/{{cookiecutter.project_metadata.project_slug}}/src/main.py @@ -2,8 +2,6 @@ import sys from crew import {{cookiecutter.project_metadata.project_name|replace('-', '')|replace('_', '')|capitalize}}Crew import agentops -from dotenv import load_dotenv -load_dotenv() agentops.init(default_tags=['crewai', 'agentstack']) diff --git a/agentstack/utils.py b/agentstack/utils.py index de008489..0bb32f93 100644 --- a/agentstack/utils.py +++ b/agentstack/utils.py @@ -1,5 +1,5 @@ from typing import Optional -import sys +import os, sys import json from ruamel.yaml import YAML import re @@ -54,9 +54,16 @@ def get_framework(path: Optional[str] = None) -> str: def get_telemetry_opt_out(path: Optional[str] = None) -> bool: + """ + Gets the telemetry opt out setting. + First checks the environment variable AGENTSTACK_TELEMETRY_OPT_OUT. + If that is not set, it checks the agentstack.json file. + """ from agentstack.generation import ConfigFile try: + return bool(os.environ['AGENTSTACK_TELEMETRY_OPT_OUT']) + except KeyError: agentstack_config = ConfigFile(path) return bool(agentstack_config.telemetry_opt_out) except FileNotFoundError: diff --git a/pyproject.toml b/pyproject.toml index 1767a397..9c9f0ce4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ dependencies = [ "packaging==23.2", "requests>=2.32", "appdirs>=1.4.4", + "python-dotenv>=1.0.1", ] [project.optional-dependencies] diff --git a/tests/test_generation_files.py b/tests/test_generation_files.py index c5fae48b..a2baf5ef 100644 --- a/tests/test_generation_files.py +++ b/tests/test_generation_files.py @@ -66,11 +66,6 @@ def test_get_framework(self): with self.assertRaises(SystemExit) as _: get_framework(BASE_PATH / "missing") - def test_get_telemetry_opt_out(self): - assert get_telemetry_opt_out(BASE_PATH / "fixtures") is False - with self.assertRaises(SystemExit) as _: - get_telemetry_opt_out(BASE_PATH / "missing") - def test_read_env(self): env = EnvFile(BASE_PATH / "fixtures") assert env.variables == {"ENV_VAR1": "value1", "ENV_VAR2": "value2"} diff --git a/tests/test_project_run.py b/tests/test_project_run.py new file mode 100644 index 00000000..787589da --- /dev/null +++ b/tests/test_project_run.py @@ -0,0 +1,46 @@ +import os +from pathlib import Path +import shutil +import unittest +from parameterized import parameterized_class + +from agentstack import frameworks +from agentstack.cli import run_project +from agentstack.generation.files import ConfigFile + +BASE_PATH = Path(__file__).parent + + +@parameterized_class([{"framework": framework} for framework in frameworks.SUPPORTED_FRAMEWORKS]) +class ProjectRunTest(unittest.TestCase): + def setUp(self): + self.project_dir = BASE_PATH / 'tmp' / self.framework + + os.makedirs(self.project_dir) + os.makedirs(self.project_dir / 'src') + (self.project_dir / 'src' / '__init__.py').touch() + + # set the framework in agentstack.json + shutil.copy(BASE_PATH / 'fixtures' / 'agentstack.json', self.project_dir / 'agentstack.json') + with ConfigFile(self.project_dir) as config: + config.framework = self.framework + + # populate the entrypoint + entrypoint_path = frameworks.get_entrypoint_path(self.framework, self.project_dir) + shutil.copy(BASE_PATH / f"fixtures/frameworks/{self.framework}/entrypoint_max.py", entrypoint_path) + + # write a basic .env file + shutil.copy(BASE_PATH / 'fixtures' / '.env', self.project_dir / '.env') + + def tearDown(self): + shutil.rmtree(self.project_dir) + + def test_run_project(self): + run_project(self.framework, self.project_dir) + + def test_env_is_set(self): + """ + After running a project, the environment variables should be set from project_dir/.env. + """ + run_project(self.framework, self.project_dir) + assert os.getenv('ENV_VAR1') == 'value1' diff --git a/tests/test_telemetry.py b/tests/test_telemetry.py new file mode 100644 index 00000000..35f3c5fa --- /dev/null +++ b/tests/test_telemetry.py @@ -0,0 +1,12 @@ +import os +import unittest +from agentstack.utils import get_telemetry_opt_out + + +class TelemetryTest(unittest.TestCase): + def test_telemetry_opt_out_env_var_set(self): + AGENTSTACK_TELEMETRY_OPT_OUT = os.getenv("AGENTSTACK_TELEMETRY_OPT_OUT") + assert AGENTSTACK_TELEMETRY_OPT_OUT + + def test_telemetry_opt_out_set_in_test_environment(self): + assert get_telemetry_opt_out() diff --git a/tox.ini b/tox.ini index 6733c3ab..fc41e805 100644 --- a/tox.ini +++ b/tox.ini @@ -13,4 +13,6 @@ deps = mypy: mypy commands = pytest -v - mypy: mypy agentops \ No newline at end of file + mypy: mypy agentops +setenv = + AGENTSTACK_TELEMETRY_OPT_OUT = 1 \ No newline at end of file