diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2022-08-05 14:53:22 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@ci3.zzzcomputing.com> | 2022-08-05 14:53:22 +0000 |
commit | e332909b103661975bd17816b3a2713e30671ae0 (patch) | |
tree | 246e49b63bf8e66befb7c3e493bfc33592f906ec /lib/sqlalchemy/orm | |
parent | 828a1a0d143976c0e36a4772d4bd908ff6484735 (diff) | |
parent | d2887d03a28b09e9be7db17d7603b6b0a4715df3 (diff) | |
download | sqlalchemy-e332909b103661975bd17816b3a2713e30671ae0.tar.gz |
Merge "Support kw_only and match_args in dataclass mapping" into main
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r-- | lib/sqlalchemy/orm/_orm_constructors.py | 49 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/decl_api.py | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/decl_base.py | 28 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 5 |
4 files changed, 52 insertions, 40 deletions
diff --git a/lib/sqlalchemy/orm/_orm_constructors.py b/lib/sqlalchemy/orm/_orm_constructors.py index 2f1128f94..8dfec0fb1 100644 --- a/lib/sqlalchemy/orm/_orm_constructors.py +++ b/lib/sqlalchemy/orm/_orm_constructors.py @@ -111,6 +111,7 @@ def mapped_column( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Optional[Any] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, nullable: Optional[ Union[bool, Literal[SchemaConst.NULL_UNSPECIFIED]] ] = SchemaConst.NULL_UNSPECIFIED, @@ -242,6 +243,9 @@ def mapped_column( specifies a default-value generation function that will take place as part of the ``__init__()`` method as generated by the dataclass process. + :param kw_only: Specific to + :ref:`orm_declarative_native_dataclasses`, indicates if this field + should be marked as keyword-only when generating the ``__init__()``. :param \**kw: All remaining keyword argments are passed through to the constructor for the :class:`_schema.Column`. @@ -257,10 +261,7 @@ def mapped_column( autoincrement=autoincrement, insert_default=insert_default, attribute_options=_AttributeOptions( - init, - repr, - default, - default_factory, + init, repr, default, default_factory, kw_only ), doc=doc, key=key, @@ -293,6 +294,7 @@ def column_property( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Optional[Any] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, active_history: bool = False, expire_on_flush: bool = True, info: Optional[_InfoType] = None, @@ -385,10 +387,7 @@ def column_property( column, *additional_columns, attribute_options=_AttributeOptions( - init, - repr, - default, - default_factory, + init, repr, default, default_factory, kw_only ), group=group, deferred=deferred, @@ -414,6 +413,7 @@ def composite( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Optional[Any] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, info: Optional[_InfoType] = None, doc: Optional[str] = None, **__kw: Any, @@ -434,6 +434,7 @@ def composite( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Optional[Any] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, info: Optional[_InfoType] = None, doc: Optional[str] = None, **__kw: Any, @@ -455,6 +456,7 @@ def composite( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Optional[Any] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, info: Optional[_InfoType] = None, doc: Optional[str] = None, **__kw: Any, @@ -517,6 +519,9 @@ def composite( specifies a default-value generation function that will take place as part of the ``__init__()`` method as generated by the dataclass process. + :param kw_only: Specific to + :ref:`orm_declarative_native_dataclasses`, indicates if this field + should be marked as keyword-only when generating the ``__init__()``. """ if __kw: @@ -526,10 +531,7 @@ def composite( _class_or_attr, *attrs, attribute_options=_AttributeOptions( - init, - repr, - default, - default_factory, + init, repr, default, default_factory, kw_only ), group=group, deferred=deferred, @@ -752,6 +754,7 @@ def relationship( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Union[_NoArg, _T] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, lazy: _LazyLoadArgumentType = "select", passive_deletes: Union[Literal["all"], bool] = False, passive_updates: bool = True, @@ -1549,7 +1552,9 @@ def relationship( specifies a default-value generation function that will take place as part of the ``__init__()`` method as generated by the dataclass process. - + :param kw_only: Specific to + :ref:`orm_declarative_native_dataclasses`, indicates if this field + should be marked as keyword-only when generating the ``__init__()``. """ @@ -1568,10 +1573,7 @@ def relationship( cascade=cascade, viewonly=viewonly, attribute_options=_AttributeOptions( - init, - repr, - default, - default_factory, + init, repr, default, default_factory, kw_only ), lazy=lazy, passive_deletes=passive_deletes, @@ -1604,6 +1606,7 @@ def synonym( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Union[_NoArg, _T] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, info: Optional[_InfoType] = None, doc: Optional[str] = None, ) -> Synonym[Any]: @@ -1716,10 +1719,7 @@ def synonym( descriptor=descriptor, comparator_factory=comparator_factory, attribute_options=_AttributeOptions( - init, - repr, - default, - default_factory, + init, repr, default, default_factory, kw_only ), doc=doc, info=info, @@ -1848,6 +1848,7 @@ def deferred( repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 default: Optional[Any] = _NoArg.NO_ARG, default_factory: Union[_NoArg, Callable[[], _T]] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, active_history: bool = False, expire_on_flush: bool = True, info: Optional[_InfoType] = None, @@ -1884,10 +1885,7 @@ def deferred( column, *additional_columns, attribute_options=_AttributeOptions( - init, - repr, - default, - default_factory, + init, repr, default, default_factory, kw_only ), group=group, deferred=True, @@ -1937,6 +1935,7 @@ def query_expression( repr, _NoArg.NO_ARG, _NoArg.NO_ARG, + _NoArg.NO_ARG, ), expire_on_flush=expire_on_flush, info=info, diff --git a/lib/sqlalchemy/orm/decl_api.py b/lib/sqlalchemy/orm/decl_api.py index 500f2786e..d34ec8c93 100644 --- a/lib/sqlalchemy/orm/decl_api.py +++ b/lib/sqlalchemy/orm/decl_api.py @@ -578,6 +578,8 @@ class MappedAsDataclass(metaclass=DCTransformDeclarative): eq: Union[_NoArg, bool] = _NoArg.NO_ARG, order: Union[_NoArg, bool] = _NoArg.NO_ARG, unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG, + match_args: Union[_NoArg, bool] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, ) -> None: apply_dc_transforms: _DataclassArguments = { @@ -586,6 +588,8 @@ class MappedAsDataclass(metaclass=DCTransformDeclarative): "eq": eq, "order": order, "unsafe_hash": unsafe_hash, + "match_args": match_args, + "kw_only": kw_only, } if hasattr(cls, "_sa_apply_dc_transforms"): @@ -1313,6 +1317,8 @@ class registry: eq: Union[_NoArg, bool] = ..., order: Union[_NoArg, bool] = ..., unsafe_hash: Union[_NoArg, bool] = ..., + match_args: Union[_NoArg, bool] = ..., + kw_only: Union[_NoArg, bool] = ..., ) -> Callable[[Type[_O]], Type[_O]]: ... @@ -1325,6 +1331,8 @@ class registry: eq: Union[_NoArg, bool] = _NoArg.NO_ARG, order: Union[_NoArg, bool] = _NoArg.NO_ARG, unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG, + match_args: Union[_NoArg, bool] = _NoArg.NO_ARG, + kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, ) -> Union[Type[_O], Callable[[Type[_O]], Type[_O]]]: """Class decorator that will apply the Declarative mapping process to a given class, and additionally convert the class to be a @@ -1348,6 +1356,8 @@ class registry: "eq": eq, "order": order, "unsafe_hash": unsafe_hash, + "match_args": match_args, + "kw_only": kw_only, } _as_declarative(self, cls, cls.__dict__) return cls diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index 108027dd5..e8d6e4c1b 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -106,6 +106,8 @@ class _DataclassArguments(TypedDict): eq: Union[_NoArg, bool] order: Union[_NoArg, bool] unsafe_hash: Union[_NoArg, bool] + match_args: Union[_NoArg, bool] + kw_only: Union[_NoArg, bool] def _declared_mapping_info( @@ -1030,22 +1032,20 @@ class _ClassScanMapperConfig(_MapperConfig): @classmethod def _assert_dc_arguments(cls, arguments: _DataclassArguments) -> None: - disallowed_args = set(arguments).difference( - { - "init", - "repr", - "order", - "eq", - "unsafe_hash", - } - ) + allowed = { + "init", + "repr", + "order", + "eq", + "unsafe_hash", + "kw_only", + "match_args", + } + disallowed_args = set(arguments).difference(allowed) if disallowed_args: + msg = ", ".join(f"{arg!r}" for arg in sorted(disallowed_args)) raise exc.ArgumentError( - f"Dataclass argument(s) " - f"""{ - ', '.join(f'{arg!r}' - for arg in sorted(disallowed_args)) - } are not accepted""" + f"Dataclass argument(s) {msg} are not accepted" ) def _collect_annotation( diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index a9ae4436f..0f66566b0 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -187,6 +187,7 @@ class _AttributeOptions(NamedTuple): dataclasses_repr: Union[_NoArg, bool] dataclasses_default: Union[_NoArg, Any] dataclasses_default_factory: Union[_NoArg, Callable[[], Any]] + dataclasses_kw_only: Union[_NoArg, bool] def _as_dataclass_field(self) -> Any: """Return a ``dataclasses.Field`` object given these arguments.""" @@ -200,6 +201,8 @@ class _AttributeOptions(NamedTuple): kw["init"] = self.dataclasses_init if self.dataclasses_repr is not _NoArg.NO_ARG: kw["repr"] = self.dataclasses_repr + if self.dataclasses_kw_only is not _NoArg.NO_ARG: + kw["kw_only"] = self.dataclasses_kw_only return dataclasses.field(**kw) @@ -226,7 +229,7 @@ class _AttributeOptions(NamedTuple): _DEFAULT_ATTRIBUTE_OPTIONS = _AttributeOptions( - _NoArg.NO_ARG, _NoArg.NO_ARG, _NoArg.NO_ARG, _NoArg.NO_ARG + _NoArg.NO_ARG, _NoArg.NO_ARG, _NoArg.NO_ARG, _NoArg.NO_ARG, _NoArg.NO_ARG ) |