]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
The ``Enum.inherit_schema`` now defaults to true
authorFederico Caselli <cfederico87@gmail.com>
Sun, 23 Jun 2024 13:01:40 +0000 (15:01 +0200)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 27 May 2025 20:06:49 +0000 (16:06 -0400)
Changed the default value of :paramref:`_types.Enum.inherit_schema` to
``True`` when :paramref:`_types.Enum.schema` and
:paramref:`_types.Enum.metadata` parameters are not provided.
The same behavior has been applied also to PostgreSQL
:class:`_postgresql.DOMAIN` type.

Fixes: #10594
Change-Id: Id3d819e3608974353e365cd063d9c5e40a071e73

doc/build/changelog/unreleased_21/10594.rst [new file with mode: 0644]
lib/sqlalchemy/sql/sqltypes.py
test/dialect/postgresql/test_types.py
test/sql/test_metadata.py
test/sql/test_types.py

diff --git a/doc/build/changelog/unreleased_21/10594.rst b/doc/build/changelog/unreleased_21/10594.rst
new file mode 100644 (file)
index 0000000..ad868b6
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: change, schema
+    :tickets: 10594
+
+    Changed the default value of :paramref:`_types.Enum.inherit_schema` to
+    ``True`` when :paramref:`_types.Enum.schema` and
+    :paramref:`_types.Enum.metadata` parameters are not provided.
+    The same behavior has been applied also to PostgreSQL
+    :class:`_postgresql.DOMAIN` type.
index 90c93bcef1bb69f1789ebfeccd44cfddc01ecb37..7d9a65bac8194bf034da169154ab058e9bae8f67 100644 (file)
@@ -6,9 +6,7 @@
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
 # mypy: allow-untyped-defs, allow-untyped-calls
 
-"""SQL specific types.
-
-"""
+"""SQL specific types."""
 from __future__ import annotations
 
 import collections.abc as collections_abc
@@ -40,6 +38,7 @@ from . import elements
 from . import operators
 from . import roles
 from . import type_api
+from .base import _NoArg
 from .base import _NONE_NAME
 from .base import NO_ARG
 from .base import SchemaEventTarget
@@ -75,6 +74,7 @@ if TYPE_CHECKING:
     from .elements import ColumnElement
     from .operators import OperatorType
     from .schema import MetaData
+    from .schema import SchemaConst
     from .type_api import _BindProcessorType
     from .type_api import _ComparatorFactory
     from .type_api import _LiteralProcessorType
@@ -1053,9 +1053,9 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
     def __init__(
         self,
         name: Optional[str] = None,
-        schema: Optional[str] = None,
+        schema: Optional[Union[str, Literal[SchemaConst.BLANK_SCHEMA]]] = None,
         metadata: Optional[MetaData] = None,
-        inherit_schema: bool = False,
+        inherit_schema: Union[bool, _NoArg] = NO_ARG,
         quote: Optional[bool] = None,
         _create_events: bool = True,
         _adapted_from: Optional[SchemaType] = None,
@@ -1066,7 +1066,18 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
             self.name = None
         self.schema = schema
         self.metadata = metadata
-        self.inherit_schema = inherit_schema
+
+        if inherit_schema is True and schema is not None:
+            raise exc.ArgumentError(
+                "Ambiguously setting inherit_schema=True while "
+                "also passing a non-None schema argument"
+            )
+        self.inherit_schema = (
+            inherit_schema
+            if inherit_schema is not NO_ARG
+            else (schema is None and metadata is None)
+        )
+        # breakpoint()
         self._create_events = _create_events
 
         if _create_events and self.metadata:
@@ -1114,6 +1125,9 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
         elif self.metadata and self.schema is None and self.metadata.schema:
             self.schema = self.metadata.schema
 
+        if self.schema is not None:
+            self.inherit_schema = False
+
         if not self._create_events:
             return
 
@@ -1443,21 +1457,28 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
               :class:`_schema.MetaData` object if present, when passed using
               the :paramref:`_types.Enum.metadata` parameter.
 
-           Otherwise, if the :paramref:`_types.Enum.inherit_schema` flag is set
-           to ``True``, the schema will be inherited from the associated
+           Otherwise, the schema will be inherited from the associated
            :class:`_schema.Table` object if any; when
-           :paramref:`_types.Enum.inherit_schema` is at its default of
+           :paramref:`_types.Enum.inherit_schema` is set to
            ``False``, the owning table's schema is **not** used.
 
 
         :param quote: Set explicit quoting preferences for the type's name.
 
         :param inherit_schema: When ``True``, the "schema" from the owning
-           :class:`_schema.Table`
-           will be copied to the "schema" attribute of this
-           :class:`.Enum`, replacing whatever value was passed for the
-           ``schema`` attribute.   This also takes effect when using the
+           :class:`_schema.Table` will be copied to the "schema"
+           attribute of this :class:`.Enum`, replacing whatever value was
+           passed for the :paramref:`_types.Enum.schema` attribute.
+           This also takes effect when using the
            :meth:`_schema.Table.to_metadata` operation.
+           Set to ``False`` to retain the schema value provided.
+           By default the behavior will be to inherit the table schema unless
+           either :paramref:`_types.Enum.schema` and / or
+           :paramref:`_types.Enum.metadata` are set.
+
+           .. versionchanged:: 2.1 The default value of this parameter
+               was changed to ``True`` when :paramref:`_types.Enum.schema`
+               and :paramref:`_types.Enum.metadata` are not provided.
 
         :param validate_strings: when True, string values that are being
            passed to the database in a SQL statement will be checked
@@ -1545,12 +1566,13 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
         # new Enum classes.
         if self.enum_class and values:
             kw.setdefault("name", self.enum_class.__name__.lower())
+
         SchemaType.__init__(
             self,
             name=kw.pop("name", None),
+            inherit_schema=kw.pop("inherit_schema", NO_ARG),
             schema=kw.pop("schema", None),
             metadata=kw.pop("metadata", None),
-            inherit_schema=kw.pop("inherit_schema", False),
             quote=kw.pop("quote", None),
             _create_events=kw.pop("_create_events", True),
             _adapted_from=kw.pop("_adapted_from", None),
index 795a897699b331b4c994c594cffdebce610d6cc5..df370f043b40c548df051ce4288560a5e78aa161 100644 (file)
@@ -266,7 +266,7 @@ class NamedTypeTest(
         ("create_type", False, "create_type"),
         ("create_type", True, "create_type"),
         ("schema", "someschema", "schema"),
-        ("inherit_schema", True, "inherit_schema"),
+        ("inherit_schema", False, "inherit_schema"),
         ("metadata", MetaData(), "metadata"),
         ("values_callable", lambda x: None, "values_callable"),
     )
@@ -443,7 +443,8 @@ class NamedTypeTest(
         t1.drop(conn, checkfirst=True)
 
     @testing.combinations(
-        ("local_schema",),
+        ("inherit_schema_false",),
+        ("inherit_schema_not_provided",),
         ("metadata_schema_only",),
         ("inherit_table_schema",),
         ("override_metadata_schema",),
@@ -457,6 +458,7 @@ class NamedTypeTest(
         """test #6373"""
 
         metadata.schema = testing.config.test_schema
+        default_schema = testing.config.db.dialect.default_schema_name
 
         def make_type(**kw):
             if datatype == "enum":
@@ -481,14 +483,14 @@ class NamedTypeTest(
             )
             assert_schema = testing.config.test_schema_2
         elif test_case == "inherit_table_schema":
-            enum = make_type(
-                metadata=metadata,
-                inherit_schema=True,
-            )
+            enum = make_type(metadata=metadata, inherit_schema=True)
             assert_schema = testing.config.test_schema_2
-        elif test_case == "local_schema":
+        elif test_case == "inherit_schema_not_provided":
             enum = make_type()
-            assert_schema = testing.config.db.dialect.default_schema_name
+            assert_schema = testing.config.test_schema_2
+        elif test_case == "inherit_schema_false":
+            enum = make_type(inherit_schema=False)
+            assert_schema = default_schema
         else:
             assert False
 
@@ -509,13 +511,11 @@ class NamedTypeTest(
                         "labels": ["four", "five", "six"],
                         "name": "mytype",
                         "schema": assert_schema,
-                        "visible": assert_schema
-                        == testing.config.db.dialect.default_schema_name,
+                        "visible": assert_schema == default_schema,
                     }
                 ],
             )
         elif datatype == "domain":
-            def_schame = testing.config.db.dialect.default_schema_name
             eq_(
                 inspect(connection).get_domains(schema=assert_schema),
                 [
@@ -525,7 +525,7 @@ class NamedTypeTest(
                         "nullable": True,
                         "default": None,
                         "schema": assert_schema,
-                        "visible": assert_schema == def_schame,
+                        "visible": assert_schema == default_schema,
                         "constraints": [
                             {
                                 "name": "mytype_check",
index ac43b1bf6206cb919d42ad461fb5a8235dea565e..0b5f70573204981ef84005404230f6d973d2ea87 100644 (file)
@@ -55,6 +55,7 @@ from sqlalchemy.sql.schema import RETAIN_SCHEMA
 from sqlalchemy.testing import assert_raises
 from sqlalchemy.testing import assert_raises_message
 from sqlalchemy.testing import AssertsCompiledSQL
+from sqlalchemy.testing import combinations
 from sqlalchemy.testing import ComparesTables
 from sqlalchemy.testing import emits_warning
 from sqlalchemy.testing import eq_
@@ -2409,6 +2410,23 @@ class SchemaTypeTest(fixtures.TestBase):
             ],
         )
 
+    def test_adapt_to_schema(self):
+        m = MetaData()
+        type_ = self.MyType()
+        eq_(type_.inherit_schema, True)
+        t1 = Table("x", m, Column("y", type_), schema="z")
+        eq_(t1.c.y.type.schema, "z")
+
+        adapted = t1.c.y.type.adapt(self.MyType)
+
+        eq_(type_.inherit_schema, False)
+        eq_(adapted.inherit_schema, False)
+
+        eq_(adapted.schema, "z")
+
+        adapted2 = t1.c.y.type.adapt(self.MyType, schema="q")
+        eq_(adapted2.schema, "q")
+
     def test_independent_schema(self):
         m = MetaData()
         type_ = self.MyType(schema="q")
@@ -2438,22 +2456,59 @@ class SchemaTypeTest(fixtures.TestBase):
 
     def test_inherit_schema(self):
         m = MetaData()
-        type_ = self.MyType(schema="q", inherit_schema=True)
+        type_ = self.MyType(inherit_schema=True)
         t1 = Table("x", m, Column("y", type_), schema="z")
         eq_(t1.c.y.type.schema, "z")
 
-    def test_independent_schema_enum(self):
-        m = MetaData()
-        type_ = sqltypes.Enum("a", schema="q")
+    @combinations({}, {"inherit_schema": False}, argnames="enum_kw")
+    @combinations({}, {"schema": "m"}, argnames="meta_kw")
+    @combinations({}, {"schema": "t"}, argnames="table_kw")
+    def test_independent_schema_enum_explicit_schema(
+        self, enum_kw, meta_kw, table_kw
+    ):
+        m = MetaData(**meta_kw)
+        type_ = sqltypes.Enum("a", schema="e", **enum_kw)
+        t1 = Table("x", m, Column("y", type_), **table_kw)
+        eq_(t1.c.y.type.schema, "e")
+
+    def test_explicit_schema_w_inherit_raises(self):
+        with expect_raises_message(
+            exc.ArgumentError,
+            "Ambiguously setting inherit_schema=True while also passing "
+            "a non-None schema argument",
+        ):
+            sqltypes.Enum("a", schema="e", inherit_schema=True)
+
+    def test_independent_schema_off_no_explicit_schema(self):
+        m = MetaData(schema="m")
+        type_ = sqltypes.Enum("a", inherit_schema=False)
         t1 = Table("x", m, Column("y", type_), schema="z")
-        eq_(t1.c.y.type.schema, "q")
+        eq_(t1.c.y.type.schema, None)
 
-    def test_inherit_schema_enum(self):
+    def test_inherit_schema_enum_auto(self):
         m = MetaData()
-        type_ = sqltypes.Enum("a", "b", "c", schema="q", inherit_schema=True)
+        type_ = sqltypes.Enum("a", "b", "c")
         t1 = Table("x", m, Column("y", type_), schema="z")
         eq_(t1.c.y.type.schema, "z")
 
+    def test_inherit_schema_enum_meta(self):
+        m = MetaData(schema="q")
+        type_ = sqltypes.Enum("a", "b", "c")
+        t1 = Table("x", m, Column("y", type_), schema="z")
+        eq_(t1.c.y.type.schema, "z")
+
+    def test_inherit_schema_enum_set_meta(self):
+        m = MetaData(schema="q")
+        type_ = sqltypes.Enum("a", "b", "c", metadata=m)
+        t1 = Table("x", m, Column("y", type_), schema="z")
+        eq_(t1.c.y.type.schema, "q")
+
+    def test_inherit_schema_enum_set_meta_explicit(self):
+        m = MetaData(schema="q")
+        type_ = sqltypes.Enum("a", "b", "c", metadata=m, schema="e")
+        t1 = Table("x", m, Column("y", type_), schema="z")
+        eq_(t1.c.y.type.schema, "e")
+
     @testing.variation("assign_metadata", [True, False])
     def test_to_metadata_copy_type(self, assign_metadata):
         m1 = MetaData()
@@ -2493,16 +2548,24 @@ class SchemaTypeTest(fixtures.TestBase):
         t2 = t1.to_metadata(m2)
         eq_(t2.c.y.type.schema, "z")
 
-    def test_to_metadata_independent_schema(self):
+    @testing.variation("inherit_schema", ["novalue", True, False])
+    def test_to_metadata_independent_schema(self, inherit_schema):
         m1 = MetaData()
 
-        type_ = self.MyType()
+        if inherit_schema.novalue:
+            type_ = self.MyType()
+        else:
+            type_ = self.MyType(inherit_schema=bool(inherit_schema))
+
         t1 = Table("x", m1, Column("y", type_))
 
         m2 = MetaData()
         t2 = t1.to_metadata(m2, schema="bar")
 
-        eq_(t2.c.y.type.schema, None)
+        if inherit_schema.novalue or inherit_schema:
+            eq_(t2.c.y.type.schema, "bar")
+        else:
+            eq_(t2.c.y.type.schema, None)
 
     @testing.combinations(
         ("name", "foobar", "name"),
@@ -2518,15 +2581,10 @@ class SchemaTypeTest(fixtures.TestBase):
 
         eq_(getattr(e1_copy, attrname), value)
 
-    @testing.variation("already_has_a_schema", [True, False])
-    def test_to_metadata_inherit_schema(self, already_has_a_schema):
+    def test_to_metadata_inherit_schema(self):
         m1 = MetaData()
 
-        if already_has_a_schema:
-            type_ = self.MyType(schema="foo", inherit_schema=True)
-            eq_(type_.schema, "foo")
-        else:
-            type_ = self.MyType(inherit_schema=True)
+        type_ = self.MyType(inherit_schema=True)
 
         t1 = Table("x", m1, Column("y", type_))
         # note that inherit_schema means the schema mutates to be that
index eb4b420129f63a7644bb883f56e966cfdcfc13fe..1a173f89d1f58115ab8b04e42b205f77523aff6e 100644 (file)
@@ -2820,21 +2820,23 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
         e = Enum("x", "y", name="somename", create_constraint=True)
         eq_(
             repr(e),
-            "Enum('x', 'y', name='somename', create_constraint=True)",
+            "Enum('x', 'y', name='somename', inherit_schema=True, "
+            "create_constraint=True)",
         )
 
     def test_repr_three(self):
         e = Enum("x", "y", native_enum=False, length=255)
         eq_(
             repr(e),
-            "Enum('x', 'y', native_enum=False, length=255)",
+            "Enum('x', 'y', inherit_schema=True, "
+            "native_enum=False, length=255)",
         )
 
     def test_repr_four(self):
         e = Enum("x", "y", length=255)
         eq_(
             repr(e),
-            "Enum('x', 'y', length=255)",
+            "Enum('x', 'y', inherit_schema=True, length=255)",
         )
 
     def test_length_native(self):
@@ -2867,7 +2869,11 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
     def test_none_length_non_native(self):
         e = Enum("x", "y", native_enum=False, length=None)
         eq_(e.length, None)
-        eq_(repr(e), "Enum('x', 'y', native_enum=False, length=None)")
+        eq_(
+            repr(e),
+            "Enum('x', 'y', inherit_schema=True, "
+            "native_enum=False, length=None)",
+        )
         self.assert_compile(e, "VARCHAR", dialect="default")
 
     def test_omit_aliases(self, connection):