plain.models 0.49.2__py3-none-any.whl → 0.51.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.
- plain/models/CHANGELOG.md +27 -0
- plain/models/README.md +26 -42
- plain/models/__init__.py +2 -0
- plain/models/aggregates.py +42 -19
- plain/models/backends/base/base.py +125 -105
- plain/models/backends/base/client.py +11 -3
- plain/models/backends/base/creation.py +24 -14
- plain/models/backends/base/features.py +10 -4
- plain/models/backends/base/introspection.py +37 -20
- plain/models/backends/base/operations.py +187 -91
- plain/models/backends/base/schema.py +338 -218
- plain/models/backends/base/validation.py +13 -4
- plain/models/backends/ddl_references.py +85 -43
- plain/models/backends/mysql/base.py +29 -26
- plain/models/backends/mysql/client.py +7 -2
- plain/models/backends/mysql/compiler.py +13 -4
- plain/models/backends/mysql/creation.py +5 -2
- plain/models/backends/mysql/features.py +24 -22
- plain/models/backends/mysql/introspection.py +22 -13
- plain/models/backends/mysql/operations.py +107 -40
- plain/models/backends/mysql/schema.py +52 -28
- plain/models/backends/mysql/validation.py +13 -6
- plain/models/backends/postgresql/base.py +41 -34
- plain/models/backends/postgresql/client.py +7 -2
- plain/models/backends/postgresql/creation.py +10 -5
- plain/models/backends/postgresql/introspection.py +15 -8
- plain/models/backends/postgresql/operations.py +110 -43
- plain/models/backends/postgresql/schema.py +88 -49
- plain/models/backends/sqlite3/_functions.py +151 -115
- plain/models/backends/sqlite3/base.py +37 -23
- plain/models/backends/sqlite3/client.py +7 -1
- plain/models/backends/sqlite3/creation.py +9 -5
- plain/models/backends/sqlite3/features.py +5 -3
- plain/models/backends/sqlite3/introspection.py +32 -16
- plain/models/backends/sqlite3/operations.py +126 -43
- plain/models/backends/sqlite3/schema.py +127 -92
- plain/models/backends/utils.py +52 -29
- plain/models/backups/cli.py +8 -6
- plain/models/backups/clients.py +16 -7
- plain/models/backups/core.py +24 -13
- plain/models/base.py +221 -229
- plain/models/cli.py +98 -67
- plain/models/config.py +1 -1
- plain/models/connections.py +23 -7
- plain/models/constraints.py +79 -56
- plain/models/database_url.py +1 -1
- plain/models/db.py +6 -2
- plain/models/deletion.py +80 -56
- plain/models/entrypoints.py +1 -1
- plain/models/enums.py +22 -11
- plain/models/exceptions.py +23 -8
- plain/models/expressions.py +441 -258
- plain/models/fields/__init__.py +272 -217
- plain/models/fields/json.py +123 -57
- plain/models/fields/mixins.py +12 -8
- plain/models/fields/related.py +324 -290
- plain/models/fields/related_descriptors.py +33 -24
- plain/models/fields/related_lookups.py +24 -12
- plain/models/fields/related_managers.py +102 -79
- plain/models/fields/reverse_related.py +66 -63
- plain/models/forms.py +101 -75
- plain/models/functions/comparison.py +71 -18
- plain/models/functions/datetime.py +79 -29
- plain/models/functions/math.py +43 -10
- plain/models/functions/mixins.py +24 -7
- plain/models/functions/text.py +104 -25
- plain/models/functions/window.py +12 -6
- plain/models/indexes.py +57 -32
- plain/models/lookups.py +228 -153
- plain/models/meta.py +505 -0
- plain/models/migrations/autodetector.py +86 -43
- plain/models/migrations/exceptions.py +7 -3
- plain/models/migrations/executor.py +33 -7
- plain/models/migrations/graph.py +79 -50
- plain/models/migrations/loader.py +45 -22
- plain/models/migrations/migration.py +23 -18
- plain/models/migrations/operations/base.py +38 -20
- plain/models/migrations/operations/fields.py +95 -48
- plain/models/migrations/operations/models.py +246 -142
- plain/models/migrations/operations/special.py +82 -25
- plain/models/migrations/optimizer.py +7 -2
- plain/models/migrations/questioner.py +58 -31
- plain/models/migrations/recorder.py +27 -16
- plain/models/migrations/serializer.py +50 -39
- plain/models/migrations/state.py +232 -156
- plain/models/migrations/utils.py +30 -14
- plain/models/migrations/writer.py +17 -14
- plain/models/options.py +189 -518
- plain/models/otel.py +16 -6
- plain/models/preflight.py +42 -17
- plain/models/query.py +400 -251
- plain/models/query_utils.py +109 -69
- plain/models/registry.py +40 -21
- plain/models/sql/compiler.py +190 -127
- plain/models/sql/datastructures.py +38 -25
- plain/models/sql/query.py +320 -225
- plain/models/sql/subqueries.py +36 -25
- plain/models/sql/where.py +54 -29
- plain/models/test/pytest.py +15 -11
- plain/models/test/utils.py +4 -2
- plain/models/transaction.py +20 -7
- plain/models/utils.py +17 -6
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/METADATA +27 -43
- plain_models-0.51.0.dist-info/RECORD +123 -0
- plain_models-0.49.2.dist-info/RECORD +0 -122
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/WHEEL +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/licenses/LICENSE +0 -0
plain/models/otel.py
CHANGED
@@ -1,10 +1,18 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import re
|
2
4
|
import traceback
|
5
|
+
from collections.abc import Generator
|
3
6
|
from contextlib import contextmanager
|
4
|
-
from typing import Any
|
7
|
+
from typing import TYPE_CHECKING, Any
|
5
8
|
|
6
9
|
from opentelemetry import context as otel_context
|
7
10
|
from opentelemetry import trace
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from opentelemetry.trace import Span
|
14
|
+
|
15
|
+
from plain.models.backends.base.base import BaseDatabaseWrapper
|
8
16
|
from opentelemetry.semconv._incubating.attributes.db_attributes import (
|
9
17
|
DB_QUERY_PARAMETER_TEMPLATE,
|
10
18
|
DB_USER,
|
@@ -99,7 +107,9 @@ def _clean_identifier(identifier: str) -> str:
|
|
99
107
|
|
100
108
|
|
101
109
|
@contextmanager
|
102
|
-
def db_span(
|
110
|
+
def db_span(
|
111
|
+
db: BaseDatabaseWrapper, sql: Any, *, many: bool = False, params: Any = None
|
112
|
+
) -> Generator[Span | None, None, None]:
|
103
113
|
"""Open an OpenTelemetry CLIENT span for a database query.
|
104
114
|
|
105
115
|
All common attributes (`db.*`, `network.*`, etc.) are set automatically.
|
@@ -107,7 +117,7 @@ def db_span(db, sql: Any, *, many: bool = False, params=None):
|
|
107
117
|
"""
|
108
118
|
|
109
119
|
# Fast-exit if instrumentation suppression flag set in context.
|
110
|
-
if otel_context.get_value(_SUPPRESS_KEY):
|
120
|
+
if otel_context.get_value(_SUPPRESS_KEY): # type: ignore[arg-type]
|
111
121
|
yield None
|
112
122
|
return
|
113
123
|
|
@@ -177,15 +187,15 @@ def db_span(db, sql: Any, *, many: bool = False, params=None):
|
|
177
187
|
|
178
188
|
|
179
189
|
@contextmanager
|
180
|
-
def suppress_db_tracing():
|
181
|
-
token = otel_context.attach(otel_context.set_value(_SUPPRESS_KEY, True))
|
190
|
+
def suppress_db_tracing() -> Generator[None, None, None]:
|
191
|
+
token = otel_context.attach(otel_context.set_value(_SUPPRESS_KEY, True)) # type: ignore[arg-type]
|
182
192
|
try:
|
183
193
|
yield
|
184
194
|
finally:
|
185
195
|
otel_context.detach(token)
|
186
196
|
|
187
197
|
|
188
|
-
def _get_code_attributes():
|
198
|
+
def _get_code_attributes() -> dict[str, Any]:
|
189
199
|
"""Extract code context attributes for the current database query.
|
190
200
|
|
191
201
|
Returns a dict of OpenTelemetry code attributes.
|
plain/models/preflight.py
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import inspect
|
2
4
|
from collections import defaultdict
|
5
|
+
from collections.abc import Callable
|
6
|
+
from typing import Any
|
3
7
|
|
4
8
|
from plain.models.db import db_connection
|
5
|
-
from plain.models.registry import models_registry
|
9
|
+
from plain.models.registry import ModelsRegistry, models_registry
|
6
10
|
from plain.packages import packages_registry
|
7
11
|
from plain.preflight import PreflightCheck, PreflightResult, register_check
|
8
12
|
|
@@ -11,7 +15,7 @@ from plain.preflight import PreflightCheck, PreflightResult, register_check
|
|
11
15
|
class CheckDatabaseBackends(PreflightCheck):
|
12
16
|
"""Validates database backend configuration when plain.models is available."""
|
13
17
|
|
14
|
-
def run(self):
|
18
|
+
def run(self) -> list[PreflightResult]:
|
15
19
|
return db_connection.validation.preflight()
|
16
20
|
|
17
21
|
|
@@ -19,14 +23,16 @@ class CheckDatabaseBackends(PreflightCheck):
|
|
19
23
|
class CheckAllModels(PreflightCheck):
|
20
24
|
"""Validates all model definitions for common issues."""
|
21
25
|
|
22
|
-
def run(self):
|
26
|
+
def run(self) -> list[PreflightResult]:
|
23
27
|
db_table_models = defaultdict(list)
|
24
28
|
indexes = defaultdict(list)
|
25
29
|
constraints = defaultdict(list)
|
26
30
|
errors = []
|
27
31
|
models = models_registry.get_models()
|
28
32
|
for model in models:
|
29
|
-
db_table_models[model.
|
33
|
+
db_table_models[model.model_options.db_table].append(
|
34
|
+
model.model_options.label
|
35
|
+
)
|
30
36
|
if not inspect.ismethod(model.preflight):
|
31
37
|
errors.append(
|
32
38
|
PreflightResult(
|
@@ -37,10 +43,10 @@ class CheckAllModels(PreflightCheck):
|
|
37
43
|
)
|
38
44
|
else:
|
39
45
|
errors.extend(model.preflight())
|
40
|
-
for model_index in model.
|
41
|
-
indexes[model_index.name].append(model.
|
42
|
-
for model_constraint in model.
|
43
|
-
constraints[model_constraint.name].append(model.
|
46
|
+
for model_index in model.model_options.indexes:
|
47
|
+
indexes[model_index.name].append(model.model_options.label)
|
48
|
+
for model_constraint in model.model_options.constraints:
|
49
|
+
constraints[model_constraint.name].append(model.model_options.label)
|
44
50
|
for db_table, model_labels in db_table_models.items():
|
45
51
|
if len(model_labels) != 1:
|
46
52
|
model_labels_str = ", ".join(model_labels)
|
@@ -84,7 +90,9 @@ class CheckAllModels(PreflightCheck):
|
|
84
90
|
return errors
|
85
91
|
|
86
92
|
|
87
|
-
def _check_lazy_references(
|
93
|
+
def _check_lazy_references(
|
94
|
+
models_registry: ModelsRegistry, packages_registry: Any
|
95
|
+
) -> list[PreflightResult]:
|
88
96
|
"""
|
89
97
|
Ensure all lazy (i.e. string) model references have been resolved.
|
90
98
|
|
@@ -98,7 +106,9 @@ def _check_lazy_references(models_registry, packages_registry):
|
|
98
106
|
if not pending_models:
|
99
107
|
return []
|
100
108
|
|
101
|
-
def extract_operation(
|
109
|
+
def extract_operation(
|
110
|
+
obj: Any,
|
111
|
+
) -> tuple[Callable[..., Any], list[Any], dict[str, Any]]:
|
102
112
|
"""
|
103
113
|
Take a callable found in Packages._pending_operations and identify the
|
104
114
|
original callable passed to Packages.lazy_model_operation(). If that
|
@@ -115,7 +125,7 @@ def _check_lazy_references(models_registry, packages_registry):
|
|
115
125
|
operation = operation.func
|
116
126
|
return operation, args, keywords
|
117
127
|
|
118
|
-
def app_model_error(model_key):
|
128
|
+
def app_model_error(model_key: tuple[str, str]) -> str:
|
119
129
|
try:
|
120
130
|
packages_registry.get_package_config(model_key[0])
|
121
131
|
model_error = "app '{}' doesn't provide model '{}'".format(*model_key)
|
@@ -129,7 +139,12 @@ def _check_lazy_references(models_registry, packages_registry):
|
|
129
139
|
# pair, the original lazy function, and its positional and keyword args as
|
130
140
|
# determined by extract_operation().
|
131
141
|
|
132
|
-
def field_error(
|
142
|
+
def field_error(
|
143
|
+
model_key: tuple[str, str],
|
144
|
+
func: Callable[..., Any],
|
145
|
+
args: list[Any],
|
146
|
+
keywords: dict[str, Any],
|
147
|
+
) -> PreflightResult:
|
133
148
|
error_msg = (
|
134
149
|
"The field %(field)s was declared with a lazy reference "
|
135
150
|
"to '%(model)s', but %(model_error)s."
|
@@ -145,7 +160,12 @@ def _check_lazy_references(models_registry, packages_registry):
|
|
145
160
|
id="fields.lazy_reference_not_resolvable",
|
146
161
|
)
|
147
162
|
|
148
|
-
def default_error(
|
163
|
+
def default_error(
|
164
|
+
model_key: tuple[str, str],
|
165
|
+
func: Callable[..., Any],
|
166
|
+
args: list[Any],
|
167
|
+
keywords: dict[str, Any],
|
168
|
+
) -> PreflightResult:
|
149
169
|
error_msg = (
|
150
170
|
"%(op)s contains a lazy reference to %(model)s, but %(model_error)s."
|
151
171
|
)
|
@@ -167,8 +187,13 @@ def _check_lazy_references(models_registry, packages_registry):
|
|
167
187
|
("plain.models.fields.related", "resolve_related_class"): field_error,
|
168
188
|
}
|
169
189
|
|
170
|
-
def build_error(
|
171
|
-
|
190
|
+
def build_error(
|
191
|
+
model_key: tuple[str, str],
|
192
|
+
func: Callable[..., Any],
|
193
|
+
args: list[Any],
|
194
|
+
keywords: dict[str, Any],
|
195
|
+
) -> PreflightResult | None:
|
196
|
+
key = (func.__module__, func.__name__) # type: ignore[attr-defined]
|
172
197
|
error_fn = known_lazy.get(key, default_error)
|
173
198
|
return error_fn(model_key, func, args, keywords) if error_fn else None
|
174
199
|
|
@@ -189,7 +214,7 @@ def _check_lazy_references(models_registry, packages_registry):
|
|
189
214
|
class CheckLazyReferences(PreflightCheck):
|
190
215
|
"""Ensures all lazy (string) model references have been resolved."""
|
191
216
|
|
192
|
-
def run(self):
|
217
|
+
def run(self) -> list[PreflightResult]:
|
193
218
|
return _check_lazy_references(models_registry, packages_registry)
|
194
219
|
|
195
220
|
|
@@ -197,7 +222,7 @@ class CheckLazyReferences(PreflightCheck):
|
|
197
222
|
class CheckDatabaseTables(PreflightCheck):
|
198
223
|
"""Checks for unknown tables in the database when plain.models is available."""
|
199
224
|
|
200
|
-
def run(self):
|
225
|
+
def run(self) -> list[PreflightResult]:
|
201
226
|
errors = []
|
202
227
|
|
203
228
|
db_tables = db_connection.introspection.table_names()
|