From f979aff468a4bdc32aad7b073583823cddf8f21c Mon Sep 17 00:00:00 2001 From: opkna Date: Thu, 4 Jul 2024 22:13:10 +0200 Subject: [PATCH] Added valid types to server_onupdate (#11555) * Added valid types to server_onupdate and mapped_column kwargs mypy tests * Joined mapped_column test files * Set _ServerOnUpdateArgument to _ServerDefaultArgument Fixes: #11546 --- lib/sqlalchemy/orm/_orm_constructors.py | 4 +- lib/sqlalchemy/sql/schema.py | 4 +- test/typing/plain_files/orm/mapped_column.py | 88 ++++++++++++++++++++ test/typing/plain_files/sql/core_ddl.py | 10 ++- 4 files changed, 102 insertions(+), 4 deletions(-) diff --git a/lib/sqlalchemy/orm/_orm_constructors.py b/lib/sqlalchemy/orm/_orm_constructors.py index 7d215059af..c800358456 100644 --- a/lib/sqlalchemy/orm/_orm_constructors.py +++ b/lib/sqlalchemy/orm/_orm_constructors.py @@ -71,7 +71,7 @@ if TYPE_CHECKING: from ..sql._typing import _TypeEngineArgument from ..sql.elements import ColumnElement from ..sql.schema import _ServerDefaultArgument - from ..sql.schema import FetchedValue + from ..sql.schema import _ServerOnUpdateArgument from ..sql.selectable import Alias from ..sql.selectable import Subquery @@ -129,7 +129,7 @@ def mapped_column( onupdate: Optional[Any] = None, insert_default: Optional[Any] = _NoArg.NO_ARG, server_default: Optional[_ServerDefaultArgument] = None, - server_onupdate: Optional[FetchedValue] = None, + server_onupdate: Optional[_ServerOnUpdateArgument] = None, active_history: bool = False, quote: Optional[bool] = None, system: bool = False, diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 276e4edf4a..8a1ffba64c 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -126,6 +126,8 @@ _ServerDefaultArgument = Union[ "FetchedValue", str, TextClause, ColumnElement[Any] ] +_ServerOnUpdateArgument = _ServerDefaultArgument + class SchemaConst(Enum): RETAIN_SCHEMA = 1 @@ -1530,7 +1532,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]): onupdate: Optional[Any] = None, primary_key: bool = False, server_default: Optional[_ServerDefaultArgument] = None, - server_onupdate: Optional[FetchedValue] = None, + server_onupdate: Optional[_ServerOnUpdateArgument] = None, quote: Optional[bool] = None, system: bool = False, comment: Optional[str] = None, diff --git a/test/typing/plain_files/orm/mapped_column.py b/test/typing/plain_files/orm/mapped_column.py index 26f5722a6f..81080a4faa 100644 --- a/test/typing/plain_files/orm/mapped_column.py +++ b/test/typing/plain_files/orm/mapped_column.py @@ -1,13 +1,20 @@ from typing import Optional +from sqlalchemy import Boolean +from sqlalchemy import FetchedValue from sqlalchemy import ForeignKey +from sqlalchemy import func from sqlalchemy import Index from sqlalchemy import Integer +from sqlalchemy import literal_column from sqlalchemy import String +from sqlalchemy import text +from sqlalchemy import true from sqlalchemy import UniqueConstraint from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import Mapped from sqlalchemy.orm import mapped_column +from sqlalchemy.sql.schema import SchemaConst class Base(DeclarativeBase): @@ -94,3 +101,84 @@ class X(Base): ) __table_args__ = (UniqueConstraint(a, b, name="uq1"), Index("ix1", c, d)) + + +mapped_column() +mapped_column( + init=True, + repr=True, + default=42, + compare=True, + kw_only=True, + primary_key=True, + deferred=True, + deferred_group="str", + deferred_raiseload=True, + use_existing_column=True, + name="str", + type_=Integer(), + doc="str", + key="str", + index=True, + unique=True, + info={"str": 42}, + active_history=True, + quote=True, + system=True, + comment="str", + sort_order=-1, + any_kwarg="str", + another_kwarg=42, +) + +mapped_column(default_factory=lambda: 1) +mapped_column(default_factory=lambda: "str") + +mapped_column(nullable=True) +mapped_column(nullable=SchemaConst.NULL_UNSPECIFIED) + +mapped_column(autoincrement=True) +mapped_column(autoincrement="auto") +mapped_column(autoincrement="ignore_fk") + +mapped_column(onupdate=1) +mapped_column(onupdate="str") + +mapped_column(insert_default=1) +mapped_column(insert_default="str") + +mapped_column(server_default=FetchedValue()) +mapped_column(server_default=true()) +mapped_column(server_default=func.now()) +mapped_column(server_default="NOW()") +mapped_column(server_default=text("NOW()")) +mapped_column(server_default=literal_column("false", Boolean)) + +mapped_column(server_onupdate=FetchedValue()) +mapped_column(server_onupdate=true()) +mapped_column(server_onupdate=func.now()) +mapped_column(server_onupdate="NOW()") +mapped_column(server_onupdate=text("NOW()")) +mapped_column(server_onupdate=literal_column("false", Boolean)) + +mapped_column( + default=None, + nullable=None, + primary_key=None, + deferred_group=None, + deferred_raiseload=None, + name=None, + type_=None, + doc=None, + key=None, + index=None, + unique=None, + info=None, + onupdate=None, + insert_default=None, + server_default=None, + server_onupdate=None, + quote=None, + comment=None, + any_kwarg=None, +) diff --git a/test/typing/plain_files/sql/core_ddl.py b/test/typing/plain_files/sql/core_ddl.py index b7e0ec5350..549375d0af 100644 --- a/test/typing/plain_files/sql/core_ddl.py +++ b/test/typing/plain_files/sql/core_ddl.py @@ -138,10 +138,18 @@ Column("name", Integer, server_default=text("now()"), nullable=False) Column(Integer, server_default=literal_column("42", Integer), nullable=False) # server_onupdate -Column("name", server_onupdate=FetchedValue(), nullable=False) Column(server_onupdate=FetchedValue(), nullable=False) +Column(server_onupdate="now()", nullable=False) +Column("name", server_onupdate=FetchedValue(), nullable=False) Column("name", Integer, server_onupdate=FetchedValue(), nullable=False) +Column("name", Integer, server_onupdate=text("now()"), nullable=False) +Column(Boolean, nullable=False, server_default=true()) Column(Integer, server_onupdate=FetchedValue(), nullable=False) +Column(DateTime, server_onupdate="now()") +Column(DateTime, server_onupdate=text("now()")) +Column(DateTime, server_onupdate=FetchedValue()) +Column(Boolean, server_onupdate=literal_column("false", Boolean)) +Column(Integer, server_onupdate=literal_column("42", Integer), nullable=False) # TypeEngine.with_variant should accept both a TypeEngine instance and the Concrete Type Integer().with_variant(Integer, "mysql") -- 2.47.2