summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-03-22 22:56:36 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2021-03-23 13:45:52 -0400
commit9ec860e7a5c944799f9ef4de9069d707cfc1ed27 (patch)
treed02f035c3f2210e4760d39b73db738f993960e16 /lib/sqlalchemy
parent2b7518ad7b4c4bb4ae6bd07221d349ac1a6af9a5 (diff)
downloadsqlalchemy-9ec860e7a5c944799f9ef4de9069d707cfc1ed27.tar.gz
Remove internal use of string attr in loader option
Fixed issue where a "removed in 2.0" warning were generated internally by the relationship loader mechanics. This changeset started the effort of converting all string usage in the test suite, however this is a much longer job as the use of strings in loader options is widespread. In particular I'm not totally comfortable with strings not being accepted in obvious spots like Load(User).load_only("x", "y", "z"), which points to a new string expecting functionality that's not what's there now. However at the moment it seems like we need to continue removing all support for strings and then figure out "immediate strings from an explicit class" later. Fixes: #6115 Change-Id: I6b314d135d2bc049fd66500914b772c1fe60b5b3
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/interfaces.py1
-rw-r--r--lib/sqlalchemy/orm/strategies.py2
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py136
-rw-r--r--lib/sqlalchemy/testing/assertions.py17
4 files changed, 87 insertions, 69 deletions
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 7aae9ec37..a660d7e1a 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -83,6 +83,7 @@ class ORMFromClauseRole(roles.StrictFromClauseRole):
_role_name = "ORM mapped entity, aliased entity, or FROM expression"
+@inspection._self_inspects
class MapperProperty(
HasCacheKey, _MappedAttribute, InspectionAttr, util.MemoizedSlots
):
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 339a5bcf1..b11758090 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -992,7 +992,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
compile_context.compile_options._current_path[
rev.parent
]
- ).lazyload(rev.key).process_compile_state(compile_context)
+ ).lazyload(rev).process_compile_state(compile_context)
stmt = stmt.add_criteria(
lambda stmt: stmt._add_context_option(
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 932c4a37d..ba4e5c466 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -234,84 +234,90 @@ class Load(Generative, LoaderOption):
raise
path = path[attr]
- elif _is_mapped_class(attr):
- # TODO: this does not appear to be a valid codepath. "attr"
- # would never be a mapper. This block is present in 1.2
- # as well however does not seem to be accessed in any tests.
- if not orm_util._entity_corresponds_to_use_path_impl(
- attr.parent, path[-1]
- ):
- if raiseerr:
- raise sa_exc.ArgumentError(
- "Attribute '%s' does not "
- "link from element '%s'" % (attr, path.entity)
- )
- else:
- return None
else:
- prop = found_property = attr.property
-
- if not orm_util._entity_corresponds_to_use_path_impl(
- attr.parent, path[-1]
- ):
- if raiseerr:
- raise sa_exc.ArgumentError(
- 'Attribute "%s" does not '
- 'link from element "%s".%s'
- % (
- attr,
- path.entity,
- (
- " Did you mean to use "
- "%s.of_type(%s)?"
- % (path[-2], attr.class_.__name__)
- if len(path) > 1
- and path.entity.is_mapper
- and attr.parent.is_aliased_class
- else ""
- ),
+ insp = inspect(attr)
+
+ if insp.is_mapper or insp.is_aliased_class:
+ # TODO: this does not appear to be a valid codepath. "attr"
+ # would never be a mapper. This block is present in 1.2
+ # as well however does not seem to be accessed in any tests.
+ if not orm_util._entity_corresponds_to_use_path_impl(
+ attr.parent, path[-1]
+ ):
+ if raiseerr:
+ raise sa_exc.ArgumentError(
+ "Attribute '%s' does not "
+ "link from element '%s'" % (attr, path.entity)
)
- )
- else:
- return None
+ else:
+ return None
+ elif insp.is_property:
+ prop = found_property = attr
+ path = path[prop]
+ elif insp.is_attribute:
+ prop = found_property = attr.property
- if attr._extra_criteria:
- self._extra_criteria = attr._extra_criteria
+ if not orm_util._entity_corresponds_to_use_path_impl(
+ attr.parent, path[-1]
+ ):
+ if raiseerr:
+ raise sa_exc.ArgumentError(
+ 'Attribute "%s" does not '
+ 'link from element "%s".%s'
+ % (
+ attr,
+ path.entity,
+ (
+ " Did you mean to use "
+ "%s.of_type(%s)?"
+ % (path[-2], attr.class_.__name__)
+ if len(path) > 1
+ and path.entity.is_mapper
+ and attr.parent.is_aliased_class
+ else ""
+ ),
+ )
+ )
+ else:
+ return None
- if getattr(attr, "_of_type", None):
- ac = attr._of_type
- ext_info = of_type_info = inspect(ac)
+ if attr._extra_criteria:
+ self._extra_criteria = attr._extra_criteria
- if polymorphic_entity_context is None:
- polymorphic_entity_context = self.context
+ if getattr(attr, "_of_type", None):
+ ac = attr._of_type
+ ext_info = of_type_info = inspect(ac)
- existing = path.entity_path[prop].get(
- polymorphic_entity_context, "path_with_polymorphic"
- )
+ if polymorphic_entity_context is None:
+ polymorphic_entity_context = self.context
- if not ext_info.is_aliased_class:
- ac = orm_util.with_polymorphic(
- ext_info.mapper.base_mapper,
- ext_info.mapper,
- aliased=True,
- _use_mapper_path=True,
- _existing_alias=inspect(existing)
- if existing is not None
- else None,
+ existing = path.entity_path[prop].get(
+ polymorphic_entity_context, "path_with_polymorphic"
)
- ext_info = inspect(ac)
+ if not ext_info.is_aliased_class:
+ ac = orm_util.with_polymorphic(
+ ext_info.mapper.base_mapper,
+ ext_info.mapper,
+ aliased=True,
+ _use_mapper_path=True,
+ _existing_alias=inspect(existing)
+ if existing is not None
+ else None,
+ )
- path.entity_path[prop].set(
- polymorphic_entity_context, "path_with_polymorphic", ac
- )
+ ext_info = inspect(ac)
- path = path[prop][ext_info]
+ path.entity_path[prop].set(
+ polymorphic_entity_context, "path_with_polymorphic", ac
+ )
- self._of_type = of_type_info
+ path = path[prop][ext_info]
- else:
- path = path[prop]
+ self._of_type = of_type_info
+
+ else:
+ path = path[prop]
if for_strategy is not None:
found_property._get_strategy(for_strategy)
diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py
index 289ac9a0a..02137474b 100644
--- a/lib/sqlalchemy/testing/assertions.py
+++ b/lib/sqlalchemy/testing/assertions.py
@@ -135,7 +135,12 @@ def uses_deprecated(*messages):
@contextlib.contextmanager
def _expect_warnings(
- exc_cls, messages, regex=True, assert_=True, py2konly=False
+ exc_cls,
+ messages,
+ regex=True,
+ assert_=True,
+ py2konly=False,
+ raise_on_any_unexpected=False,
):
if regex:
@@ -145,7 +150,13 @@ def _expect_warnings(
seen = set(filters)
- real_warn = warnings.warn
+ if raise_on_any_unexpected:
+
+ def real_warn(msg, *arg, **kw):
+ raise AssertionError("Got unexpected warning: %r" % msg)
+
+ else:
+ real_warn = warnings.warn
def our_warn(msg, *arg, **kw):
if isinstance(msg, exc_cls):
@@ -159,7 +170,7 @@ def _expect_warnings(
if not exception or not issubclass(exception, exc_cls):
return real_warn(msg, *arg, **kw)
- if not filters:
+ if not filters and not raise_on_any_unexpected:
return
for filter_ in filters: