summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqlalchemy/orm/attributes.py6
-rw-r--r--lib/sqlalchemy/orm/collections.py17
-rw-r--r--lib/sqlalchemy/orm/identity.py9
-rw-r--r--lib/sqlalchemy/orm/interfaces.py8
-rw-r--r--lib/sqlalchemy/orm/mapper.py11
-rw-r--r--lib/sqlalchemy/orm/properties.py2
-rw-r--r--lib/sqlalchemy/orm/strategies.py14
-rw-r--r--lib/sqlalchemy/schema.py6
-rw-r--r--lib/sqlalchemy/util/_collections.py3
-rw-r--r--test/orm/inheritance/test_poly_linked_list.py2
10 files changed, 48 insertions, 30 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 002215268..2ffffc034 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -340,8 +340,6 @@ class AttributeImpl(object):
callable_ = None
if callable_ is not None:
- #if passive is not PASSIVE_OFF:
- # return PASSIVE_NO_RESULT
value = callable_(passive=passive)
if value is PASSIVE_NO_RESULT:
return value
@@ -790,10 +788,8 @@ class CollectionAttributeImpl(AttributeImpl):
collection, user_data = self._initialize_collection(state)
if value:
- for item in value:
- collection.append_without_event(item)
+ collection.append_multiple_without_event(value)
- state.callables.pop(self.key, None)
state.dict[self.key] = user_data
state.commit(dict_, [self.key])
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index b52329523..99e6464f2 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -471,6 +471,9 @@ class CollectionAdapter(object):
The ORM uses an CollectionAdapter exclusively for interaction with
entity collections.
+ The usage of getattr()/setattr() is currently to allow injection
+ of custom methods, such as to unwrap Zope security proxies.
+
"""
def __init__(self, attr, owner_state, data):
self._key = attr.key
@@ -553,6 +556,12 @@ class CollectionAdapter(object):
"""Add or restore an entity to the collection, firing no events."""
getattr(self._data(), '_sa_appender')(item, _sa_initiator=False)
+ def append_multiple_without_event(self, items):
+ """Add or restore an entity to the collection, firing no events."""
+ appender = getattr(self._data(), '_sa_appender')
+ for item in items:
+ appender(item, _sa_initiator=False)
+
def remove_with_event(self, item, initiator=None):
"""Remove an entity from the collection, firing mutation events."""
getattr(self._data(), '_sa_remover')(item, _sa_initiator=initiator)
@@ -563,13 +572,17 @@ class CollectionAdapter(object):
def clear_with_event(self, initiator=None):
"""Empty the collection, firing a mutation event for each entity."""
+
+ remover = getattr(self._data(), '_sa_remover')
for item in list(self):
- self.remove_with_event(item, initiator)
+ remover(item, _sa_initiator=initiator)
def clear_without_event(self):
"""Empty the collection, firing no events."""
+
+ remover = getattr(self._data(), '_sa_remover')
for item in list(self):
- self.remove_without_event(item)
+ remover(item, _sa_initiator=False)
def __iter__(self):
"""Iterate over entities in the collection."""
diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py
index 30c3a06b7..8604c0008 100644
--- a/lib/sqlalchemy/orm/identity.py
+++ b/lib/sqlalchemy/orm/identity.py
@@ -152,17 +152,16 @@ class WeakInstanceDict(IdentityMap):
self._manage_removed_state(state)
def get(self, key, default=None):
- state = dict.get(self, key, default)
- if state is default:
+ if not dict.__contains__(self, key):
return default
+ state = dict.__getitem__(self, key)
o = state.obj()
if o is None:
o = state._is_really_none()
- if o is None:
- return default
+ if o is None:
+ return default
return o
-
def items(self):
# Py2K
return list(self.iteritems())
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 2a9d3760b..e917c675a 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -315,7 +315,7 @@ class StrategizedProperty(MapperProperty):
_reduce_path(path)), None)
if cls:
try:
- return self.__all_strategies[cls]
+ return self._strategies[cls]
except KeyError:
return self.__init_strategy(cls)
else:
@@ -323,12 +323,12 @@ class StrategizedProperty(MapperProperty):
def _get_strategy(self, cls):
try:
- return self.__all_strategies[cls]
+ return self._strategies[cls]
except KeyError:
return self.__init_strategy(cls)
def __init_strategy(self, cls):
- self.__all_strategies[cls] = strategy = cls(self)
+ self._strategies[cls] = strategy = cls(self)
strategy.init()
return strategy
@@ -341,7 +341,7 @@ class StrategizedProperty(MapperProperty):
create_row_processor(context, path, mapper, row, adapter)
def do_init(self):
- self.__all_strategies = {}
+ self._strategies = {}
self.strategy = self.__init_strategy(self.strategy_class)
def post_instrument_class(self, mapper):
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 2b050ebff..48c37f80d 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -519,7 +519,7 @@ class Mapper(object):
"key columns for mapped table '%s'" %
(self, self.mapped_table.description))
- self.primary_key = primary_key
+ self.primary_key = tuple(primary_key)
self._log("Identified primary key columns: %s", primary_key)
def _configure_properties(self):
@@ -1287,8 +1287,13 @@ class Mapper(object):
def _get_committed_state_attr_by_column(self, state, dict_, column,
passive=False):
- return self._columntoproperty[column]._getcommitted(
- state, dict_, column, passive=passive)
+
+ prop = self._columntoproperty[column]
+ value = state.manager[prop.key].impl.\
+ get_committed_value(state, dict_, passive=passive)
+ if prop.get_col_value:
+ value = prop.get_col_value(column, value)
+ return value
def _optimized_get_statement(self, state, attribute_names):
"""assemble a WHERE clause which retrieves a given state by primary
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index d628d87dc..239159f3e 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -104,7 +104,7 @@ class ColumnProperty(StrategizedProperty):
def do_init(self):
super(ColumnProperty, self).do_init()
if len(self.columns) > 1 and \
- self.parent.primary_key.issuperset(self.columns):
+ set(self.parent.primary_key).issuperset(self.columns):
util.warn(
("On mapper %s, primary key column '%s' is being combined "
"with distinct primary key column '%s' in attribute '%s'. "
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index d6fb0c005..ab7a181a7 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -580,9 +580,10 @@ class LoadLazyAttribute(object):
def __call__(self, passive=False):
state, key = self.state, self.key
- instance_mapper = mapper._state_mapper(state)
+ instance_mapper = state.manager.mapper
prop = instance_mapper._props[key]
- strategy = prop._get_strategy(LazyLoader)
+ prop_mapper = prop.mapper
+ strategy = prop._strategies[LazyLoader]
pending = not state.key
if (
@@ -595,7 +596,7 @@ class LoadLazyAttribute(object):
return attributes.PASSIVE_NO_RESULT
session = sessionlib._state_session(state)
- if session is None:
+ if not session:
raise orm_exc.DetachedInstanceError(
"Parent instance %s is not bound to a Session; "
"lazy load operation of attribute '%s' cannot proceed" %
@@ -610,13 +611,14 @@ class LoadLazyAttribute(object):
else:
get_attr = instance_mapper._get_state_attr_by_column
+ dict_ = state.dict
ident = [
get_attr(
state,
state.dict,
strategy._equated_columns[pk],
passive=passive)
- for pk in prop.mapper.primary_key
+ for pk in prop_mapper.primary_key
]
if attributes.PASSIVE_NO_RESULT in ident:
return attributes.PASSIVE_NO_RESULT
@@ -624,14 +626,14 @@ class LoadLazyAttribute(object):
if _none_set.issuperset(ident):
return None
- ident_key = prop.mapper.identity_key_from_primary_key(ident)
+ ident_key = prop_mapper.identity_key_from_primary_key(ident)
instance = Query._get_from_identity(session, ident_key, passive)
if instance is not None:
return instance
elif passive is attributes.PASSIVE_NO_FETCH:
return attributes.PASSIVE_NO_RESULT
- q = session.query(prop.mapper)._adapt_all_clauses()
+ q = session.query(prop_mapper)._adapt_all_clauses()
# don't autoflush on pending
if pending:
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index cb6b27e36..67f37e763 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -1591,7 +1591,11 @@ class ColumnCollectionConstraint(Constraint):
return self.columns.contains_column(col)
def __iter__(self):
- return iter(self.columns)
+ # inlining of
+ # return iter(self.columns)
+ # ColumnCollection->OrderedProperties->OrderedDict
+ ordered_dict = self.columns._data
+ return (ordered_dict[key] for key in ordered_dict._list)
def __len__(self):
return len(self.columns)
diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py
index 98c894e5b..022da2de8 100644
--- a/lib/sqlalchemy/util/_collections.py
+++ b/lib/sqlalchemy/util/_collections.py
@@ -18,10 +18,9 @@ class NamedTuple(tuple):
"""
def __new__(cls, vals, labels=None):
- vals = list(vals)
t = tuple.__new__(cls, vals)
if labels:
- t.__dict__ = dict(itertools.izip(labels, vals))
+ t.__dict__.update(zip(labels, vals))
t._labels = labels
return t
diff --git a/test/orm/inheritance/test_poly_linked_list.py b/test/orm/inheritance/test_poly_linked_list.py
index 8b300f06a..db622920a 100644
--- a/test/orm/inheritance/test_poly_linked_list.py
+++ b/test/orm/inheritance/test_poly_linked_list.py
@@ -113,7 +113,7 @@ class PolymorphicCircularTest(_base.MappedTest):
table3_mapper = mapper(Table3, table3, inherits=table1_mapper, polymorphic_identity='table3')
configure_mappers()
- assert table1_mapper.primary_key == [table1.c.id], table1_mapper.primary_key
+ assert table1_mapper.primary_key == (table1.c.id,), table1_mapper.primary_key
@testing.fails_on('maxdb', 'FIXME: unknown')
def testone(self):