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.
Files changed (22) hide show
  1. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/PKG-INFO +5 -5
  2. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/make.py +67 -1
  3. fastkit_cli-0.2.0/fastkit_cli/templates/module/listeners.py.jinja +56 -0
  4. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/schemas.py.jinja +4 -4
  5. fastkit_cli-0.2.0/fastkit_cli/templates/module/signals.py.jinja +24 -0
  6. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/pyproject.toml +5 -5
  7. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/.gitignore +0 -0
  8. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/README.md +0 -0
  9. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/__init__.py +0 -0
  10. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/__init__.py +0 -0
  11. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/migrate.py +0 -0
  12. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/seed.py +0 -0
  13. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/commands/server.py +0 -0
  14. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/main.py +0 -0
  15. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/__init__.py +0 -0
  16. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_repository.py.jinja +0 -0
  17. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_router.py.jinja +0 -0
  18. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/async_service.py.jinja +0 -0
  19. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/model.py.jinja +0 -0
  20. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/repository.py.jinja +0 -0
  21. {fastkit_cli-0.1.6 → fastkit_cli-0.2.0}/fastkit_cli/templates/module/router.py.jinja +0 -0
  22. {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.1.6
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://github.com/codevelo-pub/fastkit-cli
6
- Project-URL: Documentation, https://github.com/codevelo-pub/fastkit-cli#readme
7
- Project-URL: Repository, https://github.com/codevelo-pub/fastkit-cli
8
- Author-email: Codevelo <info@codevelo.io>
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
- typer.echo(f" Mode : {'async' if async_mode else 'sync'}")
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(BaseSchema):
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(BaseSchema):
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.1.6"
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 = "Codevelo", email = "info@codevelo.io"}
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://github.com/codevelo-pub/fastkit-cli"
50
- Documentation = "https://github.com/codevelo-pub/fastkit-cli#readme"
51
- Repository = "https://github.com/codevelo-pub/fastkit-cli"
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