piccolo 1.27.1__py3-none-any.whl → 1.28.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 +1 -2
- 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 +29 -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 +297 -175
- 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 +93 -94
- piccolo/table_reflection.py +9 -9
- piccolo/testing/model_builder.py +12 -11
- piccolo/testing/random_builder.py +2 -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.28.0.dist-info}/METADATA +1 -1
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/RECORD +122 -121
- 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 +2 -2
- 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_refresh.py +2 -2
- tests/table/test_select.py +58 -0
- tests/table/test_update.py +3 -3
- tests/testing/test_model_builder.py +1 -2
- tests/utils/test_pydantic.py +36 -36
- tests/utils/test_table_reflection.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/WHEEL +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/entry_points.txt +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/licenses/LICENSE +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/top_level.txt +0 -0
@@ -3,10 +3,10 @@ from __future__ import annotations
|
|
3
3
|
import datetime
|
4
4
|
import os
|
5
5
|
import string
|
6
|
-
import typing as t
|
7
6
|
from dataclasses import dataclass
|
8
7
|
from itertools import chain
|
9
8
|
from types import ModuleType
|
9
|
+
from typing import Optional
|
10
10
|
|
11
11
|
import black
|
12
12
|
import jinja2
|
@@ -33,7 +33,7 @@ JINJA_ENV = jinja2.Environment(
|
|
33
33
|
loader=jinja2.FileSystemLoader(searchpath=TEMPLATE_DIRECTORY),
|
34
34
|
)
|
35
35
|
|
36
|
-
MIGRATION_MODULES:
|
36
|
+
MIGRATION_MODULES: dict[str, ModuleType] = {}
|
37
37
|
|
38
38
|
VALID_PYTHON_MODULE_CHARACTERS = string.ascii_lowercase + string.digits + "_"
|
39
39
|
|
@@ -115,7 +115,7 @@ async def _create_new_migration(
|
|
115
115
|
app_config: AppConfig,
|
116
116
|
auto: bool = False,
|
117
117
|
description: str = "",
|
118
|
-
auto_input:
|
118
|
+
auto_input: Optional[str] = None,
|
119
119
|
) -> NewMigrationMeta:
|
120
120
|
"""
|
121
121
|
Creates a new migration file on disk.
|
@@ -170,13 +170,13 @@ async def _create_new_migration(
|
|
170
170
|
|
171
171
|
|
172
172
|
class AutoMigrationManager(BaseMigrationManager):
|
173
|
-
def __init__(self, auto_input:
|
173
|
+
def __init__(self, auto_input: Optional[str] = None, *args, **kwargs):
|
174
174
|
self.auto_input = auto_input
|
175
175
|
super().__init__(*args, **kwargs)
|
176
176
|
|
177
177
|
async def get_alter_statements(
|
178
178
|
self, app_config: AppConfig
|
179
|
-
) ->
|
179
|
+
) -> list[AlterStatements]:
|
180
180
|
"""
|
181
181
|
Works out which alter statements are required.
|
182
182
|
"""
|
@@ -214,7 +214,7 @@ async def new(
|
|
214
214
|
app_name: str,
|
215
215
|
auto: bool = False,
|
216
216
|
desc: str = "",
|
217
|
-
auto_input:
|
217
|
+
auto_input: Optional[str] = None,
|
218
218
|
):
|
219
219
|
"""
|
220
220
|
Creates a new migration file in the migrations folder.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import Optional
|
4
4
|
|
5
5
|
from piccolo.columns import Timestamp, Varchar
|
6
6
|
from piccolo.columns.defaults.timestamp import TimestampNow
|
@@ -14,8 +14,8 @@ class Migration(Table):
|
|
14
14
|
|
15
15
|
@classmethod
|
16
16
|
async def get_migrations_which_ran(
|
17
|
-
cls, app_name:
|
18
|
-
) ->
|
17
|
+
cls, app_name: Optional[str] = None
|
18
|
+
) -> list[str]:
|
19
19
|
"""
|
20
20
|
Returns the names of migrations which have already run, by inspecting
|
21
21
|
the database.
|
@@ -8,10 +8,12 @@ import sys
|
|
8
8
|
import uuid
|
9
9
|
from decimal import Decimal
|
10
10
|
from enum import Enum
|
11
|
+
from typing import Optional
|
11
12
|
|
12
13
|
from piccolo.columns import (
|
13
14
|
JSON,
|
14
15
|
UUID,
|
16
|
+
Array,
|
15
17
|
Boolean,
|
16
18
|
Date,
|
17
19
|
ForeignKey,
|
@@ -24,7 +26,7 @@ from piccolo.columns import (
|
|
24
26
|
Varchar,
|
25
27
|
)
|
26
28
|
from piccolo.columns.readable import Readable
|
27
|
-
from piccolo.engine import PostgresEngine, SQLiteEngine
|
29
|
+
from piccolo.engine import CockroachEngine, PostgresEngine, SQLiteEngine
|
28
30
|
from piccolo.engine.base import Engine
|
29
31
|
from piccolo.table import Table
|
30
32
|
from piccolo.utils.warnings import colored_string
|
@@ -149,6 +151,7 @@ class Album(Table):
|
|
149
151
|
band = ForeignKey(Band)
|
150
152
|
release_date = Date()
|
151
153
|
recorded_at = ForeignKey(RecordingStudio)
|
154
|
+
awards = Array(Varchar())
|
152
155
|
|
153
156
|
@classmethod
|
154
157
|
def get_readable(cls) -> Readable:
|
@@ -265,6 +268,7 @@ def populate():
|
|
265
268
|
Album.recorded_at: recording_studio_1,
|
266
269
|
Album.band: pythonistas,
|
267
270
|
Album.release_date: datetime.date(year=2021, month=1, day=1),
|
271
|
+
Album.awards: ["Grammy Award 2021"],
|
268
272
|
}
|
269
273
|
),
|
270
274
|
Album(
|
@@ -273,6 +277,7 @@ def populate():
|
|
273
277
|
Album.recorded_at: recording_studio_2,
|
274
278
|
Album.band: rustaceans,
|
275
279
|
Album.release_date: datetime.date(year=2022, month=2, day=2),
|
280
|
+
Album.awards: ["Mercury Prize 2022"],
|
276
281
|
}
|
277
282
|
),
|
278
283
|
).run_sync()
|
@@ -280,28 +285,29 @@ def populate():
|
|
280
285
|
|
281
286
|
def run(
|
282
287
|
engine: str = "sqlite",
|
283
|
-
user: str =
|
284
|
-
password: str =
|
288
|
+
user: Optional[str] = None,
|
289
|
+
password: Optional[str] = None,
|
285
290
|
database: str = "piccolo_playground",
|
286
291
|
host: str = "localhost",
|
287
|
-
port: int =
|
292
|
+
port: Optional[int] = None,
|
288
293
|
ipython_profile: bool = False,
|
289
294
|
):
|
290
295
|
"""
|
291
296
|
Creates a test database to play with.
|
292
297
|
|
293
298
|
:param engine:
|
294
|
-
Which database engine to use - options are sqlite or
|
299
|
+
Which database engine to use - options are sqlite, postgres or
|
300
|
+
cockroach
|
295
301
|
:param user:
|
296
|
-
|
302
|
+
Database user (ignored for SQLite)
|
297
303
|
:param password:
|
298
|
-
|
304
|
+
Database password (ignored for SQLite)
|
299
305
|
:param database:
|
300
|
-
|
306
|
+
Database name (ignored for SQLite)
|
301
307
|
:param host:
|
302
|
-
|
308
|
+
Database host (ignored for SQLite)
|
303
309
|
:param port:
|
304
|
-
|
310
|
+
Database port (ignored for SQLite)
|
305
311
|
:param ipython_profile:
|
306
312
|
Set to true to use your own IPython profile. Located at ~/.ipython/.
|
307
313
|
For more info see the IPython docs
|
@@ -320,9 +326,19 @@ def run(
|
|
320
326
|
{
|
321
327
|
"host": host,
|
322
328
|
"database": database,
|
323
|
-
"user": user,
|
324
|
-
"password": password,
|
325
|
-
"port": port,
|
329
|
+
"user": user or "piccolo",
|
330
|
+
"password": password or "piccolo",
|
331
|
+
"port": port or 5432,
|
332
|
+
}
|
333
|
+
)
|
334
|
+
elif engine.upper() == "COCKROACH":
|
335
|
+
db = CockroachEngine(
|
336
|
+
{
|
337
|
+
"host": host,
|
338
|
+
"database": database,
|
339
|
+
"user": user or "root",
|
340
|
+
"password": password or "",
|
341
|
+
"port": port or 26257,
|
326
342
|
}
|
327
343
|
)
|
328
344
|
else:
|
@@ -5,9 +5,9 @@ import dataclasses
|
|
5
5
|
import itertools
|
6
6
|
import json
|
7
7
|
import re
|
8
|
-
import typing as t
|
9
8
|
import uuid
|
10
9
|
from datetime import date, datetime
|
10
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
|
11
11
|
|
12
12
|
import black
|
13
13
|
|
@@ -43,7 +43,7 @@ from piccolo.engine.postgres import PostgresEngine
|
|
43
43
|
from piccolo.table import Table, create_table_class, sort_table_classes
|
44
44
|
from piccolo.utils.naming import _snake_to_camel
|
45
45
|
|
46
|
-
if
|
46
|
+
if TYPE_CHECKING: # pragma: no cover
|
47
47
|
from piccolo.engine.base import Engine
|
48
48
|
|
49
49
|
|
@@ -61,13 +61,13 @@ class ConstraintTable:
|
|
61
61
|
class RowMeta:
|
62
62
|
column_default: str
|
63
63
|
column_name: str
|
64
|
-
is_nullable:
|
64
|
+
is_nullable: Literal["YES", "NO"]
|
65
65
|
table_name: str
|
66
|
-
character_maximum_length:
|
66
|
+
character_maximum_length: Optional[int]
|
67
67
|
data_type: str
|
68
|
-
numeric_precision:
|
69
|
-
numeric_scale:
|
70
|
-
numeric_precision_radix:
|
68
|
+
numeric_precision: Optional[Union[int, str]]
|
69
|
+
numeric_scale: Optional[Union[int, str]]
|
70
|
+
numeric_precision_radix: Optional[Literal[2, 10]]
|
71
71
|
|
72
72
|
@classmethod
|
73
73
|
def get_column_name_str(cls) -> str:
|
@@ -76,10 +76,10 @@ class RowMeta:
|
|
76
76
|
|
77
77
|
@dataclasses.dataclass
|
78
78
|
class Constraint:
|
79
|
-
constraint_type:
|
79
|
+
constraint_type: Literal["PRIMARY KEY", "UNIQUE", "FOREIGN KEY", "CHECK"]
|
80
80
|
constraint_name: str
|
81
|
-
constraint_schema:
|
82
|
-
column_name:
|
81
|
+
constraint_schema: Optional[str] = None
|
82
|
+
column_name: Optional[str] = None
|
83
83
|
|
84
84
|
|
85
85
|
@dataclasses.dataclass
|
@@ -89,12 +89,12 @@ class TableConstraints:
|
|
89
89
|
"""
|
90
90
|
|
91
91
|
tablename: str
|
92
|
-
constraints:
|
92
|
+
constraints: list[Constraint]
|
93
93
|
|
94
94
|
def __post_init__(self) -> None:
|
95
|
-
foreign_key_constraints:
|
96
|
-
unique_constraints:
|
97
|
-
primary_key_constraints:
|
95
|
+
foreign_key_constraints: list[Constraint] = []
|
96
|
+
unique_constraints: list[Constraint] = []
|
97
|
+
primary_key_constraints: list[Constraint] = []
|
98
98
|
|
99
99
|
for constraint in self.constraints:
|
100
100
|
if constraint.constraint_type == "FOREIGN KEY":
|
@@ -141,7 +141,7 @@ class Trigger:
|
|
141
141
|
table_name: str
|
142
142
|
column_name: str
|
143
143
|
on_update: str
|
144
|
-
on_delete:
|
144
|
+
on_delete: Literal[
|
145
145
|
"NO ACTION", "RESTRICT", "CASCADE", "SET NULL", "SET_DEFAULT"
|
146
146
|
]
|
147
147
|
references_table: str
|
@@ -155,14 +155,14 @@ class TableTriggers:
|
|
155
155
|
"""
|
156
156
|
|
157
157
|
tablename: str
|
158
|
-
triggers:
|
158
|
+
triggers: list[Trigger]
|
159
159
|
|
160
|
-
def get_column_triggers(self, column_name: str) ->
|
160
|
+
def get_column_triggers(self, column_name: str) -> list[Trigger]:
|
161
161
|
return [i for i in self.triggers if i.column_name == column_name]
|
162
162
|
|
163
163
|
def get_column_ref_trigger(
|
164
164
|
self, column_name: str, references_table: str
|
165
|
-
) ->
|
165
|
+
) -> Optional[Trigger]:
|
166
166
|
for trigger in self.triggers:
|
167
167
|
if (
|
168
168
|
trigger.column_name == column_name
|
@@ -221,14 +221,14 @@ class TableIndexes:
|
|
221
221
|
"""
|
222
222
|
|
223
223
|
tablename: str
|
224
|
-
indexes:
|
224
|
+
indexes: list[Index]
|
225
225
|
|
226
|
-
def get_column_index(self, column_name: str) ->
|
226
|
+
def get_column_index(self, column_name: str) -> Optional[Index]:
|
227
227
|
return next(
|
228
228
|
(i for i in self.indexes if i.column_name == column_name), None
|
229
229
|
)
|
230
230
|
|
231
|
-
def get_warnings(self) ->
|
231
|
+
def get_warnings(self) -> list[str]:
|
232
232
|
return list(
|
233
233
|
itertools.chain(*[index.warnings for index in self.indexes])
|
234
234
|
)
|
@@ -250,13 +250,13 @@ class OutputSchema:
|
|
250
250
|
e.g. ["class MyTable(Table): ..."]
|
251
251
|
"""
|
252
252
|
|
253
|
-
imports:
|
254
|
-
warnings:
|
255
|
-
index_warnings:
|
256
|
-
trigger_warnings:
|
257
|
-
tables:
|
253
|
+
imports: list[str] = dataclasses.field(default_factory=list)
|
254
|
+
warnings: list[str] = dataclasses.field(default_factory=list)
|
255
|
+
index_warnings: list[str] = dataclasses.field(default_factory=list)
|
256
|
+
trigger_warnings: list[str] = dataclasses.field(default_factory=list)
|
257
|
+
tables: list[type[Table]] = dataclasses.field(default_factory=list)
|
258
258
|
|
259
|
-
def get_table_with_name(self, tablename: str) ->
|
259
|
+
def get_table_with_name(self, tablename: str) -> Optional[type[Table]]:
|
260
260
|
"""
|
261
261
|
Used to search for a table by name.
|
262
262
|
"""
|
@@ -287,7 +287,7 @@ class OutputSchema:
|
|
287
287
|
return self
|
288
288
|
|
289
289
|
|
290
|
-
COLUMN_TYPE_MAP:
|
290
|
+
COLUMN_TYPE_MAP: dict[str, type[Column]] = {
|
291
291
|
"bigint": BigInt,
|
292
292
|
"boolean": Boolean,
|
293
293
|
"bytea": Bytea,
|
@@ -308,12 +308,12 @@ COLUMN_TYPE_MAP: t.Dict[str, t.Type[Column]] = {
|
|
308
308
|
}
|
309
309
|
|
310
310
|
# Re-map for Cockroach compatibility.
|
311
|
-
COLUMN_TYPE_MAP_COCKROACH:
|
311
|
+
COLUMN_TYPE_MAP_COCKROACH: dict[str, type[Column]] = {
|
312
312
|
**COLUMN_TYPE_MAP,
|
313
313
|
**{"integer": BigInt, "json": JSONB},
|
314
314
|
}
|
315
315
|
|
316
|
-
COLUMN_DEFAULT_PARSER:
|
316
|
+
COLUMN_DEFAULT_PARSER: dict[type[Column], Any] = {
|
317
317
|
BigInt: re.compile(r"^'?(?P<value>-?[0-9]\d*)'?(?:::bigint)?$"),
|
318
318
|
Boolean: re.compile(r"^(?P<value>true|false)$"),
|
319
319
|
Bytea: re.compile(r"'(?P<value>.*)'::bytea$"),
|
@@ -373,15 +373,15 @@ COLUMN_DEFAULT_PARSER: t.Dict[t.Type[Column], t.Any] = {
|
|
373
373
|
}
|
374
374
|
|
375
375
|
# Re-map for Cockroach compatibility.
|
376
|
-
COLUMN_DEFAULT_PARSER_COCKROACH:
|
376
|
+
COLUMN_DEFAULT_PARSER_COCKROACH: dict[type[Column], Any] = {
|
377
377
|
**COLUMN_DEFAULT_PARSER,
|
378
378
|
BigInt: re.compile(r"^(?P<value>-?\d+)$"),
|
379
379
|
}
|
380
380
|
|
381
381
|
|
382
382
|
def get_column_default(
|
383
|
-
column_type:
|
384
|
-
) ->
|
383
|
+
column_type: type[Column], column_default: str, engine_type: str
|
384
|
+
) -> Any:
|
385
385
|
if engine_type == "cockroach":
|
386
386
|
pat = COLUMN_DEFAULT_PARSER_COCKROACH.get(column_type)
|
387
387
|
else:
|
@@ -455,7 +455,7 @@ def get_column_default(
|
|
455
455
|
return column_type.value_type(value["value"])
|
456
456
|
|
457
457
|
|
458
|
-
INDEX_METHOD_MAP:
|
458
|
+
INDEX_METHOD_MAP: dict[str, IndexMethod] = {
|
459
459
|
"btree": IndexMethod.btree,
|
460
460
|
"hash": IndexMethod.hash,
|
461
461
|
"gist": IndexMethod.gist,
|
@@ -465,7 +465,7 @@ INDEX_METHOD_MAP: t.Dict[str, IndexMethod] = {
|
|
465
465
|
|
466
466
|
# 'Indices' seems old-fashioned and obscure in this context.
|
467
467
|
async def get_indexes( # noqa: E302
|
468
|
-
table_class:
|
468
|
+
table_class: type[Table], tablename: str, schema_name: str = "public"
|
469
469
|
) -> TableIndexes:
|
470
470
|
"""
|
471
471
|
Get all of the constraints for a table.
|
@@ -492,7 +492,7 @@ async def get_indexes( # noqa: E302
|
|
492
492
|
|
493
493
|
|
494
494
|
async def get_fk_triggers(
|
495
|
-
table_class:
|
495
|
+
table_class: type[Table], tablename: str, schema_name: str = "public"
|
496
496
|
) -> TableTriggers:
|
497
497
|
"""
|
498
498
|
Get all of the constraints for a table.
|
@@ -540,7 +540,7 @@ async def get_fk_triggers(
|
|
540
540
|
|
541
541
|
|
542
542
|
async def get_constraints(
|
543
|
-
table_class:
|
543
|
+
table_class: type[Table], tablename: str, schema_name: str = "public"
|
544
544
|
) -> TableConstraints:
|
545
545
|
"""
|
546
546
|
Get all of the constraints for a table.
|
@@ -572,8 +572,8 @@ async def get_constraints(
|
|
572
572
|
|
573
573
|
|
574
574
|
async def get_tablenames(
|
575
|
-
table_class:
|
576
|
-
) ->
|
575
|
+
table_class: type[Table], schema_name: str = "public"
|
576
|
+
) -> list[str]:
|
577
577
|
"""
|
578
578
|
Get the tablenames for the schema.
|
579
579
|
|
@@ -598,8 +598,8 @@ async def get_tablenames(
|
|
598
598
|
|
599
599
|
|
600
600
|
async def get_table_schema(
|
601
|
-
table_class:
|
602
|
-
) ->
|
601
|
+
table_class: type[Table], tablename: str, schema_name: str = "public"
|
602
|
+
) -> list[RowMeta]:
|
603
603
|
"""
|
604
604
|
Get the schema from the database.
|
605
605
|
|
@@ -629,7 +629,7 @@ async def get_table_schema(
|
|
629
629
|
|
630
630
|
|
631
631
|
async def get_foreign_key_reference(
|
632
|
-
table_class:
|
632
|
+
table_class: type[Table], constraint_name: str, constraint_schema: str
|
633
633
|
) -> ConstraintTable:
|
634
634
|
"""
|
635
635
|
Retrieve the name of the table that a foreign key is referencing.
|
@@ -652,7 +652,7 @@ async def get_foreign_key_reference(
|
|
652
652
|
|
653
653
|
|
654
654
|
async def create_table_class_from_db(
|
655
|
-
table_class:
|
655
|
+
table_class: type[Table],
|
656
656
|
tablename: str,
|
657
657
|
schema_name: str,
|
658
658
|
engine_type: str,
|
@@ -674,7 +674,7 @@ async def create_table_class_from_db(
|
|
674
674
|
table_class=table_class, tablename=tablename, schema_name=schema_name
|
675
675
|
)
|
676
676
|
|
677
|
-
columns:
|
677
|
+
columns: dict[str, Column] = {}
|
678
678
|
|
679
679
|
for pg_row_meta in table_schema:
|
680
680
|
data_type = pg_row_meta.data_type
|
@@ -692,7 +692,7 @@ async def create_table_class_from_db(
|
|
692
692
|
)
|
693
693
|
column_type = Column
|
694
694
|
|
695
|
-
kwargs:
|
695
|
+
kwargs: dict[str, Any] = {
|
696
696
|
"null": pg_row_meta.is_nullable == "YES",
|
697
697
|
"unique": constraints.is_unique(column_name=column_name),
|
698
698
|
}
|
@@ -721,7 +721,7 @@ async def create_table_class_from_db(
|
|
721
721
|
constraint_schema=fk_constraint_table.schema,
|
722
722
|
)
|
723
723
|
if constraint_table.name:
|
724
|
-
referenced_table:
|
724
|
+
referenced_table: Union[str, Optional[type[Table]]]
|
725
725
|
|
726
726
|
if constraint_table.name == tablename:
|
727
727
|
referenced_output_schema = output_schema
|
@@ -805,9 +805,9 @@ async def create_table_class_from_db(
|
|
805
805
|
|
806
806
|
async def get_output_schema(
|
807
807
|
schema_name: str = "public",
|
808
|
-
include:
|
809
|
-
exclude:
|
810
|
-
engine:
|
808
|
+
include: Optional[list[str]] = None,
|
809
|
+
exclude: Optional[list[str]] = None,
|
810
|
+
engine: Optional[Engine] = None,
|
811
811
|
) -> OutputSchema:
|
812
812
|
"""
|
813
813
|
:param schema_name:
|
@@ -5,7 +5,7 @@ Credit to the Django Extensions team for inspiring this tool.
|
|
5
5
|
import dataclasses
|
6
6
|
import os
|
7
7
|
import sys
|
8
|
-
|
8
|
+
from typing import Optional
|
9
9
|
|
10
10
|
import jinja2
|
11
11
|
|
@@ -29,7 +29,7 @@ class GraphColumn:
|
|
29
29
|
@dataclasses.dataclass
|
30
30
|
class GraphTable:
|
31
31
|
name: str
|
32
|
-
columns:
|
32
|
+
columns: list[GraphColumn]
|
33
33
|
|
34
34
|
|
35
35
|
@dataclasses.dataclass
|
@@ -45,7 +45,7 @@ def render_template(**kwargs):
|
|
45
45
|
|
46
46
|
|
47
47
|
def graph(
|
48
|
-
apps: str = "all", direction: str = "LR", output:
|
48
|
+
apps: str = "all", direction: str = "LR", output: Optional[str] = None
|
49
49
|
):
|
50
50
|
"""
|
51
51
|
Prints out a graphviz .dot file for your schema.
|
@@ -73,8 +73,8 @@ def graph(
|
|
73
73
|
sys.exit(f"These apps aren't recognised: {', '.join(delta)}.")
|
74
74
|
app_names = given_app_names
|
75
75
|
|
76
|
-
tables:
|
77
|
-
relations:
|
76
|
+
tables: list[GraphTable] = []
|
77
|
+
relations: list[GraphRelation] = []
|
78
78
|
|
79
79
|
for app_name in app_names:
|
80
80
|
app_config = finder.get_app_config(app_name=app_name)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import sys
|
2
|
-
import typing as t
|
3
2
|
|
4
3
|
from piccolo.conf.apps import Finder
|
5
4
|
from piccolo.table import Table
|
@@ -13,7 +12,7 @@ except ImportError:
|
|
13
12
|
IPYTHON = False
|
14
13
|
|
15
14
|
|
16
|
-
def start_ipython_shell(**tables:
|
15
|
+
def start_ipython_shell(**tables: type[Table]): # pragma: no cover
|
17
16
|
if not IPYTHON:
|
18
17
|
sys.exit(
|
19
18
|
"Install iPython using `pip install ipython` to use this feature."
|
@@ -2,7 +2,7 @@ import os
|
|
2
2
|
import signal
|
3
3
|
import subprocess
|
4
4
|
import sys
|
5
|
-
|
5
|
+
from typing import cast
|
6
6
|
|
7
7
|
from piccolo.engine.finder import engine_finder
|
8
8
|
from piccolo.engine.postgres import PostgresEngine
|
@@ -24,7 +24,7 @@ def run() -> None:
|
|
24
24
|
|
25
25
|
# Heavily inspired by Django's dbshell command
|
26
26
|
if isinstance(engine, PostgresEngine):
|
27
|
-
engine =
|
27
|
+
engine = cast(PostgresEngine, engine)
|
28
28
|
|
29
29
|
args = ["psql"]
|
30
30
|
|
@@ -56,9 +56,9 @@ def run() -> None:
|
|
56
56
|
signal.signal(signal.SIGINT, sigint_handler)
|
57
57
|
|
58
58
|
elif isinstance(engine, SQLiteEngine):
|
59
|
-
engine =
|
59
|
+
engine = cast(SQLiteEngine, engine)
|
60
60
|
|
61
|
-
database =
|
61
|
+
database = cast(str, engine.connection_kwargs.get("database"))
|
62
62
|
if not database:
|
63
63
|
sys.exit("Unable to determine which database to connect to.")
|
64
64
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
import sys
|
5
|
-
|
5
|
+
from typing import Optional
|
6
6
|
|
7
7
|
from piccolo.table import TABLE_REGISTRY
|
8
8
|
|
@@ -25,7 +25,7 @@ class set_env_var:
|
|
25
25
|
def set_var(self, value: str):
|
26
26
|
os.environ[self.var_name] = value
|
27
27
|
|
28
|
-
def get_var(self) ->
|
28
|
+
def get_var(self) -> Optional[str]:
|
29
29
|
return os.environ.get(self.var_name)
|
30
30
|
|
31
31
|
def __enter__(self):
|
@@ -39,7 +39,7 @@ class set_env_var:
|
|
39
39
|
self.set_var(self.existing_value)
|
40
40
|
|
41
41
|
|
42
|
-
def run_pytest(pytest_args:
|
42
|
+
def run_pytest(pytest_args: list[str]) -> int: # pragma: no cover
|
43
43
|
try:
|
44
44
|
import pytest
|
45
45
|
except ImportError:
|
@@ -1,17 +1,17 @@
|
|
1
|
-
|
1
|
+
from typing import TYPE_CHECKING, Optional, Union
|
2
2
|
|
3
3
|
from piccolo.apps.user.tables import BaseUser
|
4
4
|
from piccolo.utils.warnings import Level, colored_string
|
5
5
|
|
6
|
-
if
|
6
|
+
if TYPE_CHECKING: # pragma: no cover
|
7
7
|
from piccolo.columns import Column
|
8
8
|
|
9
9
|
|
10
10
|
async def change_permissions(
|
11
11
|
username: str,
|
12
|
-
admin:
|
13
|
-
superuser:
|
14
|
-
active:
|
12
|
+
admin: Optional[bool] = None,
|
13
|
+
superuser: Optional[bool] = None,
|
14
|
+
active: Optional[bool] = None,
|
15
15
|
):
|
16
16
|
"""
|
17
17
|
Change a user's permissions.
|
@@ -34,7 +34,7 @@ async def change_permissions(
|
|
34
34
|
)
|
35
35
|
return
|
36
36
|
|
37
|
-
params:
|
37
|
+
params: dict[Union[Column, str], bool] = {}
|
38
38
|
|
39
39
|
if admin is not None:
|
40
40
|
params[BaseUser.admin] = admin
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import sys
|
2
|
-
import typing as t
|
3
2
|
from getpass import getpass, getuser
|
3
|
+
from typing import Optional
|
4
4
|
|
5
5
|
from piccolo.apps.user.tables import BaseUser
|
6
6
|
|
@@ -57,12 +57,12 @@ def get_is_active() -> bool:
|
|
57
57
|
|
58
58
|
|
59
59
|
def create(
|
60
|
-
username:
|
61
|
-
email:
|
62
|
-
password:
|
63
|
-
is_admin:
|
64
|
-
is_superuser:
|
65
|
-
is_active:
|
60
|
+
username: Optional[str] = None,
|
61
|
+
email: Optional[str] = None,
|
62
|
+
password: Optional[str] = None,
|
63
|
+
is_admin: Optional[bool] = None,
|
64
|
+
is_superuser: Optional[bool] = None,
|
65
|
+
is_active: Optional[bool] = None,
|
66
66
|
):
|
67
67
|
"""
|
68
68
|
Create a new user.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
from typing import Any
|
2
2
|
|
3
3
|
from piccolo.apps.user.tables import BaseUser
|
4
4
|
from piccolo.columns import Column
|
@@ -11,7 +11,7 @@ ORDER_BY_COLUMN_NAMES = [
|
|
11
11
|
|
12
12
|
async def get_users(
|
13
13
|
order_by: Column, ascending: bool, limit: int, page: int
|
14
|
-
) ->
|
14
|
+
) -> list[dict[str, Any]]:
|
15
15
|
return (
|
16
16
|
await BaseUser.select(
|
17
17
|
*BaseUser.all_columns(exclude=[BaseUser.password])
|