From f8a99001f51fb8c77cc0b21024d09c237a6bb79b Mon Sep 17 00:00:00 2001 From: OpenClaw Date: Mon, 28 Sep 2026 07:03:23 +0000 Subject: [PATCH 1/2] fix(cli): keep generated project settings local --- nest/cli/src/generate/generate_service.py | 14 +++++--- nest/cli/templates/blank_template.py | 2 +- nest/cli/templates/cli_templates.py | 2 +- nest/cli/templates/orm_template.py | 2 +- tests/test_cli/test_project_settings.py | 43 +++++++++++++++++++++++ 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 tests/test_cli/test_project_settings.py diff --git a/nest/cli/src/generate/generate_service.py b/nest/cli/src/generate/generate_service.py index 6336a8a..2901c4f 100644 --- a/nest/cli/src/generate/generate_service.py +++ b/nest/cli/src/generate/generate_service.py @@ -15,11 +15,15 @@ def __init__(self): @staticmethod def get_metadata(): config = {"db_type": None, "is_async": False, "is_cli": False} - setting_path = Path(__file__).parent.parent.parent.parent / "settings.yaml" - if setting_path.exists(): - with open(setting_path, "r") as file: - file = yaml.load(file, Loader=yaml.FullLoader) - config = file["config"] + # Metadata belongs to the generated project, not the installed package. + # Search upward so commands also work from a project's src/ directory. + for directory in (Path.cwd(), *Path.cwd().parents): + setting_path = directory / "settings.yaml" + if setting_path.is_file(): + with setting_path.open("r") as file: + settings = yaml.safe_load(file) or {} + config.update(settings.get("config") or {}) + break db_type = config["db_type"] is_async = config["is_async"] is_cli = config["is_cli"] if "is_cli" in config else False diff --git a/nest/cli/templates/blank_template.py b/nest/cli/templates/blank_template.py index cde225c..a0db2dc 100644 --- a/nest/cli/templates/blank_template.py +++ b/nest/cli/templates/blank_template.py @@ -118,10 +118,10 @@ def generate_module(self, module_name: str, path: str = None): self.create_module(module_name, src_path) def generate_project(self, project_name: str): - self.create_template(self.nest_path / "settings.yaml", self.settings_file()) root = self.base_path / project_name src_path = root / "src" self.create_folder(root) + self.create_template(root / "settings.yaml", self.settings_file()) self.create_template(root / "main.py", self.main_file()) self.create_template(root / "README.md", self.readme_file()) self.create_template(root / "requirements.txt", self.requirements_file()) diff --git a/nest/cli/templates/cli_templates.py b/nest/cli/templates/cli_templates.py index 1f83e9e..f21cf13 100644 --- a/nest/cli/templates/cli_templates.py +++ b/nest/cli/templates/cli_templates.py @@ -131,10 +131,10 @@ def generate_module(self, module_name: str, path: str = None): self.create_module(module_name, src_path) def generate_project(self, project_name: str): - self.create_template(self.nest_path / "settings.yaml", self.settings_file()) root = self.base_path / project_name src_path = root / "src" self.create_folder(root) + self.create_template(root / "settings.yaml", self.settings_file()) self.create_template(root / "README.md", self.readme_file()) self.create_template(root / "requirements.txt", self.requirements_file()) self.create_folder(src_path) diff --git a/nest/cli/templates/orm_template.py b/nest/cli/templates/orm_template.py index c85ce29..5cf92d3 100644 --- a/nest/cli/templates/orm_template.py +++ b/nest/cli/templates/orm_template.py @@ -182,13 +182,13 @@ def generate_module(self, module_name: str, path: str = None): self.create_module(module_name, src_path) def generate_project(self, project_name: str): - self.create_template(self.nest_path / "settings.yaml", self.settings_file()) # define paths: root, src, module root_path = self.base_path / project_name src_path = self.base_path / project_name / "src" # create folders self.create_folder(root_path) + self.create_template(root_path / "settings.yaml", self.settings_file()) self.create_folder(src_path) # create root level files diff --git a/tests/test_cli/test_project_settings.py b/tests/test_cli/test_project_settings.py new file mode 100644 index 0000000..7b0f6ce --- /dev/null +++ b/tests/test_cli/test_project_settings.py @@ -0,0 +1,43 @@ +from pathlib import Path + +import pytest +import yaml + +from nest.cli.src.generate.generate_service import GenerateService + + +@pytest.mark.parametrize( + "db_type,is_async,is_cli,expected", + [ + (None, False, False, (None, False, False)), + ("sqlite", True, False, ("sqlite", True, False)), + (None, False, True, ("", False, True)), + ], +) +def test_generated_project_keeps_cli_settings_locally( + tmp_path, monkeypatch, db_type, is_async, is_cli, expected +): + monkeypatch.chdir(tmp_path) + service = GenerateService() + package_settings = Path(__file__).parents[2] / "nest" / "settings.yaml" + assert not package_settings.exists() + + service.generate_app("sample", db_type, is_async, is_cli) + + project = tmp_path / "sample" + assert yaml.safe_load((project / "settings.yaml").read_text())["config"] + assert not package_settings.exists() + monkeypatch.chdir(project / "src") + assert service.get_metadata() == expected + + +def test_project_metadata_isolated_between_projects(tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + service = GenerateService() + service.generate_app("web", None, False, False) + service.generate_app("database", "sqlite", True, False) + + monkeypatch.chdir(tmp_path / "web") + assert service.get_metadata() == (None, False, False) + monkeypatch.chdir(tmp_path / "database" / "src") + assert service.get_metadata() == ("sqlite", True, False) From e6175213fad5992e8d37c4d03be39f511adab78c Mon Sep 17 00:00:00 2001 From: OpenClaw Date: Mon, 28 Sep 2026 07:06:45 +0000 Subject: [PATCH 2/2] fix(test): install SQLAlchemy asyncio support --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index af6005f..2040e29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ test = [ test = [ "pytest>=7.0.1,<8.0.0", "httpx>=0.27.0,<1.0.0", - "sqlalchemy>=2.0.36,<3.0.0", + "sqlalchemy[asyncio]>=2.0.36,<3.0.0", "motor>=3.2.0,<4.0.0", "beanie>=1.27.0,<2.0.0", "python-dotenv>=1.0.1,<2.0.0",