summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authorGord Thompson <gord@gordthompson.com>2021-01-09 14:56:38 -0700
committerMike Bayer <mike_mp@zzzcomputing.com>2021-01-26 16:52:30 -0500
commit22f65156bbe846dea2fb9f87fe4187abe0ed790a (patch)
treef49338a10dd2800d4d754b14d2e7fd549b4b833f /lib/sqlalchemy/orm
parent7bdb1f30f66aaea16efbcf96e314491058493e6c (diff)
downloadsqlalchemy-22f65156bbe846dea2fb9f87fe4187abe0ed790a.tar.gz
Replace with_labels() and apply_labels() in ORM/Core
Replace :meth:`_orm.Query.with_labels` and :meth:`_sql.GenerativeSelect.apply_labels` with explicit getters and setters ``get_label_style`` and ``set_label_style`` to accommodate the three supported label styles: ``LABEL_STYLE_DISAMBIGUATE_ONLY`` (default), ``LABEL_STYLE_TABLENAME_PLUS_COL``, and ``LABEL_STYLE_NONE``. In addition, for Core and "future style" ORM queries, ``LABEL_STYLE_DISAMBIGUATE_ONLY`` is now the default label style. This style differs from the existing "no labels" style in that labeling is applied in the case of column name conflicts; with ``LABEL_STYLE_NONE``, a duplicate column name is not accessible via name in any case. For legacy ORM queries using :class:`_query.Query`, the table-plus-column names labeling style applied by ``LABEL_STYLE_TABLENAME_PLUS_COL`` continues to be used so that existing test suites and logging facilities see no change in behavior by default, however this style of labeling is no longer required for SQLAlchemy queries to function, as result sets are commonly matched to columns using a positional approach since SQLAlchemy 1.0. Within test suites, all use of apply_labels() / use_labels now uses the new methods. New tests added to test/sql/test_deprecations.py nad test/orm/test_deprecations.py to cover just the old apply_labels() method call. Tests in ORM that made explicit use apply_labels()/ etc. where it isn't needed for the ORM to work correctly use default label style now. Co-authored-by: Mike Bayer <mike_mp@zzzcomputing.com> Fixes: #4757 Change-Id: I5fdcd2ed4ae8c7fe62f8be2b6d0e8f66409b6a54
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/context.py6
-rw-r--r--lib/sqlalchemy/orm/loading.py5
-rw-r--r--lib/sqlalchemy/orm/mapper.py7
-rw-r--r--lib/sqlalchemy/orm/persistence.py5
-rw-r--r--lib/sqlalchemy/orm/query.py57
-rw-r--r--lib/sqlalchemy/orm/session.py11
-rw-r--r--lib/sqlalchemy/orm/strategies.py11
7 files changed, 73 insertions, 29 deletions
diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py
index 584a07970..f9a0b72fe 100644
--- a/lib/sqlalchemy/orm/context.py
+++ b/lib/sqlalchemy/orm/context.py
@@ -373,9 +373,11 @@ class ORMFromStatementCompileState(ORMCompileState):
if (
isinstance(statement, expression.SelectBase)
and not statement._is_textual
- and not statement.use_labels
+ and statement._label_style is util.symbol("LABEL_STYLE_NONE")
):
- self.statement = statement.apply_labels()
+ self.statement = statement.set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ )
else:
self.statement = statement
self.order_by = None
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 3a85a2d7f..6c38931b4 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -31,6 +31,7 @@ from ..engine.result import ChunkedIteratorResult
from ..engine.result import FrozenResult
from ..engine.result import SimpleResultMetaData
from ..sql import util as sql_util
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
_new_runid = util.counter()
@@ -1396,7 +1397,9 @@ def load_scalar_attributes(mapper, state, attribute_names, passive):
result = load_on_ident(
session,
- future.select(mapper).apply_labels(),
+ future.select(mapper).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ ),
identity_key,
refresh_state=state,
only_load_props=attribute_names,
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 9ac0c85c6..5a9bc102e 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -54,6 +54,7 @@ from ..sql import operators
from ..sql import roles
from ..sql import util as sql_util
from ..sql import visitors
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
from ..util import HasMemoized
@@ -3008,7 +3009,11 @@ class Mapper(
cols = []
for key in col_attribute_names:
cols.extend(props[key].columns)
- return sql.select(*cols).where(cond).apply_labels()
+ return (
+ sql.select(*cols)
+ .where(cond)
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ )
def _iterate_to_target_viawpoly(self, mapper):
if self.isa(mapper):
diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index 42b787580..7ba3a26d0 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -40,6 +40,7 @@ from ..sql.base import Options
from ..sql.dml import DeleteDMLState
from ..sql.dml import UpdateDMLState
from ..sql.elements import BooleanClauseList
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
def _bulk_insert(
@@ -1521,7 +1522,9 @@ def _finalize_insert_update_commands(base_mapper, uowtransaction, states):
if toload_now:
state.key = base_mapper._identity_key_from_state(state)
- stmt = future.select(mapper).apply_labels()
+ stmt = future.select(mapper).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ )
loading.load_on_ident(
uowtransaction.session,
stmt,
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 5dd2a8a21..1422fd6a1 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -470,7 +470,7 @@ class Query(
"""
q = self.enable_eagerloads(False)
if with_labels:
- q = q.with_labels()
+ q = q.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
q = q.statement
@@ -576,7 +576,11 @@ class Query(
return self.enable_eagerloads(False).statement.scalar_subquery()
def __clause_element__(self):
- return self.enable_eagerloads(False).with_labels().statement
+ return (
+ self.enable_eagerloads(False)
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ .statement
+ )
@_generative
def only_return_tuples(self, value):
@@ -637,8 +641,27 @@ class Query(
"""
self._compile_options += {"_enable_eagerloads": value}
- @_generative
+ @util.deprecated_20(
+ ":meth:`_orm.Query.with_labels` and :meth:`_orm.Query.apply_labels`",
+ alternative="Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) "
+ "instead.",
+ )
def with_labels(self):
+ return self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+
+ apply_labels = with_labels
+
+ @property
+ def get_label_style(self):
+ """
+ Retrieve the current label style.
+
+ .. versionadded:: 1.4
+
+ """
+ return self._label_style
+
+ def set_label_style(self, style):
"""Apply column labels to the return value of Query.statement.
Indicates that this Query's `statement` accessor should return
@@ -650,26 +673,28 @@ class Query(
When the `Query` actually issues SQL to load rows, it always
uses column labeling.
- .. note:: The :meth:`_query.Query.with_labels` method *only* applies
+ .. note:: The :meth:`_query.Query.set_label_style` method *only* applies
the output of :attr:`_query.Query.statement`, and *not* to any of
the result-row invoking systems of :class:`_query.Query` itself,
e.g.
:meth:`_query.Query.first`, :meth:`_query.Query.all`, etc.
To execute
- a query using :meth:`_query.Query.with_labels`, invoke the
+ a query using :meth:`_query.Query.set_label_style`, invoke the
:attr:`_query.Query.statement` using :meth:`.Session.execute`::
- result = session.execute(query.with_labels().statement)
-
-
- """
- self._label_style = LABEL_STYLE_TABLENAME_PLUS_COL
+ result = session.execute(
+ query
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ .statement
+ )
- apply_labels = with_labels
+ .. versionadded:: 1.4
- @property
- def use_labels(self):
- return self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL
+ """ # noqa
+ if self._label_style is not style:
+ self = self._generate()
+ self._label_style = style
+ return self
@_generative
def enable_assertions(self, value):
@@ -1259,7 +1284,7 @@ class Query(
def _from_self(self, *entities):
fromclause = (
- self.with_labels()
+ self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
.enable_eagerloads(False)
.correlate(None)
.subquery()
@@ -2903,7 +2928,7 @@ class Query(
inner = (
self.enable_eagerloads(False)
.add_columns(sql.literal_column("1"))
- .with_labels()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
.statement.with_only_columns(1)
)
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 8a7a64f78..06a69b425 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -37,6 +37,7 @@ from ..sql import dml
from ..sql import roles
from ..sql import visitors
from ..sql.base import CompileState
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
__all__ = ["Session", "SessionTransaction", "sessionmaker"]
@@ -2741,15 +2742,17 @@ class Session(_SessionClassMethods):
elif instance is attributes.PASSIVE_CLASS_MISMATCH:
return None
- # apply_labels() not strictly necessary, however this will ensure that
- # tablename_colname style is used which at the moment is asserted
- # in a lot of unit tests :)
+ # set_label_style() not strictly necessary, however this will ensure
+ # that tablename_colname style is used which at the moment is
+ # asserted in a lot of unit tests :)
load_options = context.QueryContext.default_load_options
if populate_existing:
load_options += {"_populate_existing": populate_existing}
- statement = sql.select(mapper).apply_labels()
+ statement = sql.select(mapper).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ )
if with_for_update is not None:
statement._for_update_arg = query.ForUpdateArg._from_argument(
with_for_update
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 837d4d548..c80b8f5a2 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -41,6 +41,7 @@ from .. import sql
from .. import util
from ..sql import util as sql_util
from ..sql import visitors
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
def _register_attribute(
@@ -487,7 +488,9 @@ class DeferredColumnLoader(LoaderStrategy):
if (
loading.load_on_ident(
session,
- sql.select(localparent).apply_labels(),
+ sql.select(localparent).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ ),
state.key,
only_load_props=group,
refresh_state=state,
@@ -901,7 +904,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
stmt = sql.lambda_stmt(
lambda: sql.select(self.entity)
- .apply_labels()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
._set_compile_options(ORMCompileState.default_compile_options),
global_track_bound_values=False,
lambda_cache=self._query_cache,
@@ -1304,7 +1307,7 @@ class SubqueryLoader(PostLoader):
# which we'll join onto.
# LEGACY: as "q" is a Query, the before_compile() event is invoked
# here.
- embed_q = q.apply_labels().subquery()
+ embed_q = q.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL).subquery()
left_alias = orm_util.AliasedClass(
leftmost_mapper, embed_q, use_mapper_path=True
)
@@ -2751,7 +2754,7 @@ class SelectInLoader(PostLoader, util.MemoizedSlots):
lambda: sql.select(
orm_util.Bundle("pk", *pk_cols), effective_entity
)
- .apply_labels()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
._set_compile_options(ORMCompileState.default_compile_options)
._set_propagate_attrs(
{