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.
Files changed (132) hide show
  1. piccolo/__init__.py +1 -1
  2. piccolo/apps/app/commands/new.py +3 -3
  3. piccolo/apps/asgi/commands/new.py +2 -3
  4. piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja +57 -29
  5. piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja +48 -21
  6. piccolo/apps/asgi/commands/templates/app/_falcon_app.py.jinja +63 -8
  7. piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja +51 -24
  8. piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja +34 -10
  9. piccolo/apps/asgi/commands/templates/app/_quart_app.py.jinja +38 -15
  10. piccolo/apps/asgi/commands/templates/app/_sanic_app.py.jinja +34 -11
  11. piccolo/apps/fixtures/commands/dump.py +8 -8
  12. piccolo/apps/fixtures/commands/load.py +5 -5
  13. piccolo/apps/fixtures/commands/shared.py +9 -9
  14. piccolo/apps/migrations/auto/diffable_table.py +12 -12
  15. piccolo/apps/migrations/auto/migration_manager.py +59 -66
  16. piccolo/apps/migrations/auto/operations.py +14 -14
  17. piccolo/apps/migrations/auto/schema_differ.py +35 -34
  18. piccolo/apps/migrations/auto/schema_snapshot.py +3 -4
  19. piccolo/apps/migrations/auto/serialisation.py +27 -24
  20. piccolo/apps/migrations/auto/serialisation_legacy.py +2 -2
  21. piccolo/apps/migrations/commands/backwards.py +1 -2
  22. piccolo/apps/migrations/commands/base.py +12 -12
  23. piccolo/apps/migrations/commands/check.py +2 -3
  24. piccolo/apps/migrations/commands/clean.py +3 -3
  25. piccolo/apps/migrations/commands/forwards.py +1 -2
  26. piccolo/apps/migrations/commands/new.py +6 -6
  27. piccolo/apps/migrations/tables.py +3 -3
  28. piccolo/apps/playground/commands/run.py +72 -13
  29. piccolo/apps/schema/commands/generate.py +49 -49
  30. piccolo/apps/schema/commands/graph.py +5 -5
  31. piccolo/apps/shell/commands/run.py +1 -2
  32. piccolo/apps/sql_shell/commands/run.py +4 -4
  33. piccolo/apps/tester/commands/run.py +3 -3
  34. piccolo/apps/user/commands/change_permissions.py +6 -6
  35. piccolo/apps/user/commands/create.py +7 -7
  36. piccolo/apps/user/commands/list.py +2 -2
  37. piccolo/apps/user/tables.py +8 -8
  38. piccolo/columns/base.py +84 -52
  39. piccolo/columns/choices.py +2 -2
  40. piccolo/columns/column_types.py +299 -177
  41. piccolo/columns/combination.py +15 -12
  42. piccolo/columns/defaults/base.py +4 -4
  43. piccolo/columns/defaults/date.py +4 -3
  44. piccolo/columns/defaults/interval.py +4 -3
  45. piccolo/columns/defaults/time.py +4 -3
  46. piccolo/columns/defaults/timestamp.py +4 -3
  47. piccolo/columns/defaults/timestamptz.py +4 -3
  48. piccolo/columns/defaults/uuid.py +3 -2
  49. piccolo/columns/m2m.py +28 -35
  50. piccolo/columns/readable.py +4 -3
  51. piccolo/columns/reference.py +9 -9
  52. piccolo/conf/apps.py +53 -54
  53. piccolo/custom_types.py +28 -6
  54. piccolo/engine/base.py +14 -14
  55. piccolo/engine/cockroach.py +5 -4
  56. piccolo/engine/finder.py +2 -2
  57. piccolo/engine/postgres.py +20 -19
  58. piccolo/engine/sqlite.py +23 -22
  59. piccolo/query/base.py +30 -29
  60. piccolo/query/functions/__init__.py +12 -0
  61. piccolo/query/functions/aggregate.py +4 -3
  62. piccolo/query/functions/array.py +151 -0
  63. piccolo/query/functions/base.py +3 -3
  64. piccolo/query/functions/datetime.py +22 -22
  65. piccolo/query/functions/string.py +4 -4
  66. piccolo/query/functions/type_conversion.py +30 -15
  67. piccolo/query/methods/alter.py +47 -46
  68. piccolo/query/methods/count.py +11 -10
  69. piccolo/query/methods/create.py +6 -5
  70. piccolo/query/methods/create_index.py +9 -8
  71. piccolo/query/methods/delete.py +7 -6
  72. piccolo/query/methods/drop_index.py +7 -6
  73. piccolo/query/methods/exists.py +6 -5
  74. piccolo/query/methods/indexes.py +4 -4
  75. piccolo/query/methods/insert.py +21 -14
  76. piccolo/query/methods/objects.py +60 -50
  77. piccolo/query/methods/raw.py +7 -6
  78. piccolo/query/methods/refresh.py +8 -7
  79. piccolo/query/methods/select.py +56 -49
  80. piccolo/query/methods/table_exists.py +5 -5
  81. piccolo/query/methods/update.py +8 -7
  82. piccolo/query/mixins.py +56 -61
  83. piccolo/query/operators/json.py +11 -11
  84. piccolo/query/proxy.py +8 -9
  85. piccolo/querystring.py +14 -15
  86. piccolo/schema.py +10 -10
  87. piccolo/table.py +105 -98
  88. piccolo/table_reflection.py +9 -9
  89. piccolo/testing/model_builder.py +16 -13
  90. piccolo/testing/random_builder.py +14 -2
  91. piccolo/testing/test_case.py +4 -4
  92. piccolo/utils/dictionary.py +3 -3
  93. piccolo/utils/encoding.py +5 -5
  94. piccolo/utils/lazy_loader.py +3 -3
  95. piccolo/utils/list.py +7 -8
  96. piccolo/utils/objects.py +4 -6
  97. piccolo/utils/pydantic.py +21 -24
  98. piccolo/utils/sql_values.py +3 -3
  99. piccolo/utils/sync.py +4 -3
  100. piccolo/utils/warnings.py +1 -2
  101. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/METADATA +1 -1
  102. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/RECORD +132 -131
  103. tests/apps/fixtures/commands/test_dump_load.py +1 -2
  104. tests/apps/migrations/auto/integration/test_migrations.py +32 -7
  105. tests/apps/migrations/auto/test_migration_manager.py +2 -2
  106. tests/apps/migrations/auto/test_schema_differ.py +22 -23
  107. tests/apps/migrations/commands/test_forwards_backwards.py +3 -3
  108. tests/columns/m2m/base.py +20 -49
  109. tests/columns/test_array.py +176 -10
  110. tests/columns/test_boolean.py +2 -4
  111. tests/columns/test_combination.py +29 -1
  112. tests/columns/test_db_column_name.py +2 -2
  113. tests/engine/test_extra_nodes.py +2 -2
  114. tests/engine/test_pool.py +3 -3
  115. tests/engine/test_transaction.py +4 -4
  116. tests/query/test_freeze.py +4 -4
  117. tests/table/instance/test_get_related.py +2 -2
  118. tests/table/test_alter.py +4 -4
  119. tests/table/test_indexes.py +1 -2
  120. tests/table/test_metaclass.py +7 -3
  121. tests/table/test_refresh.py +2 -2
  122. tests/table/test_select.py +58 -0
  123. tests/table/test_str.py +30 -22
  124. tests/table/test_update.py +18 -3
  125. tests/testing/test_model_builder.py +1 -2
  126. tests/testing/test_random_builder.py +5 -0
  127. tests/utils/test_pydantic.py +152 -134
  128. tests/utils/test_table_reflection.py +1 -2
  129. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/WHEEL +0 -0
  130. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/entry_points.txt +0 -0
  131. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/licenses/LICENSE +0 -0
  132. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- import typing as t
1
+ from typing import Any
2
2
  from http import HTTPStatus
3
3
 
4
4
  from hypercorn.middleware import DispatcherMiddleware
@@ -6,6 +6,7 @@ from piccolo.engine import engine_finder
6
6
  from piccolo_admin.endpoints import create_admin
7
7
  from piccolo_api.crud.serializers import create_pydantic_model
8
8
  from quart import Quart
9
+ from quart.helpers import abort
9
10
  from quart_schema import (
10
11
  Info,
11
12
  QuartSchema,
@@ -24,17 +25,24 @@ app = Quart(__name__, static_folder="static")
24
25
  QuartSchema(app, info=Info(title="Quart API", version="0.1.0"))
25
26
 
26
27
 
27
- TaskModelIn: t.Any = create_pydantic_model(
28
+ TaskModelIn: Any = create_pydantic_model(
28
29
  table=Task,
29
30
  model_name="TaskModelIn",
30
31
  )
31
- TaskModelOut: t.Any = create_pydantic_model(
32
+ TaskModelOut: Any = create_pydantic_model(
32
33
  table=Task,
33
34
  include_default_columns=True,
34
35
  model_name="TaskModelOut",
35
36
  )
36
37
 
37
38
 
39
+ # Check if the record is None. Use for query callback
40
+ def check_record_not_found(result: dict[str, Any]) -> dict[str, Any]:
41
+ if result is None:
42
+ abort(code=HTTPStatus.NOT_FOUND)
43
+ return result
44
+
45
+
38
46
  @app.get("/")
39
47
  @hide
40
48
  def home():
@@ -42,10 +50,24 @@ def home():
42
50
 
43
51
 
44
52
  @app.get("/tasks/")
45
- @validate_response(t.List[TaskModelOut])
53
+ @validate_response(list[TaskModelOut])
46
54
  @tag(["Task"])
47
55
  async def tasks():
48
- return await Task.select().order_by(Task._meta.primary_key, ascending=False)
56
+ tasks = await Task.select().order_by(Task._meta.primary_key, ascending=False)
57
+ return [TaskModelOut(**task) for task in tasks], HTTPStatus.OK
58
+
59
+
60
+ @app.get("/tasks/<int:task_id>/")
61
+ @validate_response(TaskModelOut)
62
+ @tag(["Task"])
63
+ async def single_task(task_id: int):
64
+ task = (
65
+ await Task.select()
66
+ .where(Task._meta.primary_key == task_id)
67
+ .first()
68
+ .callback(check_record_not_found)
69
+ )
70
+ return TaskModelOut(**task), HTTPStatus.OK
49
71
 
50
72
 
51
73
  @app.post("/tasks/")
@@ -63,28 +85,29 @@ async def create_task(data: TaskModelIn):
63
85
  @validate_response(TaskModelOut)
64
86
  @tag(["Task"])
65
87
  async def update_task(task_id: int, data: TaskModelIn):
66
- task = await Task.objects().get(Task._meta.primary_key == task_id)
67
- if not task:
68
- return {}, HTTPStatus.NOT_FOUND
88
+ task = (
89
+ await Task.objects()
90
+ .get(Task._meta.primary_key == task_id)
91
+ .callback(check_record_not_found)
92
+ )
69
93
 
70
94
  for key, value in data.model_dump().items():
71
95
  setattr(task, key, value)
72
96
 
73
97
  await task.save()
74
98
 
75
- return task.to_dict(), HTTPStatus.OK
99
+ return TaskModelOut(**task.to_dict()), HTTPStatus.OK
76
100
 
77
101
 
78
102
  @app.delete("/tasks/<int:task_id>/")
79
- @validate_response(TaskModelOut)
80
103
  @tag(["Task"])
81
104
  async def delete_task(task_id: int):
82
- task = await Task.objects().get(Task._meta.primary_key == task_id)
83
- if not task:
84
- return {}, HTTPStatus.NOT_FOUND
85
-
105
+ task = (
106
+ await Task.objects()
107
+ .get(Task._meta.primary_key == task_id)
108
+ .callback(check_record_not_found)
109
+ )
86
110
  await task.remove()
87
-
88
111
  return {}, HTTPStatus.OK
89
112
 
90
113
 
@@ -1,11 +1,10 @@
1
- import asyncio
2
- import typing as t
1
+ from typing import Any
3
2
 
4
3
  from hypercorn.middleware import DispatcherMiddleware
5
4
  from piccolo.engine import engine_finder
6
5
  from piccolo_admin.endpoints import create_admin
7
6
  from piccolo_api.crud.serializers import create_pydantic_model
8
- from sanic import Request, Sanic, json
7
+ from sanic import NotFound, Request, Sanic, json
9
8
  from sanic_ext import openapi
10
9
 
11
10
  from home.endpoints import index
@@ -16,17 +15,24 @@ app = Sanic(__name__)
16
15
  app.static("/static/", "static")
17
16
 
18
17
 
19
- TaskModelIn: t.Any = create_pydantic_model(
18
+ TaskModelIn: Any = create_pydantic_model(
20
19
  table=Task,
21
20
  model_name="TaskModelIn",
22
21
  )
23
- TaskModelOut: t.Any = create_pydantic_model(
22
+ TaskModelOut: Any = create_pydantic_model(
24
23
  table=Task,
25
24
  include_default_columns=True,
26
25
  model_name="TaskModelOut",
27
26
  )
28
27
 
29
28
 
29
+ # Check if the record is None. Use for query callback
30
+ def check_record_not_found(result: dict[str, Any]) -> dict[str, Any]:
31
+ if result is None:
32
+ raise NotFound(message="Record not found")
33
+ return result
34
+
35
+
30
36
  @app.get("/")
31
37
  @openapi.exclude()
32
38
  def home(request: Request):
@@ -43,6 +49,19 @@ async def tasks(request: Request):
43
49
  )
44
50
 
45
51
 
52
+ @app.get("/tasks/<task_id:int>/")
53
+ @openapi.tag("Task")
54
+ @openapi.response(200, {"application/json": TaskModelOut.model_json_schema()})
55
+ async def single_task(request: Request, task_id: int):
56
+ task = (
57
+ await Task.select()
58
+ .where(Task._meta.primary_key == task_id)
59
+ .first()
60
+ .callback(check_record_not_found)
61
+ )
62
+ return json(task, status=200)
63
+
64
+
46
65
  @app.post("/tasks/")
47
66
  @openapi.definition(
48
67
  body={"application/json": TaskModelIn.model_json_schema()},
@@ -62,9 +81,11 @@ async def create_task(request: Request):
62
81
  )
63
82
  @openapi.response(200, {"application/json": TaskModelOut.model_json_schema()})
64
83
  async def update_task(request: Request, task_id: int):
65
- task = await Task.objects().get(Task._meta.primary_key == task_id)
66
- if not task:
67
- return json({}, status=404)
84
+ task = (
85
+ await Task.objects()
86
+ .get(Task._meta.primary_key == task_id)
87
+ .callback(check_record_not_found)
88
+ )
68
89
  for key, value in request.json.items():
69
90
  setattr(task, key, value)
70
91
 
@@ -75,9 +96,11 @@ async def update_task(request: Request, task_id: int):
75
96
  @app.delete("/tasks/<task_id:int>/")
76
97
  @openapi.tag("Task")
77
98
  async def delete_task(request: Request, task_id: int):
78
- task = await Task.objects().get(Task._meta.primary_key == task_id)
79
- if not task:
80
- return json({}, status=404)
99
+ task = (
100
+ await Task.objects()
101
+ .get(Task._meta.primary_key == task_id)
102
+ .callback(check_record_not_found)
103
+ )
81
104
  await task.remove()
82
105
  return json({}, status=200)
83
106
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- import typing as t
3
+ from typing import Any, Optional
4
4
 
5
5
  from piccolo.apps.fixtures.commands.shared import (
6
6
  FixtureConfig,
@@ -11,8 +11,8 @@ from piccolo.table import sort_table_classes
11
11
 
12
12
 
13
13
  async def get_dump(
14
- fixture_configs: t.List[FixtureConfig],
15
- ) -> t.Dict[str, t.Any]:
14
+ fixture_configs: list[FixtureConfig],
15
+ ) -> dict[str, Any]:
16
16
  """
17
17
  Gets the data for each table specified and returns a data structure like:
18
18
 
@@ -32,7 +32,7 @@ async def get_dump(
32
32
  """
33
33
  finder = Finder()
34
34
 
35
- output: t.Dict[str, t.Any] = {}
35
+ output: dict[str, Any] = {}
36
36
 
37
37
  for fixture_config in fixture_configs:
38
38
  app_config = finder.get_app_config(app_name=fixture_config.app_name)
@@ -53,7 +53,7 @@ async def get_dump(
53
53
 
54
54
 
55
55
  async def dump_to_json_string(
56
- fixture_configs: t.List[FixtureConfig],
56
+ fixture_configs: list[FixtureConfig],
57
57
  ) -> str:
58
58
  """
59
59
  Dumps all of the data for the given tables into a JSON string.
@@ -65,7 +65,7 @@ async def dump_to_json_string(
65
65
  return pydantic_model(**dump).model_dump_json(indent=4)
66
66
 
67
67
 
68
- def parse_args(apps: str, tables: str) -> t.List[FixtureConfig]:
68
+ def parse_args(apps: str, tables: str) -> list[FixtureConfig]:
69
69
  """
70
70
  Works out which apps and tables the user is referring to.
71
71
  """
@@ -80,11 +80,11 @@ def parse_args(apps: str, tables: str) -> t.List[FixtureConfig]:
80
80
  # Must be a single app name
81
81
  app_names.append(apps)
82
82
 
83
- table_class_names: t.Optional[t.List[str]] = None
83
+ table_class_names: Optional[list[str]] = None
84
84
 
85
85
  if tables != "all":
86
86
  table_class_names = tables.split(",") if "," in tables else [tables]
87
- output: t.List[FixtureConfig] = []
87
+ output: list[FixtureConfig] = []
88
88
 
89
89
  for app_name in app_names:
90
90
  app_config = finder.get_app_config(app_name=app_name)
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import sys
4
- import typing as t
4
+ from typing import Optional
5
5
 
6
6
  import typing_extensions
7
7
 
@@ -20,7 +20,7 @@ from piccolo.utils.list import batch
20
20
  async def load_json_string(
21
21
  json_string: str,
22
22
  chunk_size: int = 1000,
23
- on_conflict_action: t.Optional[OnConflictAction] = None,
23
+ on_conflict_action: Optional[OnConflictAction] = None,
24
24
  ):
25
25
  """
26
26
  Parses the JSON string, and inserts the parsed data into the database.
@@ -55,7 +55,7 @@ async def load_json_string(
55
55
  raise Exception("Unable to find the engine.")
56
56
 
57
57
  # This is what we want to the insert into the database:
58
- data: t.Dict[t.Type[Table], t.List[Table]] = {}
58
+ data: dict[type[Table], list[Table]] = {}
59
59
 
60
60
  for app_name in app_names:
61
61
  app_model = getattr(fixture_pydantic_model, app_name)
@@ -94,7 +94,7 @@ async def load_json_string(
94
94
  async def load(
95
95
  path: str = "fixture.json",
96
96
  chunk_size: int = 1000,
97
- on_conflict: t.Optional[
97
+ on_conflict: Optional[
98
98
  typing_extensions.Literal["DO NOTHING", "DO UPDATE"]
99
99
  ] = None,
100
100
  ):
@@ -118,7 +118,7 @@ async def load(
118
118
  with open(path, "r") as f:
119
119
  contents = f.read()
120
120
 
121
- on_conflict_action: t.Optional[OnConflictAction] = None
121
+ on_conflict_action: Optional[OnConflictAction] = None
122
122
 
123
123
  if on_conflict:
124
124
  try:
@@ -1,42 +1,42 @@
1
1
  from __future__ import annotations
2
2
 
3
- import typing as t
4
3
  from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  import pydantic
7
7
 
8
8
  from piccolo.conf.apps import Finder
9
9
  from piccolo.utils.pydantic import create_pydantic_model
10
10
 
11
- if t.TYPE_CHECKING: # pragma: no cover
11
+ if TYPE_CHECKING: # pragma: no cover
12
12
  from piccolo.table import Table
13
13
 
14
14
 
15
15
  @dataclass
16
16
  class FixtureConfig:
17
17
  app_name: str
18
- table_class_names: t.List[str]
18
+ table_class_names: list[str]
19
19
 
20
20
 
21
- def create_pydantic_fixture_model(fixture_configs: t.List[FixtureConfig]):
21
+ def create_pydantic_fixture_model(fixture_configs: list[FixtureConfig]):
22
22
  """
23
23
  Returns a nested Pydantic model for serialising and deserialising fixtures.
24
24
  """
25
- columns: t.Dict[str, t.Any] = {}
25
+ columns: dict[str, Any] = {}
26
26
 
27
27
  finder = Finder()
28
28
 
29
29
  for fixture_config in fixture_configs:
30
30
 
31
- app_columns: t.Dict[str, t.Any] = {}
31
+ app_columns: dict[str, Any] = {}
32
32
 
33
33
  for table_class_name in fixture_config.table_class_names:
34
- table_class: t.Type[Table] = finder.get_table_with_name(
34
+ table_class: type[Table] = finder.get_table_with_name(
35
35
  app_name=fixture_config.app_name,
36
36
  table_class_name=table_class_name,
37
37
  )
38
38
  app_columns[table_class_name] = (
39
- t.List[ # type: ignore
39
+ list[ # type: ignore
40
40
  create_pydantic_model(
41
41
  table_class, include_default_columns=True
42
42
  )
@@ -44,7 +44,7 @@ def create_pydantic_fixture_model(fixture_configs: t.List[FixtureConfig]):
44
44
  ...,
45
45
  )
46
46
 
47
- app_model: t.Any = pydantic.create_model(
47
+ app_model: Any = pydantic.create_model(
48
48
  f"{fixture_config.app_name.title()}Model", **app_columns
49
49
  )
50
50
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- import typing as t
4
3
  from dataclasses import dataclass, field
4
+ from typing import Any, Optional
5
5
 
6
6
  from piccolo.apps.migrations.auto.operations import (
7
7
  AddColumn,
@@ -17,8 +17,8 @@ from piccolo.table import Table, create_table_class
17
17
 
18
18
 
19
19
  def compare_dicts(
20
- dict_1: t.Dict[str, t.Any], dict_2: t.Dict[str, t.Any]
21
- ) -> t.Dict[str, t.Any]:
20
+ dict_1: dict[str, Any], dict_2: dict[str, Any]
21
+ ) -> dict[str, Any]:
22
22
  """
23
23
  Returns a new dictionary which only contains key, value pairs which are in
24
24
  the first dictionary and not the second.
@@ -59,9 +59,9 @@ def compare_dicts(
59
59
 
60
60
  @dataclass
61
61
  class TableDelta:
62
- add_columns: t.List[AddColumn] = field(default_factory=list)
63
- drop_columns: t.List[DropColumn] = field(default_factory=list)
64
- alter_columns: t.List[AlterColumn] = field(default_factory=list)
62
+ add_columns: list[AddColumn] = field(default_factory=list)
63
+ drop_columns: list[DropColumn] = field(default_factory=list)
64
+ alter_columns: list[AlterColumn] = field(default_factory=list)
65
65
 
66
66
  def __eq__(self, value: TableDelta) -> bool: # type: ignore
67
67
  """
@@ -101,12 +101,12 @@ class DiffableTable:
101
101
 
102
102
  class_name: str
103
103
  tablename: str
104
- schema: t.Optional[str] = None
105
- columns: t.List[Column] = field(default_factory=list)
106
- previous_class_name: t.Optional[str] = None
104
+ schema: Optional[str] = None
105
+ columns: list[Column] = field(default_factory=list)
106
+ previous_class_name: Optional[str] = None
107
107
 
108
108
  def __post_init__(self) -> None:
109
- self.columns_map: t.Dict[str, Column] = {
109
+ self.columns_map: dict[str, Column] = {
110
110
  i._meta.name: i for i in self.columns
111
111
  }
112
112
 
@@ -163,7 +163,7 @@ class DiffableTable:
163
163
 
164
164
  #######################################################################
165
165
 
166
- alter_columns: t.List[AlterColumn] = []
166
+ alter_columns: list[AlterColumn] = []
167
167
 
168
168
  for existing_column in value.columns:
169
169
  column = self.columns_map.get(existing_column._meta.name)
@@ -221,7 +221,7 @@ class DiffableTable:
221
221
  def __str__(self):
222
222
  return f"{self.class_name} - {self.tablename}"
223
223
 
224
- def to_table_class(self) -> t.Type[Table]:
224
+ def to_table_class(self) -> type[Table]:
225
225
  """
226
226
  Converts the DiffableTable into a Table subclass.
227
227
  """