plain.models 0.34.4__py3-none-any.whl → 0.35.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # plain-models changelog
2
2
 
3
+ ## [0.35.0](https://github.com/dropseed/plain/releases/plain-models@0.35.0) (2025-07-07)
4
+
5
+ ### What's changed
6
+
7
+ - Added the `plain models list` CLI command which prints a nicely formatted list of all installed models, including their table name, fields, and originating package. You can pass package labels to filter the output or use the `--app-only` flag to only show first-party app models ([1bc40ce](https://github.com/dropseed/plain/commit/1bc40ce)).
8
+ - The MySQL backend no longer enforces a strict `mysqlclient >= 1.4.3` version check and had several unused constraint-handling methods removed, reducing boilerplate and improving compatibility with a wider range of `mysqlclient` versions ([6322400](https://github.com/dropseed/plain/commit/6322400), [67f21f6](https://github.com/dropseed/plain/commit/67f21f6)).
9
+
10
+ ### Upgrade instructions
11
+
12
+ - No changes required
13
+
3
14
  ## [0.34.4](https://github.com/dropseed/plain/releases/plain-models@0.34.4) (2025-07-02)
4
15
 
5
16
  ### What's changed
@@ -6,23 +6,16 @@ Requires mysqlclient: https://pypi.org/project/mysqlclient/
6
6
 
7
7
  from functools import cached_property
8
8
 
9
+ import MySQLdb as Database
10
+ from MySQLdb.constants import CLIENT, FIELD_TYPE
11
+ from MySQLdb.converters import conversions
12
+
9
13
  from plain.exceptions import ImproperlyConfigured
10
14
  from plain.models.backends import utils as backend_utils
11
15
  from plain.models.backends.base.base import BaseDatabaseWrapper
12
16
  from plain.models.db import IntegrityError
13
17
  from plain.utils.regex_helper import _lazy_re_compile
14
18
 
15
- try:
16
- import MySQLdb as Database
17
- except ImportError as err:
18
- raise ImproperlyConfigured(
19
- "Error loading MySQLdb module.\nDid you install mysqlclient?"
20
- ) from err
21
-
22
- from MySQLdb.constants import CLIENT, FIELD_TYPE
23
- from MySQLdb.converters import conversions
24
-
25
- # Some of these import MySQLdb, so import them after checking if it's installed.
26
19
  from .client import DatabaseClient
27
20
  from .creation import DatabaseCreation
28
21
  from .features import DatabaseFeatures
@@ -31,13 +24,6 @@ from .operations import DatabaseOperations
31
24
  from .schema import DatabaseSchemaEditor
32
25
  from .validation import DatabaseValidation
33
26
 
34
- version = Database.version_info
35
- if version < (1, 4, 3):
36
- raise ImproperlyConfigured(
37
- f"mysqlclient 1.4.3 or newer is required; you have {Database.__version__}."
38
- )
39
-
40
-
41
27
  # MySQLdb returns TIME columns as timedelta -- they are more like timedelta in
42
28
  # terms of actual behavior as they are signed and include days -- and Plain
43
29
  # expects time.
@@ -281,37 +267,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
281
267
  with self.wrap_database_errors:
282
268
  self.connection.autocommit(autocommit)
283
269
 
284
- def disable_constraint_checking(self):
285
- """
286
- Disable foreign key checks, primarily for use in adding rows with
287
- forward references. Always return True to indicate constraint checks
288
- need to be re-enabled.
289
- """
290
- with self.cursor() as cursor:
291
- cursor.execute("SET foreign_key_checks=0")
292
- return True
293
-
294
- def enable_constraint_checking(self):
295
- """
296
- Re-enable foreign key checks after they have been disabled.
297
- """
298
- # Override needs_rollback in case constraint_checks_disabled is
299
- # nested inside transaction.atomic.
300
- self.needs_rollback, needs_rollback = False, self.needs_rollback
301
- try:
302
- with self.cursor() as cursor:
303
- cursor.execute("SET foreign_key_checks=1")
304
- finally:
305
- self.needs_rollback = needs_rollback
306
-
307
270
  def check_constraints(self, table_names=None):
308
- """
309
- Check each table name in `table_names` for rows with invalid foreign
310
- key references. This method is intended to be used in conjunction with
311
- `disable_constraint_checking()` and `enable_constraint_checking()`, to
312
- determine if rows with invalid references were entered while constraint
313
- checks were off.
314
- """
271
+ """Check ``table_names`` for rows with invalid foreign key references."""
315
272
  with self.cursor() as cursor:
316
273
  if table_names is None:
317
274
  table_names = self.introspection.table_names(cursor)
@@ -1,6 +1,8 @@
1
1
  from plain.models.backends.base.schema import BaseDatabaseSchemaEditor
2
2
  from plain.models.constants import LOOKUP_SEP
3
- from plain.models.fields import NOT_PROVIDED, F, UniqueConstraint
3
+ from plain.models.constraints import UniqueConstraint
4
+ from plain.models.expressions import F
5
+ from plain.models.fields import NOT_PROVIDED
4
6
 
5
7
 
6
8
  class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
plain/models/cli.py CHANGED
@@ -96,6 +96,37 @@ def db_wait():
96
96
  break
97
97
 
98
98
 
99
+ @cli.command(name="list")
100
+ @click.argument("package_labels", nargs=-1)
101
+ @click.option(
102
+ "--app-only",
103
+ is_flag=True,
104
+ help="Only show models from packages that start with 'app'.",
105
+ )
106
+ def list_models(package_labels, app_only):
107
+ """List installed models."""
108
+
109
+ packages = set(package_labels)
110
+
111
+ for model in sorted(
112
+ models_registry.get_models(),
113
+ key=lambda m: (m._meta.package_label, m._meta.model_name),
114
+ ):
115
+ pkg = model._meta.package_label
116
+ pkg_name = packages_registry.get_package_config(pkg).name
117
+ if app_only and not pkg_name.startswith("app"):
118
+ continue
119
+ if packages and pkg not in packages:
120
+ continue
121
+ fields = ", ".join(f.name for f in model._meta.get_fields())
122
+ click.echo(
123
+ f"{click.style(pkg, fg='cyan')}.{click.style(model.__name__, fg='blue')}"
124
+ )
125
+ click.echo(f" table: {model._meta.db_table}")
126
+ click.echo(f" fields: {fields}")
127
+ click.echo(f" package: {pkg_name}\n")
128
+
129
+
99
130
  @register_cli("makemigrations")
100
131
  @cli.command()
101
132
  @click.argument("package_labels", nargs=-1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.models
3
- Version: 0.34.4
3
+ Version: 0.35.0
4
4
  Summary: Database models for Plain.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -1,9 +1,9 @@
1
- plain/models/CHANGELOG.md,sha256=23hduuGGlZJVuZaW57q7mDNH3eJme2JBkyqooogAQVk,3260
1
+ plain/models/CHANGELOG.md,sha256=bUinpgx_HxNjgItauzHyszRtwU7F3Zm33u0mMAZBoDs,4127
2
2
  plain/models/README.md,sha256=vsZPev3Fna-Irdcs3-wrOcAoII5LOhXdcWLBMT87CS0,1626
3
3
  plain/models/__init__.py,sha256=dnU6MOXs3lGoK31nLWjCqbf7zigkaUccomchz9lNDJ8,2950
4
4
  plain/models/aggregates.py,sha256=P0mhsMl1VZt2CVHMuCHnNI8SxZ9citjDLEgioN6NOpo,7240
5
5
  plain/models/base.py,sha256=8-F9DvSF5s2_zoGyEmZU5xg9GdEigthVT0HENv9iigI,67952
6
- plain/models/cli.py,sha256=-K5ZrMbwL-fcUOze64_U4uOPpCuppa-ibdoOaCFvBF4,43966
6
+ plain/models/cli.py,sha256=4iZRHRPXxUCrsW-SzeimIE_lrSkWkLhgYOSk4BxUF_8,44985
7
7
  plain/models/config.py,sha256=OF7eIEtXNZyGwgc3eMEpb5uEAup5RXeT-0um60dfBeU,636
8
8
  plain/models/connections.py,sha256=RBNa2FZ0x3C9un6PaYL-IYzH_OesRSpdHNGKvYHGiOM,2276
9
9
  plain/models/constants.py,sha256=ndnj9TOTKW0p4YcIPLOLEbsH6mOgFi6B1-rIzr_iwwU,210
@@ -40,14 +40,14 @@ plain/models/backends/base/operations.py,sha256=Y08cS7IZwYXMKVUoEpBCjyOTh1PW2OSh
40
40
  plain/models/backends/base/schema.py,sha256=1dLiVNz1huv8xJo1JphgfWfhXXZ-YGw_MgZ6eWazKQA,65016
41
41
  plain/models/backends/base/validation.py,sha256=2zpI11hyUJr0I0cA1xmvoFwQVdZ-7_1T2F11TpQ0Rkk,1067
42
42
  plain/models/backends/mysql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
- plain/models/backends/mysql/base.py,sha256=9PEaRvRcU9MBfir-s_rNooemDmjQQpfzB1DxJJdmC14,15985
43
+ plain/models/backends/mysql/base.py,sha256=BfFi7QipjpW38LJquRINdUnm6cIBKEDVgiApMuWo1OQ,14421
44
44
  plain/models/backends/mysql/client.py,sha256=YGjk4f5VOuIKcj5SOOJeBqiSDF0Ft9m1aUPOmLzdD6c,2973
45
45
  plain/models/backends/mysql/compiler.py,sha256=NaYgcGyFUZ2lTOXXJj87hLMMMnXRAS1jUYkJq1NoCv4,3289
46
46
  plain/models/backends/mysql/creation.py,sha256=ozuc3mz65bjFz6sn5BFLRRGQsUYaxwIGjQyKod31c1Y,952
47
47
  plain/models/backends/mysql/features.py,sha256=OPHaiqPmAFAUZqnZdLOqbCmxmuGMnIqa62fJqAkYQ0o,5875
48
48
  plain/models/backends/mysql/introspection.py,sha256=nKhuFDi8xxj0DZH8_45F-XOARiHxWBoW21_2lTFARUc,14131
49
49
  plain/models/backends/mysql/operations.py,sha256=zLtg50k7WzqO3eZjLAknhKg29bxm0-ysd1_NydlDlzQ,16665
50
- plain/models/backends/mysql/schema.py,sha256=W6sV2DLdGAeM7ZX80m1XCRtV95DDhyochy8oJ18bet8,9870
50
+ plain/models/backends/mysql/schema.py,sha256=LmP62COVuhpbH4gYulcSQNJgGuolc3RTFGsudoohJOQ,9942
51
51
  plain/models/backends/mysql/validation.py,sha256=TFYpuRoy3yG3SGfMFtRewaWq5gISN6FBaq-AD0DY7SI,1946
52
52
  plain/models/backends/postgresql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  plain/models/backends/postgresql/base.py,sha256=SE6wmmxOtCnMDwycUs9yn_WATl97eV-4t8AaiK41E20,16053
@@ -113,8 +113,8 @@ plain/models/sql/where.py,sha256=ezE9Clt2BmKo-I7ARsgqZ_aVA-1UdayCwr6ULSWZL6c,126
113
113
  plain/models/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  plain/models/test/pytest.py,sha256=5mxY1MHqfCFJ7G39W1DuE0vCHfsfehQQmOyE6vI6caw,3323
115
115
  plain/models/test/utils.py,sha256=MxBNWoGMtwAtka7LbxWgilgzv7T5qqJL8ystF2SDJrs,345
116
- plain_models-0.34.4.dist-info/METADATA,sha256=lIwA7kJww6io4OCqeWiM0THgYzG7Qf-7hlDtl6IainA,1921
117
- plain_models-0.34.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
118
- plain_models-0.34.4.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
119
- plain_models-0.34.4.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
120
- plain_models-0.34.4.dist-info/RECORD,,
116
+ plain_models-0.35.0.dist-info/METADATA,sha256=v8A_EGrAuBGpAa_7thYuC1eim5Alt7jdfLskHWfUerg,1921
117
+ plain_models-0.35.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
118
+ plain_models-0.35.0.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
119
+ plain_models-0.35.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
120
+ plain_models-0.35.0.dist-info/RECORD,,