fastkit-cli 0.1.6__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/PKG-INFO +5 -5
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/make.py +67 -1
- fastkit_cli-0.2.0/fastkit_cli/templates/module/listeners.py.jinja +56 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/schemas.py.jinja +4 -4
- fastkit_cli-0.2.0/fastkit_cli/templates/module/signals.py.jinja +24 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/pyproject.toml +5 -5
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/.gitignore +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/README.md +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/__init__.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/__init__.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/migrate.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/seed.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/server.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/main.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/__init__.py +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_repository.py.jinja +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_router.py.jinja +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_service.py.jinja +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/model.py.jinja +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/repository.py.jinja +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/router.py.jinja +0 -0
- {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/service.py.jinja +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastkit-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: FastKit CLI is a code generation tool for the fastkit core package.
|
|
5
|
-
Project-URL: Homepage, https://
|
|
6
|
-
Project-URL: Documentation, https://
|
|
7
|
-
Project-URL: Repository, https://github.com/
|
|
8
|
-
Author-email:
|
|
5
|
+
Project-URL: Homepage, https://fastkit.org/docs/fastkit-cli/
|
|
6
|
+
Project-URL: Documentation, https://fastkit.org/docs/fastkit-cli/
|
|
7
|
+
Project-URL: Repository, https://github.com/fastkit-org/fastkit-cli
|
|
8
|
+
Author-email: FastKit Org <hello@fastkit.org>
|
|
9
9
|
License: MIT
|
|
10
10
|
Keywords: api,crud,database,fastapi,framework,laravel,orm,toolkit,web
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -121,6 +121,7 @@ def _print_skipped(skipped: list) -> None:
|
|
|
121
121
|
fg=typer.colors.YELLOW,
|
|
122
122
|
)
|
|
123
123
|
|
|
124
|
+
|
|
124
125
|
def _make_init_file(file, force: bool) -> None:
|
|
125
126
|
if not file.exists() or force:
|
|
126
127
|
file.write_text("")
|
|
@@ -136,6 +137,7 @@ def module(
|
|
|
136
137
|
modules_dir: str = typer.Option("modules", "--dir", "-d", help="Modules root directory"),
|
|
137
138
|
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing files"),
|
|
138
139
|
async_mode: bool = typer.Option(False, "--async", "-a", help="Use async repository and service"),
|
|
140
|
+
signals: bool = typer.Option(False, "--signals", "-s", help="Also generate signals.py and listeners.py"),
|
|
139
141
|
):
|
|
140
142
|
"""
|
|
141
143
|
Generate a new module with model, schemas, repository, and service.
|
|
@@ -154,7 +156,15 @@ def module(
|
|
|
154
156
|
typer.echo(f" Location : {module_path}/")
|
|
155
157
|
typer.echo(f" Model : {context['model_name']}")
|
|
156
158
|
typer.echo(f" Table : {context['table_name']}")
|
|
157
|
-
|
|
159
|
+
if async_mode and signals:
|
|
160
|
+
mode = "async + signals"
|
|
161
|
+
elif async_mode:
|
|
162
|
+
mode = "async"
|
|
163
|
+
elif signals:
|
|
164
|
+
mode = "sync + signals"
|
|
165
|
+
else:
|
|
166
|
+
mode = "sync"
|
|
167
|
+
typer.echo(f" Mode : {mode}")
|
|
158
168
|
typer.echo("")
|
|
159
169
|
|
|
160
170
|
module_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -173,6 +183,12 @@ def module(
|
|
|
173
183
|
("async_router.py.jinja" if async_mode else "router.py.jinja", "router.py"),
|
|
174
184
|
]
|
|
175
185
|
|
|
186
|
+
if signals:
|
|
187
|
+
templates += [
|
|
188
|
+
("signals.py.jinja", "signals.py"),
|
|
189
|
+
("listeners.py.jinja", "listeners.py"),
|
|
190
|
+
]
|
|
191
|
+
|
|
176
192
|
skipped: list = []
|
|
177
193
|
for template_name, output_filename in templates:
|
|
178
194
|
_render_and_write(
|
|
@@ -193,6 +209,11 @@ def module(
|
|
|
193
209
|
typer.echo(f" 1. Define your fields in {module_path}/models.py")
|
|
194
210
|
typer.echo(f" 2. Add schemas in {module_path}/schemas.py")
|
|
195
211
|
typer.echo(f" 3. Run: fastkit migrate make -m 'create_{context['table_name']}'")
|
|
212
|
+
|
|
213
|
+
if signals:
|
|
214
|
+
typer.echo(f" 4. Import listeners in main.py:")
|
|
215
|
+
typer.echo(f" import modules.{context['table_name']}.listeners")
|
|
216
|
+
|
|
196
217
|
typer.echo("")
|
|
197
218
|
|
|
198
219
|
|
|
@@ -372,4 +393,49 @@ def router(
|
|
|
372
393
|
|
|
373
394
|
typer.echo("")
|
|
374
395
|
typer.secho("Done!", fg=typer.colors.BRIGHT_WHITE, bold=True)
|
|
396
|
+
typer.echo("")
|
|
397
|
+
|
|
398
|
+
@app.command()
|
|
399
|
+
def signals(
|
|
400
|
+
name: str = typer.Argument(..., help="Module name in PascalCase (e.g. Invoice)"),
|
|
401
|
+
path: str = typer.Option(".", "--path", "-p", help="Path to target directory"),
|
|
402
|
+
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing files"),
|
|
403
|
+
):
|
|
404
|
+
"""
|
|
405
|
+
Generate signals.py and listeners.py for an existing module.
|
|
406
|
+
|
|
407
|
+
\b
|
|
408
|
+
Example:
|
|
409
|
+
fastkit make signals Invoice
|
|
410
|
+
fastkit make signals Invoice --path modules/invoices
|
|
411
|
+
"""
|
|
412
|
+
context = _build_context(name)
|
|
413
|
+
module_path = Path(path)
|
|
414
|
+
|
|
415
|
+
typer.echo("")
|
|
416
|
+
typer.secho(f"Generating signals: {context['model_name']}", fg=typer.colors.BRIGHT_CYAN, bold=True)
|
|
417
|
+
typer.echo(f" Location : {module_path}/")
|
|
418
|
+
typer.echo("")
|
|
419
|
+
|
|
420
|
+
skipped: list = []
|
|
421
|
+
|
|
422
|
+
for template_name, output_filename in [
|
|
423
|
+
("signals.py.jinja", "signals.py"),
|
|
424
|
+
("listeners.py.jinja", "listeners.py"),
|
|
425
|
+
]:
|
|
426
|
+
_render_and_write(
|
|
427
|
+
template_name=template_name,
|
|
428
|
+
output_path=module_path / output_filename,
|
|
429
|
+
context=context,
|
|
430
|
+
force=force,
|
|
431
|
+
skipped=skipped,
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
_print_skipped(skipped)
|
|
435
|
+
|
|
436
|
+
typer.echo("")
|
|
437
|
+
typer.secho("Done! Next steps:", fg=typer.colors.BRIGHT_WHITE, bold=True)
|
|
438
|
+
typer.echo(f" 1. Implement receivers in {module_path}/listeners.py")
|
|
439
|
+
typer.echo(f" 2. Import listeners in main.py:")
|
|
440
|
+
typer.echo(f" import modules.{context['table_name']}.listeners")
|
|
375
441
|
typer.echo("")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# {{ table_name }}/listeners.py
|
|
2
|
+
#
|
|
3
|
+
# Connect receivers to signals using the @signal.connect decorator.
|
|
4
|
+
#
|
|
5
|
+
# IMPORTANT: This file must be imported at application startup for receivers
|
|
6
|
+
# to be registered. Without the import the decorators never run and no
|
|
7
|
+
# receiver will respond to any signal — no error, just silence.
|
|
8
|
+
#
|
|
9
|
+
# Add this to your main.py lifespan or application factory:
|
|
10
|
+
# import modules.{{ table_name }}.listeners
|
|
11
|
+
#
|
|
12
|
+
from .signals import {{ snake_name }}_created, {{ snake_name }}_updated, {{ snake_name }}_deleted
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Uncomment and implement the receivers you need.
|
|
16
|
+
# Each receiver is an async function that accepts the signal payload as a dict.
|
|
17
|
+
# Receiver exceptions are caught and logged — they never propagate to the caller.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# @{{ snake_name }}_created.connect
|
|
21
|
+
# async def on_{{ snake_name }}_created(payload: dict) -> None:
|
|
22
|
+
# """
|
|
23
|
+
# Called after a {{ model_name }} is successfully created and committed.
|
|
24
|
+
#
|
|
25
|
+
# Payload keys sent by the service (add your own in after_create):
|
|
26
|
+
# id: int
|
|
27
|
+
#
|
|
28
|
+
# Common uses: send notification, invalidate cache, update search index.
|
|
29
|
+
# """
|
|
30
|
+
# pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# @{{ snake_name }}_updated.connect
|
|
34
|
+
# async def on_{{ snake_name }}_updated(payload: dict) -> None:
|
|
35
|
+
# """
|
|
36
|
+
# Called after a {{ model_name }} is successfully updated and committed.
|
|
37
|
+
#
|
|
38
|
+
# Payload keys sent by the service (add your own in after_update):
|
|
39
|
+
# id: int
|
|
40
|
+
#
|
|
41
|
+
# Common uses: invalidate cache entry, sync external system.
|
|
42
|
+
# """
|
|
43
|
+
# pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# @{{ snake_name }}_deleted.connect
|
|
47
|
+
# async def on_{{ snake_name }}_deleted(payload: dict) -> None:
|
|
48
|
+
# """
|
|
49
|
+
# Called after a {{ model_name }} is successfully deleted and committed.
|
|
50
|
+
#
|
|
51
|
+
# Payload keys sent by the service (add your own in after_delete):
|
|
52
|
+
# id: int
|
|
53
|
+
#
|
|
54
|
+
# Common uses: delete related files, revoke tokens, release resources.
|
|
55
|
+
# """
|
|
56
|
+
# pass
|
|
@@ -2,6 +2,8 @@ from typing import Any
|
|
|
2
2
|
from pydantic import Field
|
|
3
3
|
from fastkit_core.validation import (
|
|
4
4
|
BaseSchema,
|
|
5
|
+
BaseCreateSchema,
|
|
6
|
+
BaseUpdateSchema,
|
|
5
7
|
# min_length, # Uncomment for string min length: name: str = min_length(3)
|
|
6
8
|
# max_length, # Uncomment for string max length: name: str = max_length(100)
|
|
7
9
|
# length, # Uncomment for string length range: name: str = length(3, 100)
|
|
@@ -16,7 +18,7 @@ from fastkit_core.validation import (
|
|
|
16
18
|
)
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
class {{ model_name }}Create(
|
|
21
|
+
class {{ model_name }}Create(BaseCreateSchema):
|
|
20
22
|
"""
|
|
21
23
|
Schema for creating a new {{ model_name }}.
|
|
22
24
|
|
|
@@ -31,7 +33,7 @@ class {{ model_name }}Create(BaseSchema):
|
|
|
31
33
|
pass # Replace with actual fields
|
|
32
34
|
|
|
33
35
|
|
|
34
|
-
class {{ model_name }}Update(
|
|
36
|
+
class {{ model_name }}Update(BaseUpdateSchema):
|
|
35
37
|
"""
|
|
36
38
|
Schema for updating an existing {{ model_name }}.
|
|
37
39
|
|
|
@@ -61,5 +63,3 @@ class {{ model_name }}Response(BaseSchema):
|
|
|
61
63
|
# description: str | None = None
|
|
62
64
|
created_at: Any = None
|
|
63
65
|
updated_at: Any = None
|
|
64
|
-
|
|
65
|
-
model_config = {"from_attributes": True}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# {{ table_name }}/signals.py
|
|
2
|
+
#
|
|
3
|
+
# Define module-level Signal instances here.
|
|
4
|
+
# Import these in listeners.py to connect receivers.
|
|
5
|
+
# Import these in service.py to send signals from lifecycle hooks.
|
|
6
|
+
#
|
|
7
|
+
# Signal name convention: 'module_name.event_name'
|
|
8
|
+
# Each Signal instance is independent — receivers connect to the object,
|
|
9
|
+
# not to the name string. Always import from this file, never create new instances.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# from .signals import {{ snake_name }}_created, {{ snake_name }}_updated, {{ snake_name }}_deleted
|
|
13
|
+
|
|
14
|
+
from fastkit_core.events import Signal
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'{{ snake_name }}_created',
|
|
18
|
+
'{{ snake_name }}_updated',
|
|
19
|
+
'{{ snake_name }}_deleted',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
{{ snake_name }}_created = Signal('{{ snake_name }}.created')
|
|
23
|
+
{{ snake_name }}_updated = Signal('{{ snake_name }}.updated')
|
|
24
|
+
{{ snake_name }}_deleted = Signal('{{ snake_name }}.deleted')
|
|
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fastkit-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "FastKit CLI is a code generation tool for the fastkit core package."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license = {text = "MIT"}
|
|
12
12
|
authors = [
|
|
13
|
-
{name = "
|
|
13
|
+
{name = "FastKit Org", email = "hello@fastkit.org"}
|
|
14
14
|
]
|
|
15
15
|
keywords = [
|
|
16
16
|
"fastapi",
|
|
@@ -46,9 +46,9 @@ dependencies = [
|
|
|
46
46
|
fastkit = "fastkit_cli.main:app"
|
|
47
47
|
|
|
48
48
|
[project.urls]
|
|
49
|
-
Homepage = "https://
|
|
50
|
-
Documentation = "https://
|
|
51
|
-
Repository = "https://github.com/
|
|
49
|
+
Homepage = "https://fastkit.org/docs/fastkit-cli/"
|
|
50
|
+
Documentation = "https://fastkit.org/docs/fastkit-cli/"
|
|
51
|
+
Repository = "https://github.com/fastkit-org/fastkit-cli"
|
|
52
52
|
|
|
53
53
|
[tool.hatch.build.targets.wheel]
|
|
54
54
|
include = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_repository.py.jinja
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|