diff --git a/.github/workflows/cli_test.yaml b/.github/workflows/cli_test.yaml index d03d81d..c543e6a 100644 --- a/.github/workflows/cli_test.yaml +++ b/.github/workflows/cli_test.yaml @@ -30,37 +30,38 @@ jobs: - name: Test CLI Commands run: | + pynest_cmd="$GITHUB_WORKSPACE/.venv/bin/pynest" app_name="${{ matrix.app_type }}App" case "${{ matrix.app_type }}" in "Blank") - uv run pynest generate application -n "$app_name" + "$pynest_cmd" generate application -n "$app_name" ;; "SyncORM") - uv run pynest generate application -n "$app_name" -db sqlite + "$pynest_cmd" generate application -n "$app_name" -db sqlite ;; "AsyncORM") - uv run pynest generate application -n "$app_name" -db sqlite --is-async + "$pynest_cmd" generate application -n "$app_name" -db sqlite --is-async ;; "MongoDB") - uv run pynest generate application -n "$app_name" -db mongodb + "$pynest_cmd" generate application -n "$app_name" -db mongodb ;; "PostgresSync") - uv run pynest generate application -n "$app_name" -db postgresql + "$pynest_cmd" generate application -n "$app_name" -db postgresql ;; "PostgresAsync") - uv run pynest generate application -n "$app_name" -db postgresql --is-async + "$pynest_cmd" generate application -n "$app_name" -db postgresql --is-async ;; "MySQLSync") - uv run pynest generate application -n "$app_name" -db mysql + "$pynest_cmd" generate application -n "$app_name" -db mysql ;; "MySQLAsync") - uv run pynest generate application -n "$app_name" -db mysql --is-async + "$pynest_cmd" generate application -n "$app_name" -db mysql --is-async ;; esac cd "$app_name" - uv run pynest generate resource -n user - uv run pynest generate gateway -n chat -p src + "$pynest_cmd" generate resource -n user + "$pynest_cmd" generate gateway -n chat -p src - name: Verify Boilerplate run: | @@ -79,7 +80,7 @@ jobs: exit 1 fi - declare -a files=("main.py" "requirements.txt" "README.md") + declare -a files=("main.py" "pyproject.toml" "README.md" ".pynest.yaml") declare -a src_level_files=("app_module.py" "app_service.py" "app_controller.py") declare -a module_files=("user_controller.py" "user_service.py" "user_module.py" "user_model.py") @@ -121,14 +122,13 @@ jobs: echo "$gateway_file is missing the expected @WebSocketGateway decorator." exit 1 fi - echo "Boilerplate for ${{ matrix.app_type }} generated successfully." - name: Ping generated WebSocket app if: matrix.app_type == 'Blank' run: | cd "${{ matrix.app_type }}App" - uv run python - <<'PY' + uv run --project "$GITHUB_WORKSPACE" python - <<'PY' import asyncio import importlib.util import json diff --git a/README.md b/README.md index e933201..415bda4 100644 --- a/README.md +++ b/README.md @@ -41,19 +41,21 @@ pip install pynest-api ### Start with cli ```bash -pynest generate application -n my_app_name +pynest new my_app_name ``` this command will create a new project with the following structure: ```text -├── app.py +├── .pynest.yaml ├── main.py -├── requirements.txt -├── .gitignore +├── pyproject.toml ├── README.md ├── src │ ├── __init__.py +│ ├── app_module.py +│ ├── app_controller.py +│ ├── app_service.py ``` once you have created your app, get into the folder and run the following command: @@ -65,7 +67,8 @@ cd my_app_name run the server with the following command: ```bash -uvicorn "app:app" --host "0.0.0.0" --port "8000" --reload +uv sync +python main.py ``` Now you can visit [OpenAPI](http://localhost:8000/docs) in your browser to see the default API documentation. @@ -75,7 +78,7 @@ Now you can visit [OpenAPI](http://localhost:8000/docs) in your browser to see t To add a new module to your application, you can use the pynest generate module command: ```bash -pynest generate resource -n users +pynest add resource users ``` This will create a new resource called ```users``` in your application with the following structure under the ```src``` @@ -108,15 +111,58 @@ and their descriptions: #### `generate application` Subcommand -- **Description**: Create a new nest app. +- **Description**: Create a new nest app. This command is still supported for compatibility; prefer `pynest new`. - **Options**: - `--app-name`/`-n`: The name of the nest app (required). - `--db-type`/`-db`: The type of the database (optional). You can specify PostgreSQL, MySQL, SQLite, or MongoDB. - `--is-async`: Whether the project should be asynchronous (optional, default is False). + - `--package-manager`: Use `uv` by default, or `requirements` when explicitly requested. + - `--json`: Output structured JSON for agents and scripts. + - `--dry-run`: Show the generation plan without writing files. + +#### `new` Subcommand + +- **Description**: Create a new PyNest application. It supports guided prompts for humans and one-shot flags for agents. +- **Examples**: + - Guided human flow: `pynest new --prompt` + - Default API app: `pynest new my_app_name` + - Agent-friendly JSON flow: `pynest new my_app_name --preset api --database sqlite --async --yes --json` +- **Options**: + - `--preset`: `api` or `cli` (default: `api`). + - `--database`: `none`, `sqlite`, `postgresql`, `mysql`, or `mongodb` (default: `none`). + - `--async`: Use async database access for relational databases. + - `--path`: Parent directory for the new app. + - `--package-manager`: `uv` or `requirements` (default: `uv`). + - `--prompt`: Force guided prompts. + - `--yes`: Accept defaults and skip prompts. + - `--json`: Output structured JSON only. + - `--dry-run`: Show the plan without writing files. + +Generated dependency files use granular PyNest extras. For example, an async SQLite HTTP app depends on +`pynest-api[http,sqlite-async]`, which installs the HTTP stack and the SQLite async ORM stack together. + +### `add` command group + +- **Description**: Add boilerplate code to an existing PyNest application. + +#### `resource` Subcommand + +- **Description**: Add a new module with controller, service, model, and module files. Database apps also get an entity file. +- **Options**: + - `NAME`: The resource name. + - `--path`: Target app or source directory. + - `--json`: Output structured JSON. + - `--dry-run`: Show the plan without writing files. + +Example: + +```bash +pynest add resource users +``` ### `generate` command group -- **Description**: Group command for generating boilerplate code. +- **Description**: Compatibility command group for older PyNest projects and scripts. #### `resource` Subcommand @@ -127,13 +173,16 @@ and their descriptions: #### CLI Examples * create a blank nest application - - `pynest generate application -n my_app_name` + `pynest new my_app_name` * create a nest application with postgres database and async connection - - `pynest generate application -n my_app_name -db postgresql --is-async` + `pynest new my_app_name --database postgresql --async` * create new module - - `pynest generate resource -n users` + `pynest add resource users` + +* run a project health check - + `pynest doctor` ## Key Features diff --git a/docs/cli.md b/docs/cli.md index c435c92..02c4830 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,179 +1,141 @@ -# PyNest CLI Deep Dive 🔍 +# PyNest CLI -The PyNest CLI is a powerful tool that helps you quickly scaffold, develop, and manage your PyNest applications. This guide will walk you through all the commands and best practices to make the most out of the PyNest CLI. - -## Installation 💻 - -Before using the PyNest CLI, ensure you have it installed. You can install it using pip: +The PyNest CLI scaffolds applications and common application components. The primary command surface is: ```bash -pip install pynest-api +pynest new my_app +pynest add resource users +pynest add gateway chat +pynest doctor ``` -## CLI Commands and Usage 🛠️ -The PyNest CLI provides a variety of commands to help you create and manage your PyNest applications. Below are the detailed descriptions of the available commands and their usage. +Older `pynest generate ...` commands still work for compatibility. -### Generate New Application -Create a new PyNest application. +## Install ```bash -pynest generate application --app-name [--db-type ] [--is-async] -``` -**Options** - -* `--app-name`, `-n`: The name of the new application. (Required) -* `--db-type`, `-db`: The type of database to use (postgresql, mysql, sqlite, mongodb). (Optional) -* `--is-async`: Whether the project should be async or not. This is applicable only for relational databases. (Optional) -* `--is-cli`: Whether the project should be a CLI App. (Optional) - -#### Example -```bash -pynest generate application --app-name my_pynest_app --db-type postgresql --is-async +pip install pynest-api ``` -This example will create a skeleton PyNest application named `my_pynest_app` with PostgreSQL as the database and async support. +## Create An Application -#### File Structure 🗂️ -Here's the typical file structure of a PyNest application generated by the CLI: +For a guided human flow: -```text -my_pynest_app/ -├── src/ -│ ├── __init__.py -│ ├── app_module.py -│ ├── app_controller.py -│ ├── app_service.py -│ ├── config.py -├── main.py -├── requirements.txt -└── README.md +```bash +pynest new --prompt ``` -!Note: The actual file structure may vary based on the modules and components you create - - -### generate command -Generate boilerplate code for various components of the application. - -#### Subcommands - -**Resource** -Generate a new resource with the associated controller, service, model and module files, with respect to the project configurations (e.g. database type). +For a direct command: ```bash -pynest generate resource --name +pynest new my_app ``` -**Options** - +For an agent or script: -* `--name`, `-n`: The name of the new module. (Required) -* `--path`, `-p`: The path where the module should be created. (Optional) - -**Example** ```bash -pynest generate resource --name users +pynest new my_app --preset api --database sqlite --async --yes --json ``` -This will create a new resource named `users` with the associated controller, service, model and module files. - +Useful options: -**Module** +- `--preset api|cli`: choose an HTTP API app or CLI app. Default: `api`. +- `--database none|sqlite|postgresql|mysql|mongodb`: add database scaffolding. Default: `none`. +- `--async`: use async database access for relational databases. +- `--path PATH`: parent directory where the app should be created. +- `--package-manager uv|requirements`: choose generated dependency files. Default: `uv`. +- `--prompt`: force guided prompts. +- `--yes`: accept defaults and skip prompts. +- `--dry-run`: show the plan without writing files. +- `--json`: emit machine-readable JSON only. +- `--quiet`: suppress human output. +- `--force`: overwrite supported files. -Generate a new module file, which can be used to group related components of the application. +Generated API apps include: -```bash -pynest generate module --name -``` - -**Options** +```text +my_app/ +├── .pynest.yaml +├── main.py +├── README.md +├── pyproject.toml +└── src/ + ├── __init__.py + ├── app_module.py + ├── app_controller.py + └── app_service.py +``` -* `--name`, `-n`: The name of the new module. (Required) -* `--path`, `-p`: The path where the module should be created. (Optional) +Database apps also include `src/config.py`, `.env.example`, and database-specific requirements. -**Example** -```bash -pynest generate module --name auth -``` +PyNest uses `uv` by default and writes `pyproject.toml`. Use `--package-manager requirements` only when you need a legacy `requirements.txt` workflow. -This will create a new module named `auth` in the default path. +Generated dependency files use granular PyNest extras so the selected app stack resolves as one dependency: -**Controller** +- Blank HTTP app: `pynest-api[http]` +- Async SQLite HTTP app: `pynest-api[http,sqlite-async]` +- Sync PostgreSQL HTTP app: `pynest-api[http,postgresql]` +- CLI app: `pynest-api[cli]` -Generate a new controller file, which will handle the routing and responses for a specific resource. +Prompt mode also asks for package management: -```bash -pynest generate controller --name +```text +Package manager: + 1. uv + 2. requirements.txt +Choose package manager [1]: ``` -**Options** +## Add Components -* `--name`, `-n`: The name of the new controller. (Required) -* `--path`, `-p`: The path where the controller should be created. (Optional) +Run these commands inside a PyNest application, or pass `--path` to the app root. -**Example** ```bash -pynest generate controller --name users +pynest add resource users +pynest add module auth +pynest add controller users +pynest add service users +pynest add gateway chat ``` -This will create a new controller named `users` in the default path. +Shared options: -**Service** +- `--path PATH`: target app or source directory. +- `--dry-run`: show the plan without writing files. +- `--json`: emit machine-readable JSON only. +- `--quiet`: suppress human output. +- `--force`: overwrite supported files. -Generate a new service file, which will contain the business logic for a specific resource. +`pynest add` reads `.pynest.yaml` so generated resources match the app preset, database, and async settings. -```bash -pynest generate service --name -``` +`pynest add gateway ` creates a small package under `src//` (`__init__.py`, `_gateway.py`, `_module.py` with the gateway in `providers`), and registers `Module` in `src/app_module.py` — same pattern as `add resource`, without HTTP CRUD files. -**Options** +## Check A Project -* `--name`, `-n`: The name of the new service. (Required) -* `--path`, `-p`: The path where the service should be created. (Optional) - -**Example** ```bash -pynest generate service --name users +pynest doctor ``` -This will create a new service named `users` in the default path. - -**Gateway** - -Generate a new WebSocket gateway file. +`doctor` checks project metadata and source layout. For agents: ```bash -pynest generate gateway --name +pynest doctor --json ``` -**Options** +## Compatibility Commands -* `--name`, `-n`: The name of the new gateway. (Required) -* `--path`, `-p`: The path where the gateway should be created. (Optional) +These commands are still supported: -**Example** ```bash -pynest generate gateway --name chat +pynest generate application -n my_app +pynest generate resource -n users +pynest generate module -n auth +pynest generate controller -n users +pynest generate service -n users +pynest generate gateway -n chat ``` -This creates `chat_gateway.py` with a starter `@WebSocketGateway(namespace="/chat")` class and a `ping` message handler. Add the generated gateway to a module's `providers` list to mount it. - - -## Best Practices 🌟 - -To ensure a clean and maintainable codebase, follow these best practices when using the PyNest CLI: - -* **Consistent Naming Conventions**: Use consistent naming conventions for files and directories. For example, use lowercase with underscores for module names (users_module.py) and camelCase for class names (UsersController)._ - -* **Modular Structure**: Keep your code modular. Each module should encapsulate a specific functionality of your application. - -* **Service Layer**: Keep business logic within services to maintain separation of concerns. Controllers should handle HTTP requests and responses only. - -* **Dependency Injection**: Use dependency injection to manage dependencies between services and controllers. This makes your code more testable and maintainable. - -* **Environment Configuration**: Use environment variables to manage configuration settings, such as database connection strings and API keys. - -The PyNest CLI is a powerful tool that simplifies the development of PyNest applications. By following the best practices and utilizing the commands effectively, you can build scalable and maintainable applications with ease. Happy coding! +Compatibility commands also support `--json` and `--dry-run` where applicable. ---