]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
doc edits
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 6 Oct 2022 15:57:06 +0000 (11:57 -0400)
committerFederico Caselli <cfederico87@gmail.com>
Mon, 10 Oct 2022 19:27:50 +0000 (21:27 +0200)
this is addressing comments still remaining on
I9929daab7797be9515f71c888b28af1209e789ff

removes "asyncio" wording discussed in #7659

Change-Id: I1bab2a6fde330b83ef34602956c2988ee6331b21

doc/build/changelog/whatsnew_20.rst
doc/build/orm/extensions/asyncio.rst
doc/build/orm/queryguide/api.rst
doc/build/orm/queryguide/columns.rst
doc/build/orm/queryguide/dml.rst
doc/build/orm/queryguide/relationships.rst
doc/build/orm/queryguide/select.rst
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/sql/selectable.py
test/sql/test_selectable.py

index 718ea93c02d764a041e05c45fcbfa1ff6d7cf43d..061f8d4ce693bf508c00a7a957f49af34a682347 100644 (file)
@@ -1628,7 +1628,7 @@ a form which is equivalent towards:
 
     %(param_1)s / CAST(%(param_2)s AS NUMERIC)
 
-With param_1=5, param_2=10, so that the return expression will be of type
+With ``param_1=5``, ``param_2=10``, so that the return expression will be of type
 NUMERIC, typically as the Python value ``decimal.Decimal("0.5")``.
 
 Given a "floor division" operation against two integer values::
index f43c0b53e1ca71c369225ba45f1cffa4edb9bfae..b6353710150d6590108db8aa5ca7746a00bb87c5 100644 (file)
@@ -244,15 +244,6 @@ then used in a Python asynchronous context manager (i.e. ``async with:``
 statement) so that it is automatically closed at the end of the block; this is
 equivalent to calling the :meth:`_asyncio.AsyncSession.close` method.
 
-.. note:: :class:`_asyncio.AsyncSession` uses SQLAlchemy's future mode, which
-   has several potentially breaking changes.  One such change is the new
-   default behavior of ``cascade_backrefs`` is ``False``, which may affect
-   how related objects are saved to the database.
-
-   .. seealso::
-
-     :ref:`change_5150`
-
 
 .. _asyncio_orm_avoid_lazyloads:
 
@@ -333,9 +324,7 @@ Other guidelines include:
   setting, which means that the :meth:`.AsyncSession.refresh` method will
   expire the attributes on related objects, but not necessarily refresh those
   related objects assuming eager loading is not configured within the
-  :func:`_orm.relationship`, leaving them in an expired state.   A future
-  release may introduce the ability to indicate eager loader options when
-  invoking :meth:`.Session.refresh` and/or :meth:`.AsyncSession.refresh`.
+  :func:`_orm.relationship`, leaving them in an expired state.
 
 * Appropriate loader options should be employed for :func:`_orm.deferred`
   columns, if used at all, in addition to that of :func:`_orm.relationship`
index 5b6209d3db3d5ac3f4ef6a43be73c8112341882b..136b4b39bbbdaf4fffd161302d00dbe9f29a089a 100644 (file)
@@ -13,10 +13,11 @@ ORM API Features for Querying
 ORM Loader Options
 -------------------
 
-Loader options are objects that are passed to the :meth:`_sql.Select.options`
-method, which affect the loading of both column and relationship-oriented
-attributes.  The majority of loader options descend from the :class:`_orm.Load`
-hierarchy.  For a complete overview of using loader options, see the linked
+Loader options are objects which, when passed to the
+:meth:`_sql.Select.options` method of a :class:`.Select` object or similar SQL
+construct, affect the loading of both column and relationship-oriented
+attributes. The majority of loader options descend from the :class:`_orm.Load`
+hierarchy. For a complete overview of using loader options, see the linked
 sections below.
 
 .. seealso::
index 78b51b36c2d901d13a7a8d05f8fb6a3281bfb808..f9d2816a4b208510879d8b5ecb284037178fedbf 100644 (file)
@@ -98,8 +98,13 @@ from any :class:`_orm.Session`, the operation fails, raising an exception.
 
 As an alternative to lazy loading on access, deferred columns may also be
 configured to raise an informative exception when accessed, regardless of their
-attachment state. See the section :ref:`orm_queryguide_deferred_raiseload` for
-background.
+attachment state.  When using the :func:`_orm.load_only` construct, this
+may be indicated using the :paramref:`_orm.load_only.raiseload` parameter.
+See the section :ref:`orm_queryguide_deferred_raiseload` for
+background and examples.
+
+.. tip::  as noted elsewhere, lazy loading is not available when using
+   :ref:`asyncio_toplevel`.
 
 Using ``load_only()`` with multiple entities
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -240,18 +245,18 @@ Using raiseload to prevent deferred column loads
 
   >>> session.expunge_all()
 
-When using :func:`_orm.load_only` or :func:`_orm.deferred`, attributes marked
-as deferred on an object have the default behavior that when first accessed, a
-SELECT statement will be emitted within the current transaction in order to
-load their value. It is often necessary to prevent this load from occurring,
-and instead raise an exception when the attribute is accessed, indicating that
-the need to query the database for this column was not expected. A typical
-scenario is an operation where objects are loaded with all the columns that are
-known to be required for the operation to proceed, which are then passed onto a
-view layer. Any further SQL operations that emit within the view layer should
-be caught, so that the up-front loading operation can be adjusted to
-accommodate for that additional data up front, rather than incurring additional
-lazy loading.
+When using the :func:`_orm.load_only` or :func:`_orm.defer` loader options,
+attributes marked as deferred on an object have the default behavior that when
+first accessed, a SELECT statement will be emitted within the current
+transaction in order to load their value. It is often necessary to prevent this
+load from occurring, and instead raise an exception when the attribute is
+accessed, indicating that the need to query the database for this column was
+not expected. A typical scenario is an operation where objects are loaded with
+all the columns that are known to be required for the operation to proceed,
+which are then passed onto a view layer. Any further SQL operations that emit
+within the view layer should be caught, so that the up-front loading operation
+can be adjusted to accommodate for that additional data up front, rather than
+incurring additional lazy loading.
 
 For this use case the :func:`_orm.defer` and :func:`_orm.load_only` options
 include a boolean parameter :paramref:`_orm.defer.raiseload`, which when set to
@@ -515,7 +520,7 @@ Undeferring by group with ``undefer_group()``
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 If deferred columns are configured with :paramref:`_orm.mapped_column.deferred_group`
-(introduced previously at :ref:`orm_queryguide_deferred_group`), the
+as introduced in the preceding section, the
 entire group may be indicated to load eagerly using the :func:`_orm.undefer_group`
 option, passing the string name of the group to be eagerly loaded::
 
index 480604e478dad7a8d7ccf289f538b9229083ff4d..97aee3fea3e1bd8fcbdc9cb0ed09bd39438cad2c 100644 (file)
@@ -113,13 +113,8 @@ with the exception of MySQL (MariaDB is included).
 
 As an example, we can run the same statement as before, adding use of the
 :meth:`.UpdateBase.returning` method, passing the full ``User`` entity
-as what we'd like to return.  In the example below, we also
-make use of the :meth:`_orm.Session.scalars` method in order to
-invoke the statement, which is an optional
-facade around the :meth:`_orm.Session.execute` method that will yield a
-:class:`.ScalarResult` instead of a
-:class:`.Result` object, which for convenience will yield ``User`` objects
-directly without packaging them into :class:`.Row` objects::
+as what we'd like to return.  :meth:`_orm.Session.scalars` is used to allow
+iteration of ``User`` objects::
 
     >>> users = session.scalars(
     ...     insert(User).returning(User),
@@ -543,10 +538,9 @@ example in the previous section::
 The example above uses RETURNING to return ORM objects for each row inserted or
 upserted by the statement. The example also adds use of the
 :ref:`orm_queryguide_populate_existing` execution option. This option indicates
-that when a particular ``User`` object is being delivered by the statement,
-that the contents of an existing ``User`` object, if one were already present
-in the :class:`_orm.Session` for its particular identity key, should be
-**replaced** with that of the new row. For a pure :class:`_dml.Insert`
+that ``User`` objects which are already present
+in the :class:`_orm.Session` for rows that already exist should be
+**refreshed** with the data from the new row. For a pure :class:`_dml.Insert`
 statement, this option is not significant, because every row produced is a
 brand new primary key identity. However when the :class:`_dml.Insert` also
 includes "upsert" options, it may also be yielding results from rows that
index 4525a38d6c928e6c24f3fbf8c81f7b10e547ce51..fff79b31807b26dee10eeca80a5ec6d58034bde5 100644 (file)
@@ -18,6 +18,9 @@ Relationship Loading Techniques
     objects.   Readers should be familiar with
     :ref:`relationship_config_toplevel` and basic use.
 
+    Most examples here assume the "User/Address" mapping setup similar
+    to the one illustrated at :doc:`setup for selects <_plain_setup>`.
+
 A big part of SQLAlchemy is providing a wide range of control over how related
 objects get loaded when querying.   By "related objects" we refer to collections
 or scalar associations configured on a mapper using :func:`_orm.relationship`.
@@ -52,7 +55,10 @@ The primary forms of relationship loading are:
 * **lazy loading** - available via ``lazy='select'`` or the :func:`.lazyload`
   option, this is the form of loading that emits a SELECT statement at
   attribute access time to lazily load a related reference on a single
-  object at a time.  Lazy loading is detailed at :ref:`lazy_loading`.
+  object at a time.  Lazy loading is the **default loading style** for all
+  :func:`_orm.relationship` constructs that don't otherwise indicate the
+  :paramref:`_orm.relationship.lazy` option.  Lazy loading is detailed at
+  :ref:`lazy_loading`.
 
 * **select IN loading** - available via ``lazy='selectin'`` or the :func:`.selectinload`
   option, this form of loading emits a second (or more) SELECT statement which
@@ -159,11 +165,9 @@ is to set them up on a per-query basis against specific attributes using the
 :meth:`_sql.Select.options` method.  Very detailed
 control over relationship loading is available using loader options;
 the most common are
-:func:`_orm.joinedload`,
-:func:`_orm.subqueryload`, :func:`_orm.selectinload`
-and :func:`_orm.lazyload`.   The option accepts either
-the string name of an attribute against a parent, or for greater specificity
-can accommodate a class-bound attribute directly::
+:func:`_orm.joinedload`, :func:`_orm.selectinload`
+and :func:`_orm.lazyload`.   The option accepts a class-bound attribute
+referring to the specific class/attribute that should be targeted::
 
     from sqlalchemy import select
     from sqlalchemy.orm import lazyload
@@ -280,10 +284,10 @@ the :meth:`_orm.Load.options` method::
    transaction is committed or rolled back, or :meth:`.Session.expire_all` is
    used), when the ``Parent.children`` collection is next accessed in order to
    re-load it, the ``Child.subelements`` collection will again be loaded using
-   subquery eager loading.This stays the case even if the above ``Parent``
+   subquery eager loading. This stays the case even if the above ``Parent``
    object is accessed from a subsequent query that specifies a different set of
-   options.To change the options on an existing object without expunging it and
-   re-loading, they must be set explicitly in conjunction using the
+   options. To change the options on an existing object without expunging it
+   and re-loading, they must be set explicitly in conjunction using the
    :ref:`orm_queryguide_populate_existing` execution option::
 
       # change the options on Parent objects that were already loaded
@@ -693,14 +697,14 @@ returned.
 By changing the usage of :func:`_orm.joinedload` to another style of loading, we
 can change how the collection is loaded completely independently of SQL used to
 retrieve the actual ``User`` rows we want.  Below we change :func:`_orm.joinedload`
-into :func:`.subqueryload`:
+into :func:`.selectinload`:
 
 .. sourcecode:: pycon+sql
 
     >>> stmt = (
     ...     select(User)
     ...     .join(User.addresses)
-    ...     .options(subqueryload(User.addresses))
+    ...     .options(selectinload(User.addresses))
     ...     .filter(User.name == "spongebob")
     ...     .filter(Address.email_address == "someaddress@foo.com")
     ... )
@@ -716,10 +720,10 @@ into :func:`.subqueryload`:
         users.name = ?
         AND addresses.email_address = ?
     ['spongebob', 'someaddress@foo.com']
-
-    # ... subqueryload() emits a SELECT in order
+    # ... selectinload() emits a SELECT in order
     # to load all address records ...
 
+
 When using joined eager loading, if the query contains a modifier that impacts
 the rows returned externally to the joins, such as when using DISTINCT, LIMIT,
 OFFSET or equivalent, the completed statement is first wrapped inside a
@@ -738,9 +742,7 @@ no matter what the format of the query is.
 Select IN loading
 -----------------
 
-Select IN loading is similar in operation to subquery eager loading, however
-the SELECT statement which is emitted has a much simpler structure than that of
-subquery eager loading.  In most cases, selectin loading is the most simple and
+In most cases, selectin loading is the most simple and
 efficient way to eagerly load collections of objects.  The only scenario in
 which selectin eager loading is not feasible is when the model is using
 composite primary keys, and the backend database does not support tuples with
@@ -783,15 +785,12 @@ Above, the second SELECT refers to ``addresses.user_id IN (5, 7)``, where the
 "5" and "7" are the primary key values for the previous two ``User``
 objects loaded; after a batch of objects are completely loaded, their primary
 key values are injected into the ``IN`` clause for the second SELECT.
-Because the relationship between ``User`` and ``Address`` has a simple [1]_
+Because the relationship between ``User`` and ``Address`` has a simple
 primary join condition and provides that the
 primary key values for ``User`` can be derived from ``Address.user_id``, the
 statement has no joins or subqueries at all.
 
-.. versionchanged:: 1.3 selectin loading can omit the JOIN for a simple
-   one-to-many collection.
-
-For simple [1]_ many-to-one loads, a JOIN is also not needed as the foreign key
+For simple many-to-one loads, a JOIN is also not needed as the foreign key
 value from the parent object is used:
 
 .. sourcecode:: pycon+sql
@@ -814,10 +813,9 @@ value from the parent object is used:
     WHERE users.id IN (?, ?)
     (1, 2)
 
-.. versionchanged:: 1.3.6 selectin loading can also omit the JOIN for a simple
-   many-to-one relationship.
+.. tip::
 
-.. [1] by "simple" we mean that the :paramref:`_orm.relationship.primaryjoin`
+   by "simple" we mean that the :paramref:`_orm.relationship.primaryjoin`
    condition expresses an equality comparison between the primary key of the
    "one" side and a straight foreign key of the "many" side, without any
    additional criteria.
@@ -827,25 +825,6 @@ will JOIN across all three tables to match rows from one side to the other.
 
 Things to know about this kind of loading include:
 
-* The SELECT statement emitted by the "selectin" loader strategy, unlike
-  that of "subquery", does not
-  require a subquery nor does it inherit any of the performance limitations
-  of the original query; the lookup is a simple primary key lookup and should
-  have high performance.
-
-* The special ordering requirements of subqueryload described at
-  :ref:`subqueryload_ordering` also don't apply to selectin loading; selectin
-  is always linking directly to a parent primary key and can't really
-  return the wrong result.
-
-* "selectin" loading, unlike joined or subquery eager loading, always emits its
-  SELECT in terms of the immediate parent objects just loaded, and not the
-  original type of object at the top of the chain.  So if eager loading many
-  levels deep, "selectin" loading still will not require any JOINs for simple
-  one-to-many or many-to-one relationships.   In comparison, joined and
-  subquery eager loading always refer to multiple JOINs up to the original
-  parent.
-
 * The strategy emits a SELECT for up to 500 parent primary key values at a
   time, as the primary keys are rendered into a large IN expression in the
   SQL statement.   Some databases like Oracle have a hard limit on how large
@@ -863,12 +842,6 @@ Things to know about this kind of loading include:
   particular database does start supporting this syntax, it will work without
   any changes to SQLAlchemy (as was the case with SQLite).
 
-In general, "selectin" loading is probably superior to "subquery" eager loading
-in most ways, save for the syntax requirement with composite primary keys
-and possibly that it may emit many SELECT statements for larger result sets.
-As always, developers should spend time looking at the
-statements and results generated by their applications in development to
-check that things are working efficiently.
 
 .. _subquery_eager_loading:
 
@@ -888,11 +861,13 @@ Subquery Eager Loading
    keys, on the Microsoft SQL Server backend that continues to not have
    support for the "tuple IN" syntax.
 
-Subqueryload eager loading is configured in the same manner as that of
-joined eager loading;  for the :paramref:`_orm.relationship.lazy` parameter,
-we would specify ``"subquery"`` rather than ``"joined"``, and for
-the option we use the :func:`.subqueryload` option rather than the
-:func:`_orm.joinedload` option.
+Subquery loading is similar in operation to selectin eager loading, however
+the SELECT statement which is emitted is derived from the original statement,
+and has a more complex query structure as that of selectin eager loading.
+
+Subquery eager loading is provided using the ``"subquery"`` argument to
+:paramref:`_orm.relationship.lazy` or by using the :func:`.subqueryload` loader
+option.
 
 The operation of subquery eager loading is to emit a second SELECT statement
 for each relationship to be loaded, across all result objects at once.
@@ -928,44 +903,23 @@ the collection members to load them at once:
     ORDER BY anon_1.users_id, addresses.id
     ('spongebob',)
 
-The subqueryload strategy has many advantages over joined eager loading
-in the area of loading collections.   First, it allows the original query
-to proceed without changing it at all, not introducing in particular a
-LEFT OUTER JOIN that may make it less efficient.  Secondly, it allows
-for many collections to be eagerly loaded without producing a single query
-that has many JOINs in it, which can be even less efficient; each relationship
-is loaded in a fully separate query.  Finally, because the additional query
-only needs to load the collection items and not the lead object, it can
-use an inner JOIN in all cases for greater query efficiency.
-
-Disadvantages of subqueryload include that the complexity of the original
-query is transferred to the relationship queries, which when combined with the
-use of a subquery, can on some backends in some cases (notably MySQL) produce
-significantly slow queries.   Additionally, the subqueryload strategy can only
-load the full contents of all collections at once, is therefore incompatible
-with "batched" loading supplied by :ref:`Yield Per <orm_queryguide_yield_per>`, both for collection
-and scalar relationships.
-
-The newer style of loading provided by :func:`.selectinload` solves these
-limitations of :func:`.subqueryload`.
 
-.. seealso::
-
-    :ref:`selectin_eager_loading`
-
-
-.. _subqueryload_ordering:
-
-The Importance of Ordering
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Things to know about this kind of loading include:
 
-A query which makes use of :func:`.subqueryload` in conjunction with a
-limiting modifier such as :meth:`_sql.Select.limit`,
-or :meth:`_sql.Select.offset` should **always** include :meth:`_sql.Select.order_by`
-against unique column(s) such as the primary key, so that the additional queries
-emitted by :func:`.subqueryload` include
-the same ordering as used by the parent query.  Without it, there is a chance
-that the inner query could return the wrong rows::
+* The SELECT statement emitted by the "subquery" loader strategy, unlike
+  that of "selectin", requires a subquery, and will inherit whatever performance
+  limitations are present in the original query.  The subquery itself may
+  also incur performance penalties based on the specifics of the database in
+  use.
+
+* "subquery" loading imposes some special ordering requirements in order to work
+  correctly.  A query which makes use of :func:`.subqueryload` in conjunction with a
+  limiting modifier such as :meth:`_sql.Select.limit`,
+  or :meth:`_sql.Select.offset` should **always** include :meth:`_sql.Select.order_by`
+  against unique column(s) such as the primary key, so that the additional queries
+  emitted by :func:`.subqueryload` include
+  the same ordering as used by the parent query.  Without it, there is a chance
+  that the inner query could return the wrong rows::
 
     # incorrect, no ORDER BY
     stmt = select(User).options(subqueryload(User.addresses).limit(1))
@@ -981,9 +935,27 @@ that the inner query could return the wrong rows::
         .limit(1)
     )
 
+  .. seealso::
+
+       :ref:`faq_subqueryload_limit_sort` - detailed example
+
+
+* "subquery" loading also incurs additional performance / complexity issues
+  when used on a many-levels-deep eager load, as subqueries will be nested
+  repeatedly.
+
+* "subquery" loading is not compatible with the
+  "batched" loading supplied by :ref:`Yield Per <orm_queryguide_yield_per>`, both for collection
+  and scalar relationships.
+
+For the above reasons, the "selectin" strategy should be preferred over
+"subquery".
+
 .. seealso::
 
-    :ref:`faq_subqueryload_limit_sort` - detailed example
+    :ref:`selectin_eager_loading`
+
+
 
 
 .. _what_kind_of_loading:
@@ -1042,16 +1014,18 @@ the string ``'*'`` as the argument to any of these options::
 
 Above, the ``lazyload('*')`` option will supersede the ``lazy`` setting
 of all :func:`_orm.relationship` constructs in use for that query,
-except for those which use the ``'dynamic'`` style of loading.
+with the exception of those that use ``lazy='write_only'``
+or ``lazy='dynamic'``.
+
 If some relationships specify
-``lazy='joined'`` or ``lazy='subquery'``, for example,
+``lazy='joined'`` or ``lazy='selectin'``, for example,
 using ``lazyload('*')`` will unilaterally
 cause all those relationships to use ``'select'`` loading, e.g. emit a
 SELECT statement when each attribute is accessed.
 
 The option does not supersede loader options stated in the
-query, such as :func:`.eagerload`,
-:func:`.subqueryload`, etc.  The query below will still use joined loading
+query, such as :func:`.joinedload`,
+:func:`.selectinload`, etc.  The query below will still use joined loading
 for the ``widget`` relationship::
 
     from sqlalchemy import select
@@ -1060,8 +1034,10 @@ for the ``widget`` relationship::
 
     stmt = select(MyClass).options(lazyload("*"), joinedload(MyClass.widget))
 
-If multiple ``'*'`` options are passed, the last one overrides
-those previously passed.
+While the instruction for :func:`.joinedload` above will take place regardless
+of whether it appears before or after the :func:`.lazyload` option,
+if multiple options that each included ``"*"`` were passed, the last one
+will take effect.
 
 .. _orm_queryguide_relationship_per_entity_wildcard:
 
@@ -1070,7 +1046,8 @@ Per-Entity Wildcard Loading Strategies
 
 A variant of the wildcard loader strategy is the ability to set the strategy
 on a per-entity basis.  For example, if querying for ``User`` and ``Address``,
-we can instruct all relationships on ``Address`` only to use lazy loading
+we can instruct all relationships on ``Address`` to use lazy loading,
+while leaving the loader strategies for ``User`` unaffected,
 by first applying the :class:`_orm.Load` object, then specifying the ``*`` as a
 chained option::
 
@@ -1104,18 +1081,6 @@ typically using methods like :meth:`_sql.Select.join`.
 Below, we specify a join between ``User`` and ``Address``
 and additionally establish this as the basis for eager loading of ``User.addresses``::
 
-    class User(Base):
-        __tablename__ = "user"
-        id = mapped_column(Integer, primary_key=True)
-        addresses = relationship("Address")
-
-
-    class Address(Base):
-        __tablename__ = "address"
-
-        # ...
-
-
     from sqlalchemy.orm import contains_eager
 
     stmt = select(User).join(User.addresses).options(contains_eager(User.addresses))
index 7db866f8d67e93d47b76932d97fee999d28fbce0..7967bb4d57c2964bdaf1880143de50af9b187042 100644 (file)
@@ -57,6 +57,8 @@ instances of ORM-mapped objects may be returned.  When using the
 :class:`_engine.Connection` directly, result rows will only contain
 column-level data.
 
+.. _orm_queryguide_select_orm_entities:
+
 Selecting ORM Entities
 ^^^^^^^^^^^^^^^^^^^^^^
 
index 9577b4d260d092aec787c7613347463091e198fb..9a9d79113b0ed1da27c6bda631748cb295208e8c 100644 (file)
@@ -2107,6 +2107,11 @@ class Session(_SessionClassMethods, EventTarget):
 
         .. versionadded:: 1.4.24
 
+        .. seealso::
+
+            :ref:`orm_queryguide_select_orm_entities` - contrasts the behavior
+            of :meth:`_orm.Session.execute` to :meth:`_orm.Session.scalars`
+
         """
 
         return self._execute_internal(
index bdc884d7be798b950a8a8dc8d33cf9a47f5ff8ad..7c73255d780a054ea7846232e7bd1c6cb30c258a 100644 (file)
@@ -5842,7 +5842,7 @@ class Select(
         self._raw_columns = [
             coercions.expect(roles.ColumnsClauseRole, c)
             for c in coercions._expression_collection_was_a_list(
-                "columns", "Select.with_only_columns", entities
+                "entities", "Select.with_only_columns", entities
             )
         ]
         return self
index 5ef927b157ee76ddf7283577670bafc160ab079e..72c8dc28d706712f9a25aa60681881280c73b8ea 100644 (file)
@@ -824,7 +824,7 @@ class SelectableTest(
 
         with testing.expect_raises_message(
             exc.ArgumentError,
-            r"The \"columns\" argument to "
+            r"The \"entities\" argument to "
             r"Select.with_only_columns\(\), when referring "
             "to a sequence of items, is now passed",
         ):