coloco 0.5.0__tar.gz → 0.5.2__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.
- {coloco-0.5.0 → coloco-0.5.2}/PKG-INFO +2 -2
- {coloco-0.5.0 → coloco-0.5.2}/pyproject.toml +2 -3
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/__main__.py +1 -1
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/db.py +47 -2
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/db.py +1 -1
- coloco-0.5.2/src/coloco/migrations.py +99 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/pyproject.toml-tpl +1 -4
- {coloco-0.5.0 → coloco-0.5.2}/LICENSE +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/README.md +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/__init__.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/api.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/app.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/api.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/build.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/createapp.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/dev.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/node.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/package.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/serve.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/shared/logging.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/cli/shared/muiltiprocess.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/codegen.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/config.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/dependencies.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/exceptions.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/lifespan.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/static.py +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/docker/.dockerignore-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/docker/Dockerfile-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/docker/docker-compose.yml-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/.gitignore-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/README.md-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/package.json-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app/404.svelte-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app/example/api.py-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app/example/index.svelte-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app/index.svelte-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app.css-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app.svelte-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/assets/favicon.png-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/index.html-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/lib/client.ts-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/main.py-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/main.ts-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/svelte.config.js-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/tsconfig.json-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/vite-env.d.ts-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/vite.config.ts-tpl +0 -0
- {coloco-0.5.0 → coloco-0.5.2}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: coloco
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: A kit for creating FastAPI + Svelte applications
|
|
5
5
|
Author-Email: Channel Cat <channelcat@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -10,7 +10,7 @@ Requires-Dist: cyclopts>=3.18.0
|
|
|
10
10
|
Requires-Dist: fastapi>=0.115.0
|
|
11
11
|
Requires-Dist: PyJWT>=2.10.1
|
|
12
12
|
Requires-Dist: rich>=14.0.0
|
|
13
|
-
Requires-Dist: tortoise-orm[asyncpg]
|
|
13
|
+
Requires-Dist: tortoise-orm[asyncpg]==1.1.7
|
|
14
14
|
Requires-Dist: type-less>=0.1.28
|
|
15
15
|
Requires-Dist: uvicorn>=0.31.0
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "coloco"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.2"
|
|
4
4
|
description = "A kit for creating FastAPI + Svelte applications"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Channel Cat", email = "channelcat@gmail.com" },
|
|
@@ -11,7 +11,7 @@ dependencies = [
|
|
|
11
11
|
"fastapi>=0.115.0",
|
|
12
12
|
"PyJWT>=2.10.1",
|
|
13
13
|
"rich>=14.0.0",
|
|
14
|
-
"tortoise-orm[asyncpg]
|
|
14
|
+
"tortoise-orm[asyncpg]==1.1.7",
|
|
15
15
|
"type-less>=0.1.28",
|
|
16
16
|
"uvicorn>=0.31.0",
|
|
17
17
|
]
|
|
@@ -47,7 +47,6 @@ known-third-party = [
|
|
|
47
47
|
"fastapi",
|
|
48
48
|
"rich",
|
|
49
49
|
"tortoise-orm",
|
|
50
|
-
"tortoise-pathway",
|
|
51
50
|
"type-less",
|
|
52
51
|
"uvicorn",
|
|
53
52
|
]
|
|
@@ -8,9 +8,13 @@ import os
|
|
|
8
8
|
from tortoise import Tortoise
|
|
9
9
|
from tortoise.cli import cli as tortoise_cli
|
|
10
10
|
from tortoise.log import logger as tortoise_logger
|
|
11
|
+
from tortoise.migrations.autodetector import MigrationAutodetector
|
|
12
|
+
from tortoise.migrations.writer import format_migration_name
|
|
11
13
|
import cyclopts
|
|
12
14
|
|
|
13
15
|
from ..app import ColocoApp, get_current_app
|
|
16
|
+
from ..db import app_class_to_table_name
|
|
17
|
+
from ..migrations import add_same_run_dependencies
|
|
14
18
|
from .api import DEFAULT_APP, _verify_app
|
|
15
19
|
from .shared.logging import get_cli_logger
|
|
16
20
|
|
|
@@ -42,7 +46,9 @@ def db_command(func):
|
|
|
42
46
|
|
|
43
47
|
|
|
44
48
|
async def get_tortoise(coloco_app: ColocoApp):
|
|
45
|
-
return await Tortoise.init(
|
|
49
|
+
return await Tortoise.init(
|
|
50
|
+
config=coloco_app.orm_config, table_name_generator=app_class_to_table_name
|
|
51
|
+
)
|
|
46
52
|
|
|
47
53
|
|
|
48
54
|
def prep_tortoise_cli(coloco_app: ColocoApp):
|
|
@@ -67,7 +73,46 @@ async def makemigrations(
|
|
|
67
73
|
await get_tortoise(coloco_app)
|
|
68
74
|
|
|
69
75
|
ctx, app_labels = prep_tortoise_cli(coloco_app)
|
|
70
|
-
|
|
76
|
+
if empty:
|
|
77
|
+
return await tortoise_cli.makemigrations(ctx, app_labels, empty, name)
|
|
78
|
+
|
|
79
|
+
# Same flow as tortoise_cli.makemigrations, except migrations created in
|
|
80
|
+
# the same run are linked together (see add_same_run_dependencies) before
|
|
81
|
+
# being written to disk.
|
|
82
|
+
tortoise_config = tortoise_cli._load_config(ctx)
|
|
83
|
+
apps_config = tortoise_cli._select_apps(tortoise_config, app_labels or None)
|
|
84
|
+
apps_dict = {label: app_config.to_dict() for label, app_config in apps_config.items()}
|
|
85
|
+
for label, app_config in apps_dict.items():
|
|
86
|
+
migrations_module, _ = tortoise_cli._ensure_migrations_package(label, app_config)
|
|
87
|
+
app_config["migrations"] = migrations_module
|
|
88
|
+
|
|
89
|
+
config_dict = tortoise_config.to_dict()
|
|
90
|
+
config_dict["apps"] = apps_dict
|
|
91
|
+
|
|
92
|
+
async with tortoise_cli.tortoise_cli_context(config_dict) as tortoise_ctx:
|
|
93
|
+
if not tortoise_ctx.apps:
|
|
94
|
+
raise ValueError("Tortoise apps are not initialized")
|
|
95
|
+
autodetector = MigrationAutodetector(tortoise_ctx.apps, apps_dict)
|
|
96
|
+
writers = await autodetector.changes()
|
|
97
|
+
|
|
98
|
+
if not writers:
|
|
99
|
+
cli.info("No changes detected")
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
if name:
|
|
103
|
+
for writer in writers:
|
|
104
|
+
try:
|
|
105
|
+
number = int(writer.name.split("_", 1)[0])
|
|
106
|
+
except ValueError:
|
|
107
|
+
number = 1
|
|
108
|
+
writer.name = format_migration_name(number, name)
|
|
109
|
+
|
|
110
|
+
# Renaming must happen first so dependencies reference final names
|
|
111
|
+
add_same_run_dependencies(writers)
|
|
112
|
+
|
|
113
|
+
for writer in writers:
|
|
114
|
+
path = writer.write()
|
|
115
|
+
cli.info(f"Created [green]{writer.app_label}.{writer.name}[/green] ({path})")
|
|
71
116
|
|
|
72
117
|
|
|
73
118
|
@db_command
|
|
@@ -43,7 +43,7 @@ def get_orm_config(database_url: str, model_files: list[str]):
|
|
|
43
43
|
]
|
|
44
44
|
app_to_models = defaultdict(list)
|
|
45
45
|
for model_module in model_modules:
|
|
46
|
-
app = model_module.
|
|
46
|
+
app = model_module.removeprefix("src.app.").split(".")[0]
|
|
47
47
|
app_to_models[app].append(model_module)
|
|
48
48
|
return TortoiseConfig(
|
|
49
49
|
connections={"default": ConnectionConfig(db_url=database_url)},
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cross-app dependency linking for tortoise migrations.
|
|
3
|
+
|
|
4
|
+
Tortoise's autodetector only records cross-app dependencies on migrations
|
|
5
|
+
already on disk, so when two apps get migrations in the same makemigrations
|
|
6
|
+
run, the migration referencing another app's models would be written without
|
|
7
|
+
the dependency that orders it after that app's migration, and they would
|
|
8
|
+
apply in alphabetical app order. add_same_run_dependencies links migrations
|
|
9
|
+
created in the same run before they are written, so every migration file
|
|
10
|
+
carries the dependencies that order it.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from tortoise.fields.relational import (
|
|
14
|
+
ForeignKeyFieldInstance,
|
|
15
|
+
ManyToManyFieldInstance,
|
|
16
|
+
OneToOneFieldInstance,
|
|
17
|
+
)
|
|
18
|
+
from tortoise.migrations.writer import MigrationWriter
|
|
19
|
+
|
|
20
|
+
from .cli.shared.logging import get_cli_logger
|
|
21
|
+
|
|
22
|
+
cli = get_cli_logger("coloco.migrations")
|
|
23
|
+
|
|
24
|
+
_RELATION_FIELDS = (ForeignKeyFieldInstance, OneToOneFieldInstance, ManyToManyFieldInstance)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _iter_relation_references(operations):
|
|
28
|
+
"""Yield (app_label, model_name) for each relation field in operations."""
|
|
29
|
+
fields = []
|
|
30
|
+
for operation in operations:
|
|
31
|
+
fields.extend(field for _, field in getattr(operation, "fields", None) or [])
|
|
32
|
+
operation_field = getattr(operation, "field", None)
|
|
33
|
+
if operation_field is not None:
|
|
34
|
+
fields.append(operation_field)
|
|
35
|
+
|
|
36
|
+
for field in fields:
|
|
37
|
+
if not isinstance(field, _RELATION_FIELDS):
|
|
38
|
+
continue
|
|
39
|
+
model_name = field.model_name
|
|
40
|
+
if isinstance(model_name, str):
|
|
41
|
+
if "." in model_name:
|
|
42
|
+
app_label, model = model_name.split(".", 1)
|
|
43
|
+
yield app_label, model
|
|
44
|
+
elif model_name._meta.app:
|
|
45
|
+
yield model_name._meta.app, model_name.__name__
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _related_app_labels(writer: MigrationWriter) -> set[str]:
|
|
49
|
+
"""App labels referenced by relation fields in a migration's operations."""
|
|
50
|
+
labels = {app_label for app_label, _ in _iter_relation_references(writer.operations)}
|
|
51
|
+
labels.discard(writer.app_label)
|
|
52
|
+
return labels
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _depends_on(source: MigrationWriter, target_app: str, writers_by_app: dict) -> bool:
|
|
56
|
+
"""Whether source already reaches target_app through same-run dependencies."""
|
|
57
|
+
seen = set()
|
|
58
|
+
stack = [source]
|
|
59
|
+
while stack:
|
|
60
|
+
writer = stack.pop()
|
|
61
|
+
if writer.app_label in seen:
|
|
62
|
+
continue
|
|
63
|
+
seen.add(writer.app_label)
|
|
64
|
+
if writer.app_label == target_app:
|
|
65
|
+
return True
|
|
66
|
+
for dep_app, dep_name in writer.dependencies:
|
|
67
|
+
dep_writer = writers_by_app.get(dep_app)
|
|
68
|
+
if dep_writer is not None and dep_writer.name == dep_name:
|
|
69
|
+
stack.append(dep_writer)
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def add_same_run_dependencies(writers: list[MigrationWriter]) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Link migrations created in the same run so they apply in topological order.
|
|
76
|
+
|
|
77
|
+
Tortoise's autodetector only records cross-app dependencies on migrations
|
|
78
|
+
already on disk, so a migration referencing a model whose migration is
|
|
79
|
+
created in the same run would otherwise apply in alphabetical app order.
|
|
80
|
+
"""
|
|
81
|
+
writers_by_app = {writer.app_label: writer for writer in writers}
|
|
82
|
+
for writer in writers:
|
|
83
|
+
for related_app in sorted(_related_app_labels(writer)):
|
|
84
|
+
related_writer = writers_by_app.get(related_app)
|
|
85
|
+
if related_writer is None:
|
|
86
|
+
continue
|
|
87
|
+
dependency = (related_app, related_writer.name)
|
|
88
|
+
if dependency in writer.dependencies:
|
|
89
|
+
continue
|
|
90
|
+
if _depends_on(related_writer, writer.app_label, writers_by_app):
|
|
91
|
+
cli.info(
|
|
92
|
+
f"[yellow]Apps {writer.app_label} and {related_app} reference "
|
|
93
|
+
f"each other; circular migrations cannot be ordered and will "
|
|
94
|
+
f"fail to apply. Create the models in one migration and add "
|
|
95
|
+
f"the circular foreign keys in a follow-up migration.[/yellow]"
|
|
96
|
+
)
|
|
97
|
+
continue
|
|
98
|
+
writer.dependencies.append(dependency)
|
|
99
|
+
writer.dependencies.sort()
|
|
@@ -6,12 +6,9 @@ readme = "README.md"
|
|
|
6
6
|
requires-python = ">=3.13"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"coloco>={{ coloco_version }}",
|
|
9
|
-
"tortoise-
|
|
9
|
+
"tortoise-orm>=1.1.7",
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
[tool.coloco]
|
|
13
13
|
app = "src.main.app"
|
|
14
14
|
migrations_dir = "+migrations"
|
|
15
|
-
|
|
16
|
-
[tool.uv.sources]
|
|
17
|
-
tortoise-pathway = { git = "https://github.com/channelcat/tortoise-pathway", rev = "iterate-migration-apply" }
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
{coloco-0.5.0 → coloco-0.5.2}/src/coloco/templates/standard/src/app/example/index.svelte-tpl
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|