piccolo 1.27.1__py3-none-any.whl → 1.29.0__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.
- piccolo/__init__.py +1 -1
- piccolo/apps/app/commands/new.py +3 -3
- piccolo/apps/asgi/commands/new.py +2 -3
- piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja +57 -29
- piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja +48 -21
- piccolo/apps/asgi/commands/templates/app/_falcon_app.py.jinja +63 -8
- piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja +51 -24
- piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja +34 -10
- piccolo/apps/asgi/commands/templates/app/_quart_app.py.jinja +38 -15
- piccolo/apps/asgi/commands/templates/app/_sanic_app.py.jinja +34 -11
- piccolo/apps/fixtures/commands/dump.py +8 -8
- piccolo/apps/fixtures/commands/load.py +5 -5
- piccolo/apps/fixtures/commands/shared.py +9 -9
- piccolo/apps/migrations/auto/diffable_table.py +12 -12
- piccolo/apps/migrations/auto/migration_manager.py +59 -66
- piccolo/apps/migrations/auto/operations.py +14 -14
- piccolo/apps/migrations/auto/schema_differ.py +35 -34
- piccolo/apps/migrations/auto/schema_snapshot.py +3 -4
- piccolo/apps/migrations/auto/serialisation.py +27 -24
- piccolo/apps/migrations/auto/serialisation_legacy.py +2 -2
- piccolo/apps/migrations/commands/backwards.py +1 -2
- piccolo/apps/migrations/commands/base.py +12 -12
- piccolo/apps/migrations/commands/check.py +2 -3
- piccolo/apps/migrations/commands/clean.py +3 -3
- piccolo/apps/migrations/commands/forwards.py +1 -2
- piccolo/apps/migrations/commands/new.py +6 -6
- piccolo/apps/migrations/tables.py +3 -3
- piccolo/apps/playground/commands/run.py +72 -13
- piccolo/apps/schema/commands/generate.py +49 -49
- piccolo/apps/schema/commands/graph.py +5 -5
- piccolo/apps/shell/commands/run.py +1 -2
- piccolo/apps/sql_shell/commands/run.py +4 -4
- piccolo/apps/tester/commands/run.py +3 -3
- piccolo/apps/user/commands/change_permissions.py +6 -6
- piccolo/apps/user/commands/create.py +7 -7
- piccolo/apps/user/commands/list.py +2 -2
- piccolo/apps/user/tables.py +8 -8
- piccolo/columns/base.py +84 -52
- piccolo/columns/choices.py +2 -2
- piccolo/columns/column_types.py +299 -177
- piccolo/columns/combination.py +15 -12
- piccolo/columns/defaults/base.py +4 -4
- piccolo/columns/defaults/date.py +4 -3
- piccolo/columns/defaults/interval.py +4 -3
- piccolo/columns/defaults/time.py +4 -3
- piccolo/columns/defaults/timestamp.py +4 -3
- piccolo/columns/defaults/timestamptz.py +4 -3
- piccolo/columns/defaults/uuid.py +3 -2
- piccolo/columns/m2m.py +28 -35
- piccolo/columns/readable.py +4 -3
- piccolo/columns/reference.py +9 -9
- piccolo/conf/apps.py +53 -54
- piccolo/custom_types.py +28 -6
- piccolo/engine/base.py +14 -14
- piccolo/engine/cockroach.py +5 -4
- piccolo/engine/finder.py +2 -2
- piccolo/engine/postgres.py +20 -19
- piccolo/engine/sqlite.py +23 -22
- piccolo/query/base.py +30 -29
- piccolo/query/functions/__init__.py +12 -0
- piccolo/query/functions/aggregate.py +4 -3
- piccolo/query/functions/array.py +151 -0
- piccolo/query/functions/base.py +3 -3
- piccolo/query/functions/datetime.py +22 -22
- piccolo/query/functions/string.py +4 -4
- piccolo/query/functions/type_conversion.py +30 -15
- piccolo/query/methods/alter.py +47 -46
- piccolo/query/methods/count.py +11 -10
- piccolo/query/methods/create.py +6 -5
- piccolo/query/methods/create_index.py +9 -8
- piccolo/query/methods/delete.py +7 -6
- piccolo/query/methods/drop_index.py +7 -6
- piccolo/query/methods/exists.py +6 -5
- piccolo/query/methods/indexes.py +4 -4
- piccolo/query/methods/insert.py +21 -14
- piccolo/query/methods/objects.py +60 -50
- piccolo/query/methods/raw.py +7 -6
- piccolo/query/methods/refresh.py +8 -7
- piccolo/query/methods/select.py +56 -49
- piccolo/query/methods/table_exists.py +5 -5
- piccolo/query/methods/update.py +8 -7
- piccolo/query/mixins.py +56 -61
- piccolo/query/operators/json.py +11 -11
- piccolo/query/proxy.py +8 -9
- piccolo/querystring.py +14 -15
- piccolo/schema.py +10 -10
- piccolo/table.py +105 -98
- piccolo/table_reflection.py +9 -9
- piccolo/testing/model_builder.py +16 -13
- piccolo/testing/random_builder.py +14 -2
- piccolo/testing/test_case.py +4 -4
- piccolo/utils/dictionary.py +3 -3
- piccolo/utils/encoding.py +5 -5
- piccolo/utils/lazy_loader.py +3 -3
- piccolo/utils/list.py +7 -8
- piccolo/utils/objects.py +4 -6
- piccolo/utils/pydantic.py +21 -24
- piccolo/utils/sql_values.py +3 -3
- piccolo/utils/sync.py +4 -3
- piccolo/utils/warnings.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/METADATA +1 -1
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/RECORD +132 -131
- tests/apps/fixtures/commands/test_dump_load.py +1 -2
- tests/apps/migrations/auto/integration/test_migrations.py +32 -7
- tests/apps/migrations/auto/test_migration_manager.py +2 -2
- tests/apps/migrations/auto/test_schema_differ.py +22 -23
- tests/apps/migrations/commands/test_forwards_backwards.py +3 -3
- tests/columns/m2m/base.py +20 -49
- tests/columns/test_array.py +176 -10
- tests/columns/test_boolean.py +2 -4
- tests/columns/test_combination.py +29 -1
- tests/columns/test_db_column_name.py +2 -2
- tests/engine/test_extra_nodes.py +2 -2
- tests/engine/test_pool.py +3 -3
- tests/engine/test_transaction.py +4 -4
- tests/query/test_freeze.py +4 -4
- tests/table/instance/test_get_related.py +2 -2
- tests/table/test_alter.py +4 -4
- tests/table/test_indexes.py +1 -2
- tests/table/test_metaclass.py +7 -3
- tests/table/test_refresh.py +2 -2
- tests/table/test_select.py +58 -0
- tests/table/test_str.py +30 -22
- tests/table/test_update.py +18 -3
- tests/testing/test_model_builder.py +1 -2
- tests/testing/test_random_builder.py +5 -0
- tests/utils/test_pydantic.py +152 -134
- tests/utils/test_table_reflection.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/WHEEL +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/entry_points.txt +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/licenses/LICENSE +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/top_level.txt +0 -0
piccolo/testing/model_builder.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
+
import decimal
|
4
5
|
import json
|
5
|
-
|
6
|
+
from collections.abc import Callable
|
6
7
|
from decimal import Decimal
|
8
|
+
from typing import Any, Optional, Union, cast
|
7
9
|
from uuid import UUID
|
8
10
|
|
9
11
|
from piccolo.columns import JSON, JSONB, Array, Column, ForeignKey
|
@@ -13,12 +15,13 @@ from piccolo.utils.sync import run_sync
|
|
13
15
|
|
14
16
|
|
15
17
|
class ModelBuilder:
|
16
|
-
__DEFAULT_MAPPER:
|
18
|
+
__DEFAULT_MAPPER: dict[type, Callable] = {
|
17
19
|
bool: RandomBuilder.next_bool,
|
18
20
|
bytes: RandomBuilder.next_bytes,
|
19
21
|
datetime.date: RandomBuilder.next_date,
|
20
22
|
datetime.datetime: RandomBuilder.next_datetime,
|
21
23
|
float: RandomBuilder.next_float,
|
24
|
+
decimal.Decimal: RandomBuilder.next_decimal,
|
22
25
|
int: RandomBuilder.next_int,
|
23
26
|
str: RandomBuilder.next_str,
|
24
27
|
datetime.time: RandomBuilder.next_time,
|
@@ -29,8 +32,8 @@ class ModelBuilder:
|
|
29
32
|
@classmethod
|
30
33
|
async def build(
|
31
34
|
cls,
|
32
|
-
table_class:
|
33
|
-
defaults:
|
35
|
+
table_class: type[TableInstance],
|
36
|
+
defaults: Optional[dict[Union[Column, str], Any]] = None,
|
34
37
|
persist: bool = True,
|
35
38
|
minimal: bool = False,
|
36
39
|
) -> TableInstance:
|
@@ -80,8 +83,8 @@ class ModelBuilder:
|
|
80
83
|
@classmethod
|
81
84
|
def build_sync(
|
82
85
|
cls,
|
83
|
-
table_class:
|
84
|
-
defaults:
|
86
|
+
table_class: type[TableInstance],
|
87
|
+
defaults: Optional[dict[Union[Column, str], Any]] = None,
|
85
88
|
persist: bool = True,
|
86
89
|
minimal: bool = False,
|
87
90
|
) -> TableInstance:
|
@@ -100,8 +103,8 @@ class ModelBuilder:
|
|
100
103
|
@classmethod
|
101
104
|
async def _build(
|
102
105
|
cls,
|
103
|
-
table_class:
|
104
|
-
defaults:
|
106
|
+
table_class: type[TableInstance],
|
107
|
+
defaults: Optional[dict[Union[Column, str], Any]] = None,
|
105
108
|
minimal: bool = False,
|
106
109
|
persist: bool = True,
|
107
110
|
) -> TableInstance:
|
@@ -151,7 +154,7 @@ class ModelBuilder:
|
|
151
154
|
return model
|
152
155
|
|
153
156
|
@classmethod
|
154
|
-
def _randomize_attribute(cls, column: Column) ->
|
157
|
+
def _randomize_attribute(cls, column: Column) -> Any:
|
155
158
|
"""
|
156
159
|
Generate a random value for a column and apply formatting.
|
157
160
|
|
@@ -159,18 +162,18 @@ class ModelBuilder:
|
|
159
162
|
Column class to randomize.
|
160
163
|
|
161
164
|
"""
|
162
|
-
random_value:
|
165
|
+
random_value: Any
|
163
166
|
if column.value_type == Decimal:
|
164
167
|
precision, scale = column._meta.params["digits"] or (4, 2)
|
165
|
-
random_value = RandomBuilder.
|
166
|
-
|
168
|
+
random_value = RandomBuilder.next_decimal(
|
169
|
+
precision=precision, scale=scale
|
167
170
|
)
|
168
171
|
elif column.value_type == datetime.datetime:
|
169
172
|
tz_aware = getattr(column, "tz_aware", False)
|
170
173
|
random_value = RandomBuilder.next_datetime(tz_aware=tz_aware)
|
171
174
|
elif column.value_type == list:
|
172
175
|
length = RandomBuilder.next_int(maximum=10)
|
173
|
-
base_type =
|
176
|
+
base_type = cast(Array, column).base_column.value_type
|
174
177
|
random_value = [
|
175
178
|
cls.__DEFAULT_MAPPER[base_type]() for _ in range(length)
|
176
179
|
]
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import datetime
|
2
|
+
import decimal
|
2
3
|
import enum
|
3
4
|
import random
|
4
5
|
import string
|
5
|
-
import typing as t
|
6
6
|
import uuid
|
7
|
+
from typing import Any
|
7
8
|
|
8
9
|
|
9
10
|
class RandomBuilder:
|
@@ -36,13 +37,24 @@ class RandomBuilder:
|
|
36
37
|
)
|
37
38
|
|
38
39
|
@classmethod
|
39
|
-
def next_enum(cls, e:
|
40
|
+
def next_enum(cls, e: type[enum.Enum]) -> Any:
|
40
41
|
return random.choice([item.value for item in e])
|
41
42
|
|
42
43
|
@classmethod
|
43
44
|
def next_float(cls, minimum=0, maximum=2147483647, scale=5) -> float:
|
44
45
|
return round(random.uniform(minimum, maximum), scale)
|
45
46
|
|
47
|
+
@classmethod
|
48
|
+
def next_decimal(
|
49
|
+
cls, precision: int = 4, scale: int = 2
|
50
|
+
) -> decimal.Decimal:
|
51
|
+
# For precision 4 and scale 2, maximum needs to be 99.99.
|
52
|
+
maximum = (10 ** (precision - scale)) - (10 ** (-1 * scale))
|
53
|
+
float_number = cls.next_float(maximum=maximum, scale=scale)
|
54
|
+
# We convert float_number to a string first, otherwise the decimal
|
55
|
+
# value is slightly off due to floating point precision.
|
56
|
+
return decimal.Decimal(str(float_number))
|
57
|
+
|
46
58
|
@classmethod
|
47
59
|
def next_int(cls, minimum=0, maximum=2147483647) -> int:
|
48
60
|
return random.randint(minimum, maximum)
|
piccolo/testing/test_case.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import Optional
|
4
4
|
from unittest import IsolatedAsyncioTestCase, TestCase
|
5
5
|
|
6
6
|
from piccolo.engine import Engine, engine_finder
|
@@ -30,7 +30,7 @@ class TableTest(TestCase):
|
|
30
30
|
|
31
31
|
""" # noqa: E501
|
32
32
|
|
33
|
-
tables:
|
33
|
+
tables: list[type[Table]]
|
34
34
|
|
35
35
|
def setUp(self) -> None:
|
36
36
|
create_db_tables_sync(*self.tables)
|
@@ -54,7 +54,7 @@ class AsyncTableTest(IsolatedAsyncioTestCase):
|
|
54
54
|
|
55
55
|
"""
|
56
56
|
|
57
|
-
tables:
|
57
|
+
tables: list[type[Table]]
|
58
58
|
|
59
59
|
async def asyncSetUp(self) -> None:
|
60
60
|
await create_db_tables(*self.tables)
|
@@ -106,7 +106,7 @@ class AsyncTransactionTest(IsolatedAsyncioTestCase):
|
|
106
106
|
#
|
107
107
|
# ...
|
108
108
|
#
|
109
|
-
db:
|
109
|
+
db: Optional[Engine] = None
|
110
110
|
|
111
111
|
async def asyncSetUp(self) -> None:
|
112
112
|
db = self.db or engine_finder()
|
piccolo/utils/dictionary.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import Any
|
4
4
|
|
5
5
|
|
6
|
-
def make_nested(dictionary:
|
6
|
+
def make_nested(dictionary: dict[str, Any]) -> dict[str, Any]:
|
7
7
|
"""
|
8
8
|
Rows are returned from the database as a flat dictionary, with keys such
|
9
9
|
as ``'manager.name'`` if the column belongs to a related table.
|
@@ -20,7 +20,7 @@ def make_nested(dictionary: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]:
|
|
20
20
|
{'name': 'Pythonistas', 'band': {'name': 'Guido'}}
|
21
21
|
|
22
22
|
"""
|
23
|
-
output:
|
23
|
+
output: dict[str, Any] = {}
|
24
24
|
|
25
25
|
items = list(dictionary.items())
|
26
26
|
items.sort(key=lambda x: x[0])
|
piccolo/utils/encoding.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import Any
|
4
4
|
|
5
5
|
try:
|
6
6
|
import orjson
|
@@ -12,9 +12,9 @@ except ImportError:
|
|
12
12
|
ORJSON = False
|
13
13
|
|
14
14
|
|
15
|
-
def dump_json(data:
|
15
|
+
def dump_json(data: Any, pretty: bool = False) -> str:
|
16
16
|
if ORJSON:
|
17
|
-
orjson_params:
|
17
|
+
orjson_params: dict[str, Any] = {"default": str}
|
18
18
|
if pretty:
|
19
19
|
orjson_params["option"] = (
|
20
20
|
orjson.OPT_INDENT_2 | orjson.OPT_APPEND_NEWLINE # type: ignore
|
@@ -23,7 +23,7 @@ def dump_json(data: t.Any, pretty: bool = False) -> str:
|
|
23
23
|
"utf8"
|
24
24
|
)
|
25
25
|
else:
|
26
|
-
params:
|
26
|
+
params: dict[str, Any] = {"default": str}
|
27
27
|
if pretty:
|
28
28
|
params["indent"] = 2
|
29
29
|
return json.dumps(data, **params) # type: ignore
|
@@ -63,7 +63,7 @@ class JSONDict(dict):
|
|
63
63
|
...
|
64
64
|
|
65
65
|
|
66
|
-
def load_json(data: str) ->
|
66
|
+
def load_json(data: str) -> Any:
|
67
67
|
response = (
|
68
68
|
orjson.loads(data) if ORJSON else json.loads(data) # type: ignore
|
69
69
|
)
|
piccolo/utils/lazy_loader.py
CHANGED
@@ -3,7 +3,7 @@ from __future__ import absolute_import, division, print_function
|
|
3
3
|
|
4
4
|
import importlib
|
5
5
|
import types
|
6
|
-
|
6
|
+
from typing import Any
|
7
7
|
|
8
8
|
|
9
9
|
class LazyLoader(types.ModuleType):
|
@@ -48,10 +48,10 @@ class LazyLoader(types.ModuleType):
|
|
48
48
|
else:
|
49
49
|
raise exc from exc
|
50
50
|
|
51
|
-
def __getattr__(self, item) ->
|
51
|
+
def __getattr__(self, item) -> Any:
|
52
52
|
module = self._load()
|
53
53
|
return getattr(module, item)
|
54
54
|
|
55
|
-
def __dir__(self) ->
|
55
|
+
def __dir__(self) -> list[str]:
|
56
56
|
module = self._load()
|
57
57
|
return dir(module)
|
piccolo/utils/list.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
from collections.abc import Sequence
|
2
|
+
from typing import TypeVar, Union
|
2
3
|
|
3
|
-
ElementType =
|
4
|
+
ElementType = TypeVar("ElementType")
|
4
5
|
|
5
6
|
|
6
7
|
def flatten(
|
7
|
-
items:
|
8
|
-
) ->
|
8
|
+
items: Sequence[Union[ElementType, list[ElementType]]]
|
9
|
+
) -> list[ElementType]:
|
9
10
|
"""
|
10
11
|
Takes a sequence of elements, and flattens it out. For example::
|
11
12
|
|
@@ -17,7 +18,7 @@ def flatten(
|
|
17
18
|
await Band.select(Band.name, Band.manager.all_columns())
|
18
19
|
|
19
20
|
"""
|
20
|
-
_items:
|
21
|
+
_items: list[ElementType] = []
|
21
22
|
for item in items:
|
22
23
|
if isinstance(item, list):
|
23
24
|
_items.extend(item)
|
@@ -27,9 +28,7 @@ def flatten(
|
|
27
28
|
return _items
|
28
29
|
|
29
30
|
|
30
|
-
def batch(
|
31
|
-
data: t.List[ElementType], chunk_size: int
|
32
|
-
) -> t.List[t.List[ElementType]]:
|
31
|
+
def batch(data: list[ElementType], chunk_size: int) -> list[list[ElementType]]:
|
33
32
|
"""
|
34
33
|
Breaks the list down into sublists of the given ``chunk_size``. The last
|
35
34
|
sublist may have fewer elements than ``chunk_size``::
|
piccolo/utils/objects.py
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import TYPE_CHECKING, Any
|
4
4
|
|
5
5
|
from piccolo.columns.column_types import ForeignKey
|
6
6
|
|
7
|
-
if
|
7
|
+
if TYPE_CHECKING: # pragma: no cover
|
8
8
|
from piccolo.table import Table
|
9
9
|
|
10
10
|
|
11
|
-
def make_nested_object(
|
12
|
-
row: t.Dict[str, t.Any], table_class: t.Type[Table]
|
13
|
-
) -> Table:
|
11
|
+
def make_nested_object(row: dict[str, Any], table_class: type[Table]) -> Table:
|
14
12
|
"""
|
15
13
|
Takes a nested dictionary such as this:
|
16
14
|
|
@@ -38,7 +36,7 @@ def make_nested_object(
|
|
38
36
|
1
|
39
37
|
|
40
38
|
"""
|
41
|
-
table_params:
|
39
|
+
table_params: dict[str, Any] = {}
|
42
40
|
|
43
41
|
for key, value in row.items():
|
44
42
|
if isinstance(value, dict):
|
piccolo/utils/pydantic.py
CHANGED
@@ -2,9 +2,10 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import itertools
|
4
4
|
import json
|
5
|
-
import typing as t
|
6
5
|
from collections import defaultdict
|
6
|
+
from collections.abc import Callable
|
7
7
|
from functools import partial
|
8
|
+
from typing import Any, Optional, Union
|
8
9
|
|
9
10
|
import pydantic
|
10
11
|
|
@@ -30,7 +31,7 @@ except ImportError:
|
|
30
31
|
JsonDict = dict # type: ignore
|
31
32
|
|
32
33
|
|
33
|
-
def pydantic_json_validator(value:
|
34
|
+
def pydantic_json_validator(value: Optional[str], required: bool = True):
|
34
35
|
if value is None:
|
35
36
|
if required:
|
36
37
|
raise ValueError("The JSON value wasn't provided.")
|
@@ -45,7 +46,7 @@ def pydantic_json_validator(value: t.Optional[str], required: bool = True):
|
|
45
46
|
return value
|
46
47
|
|
47
48
|
|
48
|
-
def is_table_column(column: Column, table:
|
49
|
+
def is_table_column(column: Column, table: type[Table]) -> bool:
|
49
50
|
"""
|
50
51
|
Verify that the given ``Column`` belongs to the given ``Table``.
|
51
52
|
"""
|
@@ -60,9 +61,7 @@ def is_table_column(column: Column, table: t.Type[Table]) -> bool:
|
|
60
61
|
return False
|
61
62
|
|
62
63
|
|
63
|
-
def validate_columns(
|
64
|
-
columns: t.Tuple[Column, ...], table: t.Type[Table]
|
65
|
-
) -> bool:
|
64
|
+
def validate_columns(columns: tuple[Column, ...], table: type[Table]) -> bool:
|
66
65
|
"""
|
67
66
|
Verify that each column is a ``Column``` instance, and its parent is the
|
68
67
|
given ``Table``.
|
@@ -74,9 +73,7 @@ def validate_columns(
|
|
74
73
|
)
|
75
74
|
|
76
75
|
|
77
|
-
def get_array_value_type(
|
78
|
-
column: Array, inner: t.Optional[t.Type] = None
|
79
|
-
) -> t.Type:
|
76
|
+
def get_array_value_type(column: Array, inner: Optional[type] = None) -> type:
|
80
77
|
"""
|
81
78
|
Gets the correct type for an ``Array`` column (which might be
|
82
79
|
multidimensional).
|
@@ -86,14 +83,14 @@ def get_array_value_type(
|
|
86
83
|
else:
|
87
84
|
inner_type = get_pydantic_value_type(column.base_column)
|
88
85
|
|
89
|
-
return
|
86
|
+
return list[inner_type] # type: ignore
|
90
87
|
|
91
88
|
|
92
|
-
def get_pydantic_value_type(column: Column) ->
|
89
|
+
def get_pydantic_value_type(column: Column) -> type:
|
93
90
|
"""
|
94
91
|
Map the Piccolo ``Column`` to a Pydantic type.
|
95
92
|
"""
|
96
|
-
value_type:
|
93
|
+
value_type: type
|
97
94
|
|
98
95
|
if isinstance(column, (Decimal, Numeric)):
|
99
96
|
value_type = pydantic.condecimal(
|
@@ -112,20 +109,20 @@ def get_pydantic_value_type(column: Column) -> t.Type:
|
|
112
109
|
|
113
110
|
|
114
111
|
def create_pydantic_model(
|
115
|
-
table:
|
116
|
-
nested:
|
117
|
-
exclude_columns:
|
118
|
-
include_columns:
|
112
|
+
table: type[Table],
|
113
|
+
nested: Union[bool, tuple[ForeignKey, ...]] = False,
|
114
|
+
exclude_columns: tuple[Column, ...] = (),
|
115
|
+
include_columns: tuple[Column, ...] = (),
|
119
116
|
include_default_columns: bool = False,
|
120
117
|
include_readable: bool = False,
|
121
118
|
all_optional: bool = False,
|
122
|
-
model_name:
|
119
|
+
model_name: Optional[str] = None,
|
123
120
|
deserialize_json: bool = False,
|
124
121
|
recursion_depth: int = 0,
|
125
122
|
max_recursion_depth: int = 5,
|
126
|
-
pydantic_config:
|
127
|
-
json_schema_extra:
|
128
|
-
) ->
|
123
|
+
pydantic_config: Optional[pydantic.config.ConfigDict] = None,
|
124
|
+
json_schema_extra: Optional[dict[str, Any]] = None,
|
125
|
+
) -> type[pydantic.BaseModel]:
|
129
126
|
"""
|
130
127
|
Create a Pydantic model representing a table.
|
131
128
|
|
@@ -205,8 +202,8 @@ def create_pydantic_model(
|
|
205
202
|
|
206
203
|
###########################################################################
|
207
204
|
|
208
|
-
columns:
|
209
|
-
validators:
|
205
|
+
columns: dict[str, Any] = {}
|
206
|
+
validators: dict[str, Callable] = {}
|
210
207
|
|
211
208
|
piccolo_columns = tuple(
|
212
209
|
table._meta.columns
|
@@ -264,11 +261,11 @@ def create_pydantic_model(
|
|
264
261
|
else:
|
265
262
|
value_type = get_pydantic_value_type(column=column)
|
266
263
|
|
267
|
-
_type =
|
264
|
+
_type = Optional[value_type] if is_optional else value_type
|
268
265
|
|
269
266
|
#######################################################################
|
270
267
|
|
271
|
-
params:
|
268
|
+
params: dict[str, Any] = {}
|
272
269
|
if is_optional:
|
273
270
|
params["default"] = None
|
274
271
|
|
piccolo/utils/sql_values.py
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import functools
|
4
|
-
import typing as t
|
5
4
|
from enum import Enum
|
5
|
+
from typing import TYPE_CHECKING, Any
|
6
6
|
|
7
7
|
from piccolo.utils.encoding import dump_json
|
8
8
|
from piccolo.utils.warnings import colored_warning
|
9
9
|
|
10
|
-
if
|
10
|
+
if TYPE_CHECKING: # pragma: no cover
|
11
11
|
from piccolo.columns import Column
|
12
12
|
|
13
13
|
|
14
|
-
def convert_to_sql_value(value:
|
14
|
+
def convert_to_sql_value(value: Any, column: Column) -> Any:
|
15
15
|
"""
|
16
16
|
Some values which can be passed into Piccolo queries aren't valid in the
|
17
17
|
database. For example, Enums, Table instances, and dictionaries for JSON
|
piccolo/utils/sync.py
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import asyncio
|
4
|
-
|
4
|
+
from collections.abc import Coroutine
|
5
5
|
from concurrent.futures import Future, ThreadPoolExecutor
|
6
|
+
from typing import Any, TypeVar
|
6
7
|
|
7
|
-
ReturnType =
|
8
|
+
ReturnType = TypeVar("ReturnType")
|
8
9
|
|
9
10
|
|
10
11
|
def run_sync(
|
11
|
-
coroutine:
|
12
|
+
coroutine: Coroutine[Any, Any, ReturnType],
|
12
13
|
) -> ReturnType:
|
13
14
|
"""
|
14
15
|
Run the coroutine synchronously - trying to accommodate as many edge cases
|
piccolo/utils/warnings.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import typing as t
|
4
3
|
import warnings
|
5
4
|
from enum import Enum
|
6
5
|
|
@@ -21,7 +20,7 @@ def colored_string(message: str, level: Level = Level.medium) -> str:
|
|
21
20
|
|
22
21
|
def colored_warning(
|
23
22
|
message: str,
|
24
|
-
category:
|
23
|
+
category: type[Warning] = Warning,
|
25
24
|
stacklevel: int = 3,
|
26
25
|
level: Level = Level.medium,
|
27
26
|
):
|