plain.models 0.49.2__py3-none-any.whl → 0.50.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 (105) hide show
  1. plain/models/CHANGELOG.md +13 -0
  2. plain/models/aggregates.py +42 -19
  3. plain/models/backends/base/base.py +125 -105
  4. plain/models/backends/base/client.py +11 -3
  5. plain/models/backends/base/creation.py +22 -12
  6. plain/models/backends/base/features.py +10 -4
  7. plain/models/backends/base/introspection.py +29 -16
  8. plain/models/backends/base/operations.py +187 -91
  9. plain/models/backends/base/schema.py +267 -165
  10. plain/models/backends/base/validation.py +12 -3
  11. plain/models/backends/ddl_references.py +85 -43
  12. plain/models/backends/mysql/base.py +29 -26
  13. plain/models/backends/mysql/client.py +7 -2
  14. plain/models/backends/mysql/compiler.py +12 -3
  15. plain/models/backends/mysql/creation.py +5 -2
  16. plain/models/backends/mysql/features.py +24 -22
  17. plain/models/backends/mysql/introspection.py +22 -13
  18. plain/models/backends/mysql/operations.py +106 -39
  19. plain/models/backends/mysql/schema.py +48 -24
  20. plain/models/backends/mysql/validation.py +13 -6
  21. plain/models/backends/postgresql/base.py +41 -34
  22. plain/models/backends/postgresql/client.py +7 -2
  23. plain/models/backends/postgresql/creation.py +10 -5
  24. plain/models/backends/postgresql/introspection.py +15 -8
  25. plain/models/backends/postgresql/operations.py +109 -42
  26. plain/models/backends/postgresql/schema.py +85 -46
  27. plain/models/backends/sqlite3/_functions.py +151 -115
  28. plain/models/backends/sqlite3/base.py +37 -23
  29. plain/models/backends/sqlite3/client.py +7 -1
  30. plain/models/backends/sqlite3/creation.py +9 -5
  31. plain/models/backends/sqlite3/features.py +5 -3
  32. plain/models/backends/sqlite3/introspection.py +32 -16
  33. plain/models/backends/sqlite3/operations.py +125 -42
  34. plain/models/backends/sqlite3/schema.py +82 -58
  35. plain/models/backends/utils.py +52 -29
  36. plain/models/backups/cli.py +8 -6
  37. plain/models/backups/clients.py +16 -7
  38. plain/models/backups/core.py +24 -13
  39. plain/models/base.py +113 -74
  40. plain/models/cli.py +94 -63
  41. plain/models/config.py +1 -1
  42. plain/models/connections.py +23 -7
  43. plain/models/constraints.py +65 -47
  44. plain/models/database_url.py +1 -1
  45. plain/models/db.py +6 -2
  46. plain/models/deletion.py +66 -43
  47. plain/models/entrypoints.py +1 -1
  48. plain/models/enums.py +22 -11
  49. plain/models/exceptions.py +23 -8
  50. plain/models/expressions.py +440 -257
  51. plain/models/fields/__init__.py +253 -202
  52. plain/models/fields/json.py +120 -54
  53. plain/models/fields/mixins.py +12 -8
  54. plain/models/fields/related.py +284 -252
  55. plain/models/fields/related_descriptors.py +31 -22
  56. plain/models/fields/related_lookups.py +23 -11
  57. plain/models/fields/related_managers.py +81 -47
  58. plain/models/fields/reverse_related.py +58 -55
  59. plain/models/forms.py +89 -63
  60. plain/models/functions/comparison.py +71 -18
  61. plain/models/functions/datetime.py +79 -29
  62. plain/models/functions/math.py +43 -10
  63. plain/models/functions/mixins.py +24 -7
  64. plain/models/functions/text.py +104 -25
  65. plain/models/functions/window.py +12 -6
  66. plain/models/indexes.py +52 -28
  67. plain/models/lookups.py +228 -153
  68. plain/models/migrations/autodetector.py +86 -43
  69. plain/models/migrations/exceptions.py +7 -3
  70. plain/models/migrations/executor.py +33 -7
  71. plain/models/migrations/graph.py +79 -50
  72. plain/models/migrations/loader.py +45 -22
  73. plain/models/migrations/migration.py +23 -18
  74. plain/models/migrations/operations/base.py +37 -19
  75. plain/models/migrations/operations/fields.py +89 -42
  76. plain/models/migrations/operations/models.py +245 -143
  77. plain/models/migrations/operations/special.py +82 -25
  78. plain/models/migrations/optimizer.py +7 -2
  79. plain/models/migrations/questioner.py +58 -31
  80. plain/models/migrations/recorder.py +18 -11
  81. plain/models/migrations/serializer.py +50 -39
  82. plain/models/migrations/state.py +220 -133
  83. plain/models/migrations/utils.py +29 -13
  84. plain/models/migrations/writer.py +17 -14
  85. plain/models/options.py +63 -56
  86. plain/models/otel.py +16 -6
  87. plain/models/preflight.py +35 -12
  88. plain/models/query.py +323 -228
  89. plain/models/query_utils.py +93 -58
  90. plain/models/registry.py +34 -16
  91. plain/models/sql/compiler.py +146 -97
  92. plain/models/sql/datastructures.py +38 -25
  93. plain/models/sql/query.py +255 -169
  94. plain/models/sql/subqueries.py +32 -21
  95. plain/models/sql/where.py +54 -29
  96. plain/models/test/pytest.py +15 -11
  97. plain/models/test/utils.py +4 -2
  98. plain/models/transaction.py +20 -7
  99. plain/models/utils.py +13 -5
  100. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/METADATA +1 -1
  101. plain_models-0.50.0.dist-info/RECORD +122 -0
  102. plain_models-0.49.2.dist-info/RECORD +0 -122
  103. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/WHEEL +0 -0
  104. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/entry_points.txt +0 -0
  105. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,23 @@
1
+ from __future__ import annotations
2
+
1
3
  from functools import cached_property
4
+ from typing import TYPE_CHECKING, Any
2
5
 
3
6
  from plain import models
7
+ from plain.models.base import ModelBase
4
8
  from plain.models.migrations.operations.base import Operation
5
9
  from plain.models.migrations.state import ModelState
6
10
  from plain.models.migrations.utils import field_references, resolve_relation
7
11
 
8
12
  from .fields import AddField, AlterField, FieldOperation, RemoveField, RenameField
9
13
 
14
+ if TYPE_CHECKING:
15
+ from plain.models.backends.base.schema import BaseDatabaseSchemaEditor
16
+ from plain.models.fields import Field
17
+ from plain.models.migrations.state import ProjectState
18
+
10
19
 
11
- def _check_for_duplicates(arg_name, objs):
20
+ def _check_for_duplicates(arg_name: str, objs: Any) -> None:
12
21
  used_vals = set()
13
22
  for val in objs:
14
23
  if val in used_vals:
@@ -19,22 +28,24 @@ def _check_for_duplicates(arg_name, objs):
19
28
 
20
29
 
21
30
  class ModelOperation(Operation):
22
- def __init__(self, name):
31
+ def __init__(self, name: str) -> None:
23
32
  self.name = name
24
33
 
25
34
  @cached_property
26
- def name_lower(self):
35
+ def name_lower(self) -> str:
27
36
  return self.name.lower()
28
37
 
29
- def references_model(self, name, package_label):
38
+ def references_model(self, name: str, package_label: str) -> bool:
30
39
  return name.lower() == self.name_lower
31
40
 
32
- def reduce(self, operation, package_label):
33
- return super().reduce(operation, package_label) or self.can_reduce_through(
41
+ def reduce(
42
+ self, operation: Operation, package_label: str
43
+ ) -> bool | list[Operation]:
44
+ return super().reduce(operation, package_label) or self.can_reduce_through( # type: ignore[misc]
34
45
  operation, package_label
35
46
  )
36
47
 
37
- def can_reduce_through(self, operation, package_label):
48
+ def can_reduce_through(self, operation: Operation, package_label: str) -> bool:
38
49
  return not operation.references_model(self.name, package_label)
39
50
 
40
51
 
@@ -43,7 +54,13 @@ class CreateModel(ModelOperation):
43
54
 
44
55
  serialization_expand_args = ["fields", "options"]
45
56
 
46
- def __init__(self, name, fields, options=None, bases=None):
57
+ def __init__(
58
+ self,
59
+ name: str,
60
+ fields: list[tuple[str, Field]],
61
+ options: dict[str, Any] | None = None,
62
+ bases: tuple[Any, ...] | None = None,
63
+ ) -> None:
47
64
  self.fields = fields
48
65
  self.options = options or {}
49
66
  self.bases = bases or (models.Model,)
@@ -53,7 +70,7 @@ class CreateModel(ModelOperation):
53
70
  _check_for_duplicates(
54
71
  "bases",
55
72
  (
56
- base._meta.label_lower
73
+ base._meta.label_lower # type: ignore[attr-defined]
57
74
  if hasattr(base, "_meta")
58
75
  else base.lower()
59
76
  if isinstance(base, str)
@@ -62,8 +79,8 @@ class CreateModel(ModelOperation):
62
79
  ),
63
80
  )
64
81
 
65
- def deconstruct(self):
66
- kwargs = {
82
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
83
+ kwargs: dict[str, Any] = {
67
84
  "name": self.name,
68
85
  "fields": self.fields,
69
86
  }
@@ -73,7 +90,7 @@ class CreateModel(ModelOperation):
73
90
  kwargs["bases"] = self.bases
74
91
  return (self.__class__.__qualname__, [], kwargs)
75
92
 
76
- def state_forwards(self, package_label, state):
93
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
77
94
  state.add_model(
78
95
  ModelState(
79
96
  package_label,
@@ -84,19 +101,25 @@ class CreateModel(ModelOperation):
84
101
  )
85
102
  )
86
103
 
87
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
88
- model = to_state.models_registry.get_model(package_label, self.name)
104
+ def database_forwards(
105
+ self,
106
+ package_label: str,
107
+ schema_editor: BaseDatabaseSchemaEditor,
108
+ from_state: ProjectState,
109
+ to_state: ProjectState,
110
+ ) -> None:
111
+ model = to_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
89
112
  if self.allow_migrate_model(schema_editor.connection, model):
90
113
  schema_editor.create_model(model)
91
114
 
92
- def describe(self):
115
+ def describe(self) -> str:
93
116
  return f"Create model {self.name}"
94
117
 
95
118
  @property
96
- def migration_name_fragment(self):
119
+ def migration_name_fragment(self) -> str:
97
120
  return self.name_lower
98
121
 
99
- def references_model(self, name, package_label):
122
+ def references_model(self, name: str, package_label: str) -> bool:
100
123
  name_lower = name.lower()
101
124
  if name_lower == self.name_lower:
102
125
  return True
@@ -106,7 +129,7 @@ class CreateModel(ModelOperation):
106
129
  for base in self.bases:
107
130
  if (
108
131
  base is not models.Model
109
- and isinstance(base, models.base.ModelBase | str)
132
+ and isinstance(base, ModelBase | str)
110
133
  and resolve_relation(base, package_label) == reference_model_tuple
111
134
  ):
112
135
  return True
@@ -119,7 +142,9 @@ class CreateModel(ModelOperation):
119
142
  return True
120
143
  return False
121
144
 
122
- def reduce(self, operation, package_label):
145
+ def reduce(
146
+ self, operation: Operation, package_label: str
147
+ ) -> bool | list[Operation]:
123
148
  if (
124
149
  isinstance(operation, DeleteModel)
125
150
  and self.name_lower == operation.name_lower
@@ -213,104 +238,118 @@ class CreateModel(ModelOperation):
213
238
  class DeleteModel(ModelOperation):
214
239
  """Drop a model's table."""
215
240
 
216
- def deconstruct(self):
217
- kwargs = {
241
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
242
+ kwargs: dict[str, Any] = {
218
243
  "name": self.name,
219
244
  }
220
245
  return (self.__class__.__qualname__, [], kwargs)
221
246
 
222
- def state_forwards(self, package_label, state):
247
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
223
248
  state.remove_model(package_label, self.name_lower)
224
249
 
225
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
226
- model = from_state.models_registry.get_model(package_label, self.name)
250
+ def database_forwards(
251
+ self,
252
+ package_label: str,
253
+ schema_editor: BaseDatabaseSchemaEditor,
254
+ from_state: ProjectState,
255
+ to_state: ProjectState,
256
+ ) -> None:
257
+ model = from_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
227
258
  if self.allow_migrate_model(schema_editor.connection, model):
228
259
  schema_editor.delete_model(model)
229
260
 
230
- def references_model(self, name, package_label):
261
+ def references_model(self, name: str, package_label: str) -> bool:
231
262
  # The deleted model could be referencing the specified model through
232
263
  # related fields.
233
264
  return True
234
265
 
235
- def describe(self):
266
+ def describe(self) -> str:
236
267
  return f"Delete model {self.name}"
237
268
 
238
269
  @property
239
- def migration_name_fragment(self):
270
+ def migration_name_fragment(self) -> str:
240
271
  return f"delete_{self.name_lower}"
241
272
 
242
273
 
243
274
  class RenameModel(ModelOperation):
244
275
  """Rename a model."""
245
276
 
246
- def __init__(self, old_name, new_name):
277
+ def __init__(self, old_name: str, new_name: str) -> None:
247
278
  self.old_name = old_name
248
279
  self.new_name = new_name
249
280
  super().__init__(old_name)
250
281
 
251
282
  @cached_property
252
- def old_name_lower(self):
283
+ def old_name_lower(self) -> str:
253
284
  return self.old_name.lower()
254
285
 
255
286
  @cached_property
256
- def new_name_lower(self):
287
+ def new_name_lower(self) -> str:
257
288
  return self.new_name.lower()
258
289
 
259
- def deconstruct(self):
260
- kwargs = {
290
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
291
+ kwargs: dict[str, Any] = {
261
292
  "old_name": self.old_name,
262
293
  "new_name": self.new_name,
263
294
  }
264
295
  return (self.__class__.__qualname__, [], kwargs)
265
296
 
266
- def state_forwards(self, package_label, state):
297
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
267
298
  state.rename_model(package_label, self.old_name, self.new_name)
268
299
 
269
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
270
- new_model = to_state.models_registry.get_model(package_label, self.new_name)
300
+ def database_forwards(
301
+ self,
302
+ package_label: str,
303
+ schema_editor: BaseDatabaseSchemaEditor,
304
+ from_state: ProjectState,
305
+ to_state: ProjectState,
306
+ ) -> None:
307
+ new_model = to_state.models_registry.get_model(package_label, self.new_name) # type: ignore[attr-defined]
271
308
  if self.allow_migrate_model(schema_editor.connection, new_model):
272
- old_model = from_state.models_registry.get_model(
309
+ old_model = from_state.models_registry.get_model( # type: ignore[attr-defined]
273
310
  package_label, self.old_name
274
311
  )
275
312
  # Move the main table
276
313
  schema_editor.alter_db_table(
277
314
  new_model,
278
- old_model._meta.db_table,
279
- new_model._meta.db_table,
315
+ old_model._meta.db_table, # type: ignore[attr-defined]
316
+ new_model._meta.db_table, # type: ignore[attr-defined]
280
317
  )
281
318
  # Alter the fields pointing to us
282
- for related_object in old_model._meta.related_objects:
283
- if related_object.related_model == old_model:
319
+ for related_object in old_model._meta.related_objects: # type: ignore[attr-defined]
320
+ if related_object.related_model == old_model: # type: ignore[attr-defined]
284
321
  model = new_model
285
322
  related_key = (package_label, self.new_name_lower)
286
323
  else:
287
- model = related_object.related_model
324
+ model = related_object.related_model # type: ignore[attr-defined]
288
325
  related_key = (
289
- related_object.related_model._meta.package_label,
290
- related_object.related_model._meta.model_name,
326
+ related_object.related_model._meta.package_label, # type: ignore[attr-defined]
327
+ related_object.related_model._meta.model_name, # type: ignore[attr-defined]
291
328
  )
292
- to_field = to_state.models_registry.get_model(
329
+ to_field = to_state.models_registry.get_model( # type: ignore[attr-defined]
293
330
  *related_key
294
- )._meta.get_field(related_object.field.name)
331
+ )._meta.get_field(related_object.field.name) # type: ignore[attr-defined]
295
332
  schema_editor.alter_field(
296
333
  model,
297
- related_object.field,
334
+ related_object.field, # type: ignore[attr-defined]
298
335
  to_field,
299
336
  )
300
337
 
301
- def references_model(self, name, package_label):
338
+ def references_model(self, name: str, package_label: str) -> bool:
302
339
  return (
303
340
  name.lower() == self.old_name_lower or name.lower() == self.new_name_lower
304
341
  )
305
342
 
306
- def describe(self):
343
+ def describe(self) -> str:
307
344
  return f"Rename model {self.old_name} to {self.new_name}"
308
345
 
309
346
  @property
310
- def migration_name_fragment(self):
347
+ def migration_name_fragment(self) -> str:
311
348
  return f"rename_{self.old_name_lower}_{self.new_name_lower}"
312
349
 
313
- def reduce(self, operation, package_label):
350
+ def reduce(
351
+ self, operation: Operation, package_label: str
352
+ ) -> bool | list[Operation]:
314
353
  if (
315
354
  isinstance(operation, RenameModel)
316
355
  and self.new_name_lower == operation.old_name_lower
@@ -323,13 +362,15 @@ class RenameModel(ModelOperation):
323
362
  ]
324
363
  # Skip `ModelOperation.reduce` as we want to run `references_model`
325
364
  # against self.new_name.
326
- return super(ModelOperation, self).reduce(
365
+ return super(ModelOperation, self).reduce( # type: ignore[misc]
327
366
  operation, package_label
328
367
  ) or not operation.references_model(self.new_name, package_label)
329
368
 
330
369
 
331
370
  class ModelOptionOperation(ModelOperation):
332
- def reduce(self, operation, package_label):
371
+ def reduce(
372
+ self, operation: Operation, package_label: str
373
+ ) -> bool | list[Operation]:
333
374
  if (
334
375
  isinstance(operation, self.__class__ | DeleteModel)
335
376
  and self.name_lower == operation.name_lower
@@ -341,75 +382,87 @@ class ModelOptionOperation(ModelOperation):
341
382
  class AlterModelTable(ModelOptionOperation):
342
383
  """Rename a model's table."""
343
384
 
344
- def __init__(self, name, table):
385
+ def __init__(self, name: str, table: str | None) -> None:
345
386
  self.table = table
346
387
  super().__init__(name)
347
388
 
348
- def deconstruct(self):
349
- kwargs = {
389
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
390
+ kwargs: dict[str, Any] = {
350
391
  "name": self.name,
351
392
  "table": self.table,
352
393
  }
353
394
  return (self.__class__.__qualname__, [], kwargs)
354
395
 
355
- def state_forwards(self, package_label, state):
396
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
356
397
  state.alter_model_options(
357
398
  package_label, self.name_lower, {"db_table": self.table}
358
399
  )
359
400
 
360
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
361
- new_model = to_state.models_registry.get_model(package_label, self.name)
401
+ def database_forwards(
402
+ self,
403
+ package_label: str,
404
+ schema_editor: BaseDatabaseSchemaEditor,
405
+ from_state: ProjectState,
406
+ to_state: ProjectState,
407
+ ) -> None:
408
+ new_model = to_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
362
409
  if self.allow_migrate_model(schema_editor.connection, new_model):
363
- old_model = from_state.models_registry.get_model(package_label, self.name)
410
+ old_model = from_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
364
411
  schema_editor.alter_db_table(
365
412
  new_model,
366
- old_model._meta.db_table,
367
- new_model._meta.db_table,
413
+ old_model._meta.db_table, # type: ignore[attr-defined]
414
+ new_model._meta.db_table, # type: ignore[attr-defined]
368
415
  )
369
416
 
370
- def describe(self):
417
+ def describe(self) -> str:
371
418
  return "Rename table for {} to {}".format(
372
419
  self.name,
373
420
  self.table if self.table is not None else "(default)",
374
421
  )
375
422
 
376
423
  @property
377
- def migration_name_fragment(self):
424
+ def migration_name_fragment(self) -> str:
378
425
  return f"alter_{self.name_lower}_table"
379
426
 
380
427
 
381
428
  class AlterModelTableComment(ModelOptionOperation):
382
- def __init__(self, name, table_comment):
429
+ def __init__(self, name: str, table_comment: str | None) -> None:
383
430
  self.table_comment = table_comment
384
431
  super().__init__(name)
385
432
 
386
- def deconstruct(self):
387
- kwargs = {
433
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
434
+ kwargs: dict[str, Any] = {
388
435
  "name": self.name,
389
436
  "table_comment": self.table_comment,
390
437
  }
391
438
  return (self.__class__.__qualname__, [], kwargs)
392
439
 
393
- def state_forwards(self, package_label, state):
440
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
394
441
  state.alter_model_options(
395
442
  package_label, self.name_lower, {"db_table_comment": self.table_comment}
396
443
  )
397
444
 
398
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
399
- new_model = to_state.models_registry.get_model(package_label, self.name)
445
+ def database_forwards(
446
+ self,
447
+ package_label: str,
448
+ schema_editor: BaseDatabaseSchemaEditor,
449
+ from_state: ProjectState,
450
+ to_state: ProjectState,
451
+ ) -> None:
452
+ new_model = to_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
400
453
  if self.allow_migrate_model(schema_editor.connection, new_model):
401
- old_model = from_state.models_registry.get_model(package_label, self.name)
454
+ old_model = from_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
402
455
  schema_editor.alter_db_table_comment(
403
456
  new_model,
404
- old_model._meta.db_table_comment,
405
- new_model._meta.db_table_comment,
457
+ old_model._meta.db_table_comment, # type: ignore[attr-defined]
458
+ new_model._meta.db_table_comment, # type: ignore[attr-defined]
406
459
  )
407
460
 
408
- def describe(self):
461
+ def describe(self) -> str:
409
462
  return f"Alter {self.name} table comment"
410
463
 
411
464
  @property
412
- def migration_name_fragment(self):
465
+ def migration_name_fragment(self) -> str:
413
466
  return f"alter_{self.name_lower}_table_comment"
414
467
 
415
468
 
@@ -425,18 +478,18 @@ class AlterModelOptions(ModelOptionOperation):
425
478
  "ordering",
426
479
  ]
427
480
 
428
- def __init__(self, name, options):
481
+ def __init__(self, name: str, options: dict[str, Any]) -> None:
429
482
  self.options = options
430
483
  super().__init__(name)
431
484
 
432
- def deconstruct(self):
433
- kwargs = {
485
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
486
+ kwargs: dict[str, Any] = {
434
487
  "name": self.name,
435
488
  "options": self.options,
436
489
  }
437
490
  return (self.__class__.__qualname__, [], kwargs)
438
491
 
439
- def state_forwards(self, package_label, state):
492
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
440
493
  state.alter_model_options(
441
494
  package_label,
442
495
  self.name_lower,
@@ -444,14 +497,20 @@ class AlterModelOptions(ModelOptionOperation):
444
497
  self.ALTER_OPTION_KEYS,
445
498
  )
446
499
 
447
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
500
+ def database_forwards(
501
+ self,
502
+ package_label: str,
503
+ schema_editor: BaseDatabaseSchemaEditor,
504
+ from_state: ProjectState,
505
+ to_state: ProjectState,
506
+ ) -> None:
448
507
  pass
449
508
 
450
- def describe(self):
509
+ def describe(self) -> str:
451
510
  return f"Change Meta options on {self.name}"
452
511
 
453
512
  @property
454
- def migration_name_fragment(self):
513
+ def migration_name_fragment(self) -> str:
455
514
  return f"alter_{self.name_lower}_options"
456
515
 
457
516
 
@@ -459,32 +518,38 @@ class IndexOperation(Operation):
459
518
  option_name = "indexes"
460
519
 
461
520
  @cached_property
462
- def model_name_lower(self):
463
- return self.model_name.lower()
521
+ def model_name_lower(self) -> str:
522
+ return self.model_name.lower() # type: ignore[attr-defined]
464
523
 
465
524
 
466
525
  class AddIndex(IndexOperation):
467
526
  """Add an index on a model."""
468
527
 
469
- def __init__(self, model_name, index):
528
+ def __init__(self, model_name: str, index: Any) -> None:
470
529
  self.model_name = model_name
471
- if not index.name:
530
+ if not index.name: # type: ignore[attr-defined]
472
531
  raise ValueError(
473
532
  "Indexes passed to AddIndex operations require a name "
474
533
  f"argument. {index!r} doesn't have one."
475
534
  )
476
535
  self.index = index
477
536
 
478
- def state_forwards(self, package_label, state):
537
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
479
538
  state.add_index(package_label, self.model_name_lower, self.index)
480
539
 
481
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
482
- model = to_state.models_registry.get_model(package_label, self.model_name)
540
+ def database_forwards(
541
+ self,
542
+ package_label: str,
543
+ schema_editor: BaseDatabaseSchemaEditor,
544
+ from_state: ProjectState,
545
+ to_state: ProjectState,
546
+ ) -> None:
547
+ model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
483
548
  if self.allow_migrate_model(schema_editor.connection, model):
484
549
  schema_editor.add_index(model, self.index)
485
550
 
486
- def deconstruct(self):
487
- kwargs = {
551
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
552
+ kwargs: dict[str, Any] = {
488
553
  "model_name": self.model_name,
489
554
  "index": self.index,
490
555
  }
@@ -494,43 +559,49 @@ class AddIndex(IndexOperation):
494
559
  kwargs,
495
560
  )
496
561
 
497
- def describe(self):
498
- if self.index.expressions:
562
+ def describe(self) -> str:
563
+ if self.index.expressions: # type: ignore[attr-defined]
499
564
  return "Create index {} on {} on model {}".format(
500
- self.index.name,
501
- ", ".join([str(expression) for expression in self.index.expressions]),
565
+ self.index.name, # type: ignore[attr-defined]
566
+ ", ".join([str(expression) for expression in self.index.expressions]), # type: ignore[attr-defined]
502
567
  self.model_name,
503
568
  )
504
569
  return "Create index {} on field(s) {} of model {}".format(
505
- self.index.name,
506
- ", ".join(self.index.fields),
570
+ self.index.name, # type: ignore[attr-defined]
571
+ ", ".join(self.index.fields), # type: ignore[attr-defined]
507
572
  self.model_name,
508
573
  )
509
574
 
510
575
  @property
511
- def migration_name_fragment(self):
512
- return f"{self.model_name_lower}_{self.index.name.lower()}"
576
+ def migration_name_fragment(self) -> str:
577
+ return f"{self.model_name_lower}_{self.index.name.lower()}" # type: ignore[attr-defined]
513
578
 
514
579
 
515
580
  class RemoveIndex(IndexOperation):
516
581
  """Remove an index from a model."""
517
582
 
518
- def __init__(self, model_name, name):
583
+ def __init__(self, model_name: str, name: str) -> None:
519
584
  self.model_name = model_name
520
585
  self.name = name
521
586
 
522
- def state_forwards(self, package_label, state):
587
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
523
588
  state.remove_index(package_label, self.model_name_lower, self.name)
524
589
 
525
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
526
- model = from_state.models_registry.get_model(package_label, self.model_name)
590
+ def database_forwards(
591
+ self,
592
+ package_label: str,
593
+ schema_editor: BaseDatabaseSchemaEditor,
594
+ from_state: ProjectState,
595
+ to_state: ProjectState,
596
+ ) -> None:
597
+ model = from_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
527
598
  if self.allow_migrate_model(schema_editor.connection, model):
528
599
  from_model_state = from_state.models[package_label, self.model_name_lower]
529
600
  index = from_model_state.get_index_by_name(self.name)
530
601
  schema_editor.remove_index(model, index)
531
602
 
532
- def deconstruct(self):
533
- kwargs = {
603
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
604
+ kwargs: dict[str, Any] = {
534
605
  "model_name": self.model_name,
535
606
  "name": self.name,
536
607
  }
@@ -540,18 +611,24 @@ class RemoveIndex(IndexOperation):
540
611
  kwargs,
541
612
  )
542
613
 
543
- def describe(self):
614
+ def describe(self) -> str:
544
615
  return f"Remove index {self.name} from {self.model_name}"
545
616
 
546
617
  @property
547
- def migration_name_fragment(self):
618
+ def migration_name_fragment(self) -> str:
548
619
  return f"remove_{self.model_name_lower}_{self.name.lower()}"
549
620
 
550
621
 
551
622
  class RenameIndex(IndexOperation):
552
623
  """Rename an index."""
553
624
 
554
- def __init__(self, model_name, new_name, old_name=None, old_fields=None):
625
+ def __init__(
626
+ self,
627
+ model_name: str,
628
+ new_name: str,
629
+ old_name: str | None = None,
630
+ old_fields: list[str] | tuple[str, ...] | None = None,
631
+ ) -> None:
555
632
  if not old_name and not old_fields:
556
633
  raise ValueError(
557
634
  "RenameIndex requires one of old_name and old_fields arguments to be "
@@ -567,15 +644,15 @@ class RenameIndex(IndexOperation):
567
644
  self.old_fields = old_fields
568
645
 
569
646
  @cached_property
570
- def old_name_lower(self):
571
- return self.old_name.lower()
647
+ def old_name_lower(self) -> str:
648
+ return self.old_name.lower() # type: ignore[union-attr]
572
649
 
573
650
  @cached_property
574
- def new_name_lower(self):
651
+ def new_name_lower(self) -> str:
575
652
  return self.new_name.lower()
576
653
 
577
- def deconstruct(self):
578
- kwargs = {
654
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
655
+ kwargs: dict[str, Any] = {
579
656
  "model_name": self.model_name,
580
657
  "new_name": self.new_name,
581
658
  }
@@ -585,7 +662,7 @@ class RenameIndex(IndexOperation):
585
662
  kwargs["old_fields"] = self.old_fields
586
663
  return (self.__class__.__qualname__, [], kwargs)
587
664
 
588
- def state_forwards(self, package_label, state):
665
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
589
666
  if self.old_fields:
590
667
  state.add_index(
591
668
  package_label,
@@ -594,20 +671,30 @@ class RenameIndex(IndexOperation):
594
671
  )
595
672
  else:
596
673
  state.rename_index(
597
- package_label, self.model_name_lower, self.old_name, self.new_name
674
+ package_label,
675
+ self.model_name_lower,
676
+ self.old_name,
677
+ self.new_name, # type: ignore[arg-type]
598
678
  )
599
679
 
600
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
601
- model = to_state.models_registry.get_model(package_label, self.model_name)
680
+ def database_forwards(
681
+ self,
682
+ package_label: str,
683
+ schema_editor: BaseDatabaseSchemaEditor,
684
+ from_state: ProjectState,
685
+ to_state: ProjectState,
686
+ ) -> None:
687
+ model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
602
688
  if not self.allow_migrate_model(schema_editor.connection, model):
603
- return
689
+ return None
604
690
 
605
691
  if self.old_fields:
606
- from_model = from_state.models_registry.get_model(
692
+ from_model = from_state.models_registry.get_model( # type: ignore[attr-defined]
607
693
  package_label, self.model_name
608
694
  )
609
695
  columns = [
610
- from_model._meta.get_field(field).column for field in self.old_fields
696
+ from_model._meta.get_field(field).column # type: ignore[attr-defined]
697
+ for field in self.old_fields
611
698
  ]
612
699
  matching_index_name = schema_editor._constraint_names(
613
700
  from_model, column_names=columns, index=True
@@ -616,7 +703,7 @@ class RenameIndex(IndexOperation):
616
703
  raise ValueError(
617
704
  "Found wrong number ({}) of indexes for {}({}).".format(
618
705
  len(matching_index_name),
619
- from_model._meta.db_table,
706
+ from_model._meta.db_table, # type: ignore[attr-defined]
620
707
  ", ".join(columns),
621
708
  )
622
709
  )
@@ -626,16 +713,17 @@ class RenameIndex(IndexOperation):
626
713
  )
627
714
  else:
628
715
  from_model_state = from_state.models[package_label, self.model_name_lower]
629
- old_index = from_model_state.get_index_by_name(self.old_name)
716
+ old_index = from_model_state.get_index_by_name(self.old_name) # type: ignore[arg-type]
630
717
  # Don't alter when the index name is not changed.
631
- if old_index.name == self.new_name:
632
- return
718
+ if old_index.name == self.new_name: # type: ignore[attr-defined]
719
+ return None
633
720
 
634
721
  to_model_state = to_state.models[package_label, self.model_name_lower]
635
722
  new_index = to_model_state.get_index_by_name(self.new_name)
636
723
  schema_editor.rename_index(model, old_index, new_index)
724
+ return None
637
725
 
638
- def describe(self):
726
+ def describe(self) -> str:
639
727
  if self.old_name:
640
728
  return (
641
729
  f"Rename index {self.old_name} on {self.model_name} to {self.new_name}"
@@ -646,16 +734,18 @@ class RenameIndex(IndexOperation):
646
734
  )
647
735
 
648
736
  @property
649
- def migration_name_fragment(self):
737
+ def migration_name_fragment(self) -> str:
650
738
  if self.old_name:
651
739
  return f"rename_{self.old_name_lower}_{self.new_name_lower}"
652
740
  return "rename_{}_{}_{}".format(
653
741
  self.model_name_lower,
654
- "_".join(self.old_fields),
742
+ "_".join(self.old_fields), # type: ignore[arg-type]
655
743
  self.new_name_lower,
656
744
  )
657
745
 
658
- def reduce(self, operation, package_label):
746
+ def reduce(
747
+ self, operation: Operation, package_label: str
748
+ ) -> bool | list[Operation]:
659
749
  if (
660
750
  isinstance(operation, RenameIndex)
661
751
  and self.model_name_lower == operation.model_name_lower
@@ -676,19 +766,25 @@ class RenameIndex(IndexOperation):
676
766
  class AddConstraint(IndexOperation):
677
767
  option_name = "constraints"
678
768
 
679
- def __init__(self, model_name, constraint):
769
+ def __init__(self, model_name: str, constraint: Any) -> None:
680
770
  self.model_name = model_name
681
771
  self.constraint = constraint
682
772
 
683
- def state_forwards(self, package_label, state):
773
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
684
774
  state.add_constraint(package_label, self.model_name_lower, self.constraint)
685
775
 
686
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
687
- model = to_state.models_registry.get_model(package_label, self.model_name)
776
+ def database_forwards(
777
+ self,
778
+ package_label: str,
779
+ schema_editor: BaseDatabaseSchemaEditor,
780
+ from_state: ProjectState,
781
+ to_state: ProjectState,
782
+ ) -> None:
783
+ model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
688
784
  if self.allow_migrate_model(schema_editor.connection, model):
689
785
  schema_editor.add_constraint(model, self.constraint)
690
786
 
691
- def deconstruct(self):
787
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
692
788
  return (
693
789
  self.__class__.__name__,
694
790
  [],
@@ -698,32 +794,38 @@ class AddConstraint(IndexOperation):
698
794
  },
699
795
  )
700
796
 
701
- def describe(self):
702
- return f"Create constraint {self.constraint.name} on model {self.model_name}"
797
+ def describe(self) -> str:
798
+ return f"Create constraint {self.constraint.name} on model {self.model_name}" # type: ignore[attr-defined]
703
799
 
704
800
  @property
705
- def migration_name_fragment(self):
706
- return f"{self.model_name_lower}_{self.constraint.name.lower()}"
801
+ def migration_name_fragment(self) -> str:
802
+ return f"{self.model_name_lower}_{self.constraint.name.lower()}" # type: ignore[attr-defined]
707
803
 
708
804
 
709
805
  class RemoveConstraint(IndexOperation):
710
806
  option_name = "constraints"
711
807
 
712
- def __init__(self, model_name, name):
808
+ def __init__(self, model_name: str, name: str) -> None:
713
809
  self.model_name = model_name
714
810
  self.name = name
715
811
 
716
- def state_forwards(self, package_label, state):
812
+ def state_forwards(self, package_label: str, state: ProjectState) -> None:
717
813
  state.remove_constraint(package_label, self.model_name_lower, self.name)
718
814
 
719
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
720
- model = to_state.models_registry.get_model(package_label, self.model_name)
815
+ def database_forwards(
816
+ self,
817
+ package_label: str,
818
+ schema_editor: BaseDatabaseSchemaEditor,
819
+ from_state: ProjectState,
820
+ to_state: ProjectState,
821
+ ) -> None:
822
+ model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
721
823
  if self.allow_migrate_model(schema_editor.connection, model):
722
824
  from_model_state = from_state.models[package_label, self.model_name_lower]
723
825
  constraint = from_model_state.get_constraint_by_name(self.name)
724
826
  schema_editor.remove_constraint(model, constraint)
725
827
 
726
- def deconstruct(self):
828
+ def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
727
829
  return (
728
830
  self.__class__.__name__,
729
831
  [],
@@ -733,9 +835,9 @@ class RemoveConstraint(IndexOperation):
733
835
  },
734
836
  )
735
837
 
736
- def describe(self):
838
+ def describe(self) -> str:
737
839
  return f"Remove constraint {self.name} from model {self.model_name}"
738
840
 
739
841
  @property
740
- def migration_name_fragment(self):
842
+ def migration_name_fragment(self) -> str:
741
843
  return f"remove_{self.model_name_lower}_{self.name.lower()}"