summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/elements.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r--lib/sqlalchemy/sql/elements.py73
1 files changed, 34 insertions, 39 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 2b994c513..57d41b06f 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -175,7 +175,7 @@ def not_(clause):
@inspection._self_inspects
class ClauseElement(
- roles.SQLRole, SupportsWrappingAnnotations, HasCacheKey, Traversible
+ roles.SQLRole, SupportsWrappingAnnotations, HasCacheKey, Traversible,
):
"""Base class for elements of a programmatically constructed SQL
expression.
@@ -215,10 +215,9 @@ class ClauseElement(
the _copy_internals() method.
"""
+ skip = self._memoized_keys
c = self.__class__.__new__(self.__class__)
- c.__dict__ = self.__dict__.copy()
- ClauseElement._cloned_set._reset(c)
- ColumnElement.comparator._reset(c)
+ c.__dict__ = {k: v for k, v in self.__dict__.items() if k not in skip}
# this is a marker that helps to "equate" clauses to each other
# when a Select returns its list of FROM clauses. the cloning
@@ -250,7 +249,7 @@ class ClauseElement(
"""
return self.__class__
- @util.memoized_property
+ @HasMemoized.memoized_attribute
def _cloned_set(self):
"""Return the set consisting all cloned ancestors of this
ClauseElement.
@@ -276,6 +275,7 @@ class ClauseElement(
def __getstate__(self):
d = self.__dict__.copy()
d.pop("_is_clone_of", None)
+ d.pop("_generate_cache_key", None)
return d
def _execute_on_connection(self, connection, multiparams, params):
@@ -740,15 +740,7 @@ class ColumnElement(
def type(self):
return type_api.NULLTYPE
- def _with_binary_element_type(self, type_):
- cloned = self._clone()
- cloned._copy_internals(
- clone=lambda element: element._with_binary_element_type(type_)
- )
- cloned.type = type_
- return cloned
-
- @util.memoized_property
+ @HasMemoized.memoized_attribute
def comparator(self):
try:
comparator_factory = self.type.comparator_factory
@@ -1022,6 +1014,7 @@ class BindParameter(roles.InElementRole, ColumnElement):
_is_crud = False
_expanding_in_types = ()
_is_bind_parameter = True
+ _key_is_anon = False
def __init__(
self,
@@ -1273,9 +1266,6 @@ class BindParameter(roles.InElementRole, ColumnElement):
"""
- if isinstance(key, ColumnClause):
- type_ = key.type
- key = key.key
if required is NO_ARG:
required = value is NO_ARG and callable_ is None
if value is NO_ARG:
@@ -1297,8 +1287,12 @@ class BindParameter(roles.InElementRole, ColumnElement):
else "param",
)
)
+ self._key_is_anon = True
+ elif key:
+ self.key = key
else:
- self.key = key or _anonymous_label("%%(%d param)s" % id(self))
+ self.key = _anonymous_label("%%(%d param)s" % id(self))
+ self._key_is_anon = True
# identifying key that won't change across
# clones, used to identify the bind's logical
@@ -1366,6 +1360,11 @@ class BindParameter(roles.InElementRole, ColumnElement):
else:
return self.value
+ def _with_binary_element_type(self, type_):
+ c = ClauseElement._clone(self)
+ c.type = type_
+ return c
+
def _clone(self):
c = ClauseElement._clone(self)
if self.unique:
@@ -1390,7 +1389,7 @@ class BindParameter(roles.InElementRole, ColumnElement):
id_,
self.__class__,
self.type._static_cache_key,
- traversals._resolve_name_for_compare(self, self.key, anon_map),
+ self.key % anon_map if self._key_is_anon else self.key,
)
def _convert_to_unique(self):
@@ -2790,7 +2789,7 @@ class Cast(WrapsColumnExpression, ColumnElement):
return self.clause
-class TypeCoerce(HasMemoized, WrapsColumnExpression, ColumnElement):
+class TypeCoerce(WrapsColumnExpression, ColumnElement):
"""Represent a Python-side type-coercion wrapper.
:class:`.TypeCoerce` supplies the :func:`.expression.type_coerce`
@@ -2815,8 +2814,6 @@ class TypeCoerce(HasMemoized, WrapsColumnExpression, ColumnElement):
("type", InternalTraversal.dp_type),
]
- _memoized_property = util.group_expirable_memoized_property()
-
def __init__(self, expression, type_):
r"""Associate a SQL expression with a particular type, without rendering
``CAST``.
@@ -2889,7 +2886,7 @@ class TypeCoerce(HasMemoized, WrapsColumnExpression, ColumnElement):
def _from_objects(self):
return self.clause._from_objects
- @_memoized_property
+ @HasMemoized.memoized_attribute
def typed_expression(self):
if isinstance(self.clause, BindParameter):
bp = self.clause._clone()
@@ -3435,7 +3432,7 @@ class BinaryExpression(ColumnElement):
# refer to BinaryExpression directly and pass strings
if isinstance(operator, util.string_types):
operator = operators.custom_op(operator)
- self._orig = (hash(left), hash(right))
+ self._orig = (left.__hash__(), right.__hash__())
self.left = left.self_group(against=operator)
self.right = right.self_group(against=operator)
self.operator = operator
@@ -3450,7 +3447,7 @@ class BinaryExpression(ColumnElement):
def __bool__(self):
if self.operator in (operator.eq, operator.ne):
- return self.operator(self._orig[0], self._orig[1])
+ return self.operator(*self._orig)
else:
raise TypeError("Boolean value of this clause is not defined")
@@ -3546,6 +3543,9 @@ class Grouping(GroupedElement, ColumnElement):
self.element = element
self.type = getattr(element, "type", type_api.NULLTYPE)
+ def _with_binary_element_type(self, type_):
+ return Grouping(self.element._with_binary_element_type(type_))
+
@util.memoized_property
def _is_implicitly_boolean(self):
return self.element._is_implicitly_boolean
@@ -4015,7 +4015,7 @@ class FunctionFilter(ColumnElement):
)
-class Label(HasMemoized, roles.LabeledColumnExprRole, ColumnElement):
+class Label(roles.LabeledColumnExprRole, ColumnElement):
"""Represents a column label (AS).
Represent a label, as typically applied to any column-level
@@ -4031,8 +4031,6 @@ class Label(HasMemoized, roles.LabeledColumnExprRole, ColumnElement):
("_element", InternalTraversal.dp_clauseelement),
]
- _memoized_property = util.group_expirable_memoized_property()
-
def __init__(self, name, element, type_=None):
"""Return a :class:`Label` object for the
given :class:`.ColumnElement`.
@@ -4075,7 +4073,7 @@ class Label(HasMemoized, roles.LabeledColumnExprRole, ColumnElement):
def _is_implicitly_boolean(self):
return self.element._is_implicitly_boolean
- @_memoized_property
+ @HasMemoized.memoized_attribute
def _allow_label_resolve(self):
return self.element._allow_label_resolve
@@ -4089,7 +4087,7 @@ class Label(HasMemoized, roles.LabeledColumnExprRole, ColumnElement):
self._type or getattr(self._element, "type", None)
)
- @_memoized_property
+ @HasMemoized.memoized_attribute
def element(self):
return self._element.self_group(against=operators.as_)
@@ -4116,7 +4114,6 @@ class Label(HasMemoized, roles.LabeledColumnExprRole, ColumnElement):
return self.element.foreign_keys
def _copy_internals(self, clone=_clone, anonymize_labels=False, **kw):
- self._reset_memoizations()
self._element = clone(self._element, **kw)
if anonymize_labels:
self.name = self._resolve_label = _anonymous_label(
@@ -4194,8 +4191,6 @@ class ColumnClause(
_is_multiparam_column = False
- _memoized_property = util.group_expirable_memoized_property()
-
def __init__(self, text, type_=None, is_literal=False, _selectable=None):
"""Produce a :class:`.ColumnClause` object.
@@ -4312,7 +4307,7 @@ class ColumnClause(
else:
return []
- @_memoized_property
+ @HasMemoized.memoized_attribute
def _from_objects(self):
t = self.table
if t is not None:
@@ -4327,18 +4322,18 @@ class ColumnClause(
else:
return self.name.encode("ascii", "backslashreplace")
- @_memoized_property
+ @HasMemoized.memoized_attribute
def _key_label(self):
if self.key != self.name:
return self._gen_label(self.key)
else:
return self._label
- @_memoized_property
+ @HasMemoized.memoized_attribute
def _label(self):
return self._gen_label(self.name)
- @_memoized_property
+ @HasMemoized.memoized_attribute
def _render_label_in_columns_clause(self):
return self.table is not None
@@ -4599,14 +4594,14 @@ def _corresponding_column_or_error(fromclause, column, require_embedded=False):
class AnnotatedColumnElement(Annotated):
def __init__(self, element, values):
Annotated.__init__(self, element, values)
- ColumnElement.comparator._reset(self)
+ self.__dict__.pop("comparator", None)
for attr in ("name", "key", "table"):
if self.__dict__.get(attr, False) is None:
self.__dict__.pop(attr)
def _with_annotations(self, values):
clone = super(AnnotatedColumnElement, self)._with_annotations(values)
- ColumnElement.comparator._reset(clone)
+ clone.__dict__.pop("comparator", None)
return clone
@util.memoized_property