plain.postgres 0.94.0__tar.gz → 0.94.2__tar.gz

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 (135) hide show
  1. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/.gitignore +1 -0
  2. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/PKG-INFO +2 -2
  3. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/CHANGELOG.md +24 -0
  4. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/agents/.claude/skills/plain-postgres-doctor/SKILL.md +1 -0
  5. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/aggregates.py +2 -2
  6. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/base.py +3 -3
  7. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/migrations.py +2 -4
  8. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/connection.py +3 -3
  9. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/constraints.py +1 -1
  10. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/deletion.py +2 -2
  11. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/enums.py +5 -5
  12. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/expressions.py +5 -5
  13. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/encrypted.py +5 -5
  14. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/related.py +4 -7
  15. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/related_managers.py +1 -1
  16. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/reverse_related.py +3 -3
  17. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/forms.py +1 -1
  18. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/indexes.py +1 -1
  19. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/lookups.py +2 -2
  20. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/meta.py +1 -1
  21. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/__init__.py +1 -2
  22. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/autodetector.py +8 -39
  23. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/graph.py +1 -1
  24. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/migration.py +0 -17
  25. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/recorder.py +1 -1
  26. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/serializer.py +1 -10
  27. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/state.py +2 -2
  28. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/utils.py +1 -1
  29. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/writer.py +2 -9
  30. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/otel.py +11 -10
  31. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/preflight.py +1 -1
  32. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/query.py +9 -9
  33. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/query_utils.py +1 -1
  34. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/sql/compiler.py +11 -11
  35. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/sql/query.py +6 -6
  36. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/test/pytest.py +4 -4
  37. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/utils.py +1 -1
  38. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/pyproject.toml +2 -2
  39. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_connection_isolation.py +2 -2
  40. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_encrypted_fields.py +1 -1
  41. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_exceptions.py +2 -2
  42. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_models.py +3 -3
  43. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_related_descriptors.py +3 -3
  44. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/CLAUDE.md +0 -0
  45. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/LICENSE +0 -0
  46. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/README.md +0 -0
  47. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/README.md +0 -0
  48. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/__init__.py +0 -0
  49. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/agents/.claude/rules/plain-postgres.md +0 -0
  50. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/__init__.py +0 -0
  51. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/converge.py +0 -0
  52. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/core.py +0 -0
  53. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/diagnose.py +0 -0
  54. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/schema.py +0 -0
  55. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/cli/sync.py +0 -0
  56. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/config.py +0 -0
  57. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/connections.py +0 -0
  58. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/constants.py +0 -0
  59. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/convergence/__init__.py +0 -0
  60. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/convergence/analysis.py +0 -0
  61. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/convergence/fixes.py +0 -0
  62. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/convergence/planning.py +0 -0
  63. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/database_url.py +0 -0
  64. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/db.py +0 -0
  65. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/ddl.py +0 -0
  66. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/default_settings.py +0 -0
  67. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/dialect.py +0 -0
  68. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/entrypoints.py +0 -0
  69. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/exceptions.py +0 -0
  70. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/__init__.py +0 -0
  71. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/json.py +0 -0
  72. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/mixins.py +0 -0
  73. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/related_descriptors.py +0 -0
  74. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/related_lookups.py +0 -0
  75. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/reverse_descriptors.py +0 -0
  76. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/fields/timezones.py +0 -0
  77. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/__init__.py +0 -0
  78. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/comparison.py +0 -0
  79. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/datetime.py +0 -0
  80. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/math.py +0 -0
  81. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/mixins.py +0 -0
  82. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/text.py +0 -0
  83. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/functions/window.py +0 -0
  84. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/introspection/__init__.py +0 -0
  85. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/introspection/health.py +0 -0
  86. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/introspection/schema.py +0 -0
  87. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/exceptions.py +0 -0
  88. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/executor.py +0 -0
  89. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/loader.py +0 -0
  90. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/operations/__init__.py +0 -0
  91. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/operations/base.py +0 -0
  92. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/operations/fields.py +0 -0
  93. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/operations/models.py +0 -0
  94. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/operations/special.py +0 -0
  95. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/optimizer.py +0 -0
  96. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/migrations/questioner.py +0 -0
  97. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/options.py +0 -0
  98. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/registry.py +0 -0
  99. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/schema.py +0 -0
  100. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/sql/__init__.py +0 -0
  101. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/sql/constants.py +0 -0
  102. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/sql/datastructures.py +0 -0
  103. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/sql/where.py +0 -0
  104. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/test/__init__.py +0 -0
  105. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/test/utils.py +0 -0
  106. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/transaction.py +0 -0
  107. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/types.py +0 -0
  108. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/plain/postgres/types.pyi +0 -0
  109. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0001_initial.py +0 -0
  110. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0002_test_field_removed.py +0 -0
  111. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0003_deleteparent_childsetnull_childsetdefault_and_more.py +0 -0
  112. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0004_defaultquerysetmodel_mixintestmodel_and_more.py +0 -0
  113. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0005_feature_carfeature_car_features.py +0 -0
  114. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0006_secretstore.py +0 -0
  115. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/0007_treenode_unconstrainedchild.py +0 -0
  116. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/migrations/__init__.py +0 -0
  117. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/examples/models.py +0 -0
  118. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/settings.py +0 -0
  119. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/app/urls.py +0 -0
  120. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/conftest_convergence.py +0 -0
  121. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_connection_lifecycle.py +0 -0
  122. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_convergence.py +0 -0
  123. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_convergence_constraints.py +0 -0
  124. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_convergence_fk.py +0 -0
  125. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_convergence_indexes.py +0 -0
  126. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_convergence_nullability.py +0 -0
  127. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_database_url.py +0 -0
  128. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_delete_behaviors.py +0 -0
  129. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_introspection.py +0 -0
  130. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_iterator.py +0 -0
  131. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_manager_assignment.py +0 -0
  132. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_migration_executor.py +0 -0
  133. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_read_only_transactions.py +0 -0
  134. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_related_manager_api.py +0 -0
  135. {plain_postgres-0.94.0 → plain_postgres-0.94.2}/tests/test_schema_normalize_type.py +0 -0
@@ -18,6 +18,7 @@ plain*/tests/.plain
18
18
 
19
19
  .vscode
20
20
  /.claude/settings.local.json
21
+ /.claude/skills/announcements/
21
22
  /CLAUDE.local.md
22
23
  /.benchmarks
23
24
  .claude/worktrees
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.postgres
3
- Version: 0.94.0
3
+ Version: 0.94.2
4
4
  Summary: Model your data and store it in a database.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-Expression: BSD-3-Clause
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.13
9
- Requires-Dist: plain<1.0.0,>=0.129.0
9
+ Requires-Dist: plain<1.0.0,>=0.132.0
10
10
  Requires-Dist: sqlparse>=0.3.1
11
11
  Description-Content-Type: text/markdown
12
12
 
@@ -1,5 +1,29 @@
1
1
  # plain-postgres changelog
2
2
 
3
+ ## [0.94.2](https://github.com/dropseed/plain/releases/plain-postgres@0.94.2) (2026-04-13)
4
+
5
+ ### What's changed
6
+
7
+ - Updated internal references to use the fixed `app.users.models.User` convention. ([0861c9915cb6](https://github.com/dropseed/plain/commit/0861c9915cb6))
8
+ - Migrated type suppression comments to `ty: ignore` for the new ty checker version. ([4ec631a7ef51](https://github.com/dropseed/plain/commit/4ec631a7ef51))
9
+
10
+ ### Upgrade instructions
11
+
12
+ - No changes required.
13
+
14
+ ## [0.94.1](https://github.com/dropseed/plain/releases/plain-postgres@0.94.1) (2026-04-05)
15
+
16
+ ### What's changed
17
+
18
+ - **Removed deprecated `db.user` attribute from query spans.** The attribute was removed from the OTel semconv with no replacement. ([b56a9edc9c7d](https://github.com/dropseed/plain/commit/b56a9edc9c7d))
19
+ - **Switched `DbSystemValues` to stable `DbSystemNameValues`.** Migrated from the deprecated `opentelemetry.semconv.trace` module to the stable `opentelemetry.semconv.attributes.db_attributes`. ([b56a9edc9c7d](https://github.com/dropseed/plain/commit/b56a9edc9c7d))
20
+ - **Added `error.type` attribute to query spans on exceptions.** Set to the fully-qualified exception class name (e.g. `psycopg.errors.UniqueViolation`) for queryable error grouping. ([b56a9edc9c7d](https://github.com/dropseed/plain/commit/b56a9edc9c7d))
21
+ - **Removed `set_status(OK)` from query spans.** Per the OTel spec, instrumentation libraries should leave span status as Unset on success. ([b56a9edc9c7d](https://github.com/dropseed/plain/commit/b56a9edc9c7d))
22
+
23
+ ### Upgrade instructions
24
+
25
+ - No changes required.
26
+
3
27
  ## [0.94.0](https://github.com/dropseed/plain/releases/plain-postgres@0.94.0) (2026-04-02)
4
28
 
5
29
  ### What's changed
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: plain-postgres-doctor
3
3
  description: Check overall database health — schema correctness and operational health. Use when asked to check the database, validate schema, optimize indexes, or diagnose Postgres problems.
4
+ context: fork
4
5
  ---
5
6
 
6
7
  # Database Doctor
@@ -75,7 +75,7 @@ class Aggregate(Func):
75
75
  self.filter = self.filter and exprs_list.pop()
76
76
  super().set_source_expressions(exprs_list)
77
77
 
78
- def resolve_expression( # type: ignore[override]
78
+ def resolve_expression( # ty: ignore[invalid-method-override]
79
79
  self,
80
80
  query: Any = None,
81
81
  allow_joins: bool = True,
@@ -140,7 +140,7 @@ class Aggregate(Func):
140
140
  if self.filter is not None:
141
141
  # Use FILTER clause for aggregates when filter is specified
142
142
  try:
143
- filter_sql, filter_params = self.filter.as_sql(compiler, connection) # type: ignore[union-attr]
143
+ filter_sql, filter_params = self.filter.as_sql(compiler, connection) # ty: ignore[unresolved-attribute]
144
144
  except FullResultSet:
145
145
  pass
146
146
  else:
@@ -744,7 +744,7 @@ class Model(metaclass=ModelBase):
744
744
 
745
745
  if len(unique_check) == 1:
746
746
  field = meta.get_forward_field(unique_check[0])
747
- params["field_label"] = field.name # type: ignore[assignment]
747
+ params["field_label"] = field.name # ty: ignore[invalid-assignment]
748
748
  return ValidationError(
749
749
  message=field.error_messages["unique"],
750
750
  code="unique",
@@ -1215,7 +1215,7 @@ class Model(metaclass=ModelBase):
1215
1215
  fld = None
1216
1216
  for part in field.split(LOOKUP_SEP):
1217
1217
  try:
1218
- fld = _cls._model_meta.get_field(part) # type: ignore[unresolved-attribute]
1218
+ fld = _cls._model_meta.get_field(part) # ty: ignore[unresolved-attribute]
1219
1219
  if isinstance(fld, RelatedField):
1220
1220
  _cls = fld.path_infos[-1].to_meta.model
1221
1221
  else:
@@ -1413,4 +1413,4 @@ def model_unpickle(model_id: tuple[str, str] | type[Model]) -> Model:
1413
1413
 
1414
1414
 
1415
1415
  # Pickle protocol marker - functions don't normally have this attribute
1416
- model_unpickle.__safe_for_unpickle__ = True # type: ignore[attr-defined]
1416
+ model_unpickle.__safe_for_unpickle__ = True # ty: ignore[unresolved-attribute]
@@ -16,7 +16,7 @@ from ..db import get_connection
16
16
  from ..migrations.autodetector import MigrationAutodetector
17
17
  from ..migrations.executor import MigrationExecutor
18
18
  from ..migrations.loader import AmbiguityError, MigrationLoader
19
- from ..migrations.migration import Migration, SettingsTuple
19
+ from ..migrations.migration import Migration
20
20
  from ..migrations.optimizer import MigrationOptimizer
21
21
  from ..migrations.questioner import (
22
22
  InteractiveMigrationQuestioner,
@@ -971,9 +971,7 @@ def squash(
971
971
  )
972
972
  operations.extend(smigration.operations)
973
973
  for dependency in smigration.dependencies:
974
- if isinstance(dependency, SettingsTuple):
975
- dependencies.add(dependency)
976
- elif dependency[0] != smigration.package_label or first_migration:
974
+ if dependency[0] != smigration.package_label or first_migration:
977
975
  dependencies.add(dependency)
978
976
  first_migration = False
979
977
 
@@ -354,7 +354,7 @@ class DatabaseConnection:
354
354
  return False
355
355
  if new_role := self.settings_dict.get("OPTIONS", {}).get("assume_role"):
356
356
  sql_str = self.compose_sql("SET ROLE %s", [new_role])
357
- self.connection.execute(sql_str) # type: ignore[arg-type]
357
+ self.connection.execute(sql_str) # ty: ignore[invalid-argument-type]
358
358
  return True
359
359
  return False
360
360
 
@@ -373,7 +373,7 @@ class DatabaseConnection:
373
373
 
374
374
  # Register the cursor timezone only if the connection disagrees, to avoid copying the adapter map.
375
375
  tzloader = self.connection.adapters.get_loader(TIMESTAMPTZ_OID, Format.TEXT)
376
- if self.timezone != tzloader.timezone: # type: ignore[union-attr]
376
+ if self.timezone != tzloader.timezone: # ty: ignore[unresolved-attribute]
377
377
  register_tzloader(self.timezone, cursor)
378
378
  return cursor
379
379
 
@@ -1309,7 +1309,7 @@ class CursorMixin:
1309
1309
 
1310
1310
  qparts.append(psycopg_sql.SQL(")"))
1311
1311
  stmt = psycopg_sql.Composed(qparts)
1312
- self.execute(stmt) # type: ignore[attr-defined]
1312
+ self.execute(stmt) # ty: ignore[unresolved-attribute]
1313
1313
  return args
1314
1314
 
1315
1315
 
@@ -372,7 +372,7 @@ class UniqueConstraint(BaseConstraint):
372
372
  if exclude:
373
373
  for expression in self.expressions:
374
374
  if hasattr(expression, "flatten"):
375
- for expr in expression.flatten(): # type: ignore[operator]
375
+ for expr in expression.flatten(): # ty: ignore[call-non-callable]
376
376
  if isinstance(expr, F) and expr.name in exclude:
377
377
  return
378
378
  elif isinstance(expression, F) and expression.name in exclude:
@@ -160,7 +160,7 @@ class Collector:
160
160
  if not objs:
161
161
  return []
162
162
  new_objs = []
163
- model = objs[0].__class__ # type: ignore[index]
163
+ model = objs[0].__class__ # ty: ignore[not-subscriptable]
164
164
  instances = self.data[model]
165
165
  for obj in objs:
166
166
  if obj not in instances:
@@ -192,7 +192,7 @@ class Collector:
192
192
 
193
193
  def add_restricted_objects(self, field: RelatedField, objs: Iterable[Any]) -> None:
194
194
  if objs:
195
- model = objs[0].__class__ # type: ignore[index]
195
+ model = objs[0].__class__ # ty: ignore[not-subscriptable]
196
196
  self.restricted_objects[model][field].update(objs)
197
197
 
198
198
  def clear_restricted_objects_from_set(self, model: Any, objs: set[Any]) -> None:
@@ -35,26 +35,26 @@ class ChoicesMeta(enum.EnumMeta):
35
35
  # Use dict.__setitem__() to suppress defenses against double
36
36
  # assignment in enum's classdict.
37
37
  dict.__setitem__(classdict, key, value)
38
- cls = super().__new__(metacls, classname, bases, classdict, **kwds) # type: ignore[misc]
38
+ cls = super().__new__(metacls, classname, bases, classdict, **kwds) # ty: ignore[invalid-super-argument]
39
39
  for member, label in zip(cls.__members__.values(), labels):
40
40
  member._label_ = label
41
41
  return enum.unique(cls)
42
42
 
43
- def __contains__(cls, member: object) -> bool: # type: ignore[override]
43
+ def __contains__(cls, member: object) -> bool: # ty: ignore[invalid-method-override]
44
44
  if not isinstance(member, enum.Enum):
45
45
  # Allow non-enums to match against member values.
46
- return any(x.value == member for x in cls) # type: ignore[attr-defined]
46
+ return any(x.value == member for x in cls) # ty: ignore[unresolved-attribute]
47
47
  return super().__contains__(member)
48
48
 
49
49
  @property
50
50
  def names(cls) -> list[str]:
51
51
  empty = ["__empty__"] if hasattr(cls, "__empty__") else []
52
- return empty + [member.name for member in cls] # type: ignore[attr-defined]
52
+ return empty + [member.name for member in cls] # ty: ignore[unresolved-attribute]
53
53
 
54
54
  @property
55
55
  def choices(cls) -> list[tuple[Any, str]]:
56
56
  empty = [(None, cls.__empty__)] if hasattr(cls, "__empty__") else []
57
- return empty + [(member.value, member.label) for member in cls] # type: ignore[attr-defined]
57
+ return empty + [(member.value, member.label) for member in cls] # ty: ignore[unresolved-attribute, invalid-return-type]
58
58
 
59
59
  @property
60
60
  def labels(cls) -> list[str]:
@@ -432,7 +432,7 @@ class BaseExpression:
432
432
  return self.output_field.get_lookup(lookup)
433
433
 
434
434
  def get_transform(self, name: str) -> type[Transform] | None:
435
- return self.output_field.get_transform(name) # type: ignore[return-type]
435
+ return self.output_field.get_transform(name) # ty: ignore[invalid-return-type]
436
436
 
437
437
  def relabeled_clone(self, change_map: dict[str, str]) -> Self:
438
438
  clone = self.copy()
@@ -1045,7 +1045,7 @@ class Value(Expression):
1045
1045
  else:
1046
1046
  val = output_field.get_db_prep_value(val, connection=connection)
1047
1047
  if hasattr(output_field, "get_placeholder"):
1048
- return output_field.get_placeholder(val, compiler, connection), [val] # type: ignore[call-non-callable]
1048
+ return output_field.get_placeholder(val, compiler, connection), [val] # ty: ignore[call-non-callable]
1049
1049
  if val is None:
1050
1050
  return "NULL", []
1051
1051
  return "%s", [val]
@@ -1366,7 +1366,7 @@ class When(Expression):
1366
1366
  if isinstance(condition, Q) and not condition:
1367
1367
  raise ValueError("An empty Q() can't be used as a When() condition.")
1368
1368
  super().__init__(output_field=None)
1369
- self.condition = condition # type: ignore[assignment]
1369
+ self.condition = condition # ty: ignore[invalid-assignment]
1370
1370
  self.result = self._parse_expressions(then)[0]
1371
1371
 
1372
1372
  def __str__(self) -> str:
@@ -1703,10 +1703,10 @@ class OrderBy(Expression):
1703
1703
  self.nulls_last = None
1704
1704
  return self
1705
1705
 
1706
- def asc(self) -> None: # type: ignore[override]
1706
+ def asc(self) -> None: # ty: ignore[invalid-method-override]
1707
1707
  self.descending = False
1708
1708
 
1709
- def desc(self) -> None: # type: ignore[override]
1709
+ def desc(self) -> None: # ty: ignore[invalid-method-override]
1710
1710
  self.descending = True
1711
1711
 
1712
1712
 
@@ -10,11 +10,11 @@ try:
10
10
  from cryptography.hazmat.primitives import hashes
11
11
  from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
12
12
  except ImportError:
13
- Fernet = None # type: ignore[assignment,misc]
14
- InvalidToken = None # type: ignore[assignment,misc]
15
- MultiFernet = None # type: ignore[assignment,misc]
16
- hashes = None # type: ignore[assignment]
17
- PBKDF2HMAC = None # type: ignore[assignment]
13
+ Fernet = None # ty: ignore[invalid-assignment]
14
+ InvalidToken = None # ty: ignore[invalid-assignment]
15
+ MultiFernet = None # ty: ignore[invalid-assignment]
16
+ hashes = None # ty: ignore[invalid-assignment]
17
+ PBKDF2HMAC = None # ty: ignore[invalid-assignment]
18
18
 
19
19
  from plain import exceptions, preflight
20
20
  from plain.runtime import settings
@@ -11,7 +11,6 @@ from plain.postgres.exceptions import FieldDoesNotExist, FieldError
11
11
  from plain.postgres.query_utils import PathInfo, Q
12
12
  from plain.postgres.utils import make_model_tuple
13
13
  from plain.preflight import PreflightResult
14
- from plain.runtime import SettingsReference
15
14
 
16
15
  from ..registry import models_registry
17
16
  from . import Field
@@ -115,7 +114,7 @@ class RelatedField(FieldCacheMixin, Field):
115
114
  obj = super().__deepcopy__(memodict)
116
115
  obj.remote_field = copy.copy(self.remote_field)
117
116
  if hasattr(self.remote_field, "field") and self.remote_field.field is self:
118
- obj.remote_field.field = obj # type: ignore[misc]
117
+ obj.remote_field.field = obj # ty: ignore[invalid-assignment]
119
118
  return obj
120
119
 
121
120
  @cached_property
@@ -288,7 +287,7 @@ class RelatedField(FieldCacheMixin, Field):
288
287
  returned.
289
288
  """
290
289
  if callable(self.remote_field.limit_choices_to):
291
- return self.remote_field.limit_choices_to() # type: ignore[call-top-callable]
290
+ return self.remote_field.limit_choices_to() # ty: ignore[call-top-callable]
292
291
  return self.remote_field.limit_choices_to
293
292
 
294
293
  def related_query_name(self) -> str:
@@ -543,9 +542,7 @@ class ForeignKeyField(RelatedField):
543
542
  name, path, args, kwargs = super().deconstruct()
544
543
  kwargs["on_delete"] = self.remote_field.on_delete
545
544
 
546
- if isinstance(self.remote_field.model, SettingsReference):
547
- kwargs["to"] = self.remote_field.model
548
- elif isinstance(self.remote_field.model, str):
545
+ if isinstance(self.remote_field.model, str):
549
546
  if "." in self.remote_field.model:
550
547
  package_label, model_name = self.remote_field.model.split(".")
551
548
  kwargs["to"] = f"{package_label}.{model_name.lower()}"
@@ -1130,7 +1127,7 @@ class ManyToManyField(RelatedField):
1130
1127
  )
1131
1128
 
1132
1129
  # Add the descriptor for the m2m relation.
1133
- setattr(cls, self.name, ForwardManyToManyDescriptor(self.remote_field)) # type: ignore[arg-type]
1130
+ setattr(cls, self.name, ForwardManyToManyDescriptor(self.remote_field)) # ty: ignore[invalid-argument-type]
1134
1131
 
1135
1132
  # Set up the accessor for the m2m table name for the relation.
1136
1133
  self.m2m_db_table = self._get_m2m_db_table
@@ -367,7 +367,7 @@ class ManyToManyManager(BaseRelatedManager[T, QS]):
367
367
  for lh_field, rh_field in self.source_field.related_fields:
368
368
  core_filter_key = f"{self.query_field_name}__{rh_field.name}"
369
369
  self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
370
- self.id_field_names[lh_field.name] = rh_field.name # type: ignore[assignment]
370
+ self.id_field_names[lh_field.name] = rh_field.name # ty: ignore[invalid-assignment]
371
371
 
372
372
  self.related_val = self.source_field.get_foreign_related_value(instance)
373
373
  if None in self.related_val:
@@ -69,10 +69,10 @@ class ForeignObjectRel(FieldCacheMixin):
69
69
  limit_choices_to: dict[str, Any] | Q | None = None,
70
70
  on_delete: OnDeleteCallback | None = None,
71
71
  ):
72
- self.field = field # type: ignore[misc]
72
+ self.field = field # ty: ignore[invalid-assignment]
73
73
  # Initially may be a string, gets resolved to type[Model] by lazy_related_operation
74
74
  # (see related.py:250 where field.remote_field.model is overwritten)
75
- self.model = to # type: ignore[assignment]
75
+ self.model = to # ty: ignore[invalid-assignment]
76
76
  self.related_query_name = related_query_name
77
77
  self.limit_choices_to = {} if limit_choices_to is None else limit_choices_to
78
78
  self.on_delete = on_delete
@@ -290,7 +290,7 @@ class ManyToManyRel(ForeignObjectRel):
290
290
 
291
291
  # Initially may be a string, gets resolved to type[Model] by lazy_related_operation
292
292
  # (see related.py:1143 where field.remote_field.through is overwritten)
293
- self.through = through # type: ignore[assignment]
293
+ self.through = through # ty: ignore[invalid-assignment]
294
294
  self.through_fields = through_fields
295
295
 
296
296
  self.symmetrical = symmetrical
@@ -578,7 +578,7 @@ class ModelMultipleChoiceField(ModelChoiceField):
578
578
  def __init__(self, queryset: Any, **kwargs: Any) -> None:
579
579
  super().__init__(queryset, empty_label=None, **kwargs)
580
580
 
581
- def to_python(self, value: Any) -> list[Any]: # type: ignore[override]
581
+ def to_python(self, value: Any) -> list[Any]: # ty: ignore[invalid-method-override]
582
582
  if not value:
583
583
  return []
584
584
  return list(self._check_values(value))
@@ -74,7 +74,7 @@ class Index:
74
74
  self.opclasses: tuple[str, ...] = tuple(opclasses)
75
75
  self.condition = condition
76
76
  self.include = tuple(include) if include else ()
77
- self.expressions: tuple[Expression, ...] = tuple( # type: ignore[assignment]
77
+ self.expressions: tuple[Expression, ...] = tuple( # ty: ignore[invalid-assignment]
78
78
  F(expression) if isinstance(expression, str) else expression
79
79
  for expression in expressions
80
80
  )
@@ -441,7 +441,7 @@ class IntegerFieldOverflow:
441
441
  raise self.underflow_exception
442
442
  if max_value is not None and rhs > max_value:
443
443
  raise self.overflow_exception
444
- return super().process_rhs(compiler, connection) # type: ignore[misc]
444
+ return super().process_rhs(compiler, connection) # ty: ignore[unresolved-attribute]
445
445
 
446
446
 
447
447
  class IntegerFieldFloatRounding:
@@ -455,7 +455,7 @@ class IntegerFieldFloatRounding:
455
455
  def get_prep_lookup(self) -> Any:
456
456
  if isinstance(self.rhs, float):
457
457
  self.rhs = math.ceil(self.rhs)
458
- return super().get_prep_lookup() # type: ignore[misc]
458
+ return super().get_prep_lookup() # ty: ignore[unresolved-attribute]
459
459
 
460
460
 
461
461
  @IntegerField.register_lookup
@@ -367,7 +367,7 @@ class Meta:
367
367
  )
368
368
 
369
369
  try:
370
- return self.fields_map[field_name] # type: ignore[return-type]
370
+ return self.fields_map[field_name] # ty: ignore[invalid-return-type]
371
371
  except KeyError:
372
372
  raise FieldDoesNotExist(
373
373
  f"{self.model} has no reverse relation named '{field_name}'"
@@ -1,5 +1,5 @@
1
1
  from ..schema import DatabaseSchemaEditor
2
- from .migration import Migration, settings_dependency
2
+ from .migration import Migration
3
3
  from .operations import (
4
4
  AddField,
5
5
  AlterField,
@@ -19,7 +19,6 @@ from .state import StateModelsRegistry
19
19
  __all__ = [
20
20
  # Migration class
21
21
  "Migration",
22
- "settings_dependency",
23
22
  # Model operations
24
23
  "CreateModel",
25
24
  "DeleteModel",
@@ -15,7 +15,7 @@ from plain.postgres.fields import (
15
15
  from plain.postgres.fields.related import ManyToManyField, RelatedField
16
16
  from plain.postgres.fields.reverse_related import ManyToManyRel
17
17
  from plain.postgres.migrations import operations
18
- from plain.postgres.migrations.migration import Migration, SettingsTuple
18
+ from plain.postgres.migrations.migration import Migration
19
19
  from plain.postgres.migrations.operations.models import AlterModelOptions
20
20
  from plain.postgres.migrations.optimizer import MigrationOptimizer
21
21
  from plain.postgres.migrations.questioner import MigrationQuestioner
@@ -24,7 +24,6 @@ from plain.postgres.migrations.utils import (
24
24
  RegexObject,
25
25
  resolve_relation,
26
26
  )
27
- from plain.runtime import settings
28
27
 
29
28
  if TYPE_CHECKING:
30
29
  from plain.postgres.migrations.graph import MigrationGraph
@@ -230,7 +229,7 @@ class MigrationAutodetector:
230
229
  field.remote_field, "through", None
231
230
  ):
232
231
  through_key = resolve_relation(
233
- field.remote_field.through, # type: ignore[unresolved-attribute]
232
+ field.remote_field.through, # ty: ignore[unresolved-attribute]
234
233
  package_label,
235
234
  model_name,
236
235
  )
@@ -240,23 +239,6 @@ class MigrationAutodetector:
240
239
  field_name,
241
240
  )
242
241
 
243
- @staticmethod
244
- def _resolve_dependency(
245
- dependency: tuple[str, str, str | None, bool | str],
246
- ) -> tuple[tuple[str, str, str | None, bool | str], bool]:
247
- """
248
- Return the resolved dependency and a boolean denoting whether or not
249
- it was a settings dependency.
250
- """
251
- if not isinstance(dependency, SettingsTuple):
252
- return dependency, False
253
- resolved_package_label, resolved_object_name = getattr(
254
- settings, dependency[1]
255
- ).split(".")
256
- return (resolved_package_label, resolved_object_name.lower()) + dependency[
257
- 2:
258
- ], True
259
-
260
242
  def _build_migration_list(self, graph: MigrationGraph | None = None) -> None:
261
243
  """
262
244
  Chop the lists of operations up into migrations with dependencies on
@@ -285,12 +267,6 @@ class MigrationAutodetector:
285
267
  deps_satisfied = True
286
268
  operation_dependencies = set()
287
269
  for dep in operation._auto_deps:
288
- # Temporarily resolve the settings dependency to
289
- # prevent circular references. While keeping the
290
- # dependency checks on the resolved model, add the
291
- # settings dependencies.
292
- original_dep = dep
293
- dep, is_settings_dep = self._resolve_dependency(dep)
294
270
  if dep[0] != package_label:
295
271
  # External app dependency. See if it's not yet
296
272
  # satisfied.
@@ -303,11 +279,7 @@ class MigrationAutodetector:
303
279
  if not deps_satisfied:
304
280
  break
305
281
  else:
306
- if is_settings_dep:
307
- operation_dependencies.add(
308
- (original_dep[0], original_dep[1])
309
- )
310
- elif dep[0] in self.migrations:
282
+ if dep[0] in self.migrations:
311
283
  operation_dependencies.add(
312
284
  (dep[0], self.migrations[dep[0]][-1].name)
313
285
  )
@@ -381,9 +353,6 @@ class MigrationAutodetector:
381
353
  for op in ops:
382
354
  ts.add(op)
383
355
  for dep in op._auto_deps:
384
- # Resolve intra-app dependencies to handle circular
385
- # references involving a settings model.
386
- dep = self._resolve_dependency(dep)[0]
387
356
  if dep[0] != package_label:
388
357
  continue
389
358
  ts.add(op, *(x for x in ops if self.check_dependency(x, dep)))
@@ -894,19 +863,19 @@ class MigrationAutodetector:
894
863
  new_field.remote_field, "model", None
895
864
  ):
896
865
  rename_key = resolve_relation(
897
- new_field.remote_field.model, # type: ignore[unresolved-attribute]
866
+ new_field.remote_field.model, # ty: ignore[unresolved-attribute]
898
867
  package_label,
899
868
  model_name,
900
869
  )
901
870
  if rename_key in self.renamed_models:
902
- new_field.remote_field.model = old_field.remote_field.model # type: ignore[unresolved-attribute]
871
+ new_field.remote_field.model = old_field.remote_field.model # ty: ignore[unresolved-attribute]
903
872
  # Handle ForeignKeyField which can only have a single to_field.
904
873
  remote_field_name = getattr(new_field.remote_field, "field_name", None)
905
874
  if remote_field_name:
906
875
  to_field_rename_key = rename_key + (remote_field_name,)
907
876
  if to_field_rename_key in self.renamed_fields:
908
877
  # Repoint model name only
909
- new_field.remote_field.model = old_field.remote_field.model # type: ignore[unresolved-attribute]
878
+ new_field.remote_field.model = old_field.remote_field.model # ty: ignore[unresolved-attribute]
910
879
  dependencies.extend(
911
880
  self._get_dependencies_for_foreign_key(
912
881
  package_label,
@@ -919,12 +888,12 @@ class MigrationAutodetector:
919
888
  new_field.remote_field, "through", None
920
889
  ):
921
890
  rename_key = resolve_relation(
922
- new_field.remote_field.through, # type: ignore[unresolved-attribute]
891
+ new_field.remote_field.through, # ty: ignore[unresolved-attribute]
923
892
  package_label,
924
893
  model_name,
925
894
  )
926
895
  if rename_key in self.renamed_models:
927
- new_field.remote_field.through = old_field.remote_field.through # type: ignore[unresolved-attribute]
896
+ new_field.remote_field.through = old_field.remote_field.through # ty: ignore[unresolved-attribute]
928
897
  old_field_dec = self.deep_deconstruct(old_field)
929
898
  new_field_dec = self.deep_deconstruct(new_field)
930
899
  if old_field_dec != new_field_dec and old_field_name == field_name:
@@ -357,7 +357,7 @@ class MigrationGraph:
357
357
  plan = self._generate_plan(nodes, at_end)
358
358
  project_state = ProjectState(real_packages=real_packages)
359
359
  for node in plan:
360
- project_state = self.nodes[node].mutate_state(project_state, preserve=False) # type: ignore[attr-defined]
360
+ project_state = self.nodes[node].mutate_state(project_state, preserve=False) # ty: ignore[unresolved-attribute]
361
361
  return project_state
362
362
 
363
363
  def __contains__(self, node: tuple[str, str]) -> bool:
@@ -161,20 +161,3 @@ class Migration:
161
161
  break
162
162
  name = new_name
163
163
  return name
164
-
165
-
166
- class SettingsTuple(tuple):
167
- """
168
- Subclass of tuple so Plain can tell this was originally a settings
169
- dependency when it reads the migration file.
170
- """
171
-
172
- def __new__(cls, value: tuple[str, str], setting: str) -> SettingsTuple:
173
- self = tuple.__new__(cls, value)
174
- self.setting = setting
175
- return self
176
-
177
-
178
- def settings_dependency(value: str) -> SettingsTuple:
179
- """Turn a setting value into a dependency."""
180
- return SettingsTuple((value.split(".", 1)[0], "__first__"), value)
@@ -33,7 +33,7 @@ class MigrationRecorder:
33
33
 
34
34
  _migration_class: type[postgres.Model] | None = None
35
35
 
36
- @classproperty # type: ignore[invalid-argument-type]
36
+ @classproperty # ty: ignore[invalid-argument-type]
37
37
  def Migration(cls) -> type[postgres.Model]:
38
38
  """
39
39
  Lazy load to avoid PackageRegistryNotReady if installed packages import
@@ -19,7 +19,6 @@ from plain.postgres.enums import Choices
19
19
  from plain.postgres.fields import Field
20
20
  from plain.postgres.migrations.operations.base import Operation
21
21
  from plain.postgres.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
22
- from plain.runtime import SettingsReference
23
22
  from plain.utils.functional import LazyObject, Promise
24
23
 
25
24
 
@@ -277,13 +276,6 @@ class SetSerializer(BaseSequenceSerializer):
277
276
  return "{%s}" if self.value else "set(%s)"
278
277
 
279
278
 
280
- class SettingsReferenceSerializer(BaseSerializer):
281
- def serialize(self) -> tuple[str, set[str]]:
282
- return f"settings.{self.value.setting_name}", {
283
- "from plain.runtime import settings"
284
- }
285
-
286
-
287
279
  class TupleSerializer(BaseSequenceSerializer):
288
280
  def _format(self) -> str:
289
281
  # When len(value)==0, the empty tuple should be serialized as "()",
@@ -326,7 +318,6 @@ class Serializer:
326
318
  enum.Enum: EnumSerializer,
327
319
  datetime.datetime: DatetimeDatetimeSerializer,
328
320
  (datetime.date, datetime.timedelta, datetime.time): DateTimeSerializer,
329
- SettingsReference: SettingsReferenceSerializer,
330
321
  float: FloatSerializer,
331
322
  (bool, int, types.NoneType, bytes, str, range): BaseSimpleSerializer,
332
323
  decimal.Decimal: DecimalSerializer,
@@ -349,7 +340,7 @@ class Serializer:
349
340
  raise ValueError(
350
341
  f"'{serializer.__name__}' must inherit from 'BaseSerializer'."
351
342
  )
352
- cls._registry[type_] = serializer # type: ignore[assignment]
343
+ cls._registry[type_] = serializer # ty: ignore[invalid-assignment]
353
344
 
354
345
 
355
346
  def serializer_factory(value: Any) -> BaseSerializer:
@@ -170,12 +170,12 @@ class ProjectState:
170
170
  if reference.to:
171
171
  changed_field = field.clone()
172
172
  assert changed_field.remote_field is not None
173
- changed_field.remote_field.model = new_remote_model # type: ignore[assignment]
173
+ changed_field.remote_field.model = new_remote_model # ty: ignore[invalid-assignment]
174
174
  if reference.through:
175
175
  if changed_field is None:
176
176
  changed_field = field.clone()
177
177
  assert changed_field.remote_field is not None
178
- changed_field.remote_field.through = new_remote_model # type: ignore[attr-defined]
178
+ changed_field.remote_field.through = new_remote_model # ty: ignore[unresolved-attribute]
179
179
  if changed_field:
180
180
  model_state.fields[name] = changed_field
181
181
  to_reload.add((model_state.package_label, model_state.name_lower))