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/migrations/utils.py
CHANGED
@@ -1,30 +1,39 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import datetime
|
2
4
|
import re
|
3
5
|
from collections import namedtuple
|
6
|
+
from collections.abc import Generator
|
7
|
+
from typing import TYPE_CHECKING, Any
|
4
8
|
|
5
9
|
from plain.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
|
6
10
|
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from plain.models.fields import Field
|
13
|
+
|
7
14
|
FieldReference = namedtuple("FieldReference", "to through")
|
8
15
|
|
9
16
|
COMPILED_REGEX_TYPE = type(re.compile(""))
|
10
17
|
|
11
18
|
|
12
19
|
class RegexObject:
|
13
|
-
def __init__(self, obj):
|
20
|
+
def __init__(self, obj: Any) -> None:
|
14
21
|
self.pattern = obj.pattern
|
15
22
|
self.flags = obj.flags
|
16
23
|
|
17
|
-
def __eq__(self, other):
|
24
|
+
def __eq__(self, other: Any) -> bool:
|
18
25
|
if not isinstance(other, RegexObject):
|
19
26
|
return NotImplemented
|
20
27
|
return self.pattern == other.pattern and self.flags == other.flags
|
21
28
|
|
22
29
|
|
23
|
-
def get_migration_name_timestamp():
|
30
|
+
def get_migration_name_timestamp() -> str:
|
24
31
|
return datetime.datetime.now().strftime("%Y%m%d_%H%M")
|
25
32
|
|
26
33
|
|
27
|
-
def resolve_relation(
|
34
|
+
def resolve_relation(
|
35
|
+
model: str | Any, package_label: str | None = None, model_name: str | None = None
|
36
|
+
) -> tuple[str, str]:
|
28
37
|
"""
|
29
38
|
Turn a model class or model reference string and return a model tuple.
|
30
39
|
|
@@ -47,16 +56,16 @@ def resolve_relation(model, package_label=None, model_name=None):
|
|
47
56
|
"package_label must be provided to resolve unscoped model relationships."
|
48
57
|
)
|
49
58
|
return package_label, model.lower()
|
50
|
-
return model.
|
59
|
+
return model.model_options.package_label, model.model_options.model_name
|
51
60
|
|
52
61
|
|
53
62
|
def field_references(
|
54
|
-
model_tuple,
|
55
|
-
field,
|
56
|
-
reference_model_tuple,
|
57
|
-
reference_field_name=None,
|
58
|
-
reference_field=None,
|
59
|
-
):
|
63
|
+
model_tuple: tuple[str, str],
|
64
|
+
field: Field,
|
65
|
+
reference_model_tuple: tuple[str, str],
|
66
|
+
reference_field_name: str | None = None,
|
67
|
+
reference_field: Field | None = None,
|
68
|
+
) -> FieldReference | bool:
|
60
69
|
"""
|
61
70
|
Return either False or a FieldReference if `field` references provided
|
62
71
|
context.
|
@@ -97,7 +106,9 @@ def field_references(
|
|
97
106
|
return FieldReference(references_to, references_through)
|
98
107
|
|
99
108
|
|
100
|
-
def get_references(
|
109
|
+
def get_references(
|
110
|
+
state: Any, model_tuple: tuple[str, str], field_tuple: tuple[Any, ...] = ()
|
111
|
+
) -> Generator[tuple[Any, str, Field, FieldReference], None, None]:
|
101
112
|
"""
|
102
113
|
Generator of (model_state, name, field, reference) referencing
|
103
114
|
provided context.
|
@@ -108,12 +119,17 @@ def get_references(state, model_tuple, field_tuple=()):
|
|
108
119
|
for state_model_tuple, model_state in state.models.items():
|
109
120
|
for name, field in model_state.fields.items():
|
110
121
|
reference = field_references(
|
111
|
-
state_model_tuple,
|
122
|
+
state_model_tuple,
|
123
|
+
field,
|
124
|
+
model_tuple,
|
125
|
+
*field_tuple, # type: ignore[arg-type]
|
112
126
|
)
|
113
127
|
if reference:
|
114
128
|
yield model_state, name, field, reference
|
115
129
|
|
116
130
|
|
117
|
-
def field_is_referenced(
|
131
|
+
def field_is_referenced(
|
132
|
+
state: Any, model_tuple: tuple[str, str], field_tuple: tuple[Any, ...]
|
133
|
+
) -> bool:
|
118
134
|
"""Return whether `field_tuple` is referenced by any state models."""
|
119
135
|
return next(get_references(state, model_tuple, field_tuple), None) is not None
|
@@ -1,6 +1,9 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
4
|
import re
|
3
5
|
from importlib import import_module
|
6
|
+
from typing import Any
|
4
7
|
|
5
8
|
from plain.models import migrations
|
6
9
|
from plain.models.migrations.loader import MigrationLoader
|
@@ -14,13 +17,13 @@ from plain.utils.timezone import now
|
|
14
17
|
|
15
18
|
|
16
19
|
class OperationWriter:
|
17
|
-
def __init__(self, operation, indentation=2):
|
20
|
+
def __init__(self, operation: Any, indentation: int = 2) -> None:
|
18
21
|
self.operation = operation
|
19
|
-
self.buff = []
|
22
|
+
self.buff: list[str] = []
|
20
23
|
self.indentation = indentation
|
21
24
|
|
22
|
-
def serialize(self):
|
23
|
-
def _write(_arg_name, _arg_value):
|
25
|
+
def serialize(self) -> tuple[str, set[str]]:
|
26
|
+
def _write(_arg_name: str, _arg_value: Any) -> None:
|
24
27
|
if _arg_name in self.operation.serialization_expand_args and isinstance(
|
25
28
|
_arg_value, list | tuple | dict
|
26
29
|
):
|
@@ -100,16 +103,16 @@ class OperationWriter:
|
|
100
103
|
self.feed("),")
|
101
104
|
return self.render(), imports
|
102
105
|
|
103
|
-
def indent(self):
|
106
|
+
def indent(self) -> None:
|
104
107
|
self.indentation += 1
|
105
108
|
|
106
|
-
def unindent(self):
|
109
|
+
def unindent(self) -> None:
|
107
110
|
self.indentation -= 1
|
108
111
|
|
109
|
-
def feed(self, line):
|
112
|
+
def feed(self, line: str) -> None:
|
110
113
|
self.buff.append(" " * (self.indentation * 4) + line)
|
111
114
|
|
112
|
-
def render(self):
|
115
|
+
def render(self) -> str:
|
113
116
|
return "\n".join(self.buff)
|
114
117
|
|
115
118
|
|
@@ -119,12 +122,12 @@ class MigrationWriter:
|
|
119
122
|
of the migration file from it.
|
120
123
|
"""
|
121
124
|
|
122
|
-
def __init__(self, migration, include_header=True):
|
125
|
+
def __init__(self, migration: Any, include_header: bool = True) -> None:
|
123
126
|
self.migration = migration
|
124
127
|
self.include_header = include_header
|
125
128
|
self.needs_manual_porting = False
|
126
129
|
|
127
|
-
def as_string(self):
|
130
|
+
def as_string(self) -> str:
|
128
131
|
"""Return a string of the file contents."""
|
129
132
|
items = {
|
130
133
|
"replaces_str": "",
|
@@ -198,7 +201,7 @@ class MigrationWriter:
|
|
198
201
|
return MIGRATION_TEMPLATE % items
|
199
202
|
|
200
203
|
@property
|
201
|
-
def basedir(self):
|
204
|
+
def basedir(self) -> str:
|
202
205
|
migrations_package_name, _ = MigrationLoader.migrations_module(
|
203
206
|
self.migration.package_label
|
204
207
|
)
|
@@ -266,15 +269,15 @@ class MigrationWriter:
|
|
266
269
|
return final_dir
|
267
270
|
|
268
271
|
@property
|
269
|
-
def filename(self):
|
272
|
+
def filename(self) -> str:
|
270
273
|
return f"{self.migration.name}.py"
|
271
274
|
|
272
275
|
@property
|
273
|
-
def path(self):
|
276
|
+
def path(self) -> str:
|
274
277
|
return os.path.join(self.basedir, self.filename)
|
275
278
|
|
276
279
|
@classmethod
|
277
|
-
def serialize(cls, value):
|
280
|
+
def serialize(cls, value: Any) -> tuple[str, set[str]]:
|
278
281
|
return serializer_factory(value).serialize()
|
279
282
|
|
280
283
|
|