From b3d4b9e69d303680aeb690aff9194e2db6c6156d Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Fri, 30 Aug 2024 19:28:05 -0400 Subject: [PATCH 01/14] refactor: Improve cli feat: Add new command. test: Update tests --- .vscode/settings.json | 7 ++ Makefile | 24 ++++++ README.md | 4 +- pdm.lock | 61 +++++++++++++-- pyproject.toml | 1 + src/litestar_manage/cli.py | 45 +++++++++-- src/litestar_manage/renderer.py | 2 +- .../template/app/controllers/web.py | 12 --- .../{template => templates}/.gitignore | 0 .../{template => templates}/README.md.jinja2 | 0 .../{template => templates}/app/__init__.py | 0 .../app/src}/__init__.py | 0 .../app => templates/app/src}/__main__.py | 0 .../templates/app/src/app_controller.py | 18 +++++ .../templates/app/src/app_service.py | 16 ++++ .../app => templates/app/src}/assets/.gitkeep | 0 .../app => templates/app/src}/config.py | 0 .../app/app.py => templates/app/src/main.py} | 6 +- .../app/src}/templates/index.html.jinja2 | 0 .../app/tests/__init__.py | 0 .../templates/resource/__init__.py | 0 .../templates/resource/controller.py.jinja2 | 6 ++ .../templates/resource/dto.py.jinja2 | 10 +++ .../templates/resource/models.py.jinja2 | 7 ++ .../templates/resource/repository.py.jinja2 | 7 ++ .../templates/resource/service.py.jinja2 | 13 ++++ tests/__init__.py | 3 +- tests/test_renderer.py | 17 ++++- tests/test_resource.py | 76 +++++++++++++++++++ 29 files changed, 300 insertions(+), 35 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 Makefile delete mode 100644 src/litestar_manage/template/app/controllers/web.py rename src/litestar_manage/{template => templates}/.gitignore (100%) rename src/litestar_manage/{template => templates}/README.md.jinja2 (100%) rename src/litestar_manage/{template => templates}/app/__init__.py (100%) rename src/litestar_manage/{template/app/controllers => templates/app/src}/__init__.py (100%) rename src/litestar_manage/{template/app => templates/app/src}/__main__.py (100%) create mode 100644 src/litestar_manage/templates/app/src/app_controller.py create mode 100644 src/litestar_manage/templates/app/src/app_service.py rename src/litestar_manage/{template/app => templates/app/src}/assets/.gitkeep (100%) rename src/litestar_manage/{template/app => templates/app/src}/config.py (100%) rename src/litestar_manage/{template/app/app.py => templates/app/src/main.py} (89%) rename src/litestar_manage/{template/app => templates/app/src}/templates/index.html.jinja2 (100%) rename src/litestar_manage/{template => templates}/app/tests/__init__.py (100%) create mode 100644 src/litestar_manage/templates/resource/__init__.py create mode 100644 src/litestar_manage/templates/resource/controller.py.jinja2 create mode 100644 src/litestar_manage/templates/resource/dto.py.jinja2 create mode 100644 src/litestar_manage/templates/resource/models.py.jinja2 create mode 100644 src/litestar_manage/templates/resource/repository.py.jinja2 create mode 100644 src/litestar_manage/templates/resource/service.py.jinja2 create mode 100644 tests/test_resource.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9b38853 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..50fd597 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +# Variables +PYTHON := pdm run python +PYTEST := pdm run pytest +BLACK := pdm run black +FIND := find + +# Directories +SRC_DIR := src +TEST_DIR := tests + +# Targets +.PHONY: clean test run + + +#Format the files +format: + $(BLACK) $(SRC_DIR) + +# Clean target to delete __pycache__ directories +clean: + $(FIND) . -type d -name "__pycache__" -exec rm -rf {} + + +test: + $(PYTEST) $(TEST_DIR) -vv -s --showlocals diff --git a/README.md b/README.md index 767f9a9..200fca9 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@ project using the Litestar CLI. When the litestar-manage module is installed, it will extend the Litestar native CLI. To create a starter project, run the following command: -``` +```bash litestar project init --app-name MyProject ``` This command is used to initialize a Litestar project named MyProject in the current working directory. MyProject will have the following tree structure: -``` +```bash app/ ├─ templates/ │ ├─ index.html diff --git a/pdm.lock b/pdm.lock index d77c1f8..a980d39 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev", "lint", "test"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:16f390e458577185da2cbaeb42b42d1bb6dc2fd61506151b69574a9dda65b192" +content_hash = "sha256:d6036997a864485ccc3341e183c4f0bd8f5568e10e00e6943969ede35bd4e6d5" [[metadata.targets]] requires_python = ">=3.8" @@ -27,6 +27,46 @@ files = [ {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] +[[package]] +name = "black" +version = "24.8.0" +requires_python = ">=3.8" +summary = "The uncompromising code formatter." +groups = ["dev"] +dependencies = [ + "click>=8.0.0", + "mypy-extensions>=0.4.3", + "packaging>=22.0", + "pathspec>=0.9.0", + "platformdirs>=2", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.0.1; python_version < \"3.11\"", +] +files = [ + {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, + {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, + {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, + {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, + {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, + {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, + {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, + {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, + {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, + {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, + {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, + {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, + {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, + {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, + {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, + {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, + {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, + {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, + {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, + {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, + {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, + {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, +] + [[package]] name = "certifi" version = "2024.7.4" @@ -942,7 +982,7 @@ name = "mypy-extensions" version = "1.0.0" requires_python = ">=3.5" summary = "Type system extensions for programs checked with the mypy type checker." -groups = ["lint"] +groups = ["dev", "lint"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -964,18 +1004,29 @@ name = "packaging" version = "24.1" requires_python = ">=3.8" summary = "Core utilities for Python packages" -groups = ["test"] +groups = ["dev", "test"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] +[[package]] +name = "pathspec" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + [[package]] name = "platformdirs" version = "4.2.2" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -groups = ["lint"] +groups = ["dev", "lint"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -1268,7 +1319,7 @@ name = "tomli" version = "2.0.1" requires_python = ">=3.7" summary = "A lil' TOML parser" -groups = ["lint", "test"] +groups = ["dev", "lint", "test"] marker = "python_version < \"3.11\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, diff --git a/pyproject.toml b/pyproject.toml index 914316c..ace9950 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -306,6 +306,7 @@ distribution = true [tool.pdm.dev-dependencies] dev = [ "litestar[standard,cryptography,jinja]>=2.9.1", + "black>=24.8.0", ] lint = [ "pyright>=1.1.376", diff --git a/src/litestar_manage/cli.py b/src/litestar_manage/cli.py index 36d8847..ce27380 100644 --- a/src/litestar_manage/cli.py +++ b/src/litestar_manage/cli.py @@ -10,12 +10,17 @@ from litestar_manage.venv_builder import PipVenvBuilder, init_venv -@group(cls=LitestarGroup, name="project") -def project_group() -> None: - """Manage Scaffolding Tasks.""" +def is_project_initialized() -> bool: + output_dir = Path.cwd() + return (output_dir / "src").exists() or (output_dir / "venv").exists() + +@click.group(cls=LitestarGroup) +def cli(): + pass -@project_group.command(name="init", help="Initialize a new Litestar project.") + +@cli.command(name="new", help="Initialize a new Litestar project.") @option( "--app-name", type=str, @@ -31,14 +36,38 @@ def project_group() -> None: def init_project(app_name: str, venv: str | None) -> None: """CLI command to initialize a Litestar project""" - template_dir = Path(__file__).parent / "template" + template_dir = Path(__file__).parent / "templates" / "app" output_dir = Path.cwd() - ctx = RenderingContext(app_name=app_name) + if is_project_initialized(): + click.echo("Project already initialized.") + return + + ctx = RenderingContext(app_name=app_name) render_template(template_dir, output_dir, ctx, run_ruff=True) packages_to_install = ["litestar"] - venv_name = "venv" if venv == "pip": builder = PipVenvBuilder() - init_venv(output_dir / venv_name, builder, packages_to_install) + init_venv(output_dir / "venv", builder, packages_to_install) + + +@cli.command(name="resource") +@option( + "--resource-name", + "-n", + type=str, + required=True, +) +def generate_resource(resource_name: str) -> None: + """CLI command to generate a new resource (controller, service, dto, models, repository)""" + + if not is_project_initialized(): + click.echo("Project not initialized. Please initialize the project first.") + return + + template_dir = Path(__file__).parent / "templates" / "resource" + output_dir = Path.cwd() / "src" / f"{resource_name.lower()}" + ctx = RenderingContext(app_name=resource_name) + + render_template(template_dir, output_dir, ctx, run_ruff=True) diff --git a/src/litestar_manage/renderer.py b/src/litestar_manage/renderer.py index b3bf8e1..f87e4f3 100644 --- a/src/litestar_manage/renderer.py +++ b/src/litestar_manage/renderer.py @@ -101,7 +101,7 @@ def find_ruff_bin() -> Path: if scripts_path.is_file(): return scripts_path - if sys.version_info >= (3, 10): # noqa: UP036 + if sys.version_info >= (3, 10): # noqa: UP036 user_scheme = sysconfig.get_preferred_scheme("user") elif os.name == "nt": user_scheme = "nt_user" diff --git a/src/litestar_manage/template/app/controllers/web.py b/src/litestar_manage/template/app/controllers/web.py deleted file mode 100644 index 6c0321b..0000000 --- a/src/litestar_manage/template/app/controllers/web.py +++ /dev/null @@ -1,12 +0,0 @@ -from litestar import Controller, get -from litestar.response import Template -from litestar.status_codes import HTTP_200_OK - - -class WebController(Controller): - """Web controller.""" - - @get(path="/", status_code=HTTP_200_OK) - async def index(self) -> Template: - """Serve site root.""" - return Template(template_name="index.html") diff --git a/src/litestar_manage/template/.gitignore b/src/litestar_manage/templates/.gitignore similarity index 100% rename from src/litestar_manage/template/.gitignore rename to src/litestar_manage/templates/.gitignore diff --git a/src/litestar_manage/template/README.md.jinja2 b/src/litestar_manage/templates/README.md.jinja2 similarity index 100% rename from src/litestar_manage/template/README.md.jinja2 rename to src/litestar_manage/templates/README.md.jinja2 diff --git a/src/litestar_manage/template/app/__init__.py b/src/litestar_manage/templates/app/__init__.py similarity index 100% rename from src/litestar_manage/template/app/__init__.py rename to src/litestar_manage/templates/app/__init__.py diff --git a/src/litestar_manage/template/app/controllers/__init__.py b/src/litestar_manage/templates/app/src/__init__.py similarity index 100% rename from src/litestar_manage/template/app/controllers/__init__.py rename to src/litestar_manage/templates/app/src/__init__.py diff --git a/src/litestar_manage/template/app/__main__.py b/src/litestar_manage/templates/app/src/__main__.py similarity index 100% rename from src/litestar_manage/template/app/__main__.py rename to src/litestar_manage/templates/app/src/__main__.py diff --git a/src/litestar_manage/templates/app/src/app_controller.py b/src/litestar_manage/templates/app/src/app_controller.py new file mode 100644 index 0000000..0b5681f --- /dev/null +++ b/src/litestar_manage/templates/app/src/app_controller.py @@ -0,0 +1,18 @@ +from typing import Dict + +from litestar import Controller, get +from litestar.di import Provide +from litestar.enums import MediaType +from litestar.status_codes import HTTP_200_OK +from src.app_service import AppService, provide_app_service + + +class AppController(Controller): + """App controller.""" + + dependencies = {"app_service": Provide(provide_app_service)} + + @get(path="/", status_code=HTTP_200_OK, media_type=MediaType.JSON) + async def index(self, app_service: AppService) -> Dict: + """App index""" + return await app_service.app_info() diff --git a/src/litestar_manage/templates/app/src/app_service.py b/src/litestar_manage/templates/app/src/app_service.py new file mode 100644 index 0000000..0282b8f --- /dev/null +++ b/src/litestar_manage/templates/app/src/app_service.py @@ -0,0 +1,16 @@ +from typing import Dict + + +class AppService: + """App Service""" + + app_name = "" + app_version = "0.1.0" + + async def app_info(self) -> Dict[str, str]: + """Return info about the app""" + return {"app_name": self.app_name, "verion": self.app_version} + + +def provide_app_service(): + return AppService() diff --git a/src/litestar_manage/template/app/assets/.gitkeep b/src/litestar_manage/templates/app/src/assets/.gitkeep similarity index 100% rename from src/litestar_manage/template/app/assets/.gitkeep rename to src/litestar_manage/templates/app/src/assets/.gitkeep diff --git a/src/litestar_manage/template/app/config.py b/src/litestar_manage/templates/app/src/config.py similarity index 100% rename from src/litestar_manage/template/app/config.py rename to src/litestar_manage/templates/app/src/config.py diff --git a/src/litestar_manage/template/app/app.py b/src/litestar_manage/templates/app/src/main.py similarity index 89% rename from src/litestar_manage/template/app/app.py rename to src/litestar_manage/templates/app/src/main.py index 46bc5b5..d1b0aa6 100644 --- a/src/litestar_manage/template/app/app.py +++ b/src/litestar_manage/templates/app/src/main.py @@ -18,15 +18,15 @@ def create_app() -> Litestar: from litestar.static_files import create_static_files_router from litestar.template.config import TemplateConfig - from app.config import assets_path, templates_path - from app.controllers.web import WebController + from .app_controller import AppController + from .config import assets_path, templates_path logging_middleware_config = LoggingMiddlewareConfig() session_config = CookieBackendConfig(secret=urandom(16)) return Litestar( route_handlers=[ - WebController, + AppController, create_static_files_router(path="/static", directories=[assets_path]), ], middleware=[session_config.middleware, logging_middleware_config.middleware], diff --git a/src/litestar_manage/template/app/templates/index.html.jinja2 b/src/litestar_manage/templates/app/src/templates/index.html.jinja2 similarity index 100% rename from src/litestar_manage/template/app/templates/index.html.jinja2 rename to src/litestar_manage/templates/app/src/templates/index.html.jinja2 diff --git a/src/litestar_manage/template/app/tests/__init__.py b/src/litestar_manage/templates/app/tests/__init__.py similarity index 100% rename from src/litestar_manage/template/app/tests/__init__.py rename to src/litestar_manage/templates/app/tests/__init__.py diff --git a/src/litestar_manage/templates/resource/__init__.py b/src/litestar_manage/templates/resource/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/litestar_manage/templates/resource/controller.py.jinja2 b/src/litestar_manage/templates/resource/controller.py.jinja2 new file mode 100644 index 0000000..7846bbb --- /dev/null +++ b/src/litestar_manage/templates/resource/controller.py.jinja2 @@ -0,0 +1,6 @@ +from litestar.controller import Controller + + +class {{app_name.capitalize()}}Controller(Controller): + """{{app_name.capitalize()}} Controller""" + pass \ No newline at end of file diff --git a/src/litestar_manage/templates/resource/dto.py.jinja2 b/src/litestar_manage/templates/resource/dto.py.jinja2 new file mode 100644 index 0000000..610dd0d --- /dev/null +++ b/src/litestar_manage/templates/resource/dto.py.jinja2 @@ -0,0 +1,10 @@ +from advanced_alchemy.extensions.litestar.dto import SQLAlchemyDTO, SQLAlchemyDTOConfig + +from src.{{app_name.lower()}}.models import {{app_name.capitalize()}} + + +class {{app_name.capitalize()}}DTO(SQLAlchemyDTO[{{app_name.capitalize()}}]): + """ + {{app_name.capitalize()}} DTO + """ + config = SQLAlchemyDTOConfig() diff --git a/src/litestar_manage/templates/resource/models.py.jinja2 b/src/litestar_manage/templates/resource/models.py.jinja2 new file mode 100644 index 0000000..5e874ee --- /dev/null +++ b/src/litestar_manage/templates/resource/models.py.jinja2 @@ -0,0 +1,7 @@ +from litestar.contrib.sqlalchemy.base import BigIntAuditBase +from sqlalchemy.orm import Mapped, mapped_column, relationship + + +class {{app_name.capitalize()}}(BigIntAuditBase): + """{{app_name.capitalize()}} in DB model""" + pass \ No newline at end of file diff --git a/src/litestar_manage/templates/resource/repository.py.jinja2 b/src/litestar_manage/templates/resource/repository.py.jinja2 new file mode 100644 index 0000000..447f11c --- /dev/null +++ b/src/litestar_manage/templates/resource/repository.py.jinja2 @@ -0,0 +1,7 @@ +from litestar.contrib.sqlalchemy.repository import SQLAlchemyAsyncRepository + + +class {{app_name.capitalize()}}Repository(SQLAlchemyAsyncRepository[{{app_name.capitalize()}}]): # pylint: disable=duplicate-bases + """{{app_name.capitalize()}} SQLAlchemy Repository.""" + + model_type = {{app_name.capitalize()}} \ No newline at end of file diff --git a/src/litestar_manage/templates/resource/service.py.jinja2 b/src/litestar_manage/templates/resource/service.py.jinja2 new file mode 100644 index 0000000..37a5f75 --- /dev/null +++ b/src/litestar_manage/templates/resource/service.py.jinja2 @@ -0,0 +1,13 @@ +from advanced_alchemy.service import SQLAlchemyAsyncRepositoryService +from src.{{app_name.lower()}}.repository import {{app_name.capitalize()}}Repository +from src.{{app_name.lower()}}.models import {{app_name.capitalize()}} +from typing import Any + +class {{app_name.capitalize()}}Service(SQLAlchemyAsyncRepositoryService[{{app_name.capitalize()}}]): + """ {{app_name.capitalize()}} Service""" + + repository_type = {{app_name.capitalize()}}Repository + + def __init__(self, **repo_kwargs: Any) -> None: + self.repository: {{app_name.capitalize()}}Repository = self.repository_type(**repo_kwargs) #type ignore + self.model_type = self.repository.model_type \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py index e4de290..63a9345 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,4 @@ from pathlib import Path -TEMPLATE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "template" +TEMPLATE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "templates" / "app" +RESOURCE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "templates" / "resource" diff --git a/tests/test_renderer.py b/tests/test_renderer.py index 9394e40..ff87a19 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -1,6 +1,8 @@ import pytest +from click.testing import CliRunner from testfixtures import TempDirectory +from litestar_manage.cli import cli from litestar_manage.renderer import RenderingContext, _render_jinja_dir from tests import TEMPLATE_DIR @@ -10,10 +12,19 @@ def rendering_context() -> RenderingContext: return RenderingContext(app_name="TestApp") -def test_render_jinja_dir(rendering_context: RenderingContext) -> None: +@pytest.fixture +def runner() -> CliRunner: + return CliRunner() + + +def test_render_jinja_dir(rendering_context: RenderingContext, runner: CliRunner) -> None: with TempDirectory() as t: temp_path = t.as_path() _render_jinja_dir(TEMPLATE_DIR, temp_path, rendering_context) - assert (temp_path / "app").exists() - assert (temp_path / "app" / "app.py").exists() + assert (temp_path / "src").exists() + assert (temp_path / "tests").exists() + assert (temp_path / "src" / "main.py").exists() + + result = runner.invoke(cli, ["new", "--app-name", "TestApp"]) + assert result.exit_code == 0 diff --git a/tests/test_resource.py b/tests/test_resource.py new file mode 100644 index 0000000..de52104 --- /dev/null +++ b/tests/test_resource.py @@ -0,0 +1,76 @@ +from pathlib import Path + +import pytest +from click.testing import CliRunner +from testfixtures import TempDirectory + +from litestar_manage.cli import cli +from litestar_manage.renderer import RenderingContext, _render_jinja_dir +from tests import RESOURCE_DIR, TEMPLATE_DIR + + +@pytest.fixture +def rendering_context() -> RenderingContext: + return RenderingContext(app_name="User") + + +@pytest.fixture +def runner() -> CliRunner: + return CliRunner() + + +def create_mock_project_structure(temp_path: Path) -> Path: + # Initialize the project structure using _render_jinja_dir + ctx = RenderingContext(app_name="app_name") + _render_jinja_dir(TEMPLATE_DIR, temp_path, ctx) + + # Return the path to the generated src directory + return temp_path / "src" + + +def test_render_resource_dir(rendering_context: RenderingContext) -> None: + with TempDirectory() as t: + temp_path = t.as_path() + + src_path = create_mock_project_structure(temp_path) + + resource_path = src_path / "user" + + assert src_path.exists() + + _render_jinja_dir(RESOURCE_DIR, temp_path / resource_path, rendering_context) + + assert (temp_path / "src").exists() + assert (temp_path / "tests").exists() + assert (temp_path / "src" / "main.py").exists() + assert (temp_path / "src" / "app_controller.py").exists() + assert (temp_path / "src" / "app_service.py").exists() + assert (temp_path / "src" / "user").exists() + + assert (temp_path / "src" / "user" / "__init__.py").exists() + assert (temp_path / "src" / "user" / "controller.py").exists() + assert (temp_path / "src" / "user" / "service.py").exists() + assert (temp_path / "src" / "user" / "repository.py").exists() + assert (temp_path / "src" / "user" / "dto.py").exists() + assert (temp_path / "src" / "user" / "models.py").exists() + + +def test_render_resource_dir_no_app(rendering_context: RenderingContext, runner: CliRunner) -> None: + with TempDirectory() as t: + temp_path = t.as_path() + + _render_jinja_dir(RESOURCE_DIR, temp_path, rendering_context) + + assert not (temp_path / "src").exists() + assert not (temp_path / "src" / "user" / "__init__.py").exists() + assert not (temp_path / "src" / "user" / "controller.py").exists() + assert not (temp_path / "src" / "user" / "service.py").exists() + assert not (temp_path / "src" / "user" / "repository.py").exists() + assert not (temp_path / "src" / "user" / "dto.py").exists() + assert not (temp_path / "src" / "user" / "models.py").exists() + + expected = "Project already initialized." + result = runner.invoke(cli, ["new", "--app-name", "TestApp"]) + + assert result.exit_code == 0 + assert expected in result.output From a69693b10e0066eaed7d0fa95af1402d3f3f95bc Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:10:18 -0400 Subject: [PATCH 02/14] chore (pyproject): remove black as dev --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ace9950..914316c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -306,7 +306,6 @@ distribution = true [tool.pdm.dev-dependencies] dev = [ "litestar[standard,cryptography,jinja]>=2.9.1", - "black>=24.8.0", ] lint = [ "pyright>=1.1.376", From 6082b8cf9f1c080175d11fbb03046f4c6e5cbfb5 Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:12:12 -0400 Subject: [PATCH 03/14] chore (.vscode): remove folder --- .vscode/settings.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 9b38853..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "python.testing.pytestArgs": [ - "tests" - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true -} \ No newline at end of file From 93e12d2c8563cedc77c8c6ba9955d953a0b9aefd Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:12:40 -0400 Subject: [PATCH 04/14] chore (gitignore) add .vscode to file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7b6caf3..fb40b94 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,4 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ +.vscode/ \ No newline at end of file From fdc3cf991f53ac12e4b88b2f21cb5c45d5d64263 Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:15:21 -0400 Subject: [PATCH 05/14] refactor (cli): rename click group to project --- src/litestar_manage/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/litestar_manage/cli.py b/src/litestar_manage/cli.py index ce27380..2e64405 100644 --- a/src/litestar_manage/cli.py +++ b/src/litestar_manage/cli.py @@ -16,11 +16,11 @@ def is_project_initialized() -> bool: @click.group(cls=LitestarGroup) -def cli(): +def project(): pass -@cli.command(name="new", help="Initialize a new Litestar project.") +@project.command(name="new", help="Initialize a new Litestar project.") @option( "--app-name", type=str, @@ -52,7 +52,7 @@ def init_project(app_name: str, venv: str | None) -> None: init_venv(output_dir / "venv", builder, packages_to_install) -@cli.command(name="resource") +@project.command(name="resource") @option( "--resource-name", "-n", From ef05377b379572ce0cf1135db38dffb7c0fbb005 Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:16:31 -0400 Subject: [PATCH 06/14] test: fix missing module --- tests/test_renderer.py | 4 ++-- tests/test_resource.py | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_renderer.py b/tests/test_renderer.py index ff87a19..14a7dae 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -2,7 +2,7 @@ from click.testing import CliRunner from testfixtures import TempDirectory -from litestar_manage.cli import cli +from litestar_manage.cli import project from litestar_manage.renderer import RenderingContext, _render_jinja_dir from tests import TEMPLATE_DIR @@ -26,5 +26,5 @@ def test_render_jinja_dir(rendering_context: RenderingContext, runner: CliRunner assert (temp_path / "tests").exists() assert (temp_path / "src" / "main.py").exists() - result = runner.invoke(cli, ["new", "--app-name", "TestApp"]) + result = runner.invoke(project, ["new", "--app-name", "TestApp"]) assert result.exit_code == 0 diff --git a/tests/test_resource.py b/tests/test_resource.py index de52104..9728228 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -4,7 +4,7 @@ from click.testing import CliRunner from testfixtures import TempDirectory -from litestar_manage.cli import cli +from litestar_manage.cli import project from litestar_manage.renderer import RenderingContext, _render_jinja_dir from tests import RESOURCE_DIR, TEMPLATE_DIR @@ -20,11 +20,10 @@ def runner() -> CliRunner: def create_mock_project_structure(temp_path: Path) -> Path: - # Initialize the project structure using _render_jinja_dir + ctx = RenderingContext(app_name="app_name") _render_jinja_dir(TEMPLATE_DIR, temp_path, ctx) - # Return the path to the generated src directory return temp_path / "src" @@ -70,7 +69,7 @@ def test_render_resource_dir_no_app(rendering_context: RenderingContext, runner: assert not (temp_path / "src" / "user" / "models.py").exists() expected = "Project already initialized." - result = runner.invoke(cli, ["new", "--app-name", "TestApp"]) + result = runner.invoke(project, ["new", "--app-name", "TestApp"]) assert result.exit_code == 0 assert expected in result.output From eb577a99b1f42e61e4386eac8eab9fccfa838bdd Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:22:52 -0400 Subject: [PATCH 07/14] style: run ruff format on the whole project --- Makefile | 5 +++-- pyproject.toml | 2 ++ tests/test_resource.py | 1 - tests/test_venv_builder.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 50fd597..a3884d9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Variables PYTHON := pdm run python PYTEST := pdm run pytest -BLACK := pdm run black +RUFF := pdm run ruff format FIND := find # Directories @@ -14,7 +14,8 @@ TEST_DIR := tests #Format the files format: - $(BLACK) $(SRC_DIR) + $(RUFF) $(SRC_DIR) + $(RUFF) $(TEST_DIR) # Clean target to delete __pycache__ directories clean: diff --git a/pyproject.toml b/pyproject.toml index 914316c..60c7476 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -150,6 +150,8 @@ lint.ignore = [ "PT", "TD", "PERF203", # ignore for now; investigate + "COM812", + "ISC001" ] lint.select = ["ALL"] # Allow unused variables when underscore-prefixed. diff --git a/tests/test_resource.py b/tests/test_resource.py index 9728228..47ed96f 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -20,7 +20,6 @@ def runner() -> CliRunner: def create_mock_project_structure(temp_path: Path) -> Path: - ctx = RenderingContext(app_name="app_name") _render_jinja_dir(TEMPLATE_DIR, temp_path, ctx) diff --git a/tests/test_venv_builder.py b/tests/test_venv_builder.py index 18c0256..0b1d27b 100644 --- a/tests/test_venv_builder.py +++ b/tests/test_venv_builder.py @@ -9,7 +9,7 @@ def test_pip_venv_builder() -> None: with TempDirectory() as t: temp_path = t.as_path() builder = PipVenvBuilder(nopip=True) - builder.install_packages = MagicMock() # type: ignore[method-assign] + builder.install_packages = MagicMock() # type: ignore[method-assign] init_venv(temp_path, builder, ["litestar"]) assert builder.venv_path is not None From 83ee496c02b46db10b02c6666277ac4501f6e0fc Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:41:16 -0400 Subject: [PATCH 08/14] refactor (cli): factor out the virtual environment name into a constant --- src/litestar_manage/cli.py | 3 ++- src/litestar_manage/constants.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/litestar_manage/constants.py diff --git a/src/litestar_manage/cli.py b/src/litestar_manage/cli.py index 2e64405..05192e6 100644 --- a/src/litestar_manage/cli.py +++ b/src/litestar_manage/cli.py @@ -6,6 +6,7 @@ from click import group, option from litestar.cli._utils import LitestarGroup +from litestar_manage.constants import VENV_NAME from litestar_manage.renderer import RenderingContext, render_template from litestar_manage.venv_builder import PipVenvBuilder, init_venv @@ -49,7 +50,7 @@ def init_project(app_name: str, venv: str | None) -> None: packages_to_install = ["litestar"] if venv == "pip": builder = PipVenvBuilder() - init_venv(output_dir / "venv", builder, packages_to_install) + init_venv(output_dir / VENV_NAME, builder, packages_to_install) @project.command(name="resource") diff --git a/src/litestar_manage/constants.py b/src/litestar_manage/constants.py new file mode 100644 index 0000000..143c33b --- /dev/null +++ b/src/litestar_manage/constants.py @@ -0,0 +1 @@ +VENV_NAME = ".venv" From 1a666c057673f2fe1ea8e64c8f618f3c3c22392d Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Tue, 10 Sep 2024 14:49:49 -0400 Subject: [PATCH 09/14] chore: remove ruff_cache --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fb40b94..2f5d844 100644 --- a/.gitignore +++ b/.gitignore @@ -160,4 +160,5 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ -.vscode/ \ No newline at end of file +.vscode/ +.ruff_cache/ \ No newline at end of file From 62445a933e179a6b51cc0319bf8a301a2f6bd202 Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Fri, 13 Sep 2024 15:32:17 -0400 Subject: [PATCH 10/14] refactor(renderer): rename RenderingContext to AppRenderingContext --- src/litestar_manage/cli.py | 6 +++--- src/litestar_manage/renderer.py | 6 +++--- tests/test_renderer.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/litestar_manage/cli.py b/src/litestar_manage/cli.py index 05192e6..08ed200 100644 --- a/src/litestar_manage/cli.py +++ b/src/litestar_manage/cli.py @@ -7,7 +7,7 @@ from litestar.cli._utils import LitestarGroup from litestar_manage.constants import VENV_NAME -from litestar_manage.renderer import RenderingContext, render_template +from litestar_manage.renderer import AppRenderingContext, render_template from litestar_manage.venv_builder import PipVenvBuilder, init_venv @@ -44,7 +44,7 @@ def init_project(app_name: str, venv: str | None) -> None: click.echo("Project already initialized.") return - ctx = RenderingContext(app_name=app_name) + ctx = AppRenderingContext(app_name=app_name) render_template(template_dir, output_dir, ctx, run_ruff=True) packages_to_install = ["litestar"] @@ -69,6 +69,6 @@ def generate_resource(resource_name: str) -> None: template_dir = Path(__file__).parent / "templates" / "resource" output_dir = Path.cwd() / "src" / f"{resource_name.lower()}" - ctx = RenderingContext(app_name=resource_name) + ctx = ResourceRenderingContext(app_name=resource_name) render_template(template_dir, output_dir, ctx, run_ruff=True) diff --git a/src/litestar_manage/renderer.py b/src/litestar_manage/renderer.py index f87e4f3..c3b4782 100644 --- a/src/litestar_manage/renderer.py +++ b/src/litestar_manage/renderer.py @@ -14,7 +14,7 @@ def render_template( template_dir: Path, output_dir: Path, - ctx: RenderingContext, + ctx: AppRenderingContext, run_ruff: bool = True, ) -> None: """Renders a template from template_dir to output_dir using the provided context. @@ -36,7 +36,7 @@ def render_template( @dataclass -class RenderingContext: +class AppRenderingContext: """Context for rendering an application template.""" app_name: str @@ -45,7 +45,7 @@ class RenderingContext: def _render_jinja_dir( input_directory: Path, output_directory: Path, - ctx: RenderingContext, + ctx: AppRenderingContext, ) -> list[Path]: """Recursively renders all files in the input directory to the output directory, while preserving the file-tree structure. Returns the list of paths to the created files. diff --git a/tests/test_renderer.py b/tests/test_renderer.py index 14a7dae..bb02e1a 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -3,13 +3,13 @@ from testfixtures import TempDirectory from litestar_manage.cli import project -from litestar_manage.renderer import RenderingContext, _render_jinja_dir +from litestar_manage.renderer import AppRenderingContext, _render_jinja_dir from tests import TEMPLATE_DIR @pytest.fixture -def rendering_context() -> RenderingContext: - return RenderingContext(app_name="TestApp") +def rendering_context() -> AppRenderingContext: + return AppRenderingContext(app_name="TestApp") @pytest.fixture @@ -17,7 +17,7 @@ def runner() -> CliRunner: return CliRunner() -def test_render_jinja_dir(rendering_context: RenderingContext, runner: CliRunner) -> None: +def test_render_jinja_dir(rendering_context: AppRenderingContext, runner: CliRunner) -> None: with TempDirectory() as t: temp_path = t.as_path() _render_jinja_dir(TEMPLATE_DIR, temp_path, rendering_context) From 65a20c00ca2c069587df11a7321ae702aad7fa9a Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Fri, 13 Sep 2024 15:38:38 -0400 Subject: [PATCH 11/14] feat (ResourceRenderingContext): add Resource datacclass --- src/litestar_manage/cli.py | 4 ++-- src/litestar_manage/renderer.py | 12 ++++++++++-- .../templates/resource/controller.py.jinja2 | 4 ++-- src/litestar_manage/templates/resource/dto.py.jinja2 | 6 +++--- .../templates/resource/models.py.jinja2 | 4 ++-- .../templates/resource/repository.py.jinja2 | 6 +++--- .../templates/resource/service.py.jinja2 | 12 ++++++------ tests/test_resource.py | 12 ++++++------ 8 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/litestar_manage/cli.py b/src/litestar_manage/cli.py index 08ed200..07e73e9 100644 --- a/src/litestar_manage/cli.py +++ b/src/litestar_manage/cli.py @@ -7,7 +7,7 @@ from litestar.cli._utils import LitestarGroup from litestar_manage.constants import VENV_NAME -from litestar_manage.renderer import AppRenderingContext, render_template +from litestar_manage.renderer import AppRenderingContext, ResourceRenderingContext, render_template from litestar_manage.venv_builder import PipVenvBuilder, init_venv @@ -69,6 +69,6 @@ def generate_resource(resource_name: str) -> None: template_dir = Path(__file__).parent / "templates" / "resource" output_dir = Path.cwd() / "src" / f"{resource_name.lower()}" - ctx = ResourceRenderingContext(app_name=resource_name) + ctx = ResourceRenderingContext(resource_name=resource_name) render_template(template_dir, output_dir, ctx, run_ruff=True) diff --git a/src/litestar_manage/renderer.py b/src/litestar_manage/renderer.py index c3b4782..e99a6d0 100644 --- a/src/litestar_manage/renderer.py +++ b/src/litestar_manage/renderer.py @@ -7,6 +7,7 @@ import sysconfig from dataclasses import dataclass from pathlib import Path +from typing import Union from jinja2 import Template @@ -14,7 +15,7 @@ def render_template( template_dir: Path, output_dir: Path, - ctx: AppRenderingContext, + ctx: Union[AppRenderingContext, ResourceRenderingContext], run_ruff: bool = True, ) -> None: """Renders a template from template_dir to output_dir using the provided context. @@ -42,10 +43,17 @@ class AppRenderingContext: app_name: str +@dataclass +class ResourceRenderingContext: + """Context for rendering resource (controller, service, dto, model and repository).""" + + resource_name: str + + def _render_jinja_dir( input_directory: Path, output_directory: Path, - ctx: AppRenderingContext, + ctx: Union[AppRenderingContext, ResourceRenderingContext], ) -> list[Path]: """Recursively renders all files in the input directory to the output directory, while preserving the file-tree structure. Returns the list of paths to the created files. diff --git a/src/litestar_manage/templates/resource/controller.py.jinja2 b/src/litestar_manage/templates/resource/controller.py.jinja2 index 7846bbb..a34276b 100644 --- a/src/litestar_manage/templates/resource/controller.py.jinja2 +++ b/src/litestar_manage/templates/resource/controller.py.jinja2 @@ -1,6 +1,6 @@ from litestar.controller import Controller -class {{app_name.capitalize()}}Controller(Controller): - """{{app_name.capitalize()}} Controller""" +class {{resource_name.capitalize()}}Controller(Controller): + """{{resource_name.capitalize()}} Controller""" pass \ No newline at end of file diff --git a/src/litestar_manage/templates/resource/dto.py.jinja2 b/src/litestar_manage/templates/resource/dto.py.jinja2 index 610dd0d..32099fc 100644 --- a/src/litestar_manage/templates/resource/dto.py.jinja2 +++ b/src/litestar_manage/templates/resource/dto.py.jinja2 @@ -1,10 +1,10 @@ from advanced_alchemy.extensions.litestar.dto import SQLAlchemyDTO, SQLAlchemyDTOConfig -from src.{{app_name.lower()}}.models import {{app_name.capitalize()}} +from src.{{resource_name.lower()}}.models import {{resource_name.capitalize()}} -class {{app_name.capitalize()}}DTO(SQLAlchemyDTO[{{app_name.capitalize()}}]): +class {{resource_name.capitalize()}}DTO(SQLAlchemyDTO[{{resource_name.capitalize()}}]): """ - {{app_name.capitalize()}} DTO + {{resource_name.capitalize()}} DTO """ config = SQLAlchemyDTOConfig() diff --git a/src/litestar_manage/templates/resource/models.py.jinja2 b/src/litestar_manage/templates/resource/models.py.jinja2 index 5e874ee..f17ce3e 100644 --- a/src/litestar_manage/templates/resource/models.py.jinja2 +++ b/src/litestar_manage/templates/resource/models.py.jinja2 @@ -2,6 +2,6 @@ from litestar.contrib.sqlalchemy.base import BigIntAuditBase from sqlalchemy.orm import Mapped, mapped_column, relationship -class {{app_name.capitalize()}}(BigIntAuditBase): - """{{app_name.capitalize()}} in DB model""" +class {{resource_name.capitalize()}}(BigIntAuditBase): + """{{resource_name.capitalize()}} in DB model""" pass \ No newline at end of file diff --git a/src/litestar_manage/templates/resource/repository.py.jinja2 b/src/litestar_manage/templates/resource/repository.py.jinja2 index 447f11c..7d65188 100644 --- a/src/litestar_manage/templates/resource/repository.py.jinja2 +++ b/src/litestar_manage/templates/resource/repository.py.jinja2 @@ -1,7 +1,7 @@ from litestar.contrib.sqlalchemy.repository import SQLAlchemyAsyncRepository -class {{app_name.capitalize()}}Repository(SQLAlchemyAsyncRepository[{{app_name.capitalize()}}]): # pylint: disable=duplicate-bases - """{{app_name.capitalize()}} SQLAlchemy Repository.""" +class {{resource_name.capitalize()}}Repository(SQLAlchemyAsyncRepository[{{resource_name.capitalize()}}]): # pylint: disable=duplicate-bases + """{{resource_name.capitalize()}} SQLAlchemy Repository.""" - model_type = {{app_name.capitalize()}} \ No newline at end of file + model_type = {{resource_name.capitalize()}} \ No newline at end of file diff --git a/src/litestar_manage/templates/resource/service.py.jinja2 b/src/litestar_manage/templates/resource/service.py.jinja2 index 37a5f75..3078d77 100644 --- a/src/litestar_manage/templates/resource/service.py.jinja2 +++ b/src/litestar_manage/templates/resource/service.py.jinja2 @@ -1,13 +1,13 @@ from advanced_alchemy.service import SQLAlchemyAsyncRepositoryService -from src.{{app_name.lower()}}.repository import {{app_name.capitalize()}}Repository -from src.{{app_name.lower()}}.models import {{app_name.capitalize()}} +from src.{{resource_name.lower()}}.repository import {{resource_name.capitalize()}}Repository +from src.{{resource_name.lower()}}.models import {{resource_name.capitalize()}} from typing import Any -class {{app_name.capitalize()}}Service(SQLAlchemyAsyncRepositoryService[{{app_name.capitalize()}}]): - """ {{app_name.capitalize()}} Service""" +class {{resource_name.capitalize()}}Service(SQLAlchemyAsyncRepositoryService[{{resource_name.capitalize()}}]): + """ {{resource_name.capitalize()}} Service""" - repository_type = {{app_name.capitalize()}}Repository + repository_type = {{resource_name.capitalize()}}Repository def __init__(self, **repo_kwargs: Any) -> None: - self.repository: {{app_name.capitalize()}}Repository = self.repository_type(**repo_kwargs) #type ignore + self.repository: {{resource_name.capitalize()}}Repository = self.repository_type(**repo_kwargs) #type ignore self.model_type = self.repository.model_type \ No newline at end of file diff --git a/tests/test_resource.py b/tests/test_resource.py index 47ed96f..8b61104 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -5,13 +5,13 @@ from testfixtures import TempDirectory from litestar_manage.cli import project -from litestar_manage.renderer import RenderingContext, _render_jinja_dir +from litestar_manage.renderer import AppRenderingContext, ResourceRenderingContext, _render_jinja_dir from tests import RESOURCE_DIR, TEMPLATE_DIR @pytest.fixture -def rendering_context() -> RenderingContext: - return RenderingContext(app_name="User") +def rendering_context() -> ResourceRenderingContext: + return ResourceRenderingContext(resource_name="User") @pytest.fixture @@ -20,13 +20,13 @@ def runner() -> CliRunner: def create_mock_project_structure(temp_path: Path) -> Path: - ctx = RenderingContext(app_name="app_name") + ctx = AppRenderingContext(app_name="app_name") _render_jinja_dir(TEMPLATE_DIR, temp_path, ctx) return temp_path / "src" -def test_render_resource_dir(rendering_context: RenderingContext) -> None: +def test_render_resource_dir(rendering_context: ResourceRenderingContext) -> None: with TempDirectory() as t: temp_path = t.as_path() @@ -53,7 +53,7 @@ def test_render_resource_dir(rendering_context: RenderingContext) -> None: assert (temp_path / "src" / "user" / "models.py").exists() -def test_render_resource_dir_no_app(rendering_context: RenderingContext, runner: CliRunner) -> None: +def test_render_resource_dir_no_app(rendering_context: ResourceRenderingContext, runner: CliRunner) -> None: with TempDirectory() as t: temp_path = t.as_path() From f99b690ac5d90f41a6cdc6c78b497a88fa68734b Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Fri, 13 Sep 2024 15:50:53 -0400 Subject: [PATCH 12/14] refactor (test): rename constants variables in tests folder --- tests/__init__.py | 4 ++-- tests/test_resource.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 63a9345..4003eaf 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,4 +1,4 @@ from pathlib import Path -TEMPLATE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "templates" / "app" -RESOURCE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "templates" / "resource" +APP_TEMPLATE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "templates" / "app" +RESOURCE_TEMPLATE_DIR = Path(__file__).parent.parent / "src" / "litestar_manage" / "templates" / "resource" diff --git a/tests/test_resource.py b/tests/test_resource.py index 8b61104..4a9c4bd 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -6,7 +6,7 @@ from litestar_manage.cli import project from litestar_manage.renderer import AppRenderingContext, ResourceRenderingContext, _render_jinja_dir -from tests import RESOURCE_DIR, TEMPLATE_DIR +from tests import RESOURCE_TEMPLATE_DIR, APP_TEMPLATE_DIR @pytest.fixture @@ -21,7 +21,7 @@ def runner() -> CliRunner: def create_mock_project_structure(temp_path: Path) -> Path: ctx = AppRenderingContext(app_name="app_name") - _render_jinja_dir(TEMPLATE_DIR, temp_path, ctx) + _render_jinja_dir(APP_TEMPLATE_DIR, temp_path, ctx) return temp_path / "src" @@ -36,7 +36,7 @@ def test_render_resource_dir(rendering_context: ResourceRenderingContext) -> Non assert src_path.exists() - _render_jinja_dir(RESOURCE_DIR, temp_path / resource_path, rendering_context) + _render_jinja_dir(RESOURCE_TEMPLATE_DIR, temp_path / resource_path, rendering_context) assert (temp_path / "src").exists() assert (temp_path / "tests").exists() @@ -57,7 +57,7 @@ def test_render_resource_dir_no_app(rendering_context: ResourceRenderingContext, with TempDirectory() as t: temp_path = t.as_path() - _render_jinja_dir(RESOURCE_DIR, temp_path, rendering_context) + _render_jinja_dir(RESOURCE_TEMPLATE_DIR, temp_path, rendering_context) assert not (temp_path / "src").exists() assert not (temp_path / "src" / "user" / "__init__.py").exists() From 983744812e8688a7be171407aae4a7f91d269754 Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Fri, 13 Sep 2024 15:52:04 -0400 Subject: [PATCH 13/14] refactor (test_renderer): fix typo --- tests/test_renderer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_renderer.py b/tests/test_renderer.py index bb02e1a..7bf218f 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -4,7 +4,7 @@ from litestar_manage.cli import project from litestar_manage.renderer import AppRenderingContext, _render_jinja_dir -from tests import TEMPLATE_DIR +from tests import APP_TEMPLATE_DIR @pytest.fixture @@ -20,7 +20,7 @@ def runner() -> CliRunner: def test_render_jinja_dir(rendering_context: AppRenderingContext, runner: CliRunner) -> None: with TempDirectory() as t: temp_path = t.as_path() - _render_jinja_dir(TEMPLATE_DIR, temp_path, rendering_context) + _render_jinja_dir(APP_TEMPLATE_DIR, temp_path, rendering_context) assert (temp_path / "src").exists() assert (temp_path / "tests").exists() From 0831c8ed67b72c00861863ef4acf31cbb47f255e Mon Sep 17 00:00:00 2001 From: Agustin Arce Date: Fri, 13 Sep 2024 16:26:24 -0400 Subject: [PATCH 14/14] refactor (__main__): fix typo --- src/litestar_manage/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/litestar_manage/__main__.py b/src/litestar_manage/__main__.py index bf259b9..4ab8040 100644 --- a/src/litestar_manage/__main__.py +++ b/src/litestar_manage/__main__.py @@ -12,7 +12,7 @@ def run_cli() -> None: """Application Entrypoint.""" import sys - from litestar_manage.cli import project_group + from litestar_manage.cli import project try: from litestar.__main__ import run_cli as run_litestar_cli @@ -26,7 +26,7 @@ def run_cli() -> None: print(exc) # noqa: T201 sys.exit(1) else: - litestar_group.add_command(cast(RichCommand, project_group)) + litestar_group.add_command(cast(RichCommand, project)) run_litestar_cli()