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
piccolo/table.py CHANGED
@@ -3,9 +3,10 @@ from __future__ import annotations
3
3
  import inspect
4
4
  import itertools
5
5
  import types
6
- import typing as t
7
6
  import warnings
7
+ from collections.abc import Sequence
8
8
  from dataclasses import dataclass, field
9
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
9
10
 
10
11
  from piccolo.columns import Column
11
12
  from piccolo.columns.column_types import (
@@ -55,7 +56,7 @@ from piccolo.utils.sql_values import convert_to_sql_value
55
56
  from piccolo.utils.sync import run_sync
56
57
  from piccolo.utils.warnings import colored_warning
57
58
 
58
- if t.TYPE_CHECKING: # pragma: no cover
59
+ if TYPE_CHECKING: # pragma: no cover
59
60
  from piccolo.querystring import Selectable
60
61
 
61
62
  PROTECTED_TABLENAMES = ("user",)
@@ -65,7 +66,7 @@ TABLENAME_WARNING = (
65
66
  )
66
67
 
67
68
 
68
- TABLE_REGISTRY: t.List[t.Type[Table]] = []
69
+ TABLE_REGISTRY: list[type[Table]] = []
69
70
 
70
71
 
71
72
  @dataclass
@@ -75,26 +76,26 @@ class TableMeta:
75
76
  """
76
77
 
77
78
  tablename: str = ""
78
- columns: t.List[Column] = field(default_factory=list)
79
- default_columns: t.List[Column] = field(default_factory=list)
80
- non_default_columns: t.List[Column] = field(default_factory=list)
81
- array_columns: t.List[Array] = field(default_factory=list)
82
- email_columns: t.List[Email] = field(default_factory=list)
83
- foreign_key_columns: t.List[ForeignKey] = field(default_factory=list)
79
+ columns: list[Column] = field(default_factory=list)
80
+ default_columns: list[Column] = field(default_factory=list)
81
+ non_default_columns: list[Column] = field(default_factory=list)
82
+ array_columns: list[Array] = field(default_factory=list)
83
+ email_columns: list[Email] = field(default_factory=list)
84
+ foreign_key_columns: list[ForeignKey] = field(default_factory=list)
84
85
  primary_key: Column = field(default_factory=Column)
85
- json_columns: t.List[t.Union[JSON, JSONB]] = field(default_factory=list)
86
- secret_columns: t.List[Secret] = field(default_factory=list)
87
- auto_update_columns: t.List[Column] = field(default_factory=list)
88
- tags: t.List[str] = field(default_factory=list)
89
- help_text: t.Optional[str] = None
90
- _db: t.Optional[Engine] = None
91
- m2m_relationships: t.List[M2M] = field(default_factory=list)
92
- schema: t.Optional[str] = None
86
+ json_columns: list[Union[JSON, JSONB]] = field(default_factory=list)
87
+ secret_columns: list[Secret] = field(default_factory=list)
88
+ auto_update_columns: list[Column] = field(default_factory=list)
89
+ tags: list[str] = field(default_factory=list)
90
+ help_text: Optional[str] = None
91
+ _db: Optional[Engine] = None
92
+ m2m_relationships: list[M2M] = field(default_factory=list)
93
+ schema: Optional[str] = None
93
94
 
94
95
  # Records reverse foreign key relationships - i.e. when the current table
95
96
  # is the target of a foreign key. Used by external libraries such as
96
97
  # Piccolo API.
97
- _foreign_key_references: t.List[ForeignKey] = field(default_factory=list)
98
+ _foreign_key_references: list[ForeignKey] = field(default_factory=list)
98
99
 
99
100
  def get_formatted_tablename(
100
101
  self, include_schema: bool = True, quoted: bool = True
@@ -120,8 +121,8 @@ class TableMeta:
120
121
  return ".".join(components)
121
122
 
122
123
  @property
123
- def foreign_key_references(self) -> t.List[ForeignKey]:
124
- foreign_keys: t.List[ForeignKey] = list(self._foreign_key_references)
124
+ def foreign_key_references(self) -> list[ForeignKey]:
125
+ foreign_keys: list[ForeignKey] = list(self._foreign_key_references)
125
126
  lazy_column_references = LAZY_COLUMN_REFERENCES.for_tablename(
126
127
  tablename=self.tablename
127
128
  )
@@ -173,11 +174,11 @@ class TableMeta:
173
174
 
174
175
  return column_object
175
176
 
176
- def get_auto_update_values(self) -> t.Dict[Column, t.Any]:
177
+ def get_auto_update_values(self) -> dict[Column, Any]:
177
178
  """
178
179
  If columns have ``auto_update`` defined, then we retrieve these values.
179
180
  """
180
- output: t.Dict[Column, t.Any] = {}
181
+ output: dict[Column, Any] = {}
181
182
  for column in self.auto_update_columns:
182
183
  value = column._meta.auto_update
183
184
  if callable(value):
@@ -203,7 +204,7 @@ class TableMetaclass(type):
203
204
 
204
205
  # `SessionsBase` is a `Table` subclass:
205
206
  def session_auth(
206
- session_table: t.Type[SessionsBase] = SessionsBase
207
+ session_table: type[SessionsBase] = SessionsBase
207
208
  ):
208
209
  ...
209
210
 
@@ -227,11 +228,11 @@ class Table(metaclass=TableMetaclass):
227
228
 
228
229
  def __init_subclass__(
229
230
  cls,
230
- tablename: t.Optional[str] = None,
231
- db: t.Optional[Engine] = None,
232
- tags: t.Optional[t.List[str]] = None,
233
- help_text: t.Optional[str] = None,
234
- schema: t.Optional[str] = None,
231
+ tablename: Optional[str] = None,
232
+ db: Optional[Engine] = None,
233
+ tags: Optional[list[str]] = None,
234
+ help_text: Optional[str] = None,
235
+ schema: Optional[str] = None,
235
236
  ): # sourcery no-metrics
236
237
  """
237
238
  Automatically populate the _meta, which includes the tablename, and
@@ -268,17 +269,17 @@ class Table(metaclass=TableMetaclass):
268
269
  if tablename in PROTECTED_TABLENAMES:
269
270
  warnings.warn(TABLENAME_WARNING.format(tablename=tablename))
270
271
 
271
- columns: t.List[Column] = []
272
- default_columns: t.List[Column] = []
273
- non_default_columns: t.List[Column] = []
274
- array_columns: t.List[Array] = []
275
- foreign_key_columns: t.List[ForeignKey] = []
276
- secret_columns: t.List[Secret] = []
277
- json_columns: t.List[t.Union[JSON, JSONB]] = []
278
- email_columns: t.List[Email] = []
279
- auto_update_columns: t.List[Column] = []
280
- primary_key: t.Optional[Column] = None
281
- m2m_relationships: t.List[M2M] = []
272
+ columns: list[Column] = []
273
+ default_columns: list[Column] = []
274
+ non_default_columns: list[Column] = []
275
+ array_columns: list[Array] = []
276
+ foreign_key_columns: list[ForeignKey] = []
277
+ secret_columns: list[Secret] = []
278
+ json_columns: list[Union[JSON, JSONB]] = []
279
+ email_columns: list[Email] = []
280
+ auto_update_columns: list[Column] = []
281
+ primary_key: Optional[Column] = None
282
+ m2m_relationships: list[M2M] = []
282
283
 
283
284
  attribute_names = itertools.chain(
284
285
  *[i.__dict__.keys() for i in reversed(cls.__mro__)]
@@ -372,7 +373,7 @@ class Table(metaclass=TableMetaclass):
372
373
 
373
374
  def __init__(
374
375
  self,
375
- _data: t.Optional[t.Dict[Column, t.Any]] = None,
376
+ _data: Optional[dict[Column, Any]] = None,
376
377
  _ignore_missing: bool = False,
377
378
  _exists_in_db: bool = False,
378
379
  **kwargs,
@@ -412,7 +413,7 @@ class Table(metaclass=TableMetaclass):
412
413
 
413
414
  # This is used by get_or_create to indicate to the user whether it
414
415
  # was an existing row or not.
415
- self._was_created: t.Optional[bool] = None
416
+ self._was_created: Optional[bool] = None
416
417
 
417
418
  for column in self._meta.columns:
418
419
  value = _data.get(column, ...)
@@ -423,7 +424,7 @@ class Table(metaclass=TableMetaclass):
423
424
 
424
425
  if value is ...:
425
426
  value = kwargs.pop(
426
- t.cast(str, column._meta.db_column_name), ...
427
+ cast(str, column._meta.db_column_name), ...
427
428
  )
428
429
 
429
430
  if value is ...:
@@ -456,7 +457,7 @@ class Table(metaclass=TableMetaclass):
456
457
 
457
458
  @classmethod
458
459
  def from_dict(
459
- cls: t.Type[TableInstance], data: t.Dict[str, t.Any]
460
+ cls: type[TableInstance], data: dict[str, Any]
460
461
  ) -> TableInstance:
461
462
  """
462
463
  Used when loading fixtures. It can be overriden by subclasses in case
@@ -468,8 +469,8 @@ class Table(metaclass=TableMetaclass):
468
469
  ###########################################################################
469
470
 
470
471
  def save(
471
- self, columns: t.Optional[t.Sequence[t.Union[Column, str]]] = None
472
- ) -> t.Union[Insert, Update]:
472
+ self, columns: Optional[Sequence[Union[Column, str]]] = None
473
+ ) -> Union[Insert, Update]:
473
474
  """
474
475
  A proxy to an insert or update query.
475
476
 
@@ -504,7 +505,7 @@ class Table(metaclass=TableMetaclass):
504
505
  for i in columns
505
506
  ]
506
507
 
507
- values: t.Dict[Column, t.Any] = {
508
+ values: dict[Column, Any] = {
508
509
  i: getattr(self, i._meta.name, None) for i in column_instances
509
510
  }
510
511
 
@@ -525,9 +526,7 @@ class Table(metaclass=TableMetaclass):
525
526
  == getattr(self, self._meta.primary_key._meta.name)
526
527
  )
527
528
 
528
- def update_self(
529
- self, values: t.Dict[t.Union[Column, str], t.Any]
530
- ) -> UpdateSelf:
529
+ def update_self(self, values: dict[Union[Column, str], Any]) -> UpdateSelf:
531
530
  """
532
531
  This allows the user to update a single object - useful when the values
533
532
  are derived from the database in some way.
@@ -581,7 +580,7 @@ class Table(metaclass=TableMetaclass):
581
580
 
582
581
  def refresh(
583
582
  self,
584
- columns: t.Optional[t.Sequence[Column]] = None,
583
+ columns: Optional[Sequence[Column]] = None,
585
584
  load_json: bool = False,
586
585
  ) -> Refresh:
587
586
  """
@@ -611,16 +610,16 @@ class Table(metaclass=TableMetaclass):
611
610
  """
612
611
  return Refresh(instance=self, columns=columns, load_json=load_json)
613
612
 
614
- @t.overload
613
+ @overload
615
614
  def get_related(
616
615
  self, foreign_key: ForeignKey[ReferencedTable]
617
616
  ) -> GetRelated[ReferencedTable]: ...
618
617
 
619
- @t.overload
618
+ @overload
620
619
  def get_related(self, foreign_key: str) -> GetRelated[Table]: ...
621
620
 
622
621
  def get_related(
623
- self, foreign_key: t.Union[str, ForeignKey[ReferencedTable]]
622
+ self, foreign_key: Union[str, ForeignKey[ReferencedTable]]
624
623
  ) -> GetRelated[ReferencedTable]:
625
624
  """
626
625
  Used to fetch a ``Table`` instance, for the target of a foreign key.
@@ -666,7 +665,7 @@ class Table(metaclass=TableMetaclass):
666
665
  self,
667
666
  *rows: Table,
668
667
  m2m: M2M,
669
- extra_column_values: t.Dict[t.Union[Column, str], t.Any] = {},
668
+ extra_column_values: dict[Union[Column, str], Any] = {},
670
669
  ) -> M2MAddRelated:
671
670
  """
672
671
  Save the row if it doesn't already exist in the database, and insert
@@ -733,7 +732,7 @@ class Table(metaclass=TableMetaclass):
733
732
  m2m=m2m,
734
733
  )
735
734
 
736
- def to_dict(self, *columns: Column) -> t.Dict[str, t.Any]:
735
+ def to_dict(self, *columns: Column) -> dict[str, Any]:
737
736
  """
738
737
  A convenience method which returns a dictionary, mapping column names
739
738
  to values for this table instance.
@@ -785,7 +784,7 @@ class Table(metaclass=TableMetaclass):
785
784
  )
786
785
  return output
787
786
 
788
- def __setitem__(self, key: str, value: t.Any):
787
+ def __setitem__(self, key: str, value: Any):
789
788
  setattr(self, key, value)
790
789
 
791
790
  def __getitem__(self, key: str):
@@ -858,8 +857,8 @@ class Table(metaclass=TableMetaclass):
858
857
 
859
858
  @classmethod
860
859
  def all_related(
861
- cls, exclude: t.Optional[t.List[t.Union[str, ForeignKey]]] = None
862
- ) -> t.List[ForeignKey]:
860
+ cls, exclude: Optional[list[Union[str, ForeignKey]]] = None
861
+ ) -> list[ForeignKey]:
863
862
  """
864
863
  Used in conjunction with ``objects`` queries. Just as we can use
865
864
  ``all_related`` on a ``ForeignKey``, you can also use it for the table
@@ -908,8 +907,8 @@ class Table(metaclass=TableMetaclass):
908
907
 
909
908
  @classmethod
910
909
  def all_columns(
911
- cls, exclude: t.Optional[t.Sequence[t.Union[str, Column]]] = None
912
- ) -> t.List[Column]:
910
+ cls, exclude: Optional[Sequence[Union[str, Column]]] = None
911
+ ) -> list[Column]:
913
912
  """
914
913
  Used in conjunction with ``select`` queries. Just as we can use
915
914
  ``all_columns`` to retrieve all of the columns from a related table,
@@ -975,7 +974,7 @@ class Table(metaclass=TableMetaclass):
975
974
 
976
975
  @classmethod
977
976
  def insert(
978
- cls: t.Type[TableInstance], *rows: TableInstance
977
+ cls: type[TableInstance], *rows: TableInstance
979
978
  ) -> Insert[TableInstance]:
980
979
  """
981
980
  Insert rows into the database.
@@ -993,7 +992,7 @@ class Table(metaclass=TableMetaclass):
993
992
  return query
994
993
 
995
994
  @classmethod
996
- def raw(cls, sql: str, *args: t.Any) -> Raw:
995
+ def raw(cls, sql: str, *args: Any) -> Raw:
997
996
  """
998
997
  Execute raw SQL queries on the underlying engine - use with caution!
999
998
 
@@ -1012,8 +1011,8 @@ class Table(metaclass=TableMetaclass):
1012
1011
 
1013
1012
  @classmethod
1014
1013
  def _process_column_args(
1015
- cls, *columns: t.Union[Selectable, str]
1016
- ) -> t.Sequence[Selectable]:
1014
+ cls, *columns: Union[Selectable, str]
1015
+ ) -> Sequence[Selectable]:
1017
1016
  """
1018
1017
  Users can specify some column arguments as either Column instances, or
1019
1018
  as strings representing the column name, for convenience.
@@ -1030,7 +1029,7 @@ class Table(metaclass=TableMetaclass):
1030
1029
 
1031
1030
  @classmethod
1032
1031
  def select(
1033
- cls, *columns: t.Union[Selectable, str], exclude_secrets=False
1032
+ cls, *columns: Union[Selectable, str], exclude_secrets=False
1034
1033
  ) -> Select:
1035
1034
  """
1036
1035
  Get data in the form of a list of dictionaries, with each dictionary
@@ -1109,8 +1108,8 @@ class Table(metaclass=TableMetaclass):
1109
1108
 
1110
1109
  @classmethod
1111
1110
  def objects(
1112
- cls: t.Type[TableInstance],
1113
- *prefetch: t.Union[ForeignKey, t.List[ForeignKey]],
1111
+ cls: type[TableInstance],
1112
+ *prefetch: Union[ForeignKey, list[ForeignKey]],
1114
1113
  ) -> Objects[TableInstance]:
1115
1114
  """
1116
1115
  Returns a list of table instances (each representing a row), which you
@@ -1151,8 +1150,8 @@ class Table(metaclass=TableMetaclass):
1151
1150
  @classmethod
1152
1151
  def count(
1153
1152
  cls,
1154
- column: t.Optional[Column] = None,
1155
- distinct: t.Optional[t.Sequence[Column]] = None,
1153
+ column: Optional[Column] = None,
1154
+ distinct: Optional[Sequence[Column]] = None,
1156
1155
  ) -> Count:
1157
1156
  """
1158
1157
  Count the number of matching rows::
@@ -1224,7 +1223,7 @@ class Table(metaclass=TableMetaclass):
1224
1223
  @classmethod
1225
1224
  def update(
1226
1225
  cls,
1227
- values: t.Optional[t.Dict[t.Union[Column, str], t.Any]] = None,
1226
+ values: Optional[dict[Union[Column, str], Any]] = None,
1228
1227
  force: bool = False,
1229
1228
  use_auto_update: bool = True,
1230
1229
  **kwargs,
@@ -1288,7 +1287,7 @@ class Table(metaclass=TableMetaclass):
1288
1287
  @classmethod
1289
1288
  def create_index(
1290
1289
  cls,
1291
- columns: t.Union[t.List[Column], t.List[str]],
1290
+ columns: Union[list[Column], list[str]],
1292
1291
  method: IndexMethod = IndexMethod.btree,
1293
1292
  if_not_exists: bool = False,
1294
1293
  ) -> CreateIndex:
@@ -1311,7 +1310,7 @@ class Table(metaclass=TableMetaclass):
1311
1310
  @classmethod
1312
1311
  def drop_index(
1313
1312
  cls,
1314
- columns: t.Union[t.List[Column], t.List[str]],
1313
+ columns: Union[list[Column], list[str]],
1315
1314
  if_exists: bool = True,
1316
1315
  ) -> DropIndex:
1317
1316
  """
@@ -1328,7 +1327,7 @@ class Table(metaclass=TableMetaclass):
1328
1327
  ###########################################################################
1329
1328
 
1330
1329
  @classmethod
1331
- def _get_index_name(cls, column_names: t.List[str]) -> str:
1330
+ def _get_index_name(cls, column_names: list[str]) -> str:
1332
1331
  """
1333
1332
  Generates an index name from the table name and column names.
1334
1333
  """
@@ -1338,7 +1337,7 @@ class Table(metaclass=TableMetaclass):
1338
1337
 
1339
1338
  @classmethod
1340
1339
  def _table_str(
1341
- cls, abbreviated=False, excluded_params: t.Optional[t.List[str]] = None
1340
+ cls, abbreviated=False, excluded_params: Optional[list[str]] = None
1342
1341
  ):
1343
1342
  """
1344
1343
  Returns a basic string representation of the table and its columns.
@@ -1357,7 +1356,7 @@ class Table(metaclass=TableMetaclass):
1357
1356
  spacer = "\n "
1358
1357
  columns = []
1359
1358
  for col in cls._meta.columns:
1360
- params: t.List[str] = []
1359
+ params: list[str] = []
1361
1360
  for key, value in col._meta.params.items():
1362
1361
  if key in excluded_params:
1363
1362
  continue
@@ -1392,10 +1391,10 @@ class Table(metaclass=TableMetaclass):
1392
1391
 
1393
1392
  def create_table_class(
1394
1393
  class_name: str,
1395
- bases: t.Tuple[t.Type] = (Table,),
1396
- class_kwargs: t.Dict[str, t.Any] = {},
1397
- class_members: t.Dict[str, t.Any] = {},
1398
- ) -> t.Type[Table]:
1394
+ bases: tuple[type] = (Table,),
1395
+ class_kwargs: dict[str, Any] = {},
1396
+ class_members: dict[str, Any] = {},
1397
+ ) -> type[Table]:
1399
1398
  """
1400
1399
  Used to dynamically create ``Table``subclasses at runtime. Most users
1401
1400
  will not require this. It's mostly used internally for Piccolo's
@@ -1411,8 +1410,8 @@ def create_table_class(
1411
1410
  For example, `{'my_column': Varchar()}`.
1412
1411
 
1413
1412
  """
1414
- return t.cast(
1415
- t.Type[Table],
1413
+ return cast(
1414
+ type[Table],
1416
1415
  types.new_class(
1417
1416
  name=class_name,
1418
1417
  bases=bases,
@@ -1427,7 +1426,7 @@ def create_table_class(
1427
1426
 
1428
1427
 
1429
1428
  async def create_db_tables(
1430
- *tables: t.Type[Table], if_not_exists: bool = False
1429
+ *tables: type[Table], if_not_exists: bool = False
1431
1430
  ) -> None:
1432
1431
  """
1433
1432
  Creates the database table for each ``Table`` class passed in. The tables
@@ -1458,7 +1457,7 @@ async def create_db_tables(
1458
1457
 
1459
1458
 
1460
1459
  def create_db_tables_sync(
1461
- *tables: t.Type[Table], if_not_exists: bool = False
1460
+ *tables: type[Table], if_not_exists: bool = False
1462
1461
  ) -> None:
1463
1462
  """
1464
1463
  A sync wrapper around :func:`create_db_tables`.
@@ -1466,7 +1465,7 @@ def create_db_tables_sync(
1466
1465
  run_sync(create_db_tables(*tables, if_not_exists=if_not_exists))
1467
1466
 
1468
1467
 
1469
- def create_tables(*tables: t.Type[Table], if_not_exists: bool = False) -> None:
1468
+ def create_tables(*tables: type[Table], if_not_exists: bool = False) -> None:
1470
1469
  """
1471
1470
  This original implementation has been replaced, because it was synchronous,
1472
1471
  and felt at odds with the rest of the Piccolo codebase which is async
@@ -1485,7 +1484,7 @@ def create_tables(*tables: t.Type[Table], if_not_exists: bool = False) -> None:
1485
1484
  return create_db_tables_sync(*tables, if_not_exists=if_not_exists)
1486
1485
 
1487
1486
 
1488
- async def drop_db_tables(*tables: t.Type[Table]) -> None:
1487
+ async def drop_db_tables(*tables: type[Table]) -> None:
1489
1488
  """
1490
1489
  Drops the database table for each ``Table`` class passed in. The tables
1491
1490
  are dropped in the correct order, based on their foreign keys.
@@ -1518,14 +1517,14 @@ async def drop_db_tables(*tables: t.Type[Table]) -> None:
1518
1517
  await atomic.run()
1519
1518
 
1520
1519
 
1521
- def drop_db_tables_sync(*tables: t.Type[Table]) -> None:
1520
+ def drop_db_tables_sync(*tables: type[Table]) -> None:
1522
1521
  """
1523
1522
  A sync wrapper around :func:`drop_db_tables`.
1524
1523
  """
1525
1524
  run_sync(drop_db_tables(*tables))
1526
1525
 
1527
1526
 
1528
- def drop_tables(*tables: t.Type[Table]) -> None:
1527
+ def drop_tables(*tables: type[Table]) -> None:
1529
1528
  """
1530
1529
  This original implementation has been replaced, because it was synchronous,
1531
1530
  and felt at odds with the rest of the Piccolo codebase which is async
@@ -1548,8 +1547,8 @@ def drop_tables(*tables: t.Type[Table]) -> None:
1548
1547
 
1549
1548
 
1550
1549
  def sort_table_classes(
1551
- table_classes: t.List[t.Type[Table]],
1552
- ) -> t.List[t.Type[Table]]:
1550
+ table_classes: list[type[Table]],
1551
+ ) -> list[type[Table]]:
1553
1552
  """
1554
1553
  Sort the table classes based on their foreign keys, so they can be created
1555
1554
  in the correct order.
@@ -1564,7 +1563,7 @@ def sort_table_classes(
1564
1563
  sorter = TopologicalSorter(graph)
1565
1564
  ordered_tablenames = tuple(sorter.static_order())
1566
1565
 
1567
- output: t.List[t.Type[Table]] = []
1566
+ output: list[type[Table]] = []
1568
1567
  for tablename in ordered_tablenames:
1569
1568
  table_class = table_class_dict.get(tablename)
1570
1569
  if table_class is not None:
@@ -1574,10 +1573,10 @@ def sort_table_classes(
1574
1573
 
1575
1574
 
1576
1575
  def _get_graph(
1577
- table_classes: t.List[t.Type[Table]],
1576
+ table_classes: list[type[Table]],
1578
1577
  iterations: int = 0,
1579
1578
  max_iterations: int = 5,
1580
- ) -> t.Dict[str, t.Set[str]]:
1579
+ ) -> dict[str, set[str]]:
1581
1580
  """
1582
1581
  Analyses the tables based on their foreign keys, and returns a data
1583
1582
  structure like:
@@ -1590,13 +1589,13 @@ def _get_graph(
1590
1589
  to it via a foreign key.
1591
1590
 
1592
1591
  """
1593
- output: t.Dict[str, t.Set[str]] = {}
1592
+ output: dict[str, set[str]] = {}
1594
1593
 
1595
1594
  if iterations >= max_iterations:
1596
1595
  return output
1597
1596
 
1598
1597
  for table_class in table_classes:
1599
- dependents: t.Set[str] = set()
1598
+ dependents: set[str] = set()
1600
1599
  for fk in table_class._meta.foreign_key_columns:
1601
1600
  referenced_table = fk._foreign_key_meta.resolved_references
1602
1601
 
@@ -4,8 +4,8 @@ tables.
4
4
  """
5
5
 
6
6
  import asyncio
7
- import typing as t
8
7
  from dataclasses import dataclass
8
+ from typing import Any, Optional, Union
9
9
 
10
10
  from piccolo.apps.schema.commands.generate import get_output_schema
11
11
  from piccolo.engine import engine_finder
@@ -58,7 +58,7 @@ class Singleton(type):
58
58
  A metaclass that creates a Singleton base class when called.
59
59
  """
60
60
 
61
- _instances: t.Dict = {}
61
+ _instances: dict = {}
62
62
 
63
63
  def __call__(cls, *args, **kwargs):
64
64
  if cls not in cls._instances:
@@ -80,7 +80,7 @@ class TableStorage(metaclass=Singleton):
80
80
  works with Postgres.
81
81
  """
82
82
 
83
- def __init__(self, engine: t.Optional[Engine] = None):
83
+ def __init__(self, engine: Optional[Engine] = None):
84
84
  """
85
85
  :param engine:
86
86
  Which engine to use to make the database queries. If not specified,
@@ -89,13 +89,13 @@ class TableStorage(metaclass=Singleton):
89
89
  """
90
90
  self.engine = engine or engine_finder()
91
91
  self.tables = ImmutableDict()
92
- self._schema_tables: t.Dict[str, t.List[str]] = {}
92
+ self._schema_tables: dict[str, list[str]] = {}
93
93
 
94
94
  async def reflect(
95
95
  self,
96
96
  schema_name: str = "public",
97
- include: t.Union[t.List[str], str, None] = None,
98
- exclude: t.Union[t.List[str], str, None] = None,
97
+ include: Union[list[str], str, None] = None,
98
+ exclude: Union[list[str], str, None] = None,
99
99
  keep_existing: bool = False,
100
100
  ) -> None:
101
101
  """
@@ -154,7 +154,7 @@ class TableStorage(metaclass=Singleton):
154
154
  dict.clear(self.tables)
155
155
  self._schema_tables.clear()
156
156
 
157
- async def get_table(self, tablename: str) -> t.Optional[t.Type[Table]]:
157
+ async def get_table(self, tablename: str) -> Optional[type[Table]]:
158
158
  """
159
159
  Returns the ``Table`` class if it exists. If the table is not present
160
160
  in ``TableStorage``, it will try to reflect it.
@@ -177,7 +177,7 @@ class TableStorage(metaclass=Singleton):
177
177
  table_class = self.tables.get(tablename)
178
178
  return table_class
179
179
 
180
- async def _add_table(self, schema_name: str, table: t.Type[Table]) -> None:
180
+ async def _add_table(self, schema_name: str, table: type[Table]) -> None:
181
181
  if issubclass(table, Table):
182
182
  table_name = self._get_table_name(
183
183
  table._meta.tablename, schema_name
@@ -229,7 +229,7 @@ class TableStorage(metaclass=Singleton):
229
229
  raise ValueError("Couldn't find schema name.")
230
230
 
231
231
  @staticmethod
232
- def _to_list(value: t.Any) -> t.List:
232
+ def _to_list(value: Any) -> list:
233
233
  if isinstance(value, list):
234
234
  return value
235
235
  elif isinstance(value, (tuple, set)):
@@ -2,8 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import datetime
4
4
  import json
5
- import typing as t
5
+ from collections.abc import Callable
6
6
  from decimal import Decimal
7
+ from typing import Any, Optional, Union, cast
7
8
  from uuid import UUID
8
9
 
9
10
  from piccolo.columns import JSON, JSONB, Array, Column, ForeignKey
@@ -13,7 +14,7 @@ from piccolo.utils.sync import run_sync
13
14
 
14
15
 
15
16
  class ModelBuilder:
16
- __DEFAULT_MAPPER: t.Dict[t.Type, t.Callable] = {
17
+ __DEFAULT_MAPPER: dict[type, Callable] = {
17
18
  bool: RandomBuilder.next_bool,
18
19
  bytes: RandomBuilder.next_bytes,
19
20
  datetime.date: RandomBuilder.next_date,
@@ -29,8 +30,8 @@ class ModelBuilder:
29
30
  @classmethod
30
31
  async def build(
31
32
  cls,
32
- table_class: t.Type[TableInstance],
33
- defaults: t.Optional[t.Dict[t.Union[Column, str], t.Any]] = None,
33
+ table_class: type[TableInstance],
34
+ defaults: Optional[dict[Union[Column, str], Any]] = None,
34
35
  persist: bool = True,
35
36
  minimal: bool = False,
36
37
  ) -> TableInstance:
@@ -80,8 +81,8 @@ class ModelBuilder:
80
81
  @classmethod
81
82
  def build_sync(
82
83
  cls,
83
- table_class: t.Type[TableInstance],
84
- defaults: t.Optional[t.Dict[t.Union[Column, str], t.Any]] = None,
84
+ table_class: type[TableInstance],
85
+ defaults: Optional[dict[Union[Column, str], Any]] = None,
85
86
  persist: bool = True,
86
87
  minimal: bool = False,
87
88
  ) -> TableInstance:
@@ -100,8 +101,8 @@ class ModelBuilder:
100
101
  @classmethod
101
102
  async def _build(
102
103
  cls,
103
- table_class: t.Type[TableInstance],
104
- defaults: t.Optional[t.Dict[t.Union[Column, str], t.Any]] = None,
104
+ table_class: type[TableInstance],
105
+ defaults: Optional[dict[Union[Column, str], Any]] = None,
105
106
  minimal: bool = False,
106
107
  persist: bool = True,
107
108
  ) -> TableInstance:
@@ -151,7 +152,7 @@ class ModelBuilder:
151
152
  return model
152
153
 
153
154
  @classmethod
154
- def _randomize_attribute(cls, column: Column) -> t.Any:
155
+ def _randomize_attribute(cls, column: Column) -> Any:
155
156
  """
156
157
  Generate a random value for a column and apply formatting.
157
158
 
@@ -159,7 +160,7 @@ class ModelBuilder:
159
160
  Column class to randomize.
160
161
 
161
162
  """
162
- random_value: t.Any
163
+ random_value: Any
163
164
  if column.value_type == Decimal:
164
165
  precision, scale = column._meta.params["digits"] or (4, 2)
165
166
  random_value = RandomBuilder.next_float(
@@ -170,7 +171,7 @@ class ModelBuilder:
170
171
  random_value = RandomBuilder.next_datetime(tz_aware=tz_aware)
171
172
  elif column.value_type == list:
172
173
  length = RandomBuilder.next_int(maximum=10)
173
- base_type = t.cast(Array, column).base_column.value_type
174
+ base_type = cast(Array, column).base_column.value_type
174
175
  random_value = [
175
176
  cls.__DEFAULT_MAPPER[base_type]() for _ in range(length)
176
177
  ]