]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
allow any key for naming_convention dict, typing is not possible
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 12 Sep 2023 12:01:54 +0000 (08:01 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 12 Sep 2023 16:50:19 +0000 (12:50 -0400)
Fixed regression introduced in 2.0.20 via :ticket:`9600` fix which
attempted to add more formal typing to
:paramref:`_schema.MetaData.naming_convention`. This change prevented basic
naming convention dictionaries from passing typing and has been adjusted so
that a plain dictionary of strings for keys as well as dictionaries that
use constraint types as keys or a mix of both, are again accepted.

As part of this change, lesser used forms of the naming convention
dictionary are also typed, including that it currently allows for
``Constraint`` type objects as keys as well.

Fixes: #9284
Fixes: #10264
Change-Id: Ic6561dd65058e4de3a7a393295b9863fc065db13

doc/build/changelog/unreleased_20/10264.rst [new file with mode: 0644]
lib/sqlalchemy/sql/schema.py
test/sql/test_metadata.py
test/typing/plain_files/sql/schema.py

diff --git a/doc/build/changelog/unreleased_20/10264.rst b/doc/build/changelog/unreleased_20/10264.rst
new file mode 100644 (file)
index 0000000..bdfd5b9
--- /dev/null
@@ -0,0 +1,14 @@
+.. change::
+    :tags: bug, typing
+    :tickets: 10264, 9284
+
+    Fixed regression introduced in 2.0.20 via :ticket:`9600` fix which
+    attempted to add more formal typing to
+    :paramref:`_schema.MetaData.naming_convention`. This change prevented basic
+    naming convention dictionaries from passing typing and has been adjusted so
+    that a plain dictionary of strings for keys as well as dictionaries that
+    use constraint types as keys or a mix of both, are again accepted.
+
+    As part of this change, lesser used forms of the naming convention
+    dictionary are also typed, including that it currently allows for
+    ``Constraint`` type objects as keys as well.
index 008ae2c0059b722e8dbf302e3684fa09e4cb5c24..8baf2de6a4260b161bed2572fd88ad5a1ff903ba 100644 (file)
@@ -50,7 +50,6 @@ from typing import overload
 from typing import Sequence as _typing_Sequence
 from typing import Set
 from typing import Tuple
-from typing import Type
 from typing import TYPE_CHECKING
 from typing import TypeVar
 from typing import Union
@@ -5286,30 +5285,26 @@ class Index(
         )
 
 
-_AllConstraints = Union[
-    Index,
-    UniqueConstraint,
-    CheckConstraint,
-    ForeignKeyConstraint,
-    PrimaryKeyConstraint,
-]
-
-_NamingSchemaCallable = Callable[[_AllConstraints, Table], str]
+_NamingSchemaCallable = Callable[[Constraint, Table], str]
+_NamingSchemaDirective = Union[str, _NamingSchemaCallable]
 
 
 class _NamingSchemaTD(TypedDict, total=False):
-    fk: Union[str, _NamingSchemaCallable]
-    pk: Union[str, _NamingSchemaCallable]
-    ix: Union[str, _NamingSchemaCallable]
-    ck: Union[str, _NamingSchemaCallable]
-    uq: Union[str, _NamingSchemaCallable]
+    fk: _NamingSchemaDirective
+    pk: _NamingSchemaDirective
+    ix: _NamingSchemaDirective
+    ck: _NamingSchemaDirective
+    uq: _NamingSchemaDirective
 
 
 _NamingSchemaParameter = Union[
+    # it seems like the TypedDict here is useful for pylance typeahead,
+    # and not much else
     _NamingSchemaTD,
-    Mapping[
-        Union[Type[_AllConstraints], str], Union[str, _NamingSchemaCallable]
-    ],
+    # there is no form that allows Union[Type[Any], str] to work in all
+    # cases, including breaking out Mapping[] entries for each combination
+    # even, therefore keys must be `Any` (see #10264)
+    Mapping[Any, _NamingSchemaDirective],
 ]
 
 
index dce5b9984f6715d7c9e8347a3b3871084c462d6b..659409de25f6fa26bf471ede69a4135867a567ff 100644 (file)
@@ -5447,6 +5447,15 @@ class NamingConventionTest(fixtures.TestBase, AssertsCompiledSQL):
                 "CONSTRAINT %s PRIMARY KEY (x, y))" % expected_name,
             )
 
+    def test_constraint_classes_for_keys(self):
+        u1 = self._fixture(
+            naming_convention={
+                UniqueConstraint: "uq_%(table_name)s_%(column_0_name)s"
+            }
+        )
+        uq = UniqueConstraint(u1.c.data)
+        eq_(uq.name, "uq_user_data")
+
     def test_uq_name(self):
         u1 = self._fixture(
             naming_convention={"uq": "uq_%(table_name)s_%(column_0_name)s"}
index 1e0a1345aec2ea1013b45f7fe44d3c56a69707a5..7e5f0547442866cf9370614dd0474c45a3e1d149 100644 (file)
@@ -1,5 +1,6 @@
 from typing import Union
 
+from sqlalchemy import CheckConstraint
 from sqlalchemy import Constraint
 from sqlalchemy import Index
 from sqlalchemy import MetaData
@@ -31,3 +32,37 @@ MetaData(
         "foo": lambda c, t: t.name + str(c.name),
     }
 )
+
+NAMING_CONVENTIONS_ONLY_CALLABLE = {
+    "fk_guid": fk_guid,
+    "foo": lambda c, t: t.name + str(c.name),
+}
+
+MetaData(naming_convention=NAMING_CONVENTIONS_ONLY_CALLABLE)
+
+NAMING_CONVENTIONS_TYPES_FOR_KEYS_ONLY = {
+    CheckConstraint: "%(table_name)s_%(constraint_name)s_ck",
+    Index: "%(column_0_label)s_ix",
+}
+
+MetaData(naming_convention=NAMING_CONVENTIONS_TYPES_FOR_KEYS_ONLY)
+
+NAMING_CONVENTIONS_TYPES_AND_STR_FOR_KEYS = {
+    CheckConstraint: "%(table_name)s_%(constraint_name)s_ck",
+    Index: "%(column_0_label)s_ix",
+    "custom": "custom",
+    "fk": "fk_name",
+}
+
+MetaData(naming_convention=NAMING_CONVENTIONS_TYPES_AND_STR_FOR_KEYS)
+
+
+NAMING_CONVENTIONS_STR = {
+    "ix": "%(column_0_label)s_ix",
+    "uq": "%(table_name)s_%(column_0_name)s_uq",
+    "ck": "%(table_name)s_%(constraint_name)s_ck",
+    "fk": "%(table_name)s_%(column_0_name)s_%(referred_table_name)s_fk",
+    "pk": "%(table_name)s_pk",
+}
+
+MetaData(naming_convention=NAMING_CONVENTIONS_STR)