summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--lib/sqlalchemy/ext/declarative.py2
-rw-r--r--test/ext/test_declarative.py35
3 files changed, 39 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index db32156f9..a14e39dbd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -71,6 +71,11 @@ CHANGES
- The psycopg2 dialect will log NOTICE messages via the
"sqlalchemy.dialects.postgresql" logger name.
[ticket:877]
+
+- declarative
+ - Using a mixin won't break if the mixin implements an
+ unpredictable __getattribute__(), i.e. Zope interfaces.
+ [ticket:1746]
0.6beta2
========
diff --git a/lib/sqlalchemy/ext/declarative.py b/lib/sqlalchemy/ext/declarative.py
index 775efbff1..435d38161 100644
--- a/lib/sqlalchemy/ext/declarative.py
+++ b/lib/sqlalchemy/ext/declarative.py
@@ -545,7 +545,7 @@ def _as_declarative(cls, classname, dict_):
names = dir(base)
if not _is_mapped_class(base):
for name in names:
- obj = getattr(base,name)
+ obj = getattr(base,name, None)
if isinstance(obj, Column):
dict_[name]=column_copies[obj]=obj.copy()
get_mapper_args = get_mapper_args or getattr(base,'__mapper_args__',None)
diff --git a/test/ext/test_declarative.py b/test/ext/test_declarative.py
index a6f3f7a79..fbe47ee7f 100644
--- a/test/ext/test_declarative.py
+++ b/test/ext/test_declarative.py
@@ -6,7 +6,9 @@ import sqlalchemy as sa
from sqlalchemy.test import testing
from sqlalchemy import MetaData, Integer, String, ForeignKey, ForeignKeyConstraint, asc, Index
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import relationship, create_session, class_mapper, joinedload, compile_mappers, backref, clear_mappers, polymorphic_union, deferred
+from sqlalchemy.orm import relationship, create_session, class_mapper, \
+ joinedload, compile_mappers, backref, clear_mappers, \
+ polymorphic_union, deferred
from sqlalchemy.test.testing import eq_
from sqlalchemy.util import classproperty
@@ -75,7 +77,9 @@ class DeclarativeTest(DeclarativeTestBase):
__table__ = t
foo = Column(Integer, primary_key=True)
# can't specify new columns not already in the table
- assert_raises_message(sa.exc.ArgumentError, "Can't add additional column 'foo' when specifying __table__", go)
+ assert_raises_message(sa.exc.ArgumentError,
+ "Can't add additional column 'foo' when specifying __table__",
+ go)
# regular re-mapping works tho
class Bar(Base):
@@ -84,6 +88,33 @@ class DeclarativeTest(DeclarativeTestBase):
assert class_mapper(Bar).get_property('some_data').columns[0] is t.c.data
+ def test_difficult_class(self):
+ """test no getattr() errors with a customized class"""
+
+ # metaclass to mock the way zope.interface breaks getattr()
+ class BrokenMeta(type):
+ def __getattribute__(self, attr):
+ if attr == 'xyzzy':
+ raise AttributeError, 'xyzzy'
+ else:
+ return object.__getattribute__(self,attr)
+
+ # even though this class has an xyzzy attribute, getattr(cls,"xyzzy")
+ # fails
+ class BrokenParent(object):
+ __metaclass__ = BrokenMeta
+ xyzzy = "magic"
+
+ # _as_declarative() inspects obj.__class__.__bases__
+ class User(BrokenParent,ComparableEntity):
+ __tablename__ = 'users'
+ id = Column('id', Integer, primary_key=True,
+ test_needs_autoincrement=True)
+ name = Column('name', String(50))
+
+ decl.instrument_declarative(User,{},Base.metadata)
+
+
def test_undefer_column_name(self):
# TODO: not sure if there was an explicit
# test for this elsewhere