Skip to content

Commit 442f7b5

Browse files
authored
Merge pull request #171 from python-ellar/drop_storage
Drop file storage
2 parents df6ce17 + 8459b29 commit 442f7b5

31 files changed

+435
-693
lines changed
File renamed without changes.

docs/cli/command-grouping.md

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +0,0 @@
1-
# **Command Grouping**
2-
Ella CLI provides a way by which commands can be grouped.
3-
4-
For instance, a `db` command may have sub-commands like `makemigrations`, `migrate`, `reset-db` etc.
5-
6-
To achieve this use-case, let us create a file `commands.py` in the root level of the project.
7-
8-
```python
9-
from ellar.common import EllarTyper
10-
11-
db = EllarTyper(name="db")
12-
13-
14-
@db.command(name="make-migrations")
15-
def makemigrations():
16-
"""Create DB Migration """
17-
18-
@db.command()
19-
def migrate():
20-
"""Applies Migrations"""
21-
```
22-
23-
## **Register EllarTyper Command**
24-
25-
Lets, make the `db` visible on the CLI.
26-
27-
In other for Ellar CLI to identify custom command, its has to be registered to a `@Module` class.
28-
29-
```python
30-
from ellar.common import Module
31-
from ellar.core import ModuleBase
32-
from .commands import db
33-
34-
@Module(commands=[db])
35-
class ApplicationModule(ModuleBase):
36-
pass
37-
```
38-
39-
open your terminal and navigate to project directory and run the command below
40-
```shell
41-
ellar db --help
42-
```
43-
44-
command output
45-
```shell
46-
Usage: Ellar, Python Web framework db [OPTIONS] COMMAND [ARGS]...
47-
48-
Options:
49-
--help Show this message and exit.
50-
51-
Commands:
52-
make-migrations Create DB Migration
53-
migrate Applies Migrations
54-
55-
```

docs/cli/custom-commands.md

Lines changed: 153 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,192 @@
11
# **Custom Commands**
2-
In this section, we are going to go over how to create a custom command and throw more light on how Ella CLI works.
2+
In this section, we will guide you through the process of creating a command and explain why you
3+
should utilize `ellar_cli.click` as your primary Click package when working with Ellar.
4+
5+
6+
## **Command Options Arguments**
7+
The `ellar_cli.click` package offers comprehensive help messages and documentation for command options and arguments
8+
without compromising the fundamental functionality of the command.
9+
For instance:
10+
11+
```python
12+
import ellar_cli.click as click
13+
14+
@click.command()
15+
@click.argument("arg1", required=True, help="Arg1 description")
16+
@click.argument("arg2", required=False, help="Arg2 description")
17+
@click.option("-op1", required=False, help="option1 description")
18+
@click.option("-op2", required=False, help="option2 description")
19+
def my_command(arg1, arg2, op1, op2):
20+
print(f"ARG1={arg1} ARG2={arg2}; op1={op1} op2={op2}")
21+
```
22+
23+
When you register `my_command` to a `@Module` class, you can then execute it in your terminal with the following command:
24+
```shell
25+
ellar my-command --help
26+
27+
## OUTPUT
28+
29+
Usage: ellar my-command <arg1> [<arg2>] [OPTIONS]
30+
31+
ARGUMENTS:
32+
arg1: <arg1> Arg1 description [required]
33+
arg2: [<arg2>] Arg2 description
34+
35+
[OPTIONS]:
36+
-op1 TEXT option1 description
37+
-op2 TEXT option2 description
38+
--help Show this message and exit.
39+
```
40+
41+
## **With App Context Decorator**
42+
The `ellar_cli.click` module includes a command decorator function called `with_app_context`.
43+
This decorator ensures that a click command is executed within the application context,
44+
allowing `current_app`, `current_injector`, and `current_config` to have values.
45+
46+
For instance:
47+
48+
```python
49+
import ellar_cli.click as click
50+
from ellar.core import Config
51+
from ellar.app import current_injector
52+
53+
@click.command()
54+
@click.argument("arg1", required=True, help="Arg1 description")
55+
@click.with_app_context
56+
def command_context(arg1):
57+
config = current_injector.get(Config)
58+
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
59+
60+
@click.command()
61+
@click.argument("arg1", required=True, help="Arg1 description")
62+
def command_wc(arg1):
63+
config = current_injector.get(Config)
64+
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
65+
```
66+
67+
In this example, `command_context` is wrapped with `with_app_context`, while `command_wc` is not.
68+
When executing both commands, `command_context` will run successfully, and `command_wc` will raise a RuntimeError
69+
because it attempts to access a value outside the context.
70+
71+
## **AppContextGroup**
72+
`AppContextGroup` extended from `click.Group` to wrap all its commands with `with_app_context` decorator.
373

4-
## **Create Custom Command**
5-
Let's create a file called `commands.py` at the root level of the project.
674

775
```python
8-
# project_name/commands.py
76+
import ellar_cli.click as click
77+
from ellar.core import Config
78+
from ellar.app import current_injector
79+
80+
cm = click.AppContextGroup(name='cm')
81+
82+
@cm.command()
83+
@click.argument("arg1", required=True, help="Arg1 description")
84+
def command_context(arg1):
85+
config = current_injector.get(Config)
86+
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
987

10-
from ellar.common import command
1188

12-
@command
13-
def my_new_command():
14-
"""my_new_command cli description """
89+
@cm.command()
90+
@click.argument("arg1", required=True, help="Arg1 description")
91+
def command_wc(arg1):
92+
config = current_injector.get(Config)
93+
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
1594
```
95+
All commands registered under `cm` will be executed under within the context of the application.
1696

17-
## **Custom Command with Context**
97+
### **Disabling `with_app_context` in AppContextGroup**
98+
There are some cases where you may want to execute a command under `AppContextGroup` outside application context.
99+
This can be done by setting `with_app_context=False` as command parameter.
18100

19-
Ellar CLI tools is a wrapper round [typer](https://typer.tiangolo.com/).
20-
So, therefore, we can easily get the command context by adding a parameter with the annotation of `typer.Context`
101+
```python
102+
import ellar_cli.click as click
103+
104+
cm = click.AppContextGroup(name='cm')
21105

22-
Ellar CLI adds some meta-data CLI context that provides an interface for interaction with the Ellar project.
106+
@cm.command(with_app_context=False)
107+
@click.argument("arg1", required=True, help="Arg1 description")
108+
def command_wc(arg1):
109+
# config = current_injector.get(Config)
110+
print("ALLOWED_HOSTS:Unavailable;ELLAR_CONFIG_MODULE:Unavailable")
111+
```
23112

24-
For example:
113+
## Async Command
114+
The `ellar_cli.click` package provides a utility decorator function, `run_as_async`,
115+
specifically designed to execute coroutine commands.
116+
This is useful when you want to define asynchronous commands using the `click` package.
117+
Here's an example:
25118

26119
```python
27-
import typing as t
28-
import typer
29-
from ellar.common import command
30-
from ellar_cli.service import EllarCLIService
31-
from ellar_cli.constants import ELLAR_META
32-
33-
@command
34-
def my_new_command(ctx:typer.Context):
35-
"""my_new_command CLI Description """
36-
ellar_cli_service = t.cast(t.Optional[EllarCLIService], ctx.meta.get(ELLAR_META))
37-
app = ellar_cli_service.import_application()
120+
import ellar_cli.click as click
121+
from ellar.core import Config
122+
from ellar.app import current_injector
123+
124+
@click.command()
125+
@click.argument("arg1", required=True, help="Arg1 description")
126+
@click.with_app_context
127+
@click.run_as_async
128+
async def command_context(arg1):
129+
config = current_injector.get(Config)
130+
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
38131
```
39-
`EllarCLIService` is an Ellar CLI meta-data for interacting with Ellar project.
40132

41-
Some important method that may be of interest:
133+
In this example, the `run_as_async` decorator enables the `command_context` coroutine
134+
command to be executed appropriately during execution.
135+
136+
## **Custom Command With Ellar**
137+
Let's create a command group `db` which contains sub-commands such as `makemigrations`, `migrate`, `reset-db`, and so on.
138+
139+
To implement this scenario, let's create a file `commands.py` at the root level of the project and add the code below.
140+
```python
141+
from ellar_cli.click import AppContextGroup
142+
143+
db = AppContextGroup(name="db")
42144

43-
- `import_application`: returns application instance.
44-
- `get_application_config`: gets current application config.
45145

46-
## **Register a Custom Command**
146+
@db.command(name="make-migrations")
147+
def makemigrations():
148+
"""Create DB Migration """
47149

48-
Lets, make the `my_new_command` visible on the CLI.
49-
In other for Ellar CLI to identify custom command, its has to be registered to a `@Module` class.
150+
@db.command()
151+
def migrate():
152+
"""Applies Migrations"""
153+
```
154+
155+
### **Registering Command**
50156

51-
For example:
157+
To make the `db` command visible on the CLI, it **must** be registered within a `@Module` class.
158+
This ensures that the Ellar CLI can recognize and identify custom commands.
52159

53160
```python
54-
# project_name/root_module.py
55161
from ellar.common import Module
56162
from ellar.core import ModuleBase
57-
from .commands import my_new_command
163+
from .commands import db
58164

59-
@Module(commands=[my_new_command])
165+
@Module(commands=[db])
60166
class ApplicationModule(ModuleBase):
61167
pass
62168
```
63-
64-
open your terminal and navigate to project directory and run the command below
169+
Open your terminal and navigate to the project directory and run the command below
65170
```shell
66-
ellar --help
171+
ellar db --help
67172
```
68173

69174
command output
70175
```shell
71-
Usage: Ellar, Python Web framework [OPTIONS] COMMAND [ARGS]...
176+
Usage: Ellar, Python Web framework db [OPTIONS] COMMAND [ARGS]...
72177

73178
Options:
74-
-p, --project TEXT Run Specific Command on a specific project
75-
--install-completion [bash|zsh|fish|powershell|pwsh]
76-
Install completion for the specified shell.
77-
--show-completion [bash|zsh|fish|powershell|pwsh]
78-
Show completion for the specified shell, to
79-
copy it or customize the installation.
80-
--help Show this message and exit.
179+
--help Show this message and exit.
81180

82181
Commands:
83-
create-module - Scaffolds Ellar Application Module -
84-
create-project - Scaffolds Ellar Application -
85-
my-new-command - my_new_command cli description
86-
new - Runs a complete Ellar project scaffold and creates...
87-
runserver - Starts Uvicorn Server -
88-
say-hi
89-
```
90-
91-
## **Using Click Commands**
92-
If prefer click commands, Ellar-CLI supports that too. Simply create a click command and register it to any module registered in
93-
the `ApplicationModule`. For example
94-
95-
```python
96-
import click
97-
from ellar.common import JSONResponse, Module, Response, exception_handler
98-
from ellar.core import ModuleBase
99-
from ellar.core.connection import Request
182+
make-migrations Create DB Migration
183+
migrate Applies Migrations
100184

101-
@click.command()
102-
def say_hello():
103-
click.echo("Hello from ellar.")
185+
```
104186

187+
Having explored various methods for crafting commands and understanding the roles of `wrap_app_context` and `run_as_async` decorators,
188+
you now possess the knowledge to create diverse commands for your Ellar application.
105189

106-
@Module(commands=[say_hello])
107-
class ApplicationModule(ModuleBase):
108-
@exception_handler(404)
109-
def exception_404_handler(cls, request: Request, exc: Exception) -> Response:
110-
return JSONResponse({"detail": "Resource not found."})
111-
```
190+
It's crucial to keep in mind that any custom command you develop needs to be registered within a `@Module` class, which,
191+
in turn, should be registered with the `ApplicationModule`.
192+
This ensures that your commands are recognized and integrated into the Ellar application's command-line interface.

docs/cli/new-command.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,57 @@ path/to/scaffold-the-new-project/
5151

5252
## **New Command CLI Arguments**
5353
- `project-name` Set the resulting project module name.
54-
- `directory` Path to dump the scaffolded files. `.` can be used to select current directory.
54+
- `directory` Path to dump the scaffolded files. `.` can be used to select the current directory.
55+
56+
57+
## **New Project without pyproject requirement**
58+
To scaffold a new project without `pyproject.toml`, add `--plain` to the `ellar new command`. For example,
59+
60+
```shell
61+
ellar new my-project --plain
62+
```
63+
64+
This will create a folder as follows:
65+
```angular2html
66+
my-project/
67+
├─ my_project/
68+
│ ├─ apps/
69+
│ │ ├─ __init__.py
70+
│ ├─ core/
71+
│ ├─ config.py
72+
│ ├─ domain
73+
│ ├─ root_module.py
74+
│ ├─ server.py
75+
│ ├─ __init__.py
76+
├─ tests/
77+
│ ├─ __init__.py
78+
├─ manage.py
79+
├─ README.md
80+
```
81+
Inside the scaffolded project, the `manage.py` python file is not the entry point for the application.
82+
It creates a new CLI interface and uses that as the new CLI command to interact with the project.
83+
84+
```shell
85+
python manage.py
86+
87+
### OUTPUT
88+
89+
Usage: manage.py [OPTIONS] COMMAND [ARGS]...
90+
91+
Ellar, ASGI Python Web framework
92+
93+
Options:
94+
--project TEXT Run Specific Command on a specific project [default:
95+
default]
96+
-v, --version Show the version and exit.
97+
--help Show this message and exit.
98+
99+
Commands:
100+
create-module - Scaffolds Ellar Application Module -
101+
runserver - Starts Uvicorn Server -
102+
103+
```
104+
Other ellar commands and will be executed through `manage.py` python file. Eg:
105+
```shell
106+
python manage.py runserver
107+
```

docs/custom-setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Create a file `controller.py`:
1111
```Python
1212
from ellar.common import ModuleRouter, Controller, get
1313

14-
router = ModuleRouter('', tag='Math')
14+
router = ModuleRouter('')
1515

1616

1717
@router.get("/add")

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Ellar was deeply influenced by [NestJS](https://docs.nestjs.com/){target="_blank
2323
Also, Ellar took some concepts from [FastAPI](https://fastapi.tiangolo.com/){target="_blank"} in terms of request parameter handling and data serialization with Pydantic.
2424

2525
The objective of Ellar is to provide a high level of abstracted interface to your python web app, along with a well-structured project setup, give room for object-oriented approach to web application design,
26-
allow you chose your desired application architecture, and ultimately, deliver speedy handling to requests using any ASGI server.
26+
allow you to choose your desired application architecture, and ultimately, deliver speedy handling to requests using any ASGI server.
2727

2828
## **Project Status**
2929
Beta version

0 commit comments

Comments
 (0)