coloco 0.4.4__tar.gz → 0.4.6__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.4.4 → coloco-0.4.6}/PKG-INFO +1 -1
- {coloco-0.4.4 → coloco-0.4.6}/pyproject.toml +1 -1
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/api.py +5 -3
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/app.py +10 -5
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/db.py +5 -2
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/db.py +28 -15
- {coloco-0.4.4 → coloco-0.4.6}/LICENSE +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/README.md +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/__init__.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/__main__.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/api.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/build.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/createapp.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/dev.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/node.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/package.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/cli/serve.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/codegen.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/config.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/dependencies.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/exceptions.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/lifespan.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/static.py +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/docker/.dockerignore-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/docker/Dockerfile-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/docker/docker-compose.yml-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+app/404.svelte-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+app/app.css-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+app/app.svelte-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+app/index.html-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+app/index.svelte-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+app/main.ts-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+node/openapi-ts.config.ts-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+node/package.json-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+node/svelte.config.js-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+node/tsconfig.json-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+node/vite-env.d.ts-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/+node/vite.config.ts-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/.gitignore-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/README.md-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/example/api.py-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/example/index.svelte-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/main.py-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/pyproject.toml-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/src/coloco/templates/standard/tsconfig.json-tpl +0 -0
- {coloco-0.4.4 → coloco-0.4.6}/tests/__init__.py +0 -0
|
@@ -87,12 +87,12 @@ def create_api(is_dev: bool = False):
|
|
|
87
87
|
global_routes: list[ColocoRoute] = []
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
def api(func):
|
|
90
|
+
def api(func: T) -> T:
|
|
91
91
|
# Auto-route
|
|
92
92
|
return _add_global_route([f"/{func.__name__}"], {}, func, "GET")
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
def _add_global_route(args, kwargs, func, method: str):
|
|
95
|
+
def _add_global_route(args, kwargs, func: T, method: str) -> T:
|
|
96
96
|
module_name = func.__module__.lstrip("src.app")
|
|
97
97
|
|
|
98
98
|
# Prepend module name to path
|
|
@@ -113,7 +113,9 @@ def _add_global_route(args, kwargs, func, method: str):
|
|
|
113
113
|
else:
|
|
114
114
|
kwargs["path"] = path
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
global_routes.append(ColocoRoute(args, kwargs, func, method, module_name))
|
|
117
|
+
|
|
118
|
+
return func
|
|
117
119
|
|
|
118
120
|
|
|
119
121
|
def _make_route_decorator(method: str) -> Callable[..., Callable[[T], T]]:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from .api import create_api, global_routes
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from .db import (
|
|
4
|
+
create_model_serializers,
|
|
4
5
|
get_orm_config,
|
|
5
6
|
inject_model_serializers,
|
|
6
7
|
register_db_lifecycle,
|
|
@@ -71,10 +72,6 @@ def create_app(name: str, database_url: str = None) -> ColocoApp:
|
|
|
71
72
|
print(traceback.format_exc())
|
|
72
73
|
continue
|
|
73
74
|
|
|
74
|
-
# Inject type hints
|
|
75
|
-
for route in global_routes:
|
|
76
|
-
fill_type_hints(route.func, use_literals=True)
|
|
77
|
-
|
|
78
75
|
# Setup Database
|
|
79
76
|
# We need this first to grab the models for route type hints
|
|
80
77
|
has_database = bool(database_url)
|
|
@@ -83,10 +80,18 @@ def create_app(name: str, database_url: str = None) -> ColocoApp:
|
|
|
83
80
|
database_url,
|
|
84
81
|
model_files=discover_files(src_path, name="models.py", is_dev=mode == "dev"),
|
|
85
82
|
)
|
|
86
|
-
|
|
83
|
+
model_to_serializer = create_model_serializers(orm_config)
|
|
87
84
|
else:
|
|
88
85
|
orm_config = None
|
|
89
86
|
|
|
87
|
+
# Inject type hints
|
|
88
|
+
for route in global_routes:
|
|
89
|
+
fill_type_hints(route.func, use_literals=True)
|
|
90
|
+
|
|
91
|
+
# Inject model serializers after type hints
|
|
92
|
+
if has_database:
|
|
93
|
+
inject_model_serializers(model_to_serializer, global_routes)
|
|
94
|
+
|
|
90
95
|
router = APIRouter()
|
|
91
96
|
for route in global_routes:
|
|
92
97
|
router.api_route(
|
|
@@ -40,8 +40,11 @@ def db_command(func):
|
|
|
40
40
|
def wrapper(*args, **kwargs):
|
|
41
41
|
tortoise_logger.setLevel(logging.WARNING)
|
|
42
42
|
run(func(*args, **kwargs))
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
try:
|
|
44
|
+
run(Tortoise.close_connections())
|
|
45
|
+
except RuntimeError:
|
|
46
|
+
# TODO: figure out why the event loop is closed already when using postgres
|
|
47
|
+
pass
|
|
45
48
|
|
|
46
49
|
return app.command(name=func.__name__)(wrapper)
|
|
47
50
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from .api import ColocoRoute
|
|
2
2
|
from contextlib import asynccontextmanager
|
|
3
3
|
from collections import defaultdict
|
|
4
|
+
from copy import copy
|
|
4
5
|
from functools import wraps
|
|
5
6
|
from .lifespan import register_lifespan
|
|
6
7
|
from rich import print
|
|
8
|
+
from tortoise.fields import Field
|
|
7
9
|
from type_less import replace_type_hint_map_deep
|
|
8
|
-
from typing import
|
|
9
|
-
|
|
10
|
+
from typing import *
|
|
11
|
+
import datetime
|
|
10
12
|
|
|
11
13
|
CLS = TypeVar("CLS")
|
|
12
14
|
|
|
@@ -76,7 +78,7 @@ def register_db_lifecycle(app):
|
|
|
76
78
|
register_lifespan(lifecycle_connect_database)
|
|
77
79
|
|
|
78
80
|
|
|
79
|
-
def
|
|
81
|
+
def create_model_serializers(orm_config: dict):
|
|
80
82
|
try:
|
|
81
83
|
from tortoise import Tortoise
|
|
82
84
|
from tortoise.contrib.pydantic import pydantic_model_creator
|
|
@@ -99,14 +101,25 @@ def inject_model_serializers(orm_config: dict, routes: list[ColocoRoute]):
|
|
|
99
101
|
for model_class in model_classes:
|
|
100
102
|
# Wrapped with @serializable
|
|
101
103
|
if getattr(model_class, "__model_serializer_create", None):
|
|
102
|
-
model_class
|
|
104
|
+
model_to_serializer[model_class] = pydantic_model_creator(
|
|
103
105
|
model_class, **model_class.__model_serializer_create
|
|
104
106
|
)
|
|
105
107
|
# Create a general serializer
|
|
106
|
-
elif not
|
|
107
|
-
model_class
|
|
108
|
-
|
|
108
|
+
elif not model_class in model_to_serializer:
|
|
109
|
+
model_to_serializer[model_class] = pydantic_model_creator(model_class)
|
|
110
|
+
|
|
111
|
+
# Inject type annotations into model
|
|
112
|
+
# TODO: find a better way to do this that's less dependent on Tortoise internals
|
|
113
|
+
description = model_class.describe(serializable=False)
|
|
114
|
+
fields = [*description["data_fields"], description["pk_field"]]
|
|
115
|
+
for field in fields:
|
|
116
|
+
if field["name"] not in model_class.__annotations__:
|
|
117
|
+
model_class.__annotations__[field["name"]] = field["python_type"]
|
|
118
|
+
|
|
119
|
+
return model_to_serializer
|
|
120
|
+
|
|
109
121
|
|
|
122
|
+
def inject_model_serializers(model_to_serializer: dict, routes: list[ColocoRoute]):
|
|
110
123
|
for route in routes:
|
|
111
124
|
route.func.__annotations__["return"], occurrences = replace_type_hint_map_deep(
|
|
112
125
|
route.func.__annotations__["return"],
|
|
@@ -120,25 +133,25 @@ def inject_model_serializers(orm_config: dict, routes: list[ColocoRoute]):
|
|
|
120
133
|
# - Pydantic - sync serialization only
|
|
121
134
|
# - JSON Encoder - sync serialization only, + happens after serialization
|
|
122
135
|
if occurrences:
|
|
123
|
-
route.func = _wrap_model_serializer(route.func)
|
|
136
|
+
route.func = _wrap_model_serializer(route.func, model_to_serializer)
|
|
124
137
|
|
|
125
138
|
|
|
126
|
-
async def _serialize_models(obj):
|
|
139
|
+
async def _serialize_models(obj, model_to_serializer):
|
|
127
140
|
"""
|
|
128
141
|
Auto-runs the serializer for tortoise models
|
|
129
142
|
"""
|
|
130
|
-
if
|
|
131
|
-
return await obj.
|
|
143
|
+
if type(obj) in model_to_serializer:
|
|
144
|
+
return await model_to_serializer[type(obj)].from_tortoise_orm(obj)
|
|
132
145
|
elif isinstance(obj, list):
|
|
133
|
-
return [await _serialize_models(item) for item in obj]
|
|
146
|
+
return [await _serialize_models(item, model_to_serializer) for item in obj]
|
|
134
147
|
elif isinstance(obj, dict):
|
|
135
|
-
return {k: await _serialize_models(v) for k, v in obj.items()}
|
|
148
|
+
return {k: await _serialize_models(v, model_to_serializer) for k, v in obj.items()}
|
|
136
149
|
return obj
|
|
137
150
|
|
|
138
151
|
|
|
139
|
-
def _wrap_model_serializer(func):
|
|
152
|
+
def _wrap_model_serializer(func, model_to_serializer):
|
|
140
153
|
@wraps(func)
|
|
141
154
|
async def wrapper(*args, **kwargs):
|
|
142
|
-
return await _serialize_models(await func(*args, **kwargs))
|
|
155
|
+
return await _serialize_models(await func(*args, **kwargs), model_to_serializer)
|
|
143
156
|
|
|
144
157
|
return wrapper
|
|
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
|
|
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
|