scaffold-ca-python 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- scaffold_ca_python/__init__.py +0 -1
- scaffold_ca_python/commands/delete_module.py +6 -21
- scaffold_ca_python/commands/generate_driven_adapter.py +11 -6
- scaffold_ca_python/commands/generate_entry_point.py +7 -5
- scaffold_ca_python/commands/generate_helper.py +4 -4
- scaffold_ca_python/commands/generate_model.py +4 -4
- scaffold_ca_python/commands/generate_project.py +1 -1
- scaffold_ca_python/commands/generate_use_case.py +6 -4
- scaffold_ca_python/core/module_builder.py +36 -3
- scaffold_ca_python/core/name_utils.py +14 -0
- scaffold_ca_python/core/pyproject_writer.py +84 -1
- scaffold_ca_python/factory/driven_adapters/da_rest_consumer.py +5 -3
- scaffold_ca_python/factory/driven_adapters/da_secrets.py +2 -2
- scaffold_ca_python/factory/entry_points/ep_agent.py +2 -2
- scaffold_ca_python/factory/entry_points/ep_mcp.py +7 -7
- scaffold_ca_python/factory/entry_points/ep_restapi.py +8 -8
- scaffold_ca_python/templates/driven_adapter/rest_consumer/test_rest_consumer.py.jinja2 +1 -1
- scaffold_ca_python/templates/entry_point/agent/agent.py.jinja2 +5 -4
- scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2 +6 -3
- scaffold_ca_python/templates/entry_point/mcp/prompts.py.jinja2 +2 -2
- scaffold_ca_python/templates/entry_point/mcp/resources.py.jinja2 +2 -2
- scaffold_ca_python/templates/entry_point/mcp/server.py.jinja2 +1 -1
- scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2 +0 -2
- scaffold_ca_python/templates/entry_point/mcp/tools.py.jinja2 +2 -2
- scaffold_ca_python/templates/entry_point/restapi/app.py.jinja2 +1 -1
- scaffold_ca_python/templates/entry_point/restapi/test_app.py.jinja2 +3 -3
- scaffold_ca_python/templates/project/application/config/container.py.jinja2 +1 -1
- scaffold_ca_python/templates/project/application/config/driven_adapters_container.py.jinja2 +1 -1
- scaffold_ca_python/templates/project/application/config/resource_container.py.jinja2 +2 -2
- scaffold_ca_python/templates/project/pyproject_toml.jinja2 +15 -8
- {scaffold_ca_python-0.1.2.dist-info → scaffold_ca_python-0.1.4.dist-info}/METADATA +18 -18
- {scaffold_ca_python-0.1.2.dist-info → scaffold_ca_python-0.1.4.dist-info}/RECORD +35 -35
- {scaffold_ca_python-0.1.2.dist-info → scaffold_ca_python-0.1.4.dist-info}/WHEEL +1 -1
- {scaffold_ca_python-0.1.2.dist-info → scaffold_ca_python-0.1.4.dist-info}/entry_points.txt +0 -0
- {scaffold_ca_python-0.1.2.dist-info → scaffold_ca_python-0.1.4.dist-info}/licenses/LICENSE +0 -0
scaffold_ca_python/__init__.py
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -10,7 +10,7 @@ import typer
|
|
|
10
10
|
from rich.console import Console
|
|
11
11
|
|
|
12
12
|
from scaffold_ca_python.core.module_builder import ModuleBuilder
|
|
13
|
-
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case,
|
|
13
|
+
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case, validate_module_name
|
|
14
14
|
from scaffold_ca_python.core.project_detector import find_project_root, resolve_tests_root
|
|
15
15
|
from scaffold_ca_python.factory import ModuleFactory
|
|
16
16
|
from scaffold_ca_python.factory.simple.delete_module_factory import DeleteModuleFactory
|
|
@@ -24,7 +24,7 @@ _REGISTRY: dict[str, type[ModuleFactory]] = {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
_DM_HELP = "Delete a previously generated module and its test mirror. Alias 'dm'."
|
|
27
|
-
_DM_EPILOG = "Examples:\n\n * scaffold dm --name
|
|
27
|
+
_DM_EPILOG = "Examples:\n\n * scaffold dm --name order\n\n * scaffold delete-module --name my_adapter\n\n"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
# ---------------------------------------------------------------------------
|
|
@@ -32,7 +32,7 @@ _DM_EPILOG = "Examples:\n\n * scaffold dm --name Order\n\n * scaffold delete-m
|
|
|
32
32
|
# ---------------------------------------------------------------------------
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def _find_module_targets(project_root: Path, snake: str) -> list[tuple[Path, Path | None]]:
|
|
35
|
+
def _find_module_targets(pkg: str, project_root: Path, snake: str) -> list[tuple[Path, Path | None]]:
|
|
36
36
|
"""Return a list of (target_path, test_path_or_None) for all matches of *snake*.
|
|
37
37
|
|
|
38
38
|
Searches across:
|
|
@@ -42,7 +42,6 @@ def _find_module_targets(project_root: Path, snake: str) -> list[tuple[Path, Pat
|
|
|
42
42
|
4. infrastructure/entry_points/<snake>/
|
|
43
43
|
5. infrastructure/helpers/<snake>/
|
|
44
44
|
"""
|
|
45
|
-
pkg = _get_python_package(project_root)
|
|
46
45
|
src_root = project_root / "src" / pkg
|
|
47
46
|
tests_root = resolve_tests_root(project_root)
|
|
48
47
|
|
|
@@ -77,20 +76,6 @@ def _find_module_targets(project_root: Path, snake: str) -> list[tuple[Path, Pat
|
|
|
77
76
|
return candidates
|
|
78
77
|
|
|
79
78
|
|
|
80
|
-
def _get_python_package(root: Path) -> str:
|
|
81
|
-
pyproject = root / "pyproject.toml"
|
|
82
|
-
with pyproject.open("rb") as fh:
|
|
83
|
-
data = tomllib.load(fh)
|
|
84
|
-
section = data.get("tool", {}).get("scaffold-ca-python", {})
|
|
85
|
-
name = section.get("name", root.name)
|
|
86
|
-
import re
|
|
87
|
-
|
|
88
|
-
s = name.replace("-", "_")
|
|
89
|
-
s = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", s)
|
|
90
|
-
s = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s)
|
|
91
|
-
return s.lower()
|
|
92
|
-
|
|
93
|
-
|
|
94
79
|
# ---------------------------------------------------------------------------
|
|
95
80
|
# Implementation
|
|
96
81
|
# ---------------------------------------------------------------------------
|
|
@@ -99,7 +84,7 @@ def _get_python_package(root: Path) -> str:
|
|
|
99
84
|
def _delete_module_impl(name: str, confirm: bool, dry_run: bool) -> None:
|
|
100
85
|
# Validate name
|
|
101
86
|
try:
|
|
102
|
-
|
|
87
|
+
validate_module_name(name)
|
|
103
88
|
except ScaffoldError as exc:
|
|
104
89
|
console.print(f"[red]Error:[/red] {exc}")
|
|
105
90
|
raise typer.Exit(code=1) from None
|
|
@@ -118,7 +103,7 @@ def _delete_module_impl(name: str, confirm: bool, dry_run: bool) -> None:
|
|
|
118
103
|
|
|
119
104
|
# Find targets
|
|
120
105
|
snake = to_snake_case(name)
|
|
121
|
-
targets = _find_module_targets(project_root, snake)
|
|
106
|
+
targets = _find_module_targets(project_ctx.python_package, project_root, snake)
|
|
122
107
|
|
|
123
108
|
if not targets:
|
|
124
109
|
console.print(
|
|
@@ -174,7 +159,7 @@ def register(app: typer.Typer) -> None:
|
|
|
174
159
|
def delete_module(
|
|
175
160
|
ctx: typer.Context,
|
|
176
161
|
name: Annotated[
|
|
177
|
-
str | None, typer.Option("--name", help="Module name (
|
|
162
|
+
str | None, typer.Option("--name", help="Module name (snake_case).", rich_help_panel="Required")
|
|
178
163
|
] = None,
|
|
179
164
|
confirm: Annotated[
|
|
180
165
|
bool,
|
|
@@ -8,10 +8,11 @@ from typing import Annotated
|
|
|
8
8
|
|
|
9
9
|
import typer
|
|
10
10
|
from rich.console import Console
|
|
11
|
+
from rich.markup import escape
|
|
11
12
|
from rich.tree import Tree
|
|
12
13
|
|
|
13
14
|
from scaffold_ca_python.core.module_builder import ModuleBuilder
|
|
14
|
-
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case,
|
|
15
|
+
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case, validate_module_name
|
|
15
16
|
from scaffold_ca_python.core.project_detector import find_project_root
|
|
16
17
|
from scaffold_ca_python.factory import ModuleFactory
|
|
17
18
|
from scaffold_ca_python.factory.driven_adapters.da_generic import DrivenAdapterGeneric
|
|
@@ -37,7 +38,7 @@ _GDA_EPILOG = (
|
|
|
37
38
|
" ==================================================\n\n"
|
|
38
39
|
"Examples:\n\n"
|
|
39
40
|
" * scaffold gda --type rest-consumer\n\n"
|
|
40
|
-
" * scaffold generate-driven-adapter --type generic --name
|
|
41
|
+
" * scaffold generate-driven-adapter --type generic --name my_adapter\n\n"
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
|
|
@@ -55,7 +56,7 @@ def _generate_driven_adapter_impl(type_: str, name: str | None, dry_run: bool) -
|
|
|
55
56
|
# --- Validate name if provided ---
|
|
56
57
|
if name:
|
|
57
58
|
try:
|
|
58
|
-
|
|
59
|
+
validate_module_name(name)
|
|
59
60
|
except ScaffoldError as exc:
|
|
60
61
|
console.print(f"[red]Error:[/red] {exc}")
|
|
61
62
|
raise typer.Exit(code=1) from None
|
|
@@ -116,8 +117,12 @@ def _generate_driven_adapter_impl(type_: str, name: str | None, dry_run: bool) -
|
|
|
116
117
|
for p in sorted(created):
|
|
117
118
|
tree.add(str(p.relative_to(project_root)))
|
|
118
119
|
console.print(tree)
|
|
119
|
-
if builder.
|
|
120
|
-
|
|
120
|
+
if builder.pending_dependencies:
|
|
121
|
+
target = escape("[project.dependencies]")
|
|
122
|
+
console.print(f"[dim]Would add to {target}: {', '.join(builder.pending_dependencies)}[/dim]")
|
|
123
|
+
for grp, pkgs in builder.pending_group_dependencies.items():
|
|
124
|
+
target = escape(f"[dependency-groups.{grp}]")
|
|
125
|
+
console.print(f"[dim]Would add to {target}: {', '.join(pkgs)}[/dim]")
|
|
121
126
|
return
|
|
122
127
|
|
|
123
128
|
console.print(f"[green]✓[/green] Driven adapter [bold]{subdir}[/bold] created. Created {len(created)} file(s).")
|
|
@@ -146,7 +151,7 @@ def register(app: typer.Typer) -> None:
|
|
|
146
151
|
str | None,
|
|
147
152
|
typer.Option(
|
|
148
153
|
"--name",
|
|
149
|
-
help="Adapter name (required for --type generic).",
|
|
154
|
+
help="Adapter name in snake_case, e.g. my_adapter (required for --type generic).",
|
|
150
155
|
rich_help_panel="Options",
|
|
151
156
|
),
|
|
152
157
|
] = None,
|
|
@@ -10,10 +10,11 @@ from typing import Annotated
|
|
|
10
10
|
import typer
|
|
11
11
|
import yaml
|
|
12
12
|
from rich.console import Console
|
|
13
|
+
from rich.markup import escape
|
|
13
14
|
from rich.tree import Tree
|
|
14
15
|
|
|
15
16
|
from scaffold_ca_python.core.module_builder import ModuleBuilder
|
|
16
|
-
from scaffold_ca_python.core.name_utils import ScaffoldError
|
|
17
|
+
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case
|
|
17
18
|
from scaffold_ca_python.core.project_detector import find_project_root
|
|
18
19
|
from scaffold_ca_python.factory import ModuleFactory
|
|
19
20
|
from scaffold_ca_python.factory.entry_points.ep_agent import EntryPointAgent
|
|
@@ -59,7 +60,7 @@ def _load_project_context(project_root: Path) -> ProjectContext:
|
|
|
59
60
|
pyproject_path = project_root / "pyproject.toml"
|
|
60
61
|
with open(pyproject_path, "rb") as f:
|
|
61
62
|
data = tomllib.load(f)
|
|
62
|
-
project_name = data.get("project", {}).get("name", "project")
|
|
63
|
+
project_name = to_snake_case(data.get("project", {}).get("name", "project"))
|
|
63
64
|
return ProjectContext(name=project_name)
|
|
64
65
|
|
|
65
66
|
|
|
@@ -190,9 +191,10 @@ def _generate_entry_point_impl(
|
|
|
190
191
|
tree.add(str(p.relative_to(project_root)))
|
|
191
192
|
console.print(tree)
|
|
192
193
|
|
|
193
|
-
#
|
|
194
|
-
if builder.
|
|
195
|
-
|
|
194
|
+
# Report any runtime dependencies queued for injection
|
|
195
|
+
if builder.pending_dependencies:
|
|
196
|
+
target = escape("[project.dependencies]")
|
|
197
|
+
console.print(f"[dim]Would add to {target}: {', '.join(builder.pending_dependencies)}[/dim]")
|
|
196
198
|
|
|
197
199
|
if type_ == "restapi":
|
|
198
200
|
main_py = project_root / "src" / pkg / "main.py"
|
|
@@ -11,7 +11,7 @@ from rich.console import Console
|
|
|
11
11
|
from rich.tree import Tree
|
|
12
12
|
|
|
13
13
|
from scaffold_ca_python.core.module_builder import ModuleBuilder
|
|
14
|
-
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case,
|
|
14
|
+
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case, validate_module_name
|
|
15
15
|
from scaffold_ca_python.core.project_detector import find_project_root
|
|
16
16
|
from scaffold_ca_python.factory import ModuleFactory
|
|
17
17
|
from scaffold_ca_python.factory.simple.helper_factory import HelperFactory
|
|
@@ -25,13 +25,13 @@ _REGISTRY: dict[str, type[ModuleFactory]] = {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
_GH_HELP = "Scaffold a helper utility module and test stub. Alias 'gh'."
|
|
28
|
-
_GH_EPILOG = "Example:\n\n * scaffold gh --name
|
|
28
|
+
_GH_EPILOG = "Example:\n\n * scaffold gh --name json_parser\n\n * scaffold generate-helper --name json_parser\n\n"
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def _generate_helper_impl(name: str, dry_run: bool) -> None:
|
|
32
32
|
# --- Validate name ---
|
|
33
33
|
try:
|
|
34
|
-
|
|
34
|
+
validate_module_name(name)
|
|
35
35
|
except ScaffoldError as exc:
|
|
36
36
|
console.print(f"[red]Error:[/red] {exc}")
|
|
37
37
|
raise typer.Exit(code=1) from None
|
|
@@ -100,7 +100,7 @@ def register(app: typer.Typer) -> None:
|
|
|
100
100
|
def generate_helper(
|
|
101
101
|
ctx: typer.Context,
|
|
102
102
|
name: Annotated[
|
|
103
|
-
str | None, typer.Option("--name", help="Helper name (
|
|
103
|
+
str | None, typer.Option("--name", help="Helper name (snake_case).", rich_help_panel="Required")
|
|
104
104
|
] = None,
|
|
105
105
|
dry_run: Annotated[
|
|
106
106
|
bool,
|
|
@@ -11,7 +11,7 @@ from rich.console import Console
|
|
|
11
11
|
from rich.tree import Tree
|
|
12
12
|
|
|
13
13
|
from scaffold_ca_python.core.module_builder import ModuleBuilder
|
|
14
|
-
from scaffold_ca_python.core.name_utils import ScaffoldError,
|
|
14
|
+
from scaffold_ca_python.core.name_utils import ScaffoldError, validate_module_name
|
|
15
15
|
from scaffold_ca_python.core.project_detector import find_project_root
|
|
16
16
|
from scaffold_ca_python.factory import ModuleFactory
|
|
17
17
|
from scaffold_ca_python.factory.simple.model_factory import ModelFactory
|
|
@@ -24,13 +24,13 @@ _REGISTRY: dict[str, type[ModuleFactory]] = {
|
|
|
24
24
|
"model": ModelFactory,
|
|
25
25
|
}
|
|
26
26
|
_GM_HELP = "Scaffold a Pydantic v2 domain model and test stub. Alias 'gm'."
|
|
27
|
-
_GM_EPILOG = "Example:\n\n * scaffold gm --name
|
|
27
|
+
_GM_EPILOG = "Example:\n\n * scaffold gm --name order\n\n * scaffold generate-model --name order\n\n"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def _generate_model_impl(name: str, dry_run: bool) -> None:
|
|
31
31
|
# --- Validate name ---
|
|
32
32
|
try:
|
|
33
|
-
|
|
33
|
+
validate_module_name(name)
|
|
34
34
|
except ScaffoldError as exc:
|
|
35
35
|
console.print(f"[red]Error:[/red] {exc}")
|
|
36
36
|
raise typer.Exit(code=1) from None
|
|
@@ -100,7 +100,7 @@ def register(app: typer.Typer) -> None:
|
|
|
100
100
|
def generate_model(
|
|
101
101
|
ctx: typer.Context,
|
|
102
102
|
name: Annotated[
|
|
103
|
-
str | None, typer.Option("--name", help="Model name (
|
|
103
|
+
str | None, typer.Option("--name", help="Model name (snake_case).", rich_help_panel="Required")
|
|
104
104
|
] = None,
|
|
105
105
|
dry_run: Annotated[
|
|
106
106
|
bool,
|
|
@@ -151,7 +151,7 @@ def register(app: typer.Typer) -> None:
|
|
|
151
151
|
str,
|
|
152
152
|
typer.Option(
|
|
153
153
|
"--name",
|
|
154
|
-
help="Project name (
|
|
154
|
+
help="Project name (kebab-case or snake_case).",
|
|
155
155
|
rich_help_panel="Required",
|
|
156
156
|
),
|
|
157
157
|
] = None, # type: ignore[assignment]
|
|
@@ -11,7 +11,7 @@ from rich.console import Console
|
|
|
11
11
|
from rich.tree import Tree
|
|
12
12
|
|
|
13
13
|
from scaffold_ca_python.core.module_builder import ModuleBuilder
|
|
14
|
-
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case,
|
|
14
|
+
from scaffold_ca_python.core.name_utils import ScaffoldError, to_snake_case, validate_module_name
|
|
15
15
|
from scaffold_ca_python.core.project_detector import find_project_root
|
|
16
16
|
from scaffold_ca_python.factory import ModuleFactory
|
|
17
17
|
from scaffold_ca_python.factory.simple.use_case_factory import UseCaseFactory
|
|
@@ -24,13 +24,15 @@ _REGISTRY: dict[str, type[ModuleFactory]] = {
|
|
|
24
24
|
"use_case": UseCaseFactory,
|
|
25
25
|
}
|
|
26
26
|
_GUC_HELP = "Scaffold a use case in domain/usecase/. Alias 'guc'."
|
|
27
|
-
_GUC_EPILOG =
|
|
27
|
+
_GUC_EPILOG = (
|
|
28
|
+
"Example:\n\n * scaffold guc --name create_order\n\n * scaffold generate-use-case --name create_order\n\n"
|
|
29
|
+
)
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
def _generate_use_case_impl(name: str, dry_run: bool) -> None:
|
|
31
33
|
# --- Validate name ---
|
|
32
34
|
try:
|
|
33
|
-
|
|
35
|
+
validate_module_name(name)
|
|
34
36
|
except ScaffoldError as exc:
|
|
35
37
|
console.print(f"[red]Error:[/red] {exc}")
|
|
36
38
|
raise typer.Exit(code=1) from None
|
|
@@ -102,7 +104,7 @@ def register(app: typer.Typer) -> None:
|
|
|
102
104
|
def generate_use_case(
|
|
103
105
|
ctx: typer.Context,
|
|
104
106
|
name: Annotated[
|
|
105
|
-
str | None, typer.Option("--name", help="Use case name (
|
|
107
|
+
str | None, typer.Option("--name", help="Use case name (snake_case).", rich_help_panel="Required")
|
|
106
108
|
] = None,
|
|
107
109
|
dry_run: Annotated[
|
|
108
110
|
bool,
|
|
@@ -9,9 +9,11 @@ from pydantic import BaseModel
|
|
|
9
9
|
|
|
10
10
|
from scaffold_ca_python.core.file_writer import FileWriter
|
|
11
11
|
from scaffold_ca_python.core.pyproject_writer import (
|
|
12
|
+
dry_run_group_inject,
|
|
12
13
|
dry_run_inject,
|
|
13
14
|
dry_run_scripts_update,
|
|
14
15
|
inject_dependencies,
|
|
16
|
+
inject_group_dependencies,
|
|
15
17
|
update_project_scripts,
|
|
16
18
|
)
|
|
17
19
|
from scaffold_ca_python.core.template_renderer import TemplateRenderer
|
|
@@ -48,6 +50,7 @@ class ModuleBuilder:
|
|
|
48
50
|
|
|
49
51
|
self._operations: list[FileOperation] = []
|
|
50
52
|
self._dependencies: list[str] = []
|
|
53
|
+
self._group_dependencies: dict[str, list[str]] = {}
|
|
51
54
|
self._params: dict[str, object] = {}
|
|
52
55
|
|
|
53
56
|
def add_file(
|
|
@@ -89,9 +92,33 @@ class ModuleBuilder:
|
|
|
89
92
|
"""Render a template through the shared renderer."""
|
|
90
93
|
return self._renderer.render(template_name, context)
|
|
91
94
|
|
|
92
|
-
def add_dependency(self, package: str) -> None:
|
|
93
|
-
"""Queue a package dependency to inject into pyproject.toml.
|
|
94
|
-
|
|
95
|
+
def add_dependency(self, package: str, *, group: str | None = None) -> None:
|
|
96
|
+
"""Queue a package dependency to inject into pyproject.toml.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
package:
|
|
101
|
+
Package specifier, e.g. ``"httpx>=0.27"`` or ``"respx>=0.22"``.
|
|
102
|
+
group:
|
|
103
|
+
When ``None`` (default) the package is injected into
|
|
104
|
+
``[project.dependencies]`` (runtime). When set to a group name such as
|
|
105
|
+
``"test"``, the package is injected into
|
|
106
|
+
``[dependency-groups.<group>]`` instead.
|
|
107
|
+
"""
|
|
108
|
+
if group is None:
|
|
109
|
+
self._dependencies.append(package)
|
|
110
|
+
else:
|
|
111
|
+
self._group_dependencies.setdefault(group, []).append(package)
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def pending_dependencies(self) -> list[str]:
|
|
115
|
+
"""Runtime dependencies queued for injection (read-only copy)."""
|
|
116
|
+
return list(self._dependencies)
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def pending_group_dependencies(self) -> dict[str, list[str]]:
|
|
120
|
+
"""Dependency-group deps queued for injection, keyed by group (read-only copy)."""
|
|
121
|
+
return {group: list(pkgs) for group, pkgs in self._group_dependencies.items()}
|
|
95
122
|
|
|
96
123
|
def add_param(self, key: str, value: object) -> None:
|
|
97
124
|
"""Store an ad-hoc value used by factories/commands."""
|
|
@@ -115,6 +142,12 @@ class ModuleBuilder:
|
|
|
115
142
|
else:
|
|
116
143
|
inject_dependencies(self.project_root, self._dependencies)
|
|
117
144
|
|
|
145
|
+
for grp, pkgs in self._group_dependencies.items():
|
|
146
|
+
if self.dry_run:
|
|
147
|
+
dry_run_group_inject(self.project_root, grp, pkgs)
|
|
148
|
+
else:
|
|
149
|
+
inject_group_dependencies(self.project_root, grp, pkgs)
|
|
150
|
+
|
|
118
151
|
# Optional script update hook used by entry-point factory implementations.
|
|
119
152
|
if bool(self._params.get("scripts_entry", False)):
|
|
120
153
|
pkg = self.project_ctx
|
|
@@ -6,6 +6,9 @@ import re
|
|
|
6
6
|
|
|
7
7
|
NAME_RE = re.compile(r"^[a-z][a-z0-9]*([_-][a-z0-9]+)*$")
|
|
8
8
|
|
|
9
|
+
# Stricter pattern for module/class-generating commands: snake_case only (no hyphens).
|
|
10
|
+
MODULE_NAME_RE = re.compile(r"^[a-z][a-z0-9]*(_[a-z0-9]+)*$")
|
|
11
|
+
|
|
9
12
|
# Matches transitions: lowercase→uppercase and letter→digit boundary runs
|
|
10
13
|
_CAMEL_BOUNDARY_RE = re.compile(r"(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])")
|
|
11
14
|
|
|
@@ -32,6 +35,17 @@ def validate_name(name: str) -> str:
|
|
|
32
35
|
return name
|
|
33
36
|
|
|
34
37
|
|
|
38
|
+
def validate_module_name(name: str) -> str:
|
|
39
|
+
"""Validate *name* for module/class-generating commands: snake_case only.
|
|
40
|
+
|
|
41
|
+
Raises :class:`ScaffoldError` with a hint if the name is not snake_case.
|
|
42
|
+
Returns the original name unchanged when valid.
|
|
43
|
+
"""
|
|
44
|
+
if not MODULE_NAME_RE.match(name):
|
|
45
|
+
raise ScaffoldError(f"Invalid name {name!r}. Use snake_case (e.g., 'create_order').")
|
|
46
|
+
return name
|
|
47
|
+
|
|
48
|
+
|
|
35
49
|
def to_snake_case(name: str) -> str:
|
|
36
50
|
"""Convert *name* (PascalCase, camelCase, kebab-case, or already snake_case) to snake_case."""
|
|
37
51
|
# Normalise hyphens to underscores first (kebab-case support)
|
|
@@ -18,8 +18,9 @@ def _name_prefix(package: str) -> str:
|
|
|
18
18
|
"fastapi>=0.100" -> "fastapi"
|
|
19
19
|
"uvicorn[standard]>=0.20" -> "uvicorn"
|
|
20
20
|
"a2a-sdk>=0.1" -> "a2a-sdk"
|
|
21
|
+
"boto3~=1.43.98" -> "boto3"
|
|
21
22
|
"""
|
|
22
|
-
name = package.split(">=")[0].split("==")[0].split("<")[0].split("!=")[0]
|
|
23
|
+
name = package.split("~=")[0].split(">=")[0].split("==")[0].split("<")[0].split("!=")[0]
|
|
23
24
|
name = name.split("[")[0]
|
|
24
25
|
return name.strip().lower()
|
|
25
26
|
|
|
@@ -72,6 +73,88 @@ def inject_dependencies(project_root: Path, packages: list[str]) -> list[str]:
|
|
|
72
73
|
return to_add
|
|
73
74
|
|
|
74
75
|
|
|
76
|
+
def inject_group_dependencies(project_root: Path, group: str, packages: list[str]) -> list[str]:
|
|
77
|
+
"""Add *packages* to ``[dependency-groups.<group>]`` in ``pyproject.toml``.
|
|
78
|
+
|
|
79
|
+
Idempotent: a package whose bare name is already present is skipped. The group
|
|
80
|
+
is created when absent. Non-string entries (e.g. ``{include-group = ...}``) are
|
|
81
|
+
preserved and ignored for duplicate detection.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
project_root:
|
|
86
|
+
Directory containing ``pyproject.toml``.
|
|
87
|
+
group:
|
|
88
|
+
Dependency-group name (e.g. ``"test"``).
|
|
89
|
+
packages:
|
|
90
|
+
Packages to inject, e.g. ``["respx>=0.22"]``.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
list[str]
|
|
95
|
+
The packages that were actually added (empty when all were already present).
|
|
96
|
+
|
|
97
|
+
Raises
|
|
98
|
+
------
|
|
99
|
+
FileNotFoundError
|
|
100
|
+
If ``pyproject.toml`` does not exist in *project_root*.
|
|
101
|
+
tomllib.TOMLDecodeError
|
|
102
|
+
If ``pyproject.toml`` is malformed.
|
|
103
|
+
"""
|
|
104
|
+
pyproject = project_root / "pyproject.toml"
|
|
105
|
+
with pyproject.open("rb") as fh:
|
|
106
|
+
data = tomllib.load(fh)
|
|
107
|
+
|
|
108
|
+
groups: dict[str, list[object]] = data.setdefault("dependency-groups", {})
|
|
109
|
+
entries: list[object] = groups.setdefault(group, [])
|
|
110
|
+
existing = [e for e in entries if isinstance(e, str)]
|
|
111
|
+
to_add = _missing(existing, packages)
|
|
112
|
+
if not to_add:
|
|
113
|
+
return []
|
|
114
|
+
|
|
115
|
+
entries.extend(to_add)
|
|
116
|
+
|
|
117
|
+
with pyproject.open("wb") as fh:
|
|
118
|
+
tomli_w.dump(data, fh)
|
|
119
|
+
|
|
120
|
+
return to_add
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def dry_run_group_inject(project_root: Path, group: str, packages: list[str]) -> list[str]:
|
|
124
|
+
"""Return packages that *would* be added to ``[dependency-groups.<group>]``.
|
|
125
|
+
|
|
126
|
+
Read-only: never modifies ``pyproject.toml``.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
project_root:
|
|
131
|
+
Directory containing ``pyproject.toml``.
|
|
132
|
+
group:
|
|
133
|
+
Dependency-group name (e.g. ``"test"``).
|
|
134
|
+
packages:
|
|
135
|
+
Packages to check.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
list[str]
|
|
140
|
+
The packages that would be added if :func:`inject_group_dependencies` were called.
|
|
141
|
+
|
|
142
|
+
Raises
|
|
143
|
+
------
|
|
144
|
+
FileNotFoundError
|
|
145
|
+
If ``pyproject.toml`` does not exist in *project_root*.
|
|
146
|
+
tomllib.TOMLDecodeError
|
|
147
|
+
If ``pyproject.toml`` is malformed.
|
|
148
|
+
"""
|
|
149
|
+
pyproject = project_root / "pyproject.toml"
|
|
150
|
+
with pyproject.open("rb") as fh:
|
|
151
|
+
data = tomllib.load(fh)
|
|
152
|
+
|
|
153
|
+
entries = data.get("dependency-groups", {}).get(group, [])
|
|
154
|
+
existing = [e for e in entries if isinstance(e, str)]
|
|
155
|
+
return _missing(existing, packages)
|
|
156
|
+
|
|
157
|
+
|
|
75
158
|
def dry_run_inject(project_root: Path, packages: list[str]) -> list[str]:
|
|
76
159
|
"""Return packages that *would* be added without writing to disk.
|
|
77
160
|
|
|
@@ -23,7 +23,8 @@ class DrivenAdapterRestConsumer(ModuleFactory):
|
|
|
23
23
|
- tests/infrastructure/driven_adapters/rest_consumer/test_rest_consumer.py
|
|
24
24
|
|
|
25
25
|
Injects:
|
|
26
|
-
- httpx
|
|
26
|
+
- httpx~=0.28.1 (runtime dependency)
|
|
27
|
+
- respx~=0.23.1 (test dependency-group)
|
|
27
28
|
"""
|
|
28
29
|
project_root = builder.project_root
|
|
29
30
|
pkg = builder.project_ctx.python_package
|
|
@@ -60,5 +61,6 @@ class DrivenAdapterRestConsumer(ModuleFactory):
|
|
|
60
61
|
is_test=True,
|
|
61
62
|
)
|
|
62
63
|
|
|
63
|
-
# Add
|
|
64
|
-
builder.add_dependency("httpx
|
|
64
|
+
# Add dependencies: httpx at runtime, respx only in test group
|
|
65
|
+
builder.add_dependency("httpx~=0.28.1")
|
|
66
|
+
builder.add_dependency("respx~=0.23.1", group="test")
|
|
@@ -23,7 +23,7 @@ class DrivenAdapterSecrets(ModuleFactory):
|
|
|
23
23
|
- tests/infrastructure/driven_adapters/secrets/test_secrets_adapter.py
|
|
24
24
|
|
|
25
25
|
Injects:
|
|
26
|
-
- boto3
|
|
26
|
+
- boto3~=1.43.98
|
|
27
27
|
"""
|
|
28
28
|
project_root = builder.project_root
|
|
29
29
|
pkg = builder.project_ctx.python_package
|
|
@@ -61,4 +61,4 @@ class DrivenAdapterSecrets(ModuleFactory):
|
|
|
61
61
|
)
|
|
62
62
|
|
|
63
63
|
# Add dependency
|
|
64
|
-
builder.add_dependency("boto3
|
|
64
|
+
builder.add_dependency("boto3~=1.43.98")
|
|
@@ -27,7 +27,7 @@ class EntryPointAgent(ModuleFactory):
|
|
|
27
27
|
- src/main.py (if exists)
|
|
28
28
|
|
|
29
29
|
Injects:
|
|
30
|
-
- a2a-sdk
|
|
30
|
+
- a2a-sdk~=1.1.4
|
|
31
31
|
"""
|
|
32
32
|
project_root = builder.project_root
|
|
33
33
|
pkg = builder.project_ctx.python_package
|
|
@@ -88,4 +88,4 @@ class EntryPointAgent(ModuleFactory):
|
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
# Add dependency
|
|
91
|
-
builder.add_dependency("a2a-sdk
|
|
91
|
+
builder.add_dependency("a2a-sdk~=1.1.4")
|
|
@@ -26,8 +26,8 @@ class EntryPointMcp(ModuleFactory):
|
|
|
26
26
|
- resources.py + test_resources.py (with_resources=True)
|
|
27
27
|
- prompts.py + test_prompts.py (with_prompts=True)
|
|
28
28
|
|
|
29
|
-
Injects: mcp
|
|
30
|
-
dependency-injector
|
|
29
|
+
Injects: mcp~=1.30.0, uvicorn[standard]~=0.53.0, starlette~=1.6.0,
|
|
30
|
+
dependency-injector~=4.49.1, pydantic-settings~=2.15.0
|
|
31
31
|
|
|
32
32
|
Sets builder params: scripts_entry_fn="main"
|
|
33
33
|
"""
|
|
@@ -127,11 +127,11 @@ class EntryPointMcp(ModuleFactory):
|
|
|
127
127
|
)
|
|
128
128
|
|
|
129
129
|
# Dependencies
|
|
130
|
-
builder.add_dependency("mcp
|
|
131
|
-
builder.add_dependency("uvicorn[standard]
|
|
132
|
-
builder.add_dependency("starlette
|
|
133
|
-
builder.add_dependency("dependency-injector
|
|
134
|
-
builder.add_dependency("pydantic-settings
|
|
130
|
+
builder.add_dependency("mcp~=1.30.0") # ~=1.30.0 caps below 2.0; templates target the 1.x FastMCP API
|
|
131
|
+
builder.add_dependency("uvicorn[standard]~=0.53.0")
|
|
132
|
+
builder.add_dependency("starlette~=1.6.0")
|
|
133
|
+
builder.add_dependency("dependency-injector~=4.49.1")
|
|
134
|
+
builder.add_dependency("pydantic-settings~=2.15.0")
|
|
135
135
|
|
|
136
136
|
# Signal to module_builder.persist() to update pyproject.toml scripts
|
|
137
137
|
builder.add_param("scripts_entry", True)
|
|
@@ -32,10 +32,10 @@ class EntryPointRestApi(ModuleFactory):
|
|
|
32
32
|
- src/main.py
|
|
33
33
|
|
|
34
34
|
Injects:
|
|
35
|
-
- fastapi[standard]
|
|
36
|
-
- uvicorn[standard]
|
|
37
|
-
- dependency-injector
|
|
38
|
-
- pydantic-settings
|
|
35
|
+
- fastapi[standard]~=0.141.1
|
|
36
|
+
- uvicorn[standard]~=0.53.0
|
|
37
|
+
- dependency-injector~=4.49.1
|
|
38
|
+
- pydantic-settings~=2.15.0
|
|
39
39
|
"""
|
|
40
40
|
project_root = builder.project_root
|
|
41
41
|
pkg = builder.project_ctx.python_package
|
|
@@ -121,10 +121,10 @@ class EntryPointRestApi(ModuleFactory):
|
|
|
121
121
|
|
|
122
122
|
# Add dependencies
|
|
123
123
|
deps = [
|
|
124
|
-
"fastapi[standard]
|
|
125
|
-
"uvicorn[standard]
|
|
126
|
-
"dependency-injector
|
|
127
|
-
"pydantic-settings
|
|
124
|
+
"fastapi[standard]~=0.141.1",
|
|
125
|
+
"uvicorn[standard]~=0.53.0",
|
|
126
|
+
"dependency-injector~=4.49.1",
|
|
127
|
+
"pydantic-settings~=2.15.0",
|
|
128
128
|
]
|
|
129
129
|
for dep in deps:
|
|
130
130
|
builder.add_dependency(dep)
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"""A2A async agent handler stub."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
+
{%- if enable_kafka %}
|
|
4
5
|
|
|
5
|
-
{% if enable_kafka %}
|
|
6
6
|
# Kafka consumer stub — replace with your actual broker configuration.
|
|
7
7
|
# from aiokafka import AIOKafkaConsumer
|
|
8
|
-
{
|
|
9
|
-
{
|
|
8
|
+
{%- endif %}
|
|
9
|
+
{%- if enable_mcp_client %}
|
|
10
|
+
|
|
10
11
|
# MCP tool-call client stub — replace with your actual MCP client.
|
|
11
12
|
# from mcp import ClientSession
|
|
12
|
-
{
|
|
13
|
+
{%- endif %}
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class {{ project.name }}Agent:
|
|
@@ -10,9 +10,12 @@ from starlette.routing import Mount
|
|
|
10
10
|
|
|
11
11
|
from {{ project.python_package }}.application.config.container import Container
|
|
12
12
|
from {{ project.python_package }}.infrastructure.entry_points.mcp_server import tools
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
{
|
|
13
|
+
{%- if with_resources %}
|
|
14
|
+
from {{ project.python_package }}.infrastructure.entry_points.mcp_server import resources
|
|
15
|
+
{%- endif %}
|
|
16
|
+
{%- if with_prompts %}
|
|
17
|
+
from {{ project.python_package }}.infrastructure.entry_points.mcp_server import prompts
|
|
18
|
+
{%- endif %}
|
|
16
19
|
|
|
17
20
|
mcp: FastMCP = FastMCP("{{ project.name }}", stateless_http=True)
|
|
18
21
|
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from dependency_injector.wiring import Provide, inject
|
|
5
|
+
from dependency_injector.wiring import Provide, inject # noqa: F401
|
|
6
6
|
from mcp.server.fastmcp import FastMCP
|
|
7
7
|
|
|
8
|
-
from {{ project.python_package }}.application.config.container import Container
|
|
8
|
+
from {{ project.python_package }}.application.config.container import Container # noqa: F401
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@inject
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from dependency_injector.wiring import Provide, inject
|
|
5
|
+
from dependency_injector.wiring import Provide, inject # noqa: F401
|
|
6
6
|
from mcp.server.fastmcp import FastMCP
|
|
7
7
|
|
|
8
|
-
from {{ project.python_package }}.application.config.container import Container
|
|
8
|
+
from {{ project.python_package }}.application.config.container import Container # noqa: F401
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@inject
|
|
@@ -6,8 +6,8 @@ import sys
|
|
|
6
6
|
|
|
7
7
|
import uvicorn
|
|
8
8
|
|
|
9
|
-
from {{ project.python_package }}.application.config.config import settings
|
|
10
9
|
from {{ project.python_package }}.application import app
|
|
10
|
+
from {{ project.python_package }}.application.config.config import settings
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def main() -> None:
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from dependency_injector.wiring import Provide, inject
|
|
5
|
+
from dependency_injector.wiring import Provide, inject # noqa: F401
|
|
6
6
|
from mcp.server.fastmcp import FastMCP
|
|
7
7
|
|
|
8
|
-
from {{ project.python_package }}.application.config.container import Container
|
|
8
|
+
from {{ project.python_package }}.application.config.container import Container # noqa: F401
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@inject
|
|
@@ -9,8 +9,8 @@ from fastapi import FastAPI
|
|
|
9
9
|
from fastapi.exceptions import RequestValidationError
|
|
10
10
|
from starlette.exceptions import HTTPException
|
|
11
11
|
|
|
12
|
-
from {{ project.python_package }}.application.config.container import Container
|
|
13
12
|
from {{ project.python_package }}.application.config.config import Settings
|
|
13
|
+
from {{ project.python_package }}.application.config.container import Container
|
|
14
14
|
from {{ project.python_package }}.infrastructure.entry_points.api.v1 import rest_controller
|
|
15
15
|
from {{ project.python_package }}.infrastructure.entry_points.api.v1.exception_handler import (
|
|
16
16
|
generic_exception_handler,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
from fastapi import FastAPI
|
|
5
|
+
from fastapi.testclient import TestClient
|
|
5
6
|
|
|
6
7
|
from {{ project.python_package }}.application.app import create_app
|
|
7
8
|
|
|
@@ -12,9 +13,8 @@ def test_create_app_returns_fastapi_instance() -> None:
|
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def test_create_app_has_router_included() -> None:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
assert any("/api" in p or "/health" in p for p in routes)
|
|
16
|
+
client = TestClient(create_app())
|
|
17
|
+
assert client.get("/v1/health").status_code == 200
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def test_create_app_registers_exception_handlers() -> None:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Root application DI container."""
|
|
2
2
|
from dependency_injector import containers, providers
|
|
3
3
|
|
|
4
|
-
from {{ python_package }}.application.config.resource_container import ResourceContainer
|
|
5
4
|
from {{ python_package }}.application.config.driven_adapters_container import DAContainer
|
|
5
|
+
from {{ python_package }}.application.config.resource_container import ResourceContainer
|
|
6
6
|
from {{ python_package }}.application.config.usecases_container import UseCaseContainer
|
|
7
7
|
|
|
8
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Driven-adapters DI container."""
|
|
2
|
-
from dependency_injector import containers, providers
|
|
2
|
+
from dependency_injector import containers, providers # noqa: F401
|
|
3
3
|
|
|
4
4
|
# Import driven-adapter classes here to wire them in the DAContainer below.
|
|
5
5
|
#{{ python_package }}.infrastructure.driven_adapters.my_repo.MyRepo
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Resource DI container — wires infrastructure resources (DB pools, HTTP clients, etc.)."""
|
|
2
|
-
from dependency_injector import containers, providers
|
|
2
|
+
from dependency_injector import containers, providers # noqa: F401
|
|
3
3
|
|
|
4
|
-
from {{ python_package }}.application.config.config import settings
|
|
4
|
+
from {{ python_package }}.application.config.config import settings # noqa: F401
|
|
5
5
|
|
|
6
6
|
# Import resource-level classes here to wire them in the ResourceContainer below.
|
|
7
7
|
#{{ python_package }}.infrastructure.driven_adapters.my_repo.MyResource
|
|
@@ -4,16 +4,19 @@ version = "0.1.0"
|
|
|
4
4
|
description = "Clean Architecture Python project"
|
|
5
5
|
requires-python = ">=3.13"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"dependency-injector==4.49.
|
|
8
|
-
"pydantic-settings==2.
|
|
7
|
+
"dependency-injector==4.49.1",
|
|
8
|
+
"pydantic-settings==2.15.0",
|
|
9
9
|
]
|
|
10
10
|
|
|
11
11
|
[dependency-groups]
|
|
12
|
-
|
|
13
|
-
"pytest==9.
|
|
12
|
+
test = [
|
|
13
|
+
"pytest==9.1.1",
|
|
14
14
|
"pytest-cov==7.1.0",
|
|
15
|
-
"pytest-asyncio==1.
|
|
16
|
-
|
|
15
|
+
"pytest-asyncio==1.4.0",
|
|
16
|
+
]
|
|
17
|
+
dev = [
|
|
18
|
+
"ruff==0.16.8",
|
|
19
|
+
{ include-group = "test" },
|
|
17
20
|
]
|
|
18
21
|
|
|
19
22
|
[project.scripts]
|
|
@@ -34,7 +37,6 @@ target-version = "py313"
|
|
|
34
37
|
|
|
35
38
|
[tool.ruff.lint]
|
|
36
39
|
select = ["E", "F", "I", "UP", "ANN"]
|
|
37
|
-
ignore = ["ANN101", "ANN102"]
|
|
38
40
|
|
|
39
41
|
[tool.ruff.lint.per-file-ignores]
|
|
40
42
|
"src/tests/**/*.py" = ["ANN"]
|
|
@@ -62,5 +64,10 @@ exclude_also = [
|
|
|
62
64
|
]
|
|
63
65
|
|
|
64
66
|
[tool.pytest.ini_options]
|
|
65
|
-
addopts = "--cov={{ python_package }} --cov-fail-under=80"
|
|
67
|
+
addopts = "--cov={{ python_package }} --cov-fail-under=80 --import-mode=importlib"
|
|
66
68
|
testpaths = ["src/tests"]
|
|
69
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
70
|
+
filterwarnings = [
|
|
71
|
+
"ignore:.*httpx.*:DeprecationWarning",
|
|
72
|
+
"ignore:.*BlockingPortal.*:DeprecationWarning",
|
|
73
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: scaffold-ca-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Scaffolder to generate Clean Architecture apps
|
|
5
5
|
Project-URL: Homepage, https://github.com/bancolombia/scaffold-clean-architecture-py
|
|
6
6
|
Project-URL: Repository, https://github.com/bancolombia/scaffold-clean-architecture-py
|
|
@@ -22,11 +22,11 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
|
22
22
|
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Python: >=3.13
|
|
24
24
|
Requires-Dist: jinja2~=3.1.6
|
|
25
|
-
Requires-Dist: pydantic~=2.13.
|
|
25
|
+
Requires-Dist: pydantic~=2.13.5
|
|
26
26
|
Requires-Dist: pyyaml~=6.0.3
|
|
27
27
|
Requires-Dist: rich~=15.0.0
|
|
28
28
|
Requires-Dist: tomli-w~=1.2.0
|
|
29
|
-
Requires-Dist: typer~=0.
|
|
29
|
+
Requires-Dist: typer~=0.27.2
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
32
32
|
# scaffold-ca-python
|
|
@@ -80,7 +80,7 @@ cd my-app
|
|
|
80
80
|
3. Generate a domain model.
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
scaffold gm --name
|
|
83
|
+
scaffold gm --name order
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
4. Validate the project structure.
|
|
@@ -108,11 +108,11 @@ scaffold ca --name my-project --dry-run
|
|
|
108
108
|
Scaffold a Pydantic v2 domain model and its test stub.
|
|
109
109
|
|
|
110
110
|
```bash
|
|
111
|
-
scaffold gm --name
|
|
111
|
+
scaffold gm --name order
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
```bash
|
|
115
|
-
scaffold gm --name
|
|
115
|
+
scaffold gm --name order --dry-run
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
### scaffold guc
|
|
@@ -120,11 +120,11 @@ scaffold gm --name Order --dry-run
|
|
|
120
120
|
Scaffold a use case in `domain/usecase/`.
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
scaffold guc --name
|
|
123
|
+
scaffold guc --name create_order
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
```bash
|
|
127
|
-
scaffold guc --name
|
|
127
|
+
scaffold guc --name create_order --dry-run
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
### scaffold gda
|
|
@@ -136,7 +136,7 @@ scaffold gda --type rest-consumer
|
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
```bash
|
|
139
|
-
scaffold gda --type generic --name
|
|
139
|
+
scaffold gda --type generic --name my_adapter --dry-run
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
### scaffold gep
|
|
@@ -156,11 +156,11 @@ scaffold gep --type mcp --with-resources --with-prompts --dry-run
|
|
|
156
156
|
Scaffold a helper utility module and its test stub.
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
|
-
scaffold gh --name
|
|
159
|
+
scaffold gh --name json_parser
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
|
-
scaffold gh --name
|
|
163
|
+
scaffold gh --name json_parser --dry-run
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
### scaffold gpipe
|
|
@@ -192,11 +192,11 @@ scaffold vs --dry-run
|
|
|
192
192
|
Delete a previously generated module and its mirrored test file.
|
|
193
193
|
|
|
194
194
|
```bash
|
|
195
|
-
scaffold dm --name
|
|
195
|
+
scaffold dm --name order
|
|
196
196
|
```
|
|
197
197
|
|
|
198
198
|
```bash
|
|
199
|
-
scaffold dm --name
|
|
199
|
+
scaffold dm --name order --dry-run
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
### scaffold up
|
|
@@ -217,8 +217,8 @@ scaffold update-project --dry-run
|
|
|
217
217
|
|----------------|---------|------|
|
|
218
218
|
| Python | >=3.13 | Runtime |
|
|
219
219
|
| uv | latest | Dependency management, build, and publish |
|
|
220
|
-
| Typer | >=0.
|
|
221
|
-
| Rich | >=
|
|
220
|
+
| Typer | >=0.27.2 | CLI framework |
|
|
221
|
+
| Rich | >=15.0.0 | Terminal output formatting |
|
|
222
222
|
| Jinja2 | >=3.1 | Template engine for code generation |
|
|
223
223
|
| Pydantic v2 | >=2.0 | Runtime validation of template context |
|
|
224
224
|
| hatchling | latest | Build backend |
|
|
@@ -248,12 +248,12 @@ scaffold update-project --dry-run
|
|
|
248
248
|
|
|
249
249
|
## Contributing
|
|
250
250
|
|
|
251
|
-
1. Fork the upstream repository on GitHub: https://github.com/
|
|
251
|
+
1. Fork the upstream repository on GitHub: https://github.com/bancolombia/scaffold-clean-architecture-py
|
|
252
252
|
2. Clone your fork.
|
|
253
253
|
|
|
254
254
|
```bash
|
|
255
|
-
git clone https://github.com/YOUR-USER/scaffold-
|
|
256
|
-
cd scaffold-
|
|
255
|
+
git clone https://github.com/YOUR-USER/scaffold-clean-architecture-py.git
|
|
256
|
+
cd scaffold-clean-architecture-py
|
|
257
257
|
```
|
|
258
258
|
|
|
259
259
|
3. Set up the development environment.
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
scaffold_ca_python/__init__.py,sha256=
|
|
1
|
+
scaffold_ca_python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
scaffold_ca_python/cli.py,sha256=A0h0pkoNPy3EE55lApnjRuevhWb_Aa-IB7jekaaiAcM,971
|
|
3
3
|
scaffold_ca_python/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
scaffold_ca_python/commands/delete_module.py,sha256=
|
|
5
|
-
scaffold_ca_python/commands/generate_driven_adapter.py,sha256=
|
|
6
|
-
scaffold_ca_python/commands/generate_entry_point.py,sha256=
|
|
7
|
-
scaffold_ca_python/commands/generate_helper.py,sha256
|
|
8
|
-
scaffold_ca_python/commands/generate_model.py,sha256=
|
|
4
|
+
scaffold_ca_python/commands/delete_module.py,sha256=DZa4rTVhPpt5-HV6dCZY-qWOV18K9qns6gKCsgjDepg,7124
|
|
5
|
+
scaffold_ca_python/commands/generate_driven_adapter.py,sha256=ckHdHVUV5T3SSvLwPp_jQYdp-Av9j2AV836So6tMODk,6938
|
|
6
|
+
scaffold_ca_python/commands/generate_entry_point.py,sha256=nSEz218Ar3WzkzOZOU_7DJ5KzEwGa7w6h9XVV2WQmOw,11943
|
|
7
|
+
scaffold_ca_python/commands/generate_helper.py,sha256=i5zaqGvTO6nEvVOGVdOsZoDpJf1cWX7GbGaNcEYLSWY,4470
|
|
8
|
+
scaffold_ca_python/commands/generate_model.py,sha256=I1dMNoVMNytdMZ5mzBAF1WzJDIHMacxwLOmhH29nTIc,4546
|
|
9
9
|
scaffold_ca_python/commands/generate_pipeline.py,sha256=EYPM9csDnrYB3bpnC4YSycqI3bAE8bYy1283OEEC5Ts,5537
|
|
10
|
-
scaffold_ca_python/commands/generate_project.py,sha256=
|
|
11
|
-
scaffold_ca_python/commands/generate_use_case.py,sha256=
|
|
10
|
+
scaffold_ca_python/commands/generate_project.py,sha256=6jzX5o1451YmWYFqJIhDVCPz8kh9vDBQ4ixDddkaLm8,6867
|
|
11
|
+
scaffold_ca_python/commands/generate_use_case.py,sha256=w6BUdF3uXeo3dNsLN76oSYvQu-5WOqvpjwlot29sA7U,4536
|
|
12
12
|
scaffold_ca_python/commands/update_project.py,sha256=cW9IuAF1yIFkAkzOJdioFv97wr7mRiid08KkqOlFmrM,2845
|
|
13
13
|
scaffold_ca_python/commands/validate_structure.py,sha256=JF6Cb3IQ9d6VcjaReSHHzoXGSmqyoyMWNFplqSCFCOQ,2846
|
|
14
14
|
scaffold_ca_python/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
scaffold_ca_python/core/file_writer.py,sha256=DdgD6h4lx6FhKtc0AJvOIBryHgfTE4d4ZCMOfrEAuAI,5030
|
|
16
|
-
scaffold_ca_python/core/module_builder.py,sha256=
|
|
17
|
-
scaffold_ca_python/core/name_utils.py,sha256=
|
|
16
|
+
scaffold_ca_python/core/module_builder.py,sha256=rcWSWxRX4bsaWLCtCHNTAcVFZiHABA5zTn9rilUojKE,5965
|
|
17
|
+
scaffold_ca_python/core/name_utils.py,sha256=OAMl4YrgvaZgulemcqYpUp8iHNvR8ieTrccNVc_zQB4,2765
|
|
18
18
|
scaffold_ca_python/core/project_detector.py,sha256=G-n9domRQp65uzUbb7CXJk1nFMCTb347RMvfiVoYAxI,3321
|
|
19
|
-
scaffold_ca_python/core/pyproject_writer.py,sha256=
|
|
19
|
+
scaffold_ca_python/core/pyproject_writer.py,sha256=zpxgubt-XSZR5domgL4LG_9AWD9b_cNrDM8fuHmZRzE,7792
|
|
20
20
|
scaffold_ca_python/core/structure_validator.py,sha256=Cco8Ghpjyit5t2AKxuFpCmfwsG4D9yqz3adycrz7YR8,5841
|
|
21
21
|
scaffold_ca_python/core/template_renderer.py,sha256=sMu6iwlObtIYOuRRsyNZu1J-M_jkzx5yHzBwlGZkHOI,3421
|
|
22
22
|
scaffold_ca_python/factory/__init__.py,sha256=6MZYzBgYxvvJwjGrYSaW1E_fNFaFAQ0EHJKSKMo_DHQ,492
|
|
23
23
|
scaffold_ca_python/factory/driven_adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
scaffold_ca_python/factory/driven_adapters/da_generic.py,sha256=iKsskAkBHEmutXb5QybF_3521PnMLYlv3cpEMHClptk,2412
|
|
25
|
-
scaffold_ca_python/factory/driven_adapters/da_rest_consumer.py,sha256=
|
|
26
|
-
scaffold_ca_python/factory/driven_adapters/da_secrets.py,sha256=
|
|
25
|
+
scaffold_ca_python/factory/driven_adapters/da_rest_consumer.py,sha256=6ybnAAHeMMJMXRl2x7rqAS36GeZS-vEf8I4L2NMOAaU,2465
|
|
26
|
+
scaffold_ca_python/factory/driven_adapters/da_secrets.py,sha256=Qmhdt_DSfZXx4EY2MKSBhbAoyVAWHVftbgsN2okyvZA,2240
|
|
27
27
|
scaffold_ca_python/factory/entry_points/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
scaffold_ca_python/factory/entry_points/ep_agent.py,sha256=
|
|
28
|
+
scaffold_ca_python/factory/entry_points/ep_agent.py,sha256=EcJZnCVW2_I-Zgbdxu1t4mXPnKg1PSinBzKwXyHGHZQ,3033
|
|
29
29
|
scaffold_ca_python/factory/entry_points/ep_generic.py,sha256=4CYtmv1svJ6zJgLTqF6awXUlhSSf7Mj2IMGyv8KjhbU,2494
|
|
30
|
-
scaffold_ca_python/factory/entry_points/ep_mcp.py,sha256
|
|
31
|
-
scaffold_ca_python/factory/entry_points/ep_restapi.py,sha256=
|
|
30
|
+
scaffold_ca_python/factory/entry_points/ep_mcp.py,sha256=-MbR5u5-ibi3ZrB4Ob9L7zmmdneMfNfzsSVNnO910kQ,5473
|
|
31
|
+
scaffold_ca_python/factory/entry_points/ep_restapi.py,sha256=pXea8u6eVodc5sZ_m1PyhM5_ylJ5I-1lyiYZEDuldjQ,4796
|
|
32
32
|
scaffold_ca_python/factory/simple/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
scaffold_ca_python/factory/simple/delete_module_factory.py,sha256=omsMgjmHbWXwV1ASZU_OAtvy0qG5BPYQCg2BDg_bw9o,3237
|
|
34
34
|
scaffold_ca_python/factory/simple/helper_factory.py,sha256=vN8z7-4IxeSvqRSEWWOreFnp7jQxFB10kztuHN0CCJs,2302
|
|
@@ -45,12 +45,12 @@ scaffold_ca_python/templates/driven_adapter/generic/adapter.py.jinja2,sha256=54K
|
|
|
45
45
|
scaffold_ca_python/templates/driven_adapter/generic/test_adapter.py.jinja2,sha256=Q_eyB5KW6Q9m391TKEcdLgMpg_Rs_JeUG51HebX1Lrk,563
|
|
46
46
|
scaffold_ca_python/templates/driven_adapter/rest_consumer/__init__.py.jinja2,sha256=bq5MGxcHGw7lPknR-uuq00xo_lodxJ4c-mHro88cYnE,44
|
|
47
47
|
scaffold_ca_python/templates/driven_adapter/rest_consumer/rest_consumer.py.jinja2,sha256=cgXzrREAY-517wSnpYz-p8-0sK57yhR15dsCyIAw_lI,988
|
|
48
|
-
scaffold_ca_python/templates/driven_adapter/rest_consumer/test_rest_consumer.py.jinja2,sha256=
|
|
48
|
+
scaffold_ca_python/templates/driven_adapter/rest_consumer/test_rest_consumer.py.jinja2,sha256=pCHbhfGM6-TK8D8tETiBhOS0TVfY2GRGHSrmPj-6Ygc,637
|
|
49
49
|
scaffold_ca_python/templates/driven_adapter/secrets/__init__.py.jinja2,sha256=n_-tUwoq5VGFv_KxlbzO1TECmPnME1LaF3nVSBwlPl4,31
|
|
50
50
|
scaffold_ca_python/templates/driven_adapter/secrets/secrets_adapter.py.jinja2,sha256=uy3bl5_vM_ZnAL4WSYbL9vhoXSSAJ0KdtkCQHRiKORE,1217
|
|
51
51
|
scaffold_ca_python/templates/driven_adapter/secrets/test_secrets_adapter.py.jinja2,sha256=Tuy0-gVdN7aRVnTXGrdN-at5d2cLmelwJVcw_ypdxTI,688
|
|
52
52
|
scaffold_ca_python/templates/entry_point/agent/__init__.py.jinja2,sha256=pbboGjTM3_gkQ9QXzM3QFHYsfMETHzkLAseIJa41GVM,33
|
|
53
|
-
scaffold_ca_python/templates/entry_point/agent/agent.py.jinja2,sha256=
|
|
53
|
+
scaffold_ca_python/templates/entry_point/agent/agent.py.jinja2,sha256=wQpDne1xXaHxikCB9MVsVQisqQiAuEeUOMGZhhBb4TM,1588
|
|
54
54
|
scaffold_ca_python/templates/entry_point/agent/card.py.jinja2,sha256=M8RbWj0c8B9bjBBmCgUdAdRPcUhEETc6BEFrB5ZeKCA,415
|
|
55
55
|
scaffold_ca_python/templates/entry_point/agent/entrypoint_main.py.jinja2,sha256=igDSxs4vUXV3oGW10fawgM9dhwPgO5SjAeBmmK01ZuI,247
|
|
56
56
|
scaffold_ca_python/templates/entry_point/agent/test_agent.py.jinja2,sha256=DDl55Pg-m3gI_nD8mbDHbtnFqaDExBNf9z1xOLGDS8Q,591
|
|
@@ -59,22 +59,22 @@ scaffold_ca_python/templates/entry_point/generic/entrypoint_main.py.jinja2,sha25
|
|
|
59
59
|
scaffold_ca_python/templates/entry_point/generic/handler.py.jinja2,sha256=glCst1soTiKG_gDdq5C-OogzljOJ_QooaW_boYt7gsg,417
|
|
60
60
|
scaffold_ca_python/templates/entry_point/generic/test_handler.py.jinja2,sha256=gRhvVabkylQ8z06JZ9L2CHdTa83oxL1X4ldR3_DZQWg,1195
|
|
61
61
|
scaffold_ca_python/templates/entry_point/mcp/__init__.py.jinja2,sha256=8J_YmIXHUh26PkaxeM8z5lf-dtK0da1T4haOM8U6Y9A,38
|
|
62
|
-
scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2,sha256=
|
|
63
|
-
scaffold_ca_python/templates/entry_point/mcp/prompts.py.jinja2,sha256=
|
|
64
|
-
scaffold_ca_python/templates/entry_point/mcp/resources.py.jinja2,sha256=
|
|
65
|
-
scaffold_ca_python/templates/entry_point/mcp/server.py.jinja2,sha256=
|
|
66
|
-
scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2,sha256=
|
|
62
|
+
scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2,sha256=VMU2AWXAVJVT0IqTI3E6XGBGn2rR80ViSN0jNyRf3E4,1916
|
|
63
|
+
scaffold_ca_python/templates/entry_point/mcp/prompts.py.jinja2,sha256=PUFRtuWlEzR7bg7zY0O8dx-5tNrEZXrNZ5XgBoUMulQ,765
|
|
64
|
+
scaffold_ca_python/templates/entry_point/mcp/resources.py.jinja2,sha256=ZV_2WwklhSGhVFel3stS00zmPJuTlznfvFrpiM9dDKo,840
|
|
65
|
+
scaffold_ca_python/templates/entry_point/mcp/server.py.jinja2,sha256=gVzJm_ugY9E7-1RYIfbEKduDR71gluq4l3OB_aTRr1w,656
|
|
66
|
+
scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2,sha256=MjVDhAXTz35HcCOVTsaWA--qvD_Qyn2SNG99CF6wctk,967
|
|
67
67
|
scaffold_ca_python/templates/entry_point/mcp/test_prompts.py.jinja2,sha256=Y9C7z7jpjoTKANlFB6hNJUUw2abt5qF2C4Nm7MkvDvA,1566
|
|
68
68
|
scaffold_ca_python/templates/entry_point/mcp/test_resources.py.jinja2,sha256=2jHfPqyJ4TJZJupxe8T7gVz2ysaqZHcAog6186ie2CI,1763
|
|
69
69
|
scaffold_ca_python/templates/entry_point/mcp/test_tools.py.jinja2,sha256=bd_8nvLuqPApKIYQoBhEokMYZrPYFUn1pnDEIOVxwCo,1550
|
|
70
|
-
scaffold_ca_python/templates/entry_point/mcp/tools.py.jinja2,sha256=
|
|
70
|
+
scaffold_ca_python/templates/entry_point/mcp/tools.py.jinja2,sha256=Eqxa-pc_Mf4L0QvWMefKeg43bnjxwYuaNXRg6I9H1pQ,753
|
|
71
71
|
scaffold_ca_python/templates/entry_point/restapi/__init__.py.jinja2,sha256=BrpLExG7nc6cEOYWpJKymUXEvGVc1lU9sb_kBw_HPYg,36
|
|
72
|
-
scaffold_ca_python/templates/entry_point/restapi/app.py.jinja2,sha256=
|
|
72
|
+
scaffold_ca_python/templates/entry_point/restapi/app.py.jinja2,sha256=HQQqi8ZiLTaNIt9g9_iJyjxAGt6KXj4lqGcJLI1Qx9s,2626
|
|
73
73
|
scaffold_ca_python/templates/entry_point/restapi/exception_handler.py.jinja2,sha256=_wON4AvW6liZutgHx-TGWrBpJOC8q0ZY3mPhIS8Aveg,1343
|
|
74
74
|
scaffold_ca_python/templates/entry_point/restapi/health.py.jinja2,sha256=nKEtxuoAQ4Le9SGhM3Wz9K77XcCu7wnvBgjhquGqr3E,244
|
|
75
75
|
scaffold_ca_python/templates/entry_point/restapi/rest_controller.py.jinja2,sha256=rKsSdx0arV_K87HL-VRyI7HFpSD3k-jfK9zIG4A03xc,728
|
|
76
76
|
scaffold_ca_python/templates/entry_point/restapi/server.py.jinja2,sha256=F6AYRMP3q02WMm09RWbX3tAEYG_6PkoDYI3c5A8AIdc,207
|
|
77
|
-
scaffold_ca_python/templates/entry_point/restapi/test_app.py.jinja2,sha256=
|
|
77
|
+
scaffold_ca_python/templates/entry_point/restapi/test_app.py.jinja2,sha256=YC2j7SI9eXsIx_ymNMHP1pqRpegWQ4Xc2MJrKwFcK7s,647
|
|
78
78
|
scaffold_ca_python/templates/entry_point/restapi/test_exception_handler.py.jinja2,sha256=O7Sqf1d9mPTeB0DDXtnyCrbKE4o2zNsgYzf-PdD3rU4,1361
|
|
79
79
|
scaffold_ca_python/templates/entry_point/restapi/test_rest_controller.py.jinja2,sha256=Un01qIR8L5bgLRKbChWptrbTCL4t45PAmrXwKMvKShQ,1142
|
|
80
80
|
scaffold_ca_python/templates/entry_point/restapi/test_server.py.jinja2,sha256=7_mDfqP14onocc1RjJ732ODpoUAVPiB1Zsf5WEqAlaI,426
|
|
@@ -92,18 +92,18 @@ scaffold_ca_python/templates/project/gitignore.jinja2,sha256=ZRf2cRtqbe2d48RfWJW
|
|
|
92
92
|
scaffold_ca_python/templates/project/layer_init.jinja2,sha256=oIlTSrce4ozqEKUU_1TB4473ufiE0SiGG_PJmEkT4FA,25
|
|
93
93
|
scaffold_ca_python/templates/project/main.py.jinja2,sha256=di_ujhkFafXqJUymSdVjEF0tihQ_0xKbKSIyV91rPpk,161
|
|
94
94
|
scaffold_ca_python/templates/project/mypy_ini.jinja2,sha256=SJ_UiLRZ8wBJ7hqSo3QDeMSsempBfaGvqiR_ASyIxR0,93
|
|
95
|
-
scaffold_ca_python/templates/project/pyproject_toml.jinja2,sha256=
|
|
95
|
+
scaffold_ca_python/templates/project/pyproject_toml.jinja2,sha256=O8G8S3f7rmRzQkjuRj2n_445bGD8fBDZu6S0QkwSzi0,1574
|
|
96
96
|
scaffold_ca_python/templates/project/python_version.jinja2,sha256=Auc1s9_hwygz61ULf_j_oX9fK8P6HnuuYaj1o4g845g,5
|
|
97
97
|
scaffold_ca_python/templates/project/application/config/__init__.py.jinja2,sha256=L9xWIW2Gd3VhRdx1RfUf7efBrIuFf3ft54eLQT1tG9g,32
|
|
98
98
|
scaffold_ca_python/templates/project/application/config/config.py.jinja2,sha256=218sZQ1115odJcoI7W6-1kiFjkWjO56d80fqQXk4dyM,323
|
|
99
|
-
scaffold_ca_python/templates/project/application/config/container.py.jinja2,sha256=
|
|
100
|
-
scaffold_ca_python/templates/project/application/config/driven_adapters_container.py.jinja2,sha256=
|
|
101
|
-
scaffold_ca_python/templates/project/application/config/resource_container.py.jinja2,sha256=
|
|
99
|
+
scaffold_ca_python/templates/project/application/config/container.py.jinja2,sha256=zhGtAtqp6h73IpO-k6Bj2qgI7BmshfULDh9smBRr-D0,697
|
|
100
|
+
scaffold_ca_python/templates/project/application/config/driven_adapters_container.py.jinja2,sha256=WhRpupvLP8tOJgp4IJ0A5RitntfRPVFjCDUjhAhBt8U,464
|
|
101
|
+
scaffold_ca_python/templates/project/application/config/resource_container.py.jinja2,sha256=k3wy8uSD7GJZNEf379fv2lMEzdq5eaNqmoaOw9Jq1vs,643
|
|
102
102
|
scaffold_ca_python/templates/project/application/config/usecases_container.py.jinja2,sha256=3fEHe6mkXkDHlfO5nhLqzLB7ccTpqwtjHZfLyfysbro,527
|
|
103
103
|
scaffold_ca_python/templates/use_case/test_use_case.py.jinja2,sha256=3K1bNKDBQc29rcv8UHUZnROCUmcFSCwJhbm0xP9Uako,364
|
|
104
104
|
scaffold_ca_python/templates/use_case/use_case.py.jinja2,sha256=KPtaK1wvZ-7qHdDZyuVfqXTPYwJdNUMPXQZGuKZFA7Y,217
|
|
105
|
-
scaffold_ca_python-0.1.
|
|
106
|
-
scaffold_ca_python-0.1.
|
|
107
|
-
scaffold_ca_python-0.1.
|
|
108
|
-
scaffold_ca_python-0.1.
|
|
109
|
-
scaffold_ca_python-0.1.
|
|
105
|
+
scaffold_ca_python-0.1.4.dist-info/METADATA,sha256=Uk7rsmYTy1wNQRZZVXquueaB2t-KUqrLpFJx52hIvLM,6803
|
|
106
|
+
scaffold_ca_python-0.1.4.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
107
|
+
scaffold_ca_python-0.1.4.dist-info/entry_points.txt,sha256=4PyYg6mNCvAlt2yF_o1-QR2CBXiowYGpNyqcP88tu6I,104
|
|
108
|
+
scaffold_ca_python-0.1.4.dist-info/licenses/LICENSE,sha256=3ZZEP7DK_h3lEjS8r-DvQCec2q7zAqqq7HmSq6cuL0E,1068
|
|
109
|
+
scaffold_ca_python-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|