summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/_orm_constructors.py49
-rw-r--r--lib/sqlalchemy/orm/decl_api.py10
-rw-r--r--lib/sqlalchemy/orm/decl_base.py28
-rw-r--r--lib/sqlalchemy/orm/interfaces.py5
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
)