piccolo 1.27.0__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.
Files changed (122) hide show
  1. piccolo/__init__.py +1 -1
  2. piccolo/apps/app/commands/new.py +3 -3
  3. piccolo/apps/asgi/commands/new.py +1 -2
  4. piccolo/apps/fixtures/commands/dump.py +8 -8
  5. piccolo/apps/fixtures/commands/load.py +5 -5
  6. piccolo/apps/fixtures/commands/shared.py +9 -9
  7. piccolo/apps/migrations/auto/diffable_table.py +12 -12
  8. piccolo/apps/migrations/auto/migration_manager.py +59 -66
  9. piccolo/apps/migrations/auto/operations.py +14 -14
  10. piccolo/apps/migrations/auto/schema_differ.py +35 -34
  11. piccolo/apps/migrations/auto/schema_snapshot.py +3 -4
  12. piccolo/apps/migrations/auto/serialisation.py +27 -24
  13. piccolo/apps/migrations/auto/serialisation_legacy.py +2 -2
  14. piccolo/apps/migrations/commands/backwards.py +1 -2
  15. piccolo/apps/migrations/commands/base.py +12 -12
  16. piccolo/apps/migrations/commands/check.py +2 -3
  17. piccolo/apps/migrations/commands/clean.py +3 -3
  18. piccolo/apps/migrations/commands/forwards.py +1 -2
  19. piccolo/apps/migrations/commands/new.py +6 -6
  20. piccolo/apps/migrations/tables.py +3 -3
  21. piccolo/apps/playground/commands/run.py +29 -13
  22. piccolo/apps/schema/commands/generate.py +49 -49
  23. piccolo/apps/schema/commands/graph.py +5 -5
  24. piccolo/apps/shell/commands/run.py +1 -2
  25. piccolo/apps/sql_shell/commands/run.py +4 -4
  26. piccolo/apps/tester/commands/run.py +3 -3
  27. piccolo/apps/user/commands/change_permissions.py +6 -6
  28. piccolo/apps/user/commands/create.py +7 -7
  29. piccolo/apps/user/commands/list.py +2 -2
  30. piccolo/apps/user/tables.py +8 -8
  31. piccolo/columns/base.py +84 -52
  32. piccolo/columns/choices.py +2 -2
  33. piccolo/columns/column_types.py +297 -175
  34. piccolo/columns/combination.py +15 -12
  35. piccolo/columns/defaults/base.py +4 -4
  36. piccolo/columns/defaults/date.py +4 -3
  37. piccolo/columns/defaults/interval.py +4 -3
  38. piccolo/columns/defaults/time.py +4 -3
  39. piccolo/columns/defaults/timestamp.py +4 -3
  40. piccolo/columns/defaults/timestamptz.py +4 -3
  41. piccolo/columns/defaults/uuid.py +3 -2
  42. piccolo/columns/m2m.py +28 -35
  43. piccolo/columns/readable.py +4 -3
  44. piccolo/columns/reference.py +9 -9
  45. piccolo/conf/apps.py +53 -54
  46. piccolo/custom_types.py +28 -6
  47. piccolo/engine/base.py +14 -14
  48. piccolo/engine/cockroach.py +5 -4
  49. piccolo/engine/finder.py +2 -2
  50. piccolo/engine/postgres.py +20 -19
  51. piccolo/engine/sqlite.py +23 -22
  52. piccolo/query/base.py +30 -29
  53. piccolo/query/functions/__init__.py +12 -0
  54. piccolo/query/functions/aggregate.py +4 -3
  55. piccolo/query/functions/array.py +151 -0
  56. piccolo/query/functions/base.py +3 -3
  57. piccolo/query/functions/datetime.py +22 -22
  58. piccolo/query/functions/string.py +4 -4
  59. piccolo/query/functions/type_conversion.py +30 -15
  60. piccolo/query/methods/alter.py +47 -46
  61. piccolo/query/methods/count.py +11 -10
  62. piccolo/query/methods/create.py +6 -5
  63. piccolo/query/methods/create_index.py +9 -8
  64. piccolo/query/methods/delete.py +7 -6
  65. piccolo/query/methods/drop_index.py +7 -6
  66. piccolo/query/methods/exists.py +6 -5
  67. piccolo/query/methods/indexes.py +4 -4
  68. piccolo/query/methods/insert.py +21 -14
  69. piccolo/query/methods/objects.py +60 -50
  70. piccolo/query/methods/raw.py +7 -6
  71. piccolo/query/methods/refresh.py +8 -7
  72. piccolo/query/methods/select.py +56 -49
  73. piccolo/query/methods/table_exists.py +5 -5
  74. piccolo/query/methods/update.py +8 -7
  75. piccolo/query/mixins.py +56 -61
  76. piccolo/query/operators/json.py +11 -11
  77. piccolo/query/proxy.py +8 -9
  78. piccolo/querystring.py +14 -15
  79. piccolo/schema.py +10 -10
  80. piccolo/table.py +93 -94
  81. piccolo/table_reflection.py +9 -9
  82. piccolo/testing/model_builder.py +12 -11
  83. piccolo/testing/random_builder.py +2 -2
  84. piccolo/testing/test_case.py +4 -4
  85. piccolo/utils/dictionary.py +3 -3
  86. piccolo/utils/encoding.py +5 -5
  87. piccolo/utils/lazy_loader.py +3 -3
  88. piccolo/utils/list.py +7 -8
  89. piccolo/utils/objects.py +4 -6
  90. piccolo/utils/pydantic.py +21 -24
  91. piccolo/utils/sql_values.py +3 -3
  92. piccolo/utils/sync.py +4 -3
  93. piccolo/utils/warnings.py +1 -2
  94. {piccolo-1.27.0.dist-info → piccolo-1.28.0.dist-info}/METADATA +1 -1
  95. {piccolo-1.27.0.dist-info → piccolo-1.28.0.dist-info}/RECORD +122 -121
  96. tests/apps/fixtures/commands/test_dump_load.py +1 -2
  97. tests/apps/migrations/auto/integration/test_migrations.py +32 -7
  98. tests/apps/migrations/auto/test_migration_manager.py +2 -2
  99. tests/apps/migrations/auto/test_schema_differ.py +22 -23
  100. tests/apps/migrations/commands/test_forwards_backwards.py +3 -3
  101. tests/columns/m2m/base.py +2 -2
  102. tests/columns/test_array.py +176 -10
  103. tests/columns/test_boolean.py +2 -4
  104. tests/columns/test_combination.py +29 -1
  105. tests/columns/test_db_column_name.py +2 -2
  106. tests/engine/test_extra_nodes.py +2 -2
  107. tests/engine/test_pool.py +3 -3
  108. tests/engine/test_transaction.py +4 -4
  109. tests/query/test_freeze.py +4 -4
  110. tests/table/instance/test_get_related.py +2 -2
  111. tests/table/test_alter.py +4 -4
  112. tests/table/test_indexes.py +1 -2
  113. tests/table/test_refresh.py +2 -2
  114. tests/table/test_select.py +58 -0
  115. tests/table/test_update.py +3 -3
  116. tests/testing/test_model_builder.py +1 -2
  117. tests/utils/test_pydantic.py +36 -36
  118. tests/utils/test_table_reflection.py +1 -2
  119. {piccolo-1.27.0.dist-info → piccolo-1.28.0.dist-info}/WHEEL +0 -0
  120. {piccolo-1.27.0.dist-info → piccolo-1.28.0.dist-info}/entry_points.txt +0 -0
  121. {piccolo-1.27.0.dist-info → piccolo-1.28.0.dist-info}/licenses/LICENSE +0 -0
  122. {piccolo-1.27.0.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: t.Dict[str, ModuleType] = {}
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: t.Optional[str] = None,
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: t.Optional[str] = None, *args, **kwargs):
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
- ) -> t.List[AlterStatements]:
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: t.Optional[str] = None,
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
- import typing as t
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: t.Optional[str] = None
18
- ) -> t.List[str]:
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 = "piccolo",
284
- password: str = "piccolo",
288
+ user: Optional[str] = None,
289
+ password: Optional[str] = None,
285
290
  database: str = "piccolo_playground",
286
291
  host: str = "localhost",
287
- port: int = 5432,
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 postgres
299
+ Which database engine to use - options are sqlite, postgres or
300
+ cockroach
295
301
  :param user:
296
- Postgres user
302
+ Database user (ignored for SQLite)
297
303
  :param password:
298
- Postgres password
304
+ Database password (ignored for SQLite)
299
305
  :param database:
300
- Postgres database
306
+ Database name (ignored for SQLite)
301
307
  :param host:
302
- Postgres host
308
+ Database host (ignored for SQLite)
303
309
  :param port:
304
- Postgres port
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 t.TYPE_CHECKING: # pragma: no cover
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: t.Literal["YES", "NO"]
64
+ is_nullable: Literal["YES", "NO"]
65
65
  table_name: str
66
- character_maximum_length: t.Optional[int]
66
+ character_maximum_length: Optional[int]
67
67
  data_type: str
68
- numeric_precision: t.Optional[t.Union[int, str]]
69
- numeric_scale: t.Optional[t.Union[int, str]]
70
- numeric_precision_radix: t.Optional[t.Literal[2, 10]]
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: t.Literal["PRIMARY KEY", "UNIQUE", "FOREIGN KEY", "CHECK"]
79
+ constraint_type: Literal["PRIMARY KEY", "UNIQUE", "FOREIGN KEY", "CHECK"]
80
80
  constraint_name: str
81
- constraint_schema: t.Optional[str] = None
82
- column_name: t.Optional[str] = None
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: t.List[Constraint]
92
+ constraints: list[Constraint]
93
93
 
94
94
  def __post_init__(self) -> None:
95
- foreign_key_constraints: t.List[Constraint] = []
96
- unique_constraints: t.List[Constraint] = []
97
- primary_key_constraints: t.List[Constraint] = []
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: t.Literal[
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: t.List[Trigger]
158
+ triggers: list[Trigger]
159
159
 
160
- def get_column_triggers(self, column_name: str) -> t.List[Trigger]:
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
- ) -> t.Optional[Trigger]:
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: t.List[Index]
224
+ indexes: list[Index]
225
225
 
226
- def get_column_index(self, column_name: str) -> t.Optional[Index]:
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) -> t.List[str]:
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: t.List[str] = dataclasses.field(default_factory=list)
254
- warnings: t.List[str] = dataclasses.field(default_factory=list)
255
- index_warnings: t.List[str] = dataclasses.field(default_factory=list)
256
- trigger_warnings: t.List[str] = dataclasses.field(default_factory=list)
257
- tables: t.List[t.Type[Table]] = dataclasses.field(default_factory=list)
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) -> t.Optional[t.Type[Table]]:
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: t.Dict[str, t.Type[Column]] = {
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: t.Dict[str, t.Type[Column]] = {
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: t.Dict[t.Type[Column], t.Any] = {
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: t.Dict[t.Type[Column], t.Any] = {
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: t.Type[Column], column_default: str, engine_type: str
384
- ) -> t.Any:
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: t.Dict[str, IndexMethod] = {
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: t.Type[Table], tablename: str, schema_name: str = "public"
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: t.Type[Table], tablename: str, schema_name: str = "public"
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: t.Type[Table], tablename: str, schema_name: str = "public"
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: t.Type[Table], schema_name: str = "public"
576
- ) -> t.List[str]:
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: t.Type[Table], tablename: str, schema_name: str = "public"
602
- ) -> t.List[RowMeta]:
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: t.Type[Table], constraint_name: str, constraint_schema: str
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: t.Type[Table],
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: t.Dict[str, Column] = {}
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: t.Dict[str, t.Any] = {
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: t.Union[str, t.Optional[t.Type[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: t.Optional[t.List[str]] = None,
809
- exclude: t.Optional[t.List[str]] = None,
810
- engine: t.Optional[Engine] = None,
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
- import typing as t
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: t.List[GraphColumn]
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: t.Optional[str] = None
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: t.List[GraphTable] = []
77
- relations: t.List[GraphRelation] = []
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: t.Type[Table]): # pragma: no cover
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
- import typing as t
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 = t.cast(PostgresEngine, 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 = t.cast(SQLiteEngine, engine)
59
+ engine = cast(SQLiteEngine, engine)
60
60
 
61
- database = t.cast(str, engine.connection_kwargs.get("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
- import typing as t
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) -> t.Optional[str]:
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: t.List[str]) -> int: # pragma: no cover
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
- import typing as t
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 t.TYPE_CHECKING: # pragma: no cover
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: t.Optional[bool] = None,
13
- superuser: t.Optional[bool] = None,
14
- active: t.Optional[bool] = None,
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: t.Dict[t.Union[Column, str], bool] = {}
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: t.Optional[str] = None,
61
- email: t.Optional[str] = None,
62
- password: t.Optional[str] = None,
63
- is_admin: t.Optional[bool] = None,
64
- is_superuser: t.Optional[bool] = None,
65
- is_active: t.Optional[bool] = None,
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
- import typing as t
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
- ) -> t.List[t.Dict[str, t.Any]]:
14
+ ) -> list[dict[str, Any]]:
15
15
  return (
16
16
  await BaseUser.select(
17
17
  *BaseUser.all_columns(exclude=[BaseUser.password])