Issue 1:
Migrated issue, originally created by Michael Bayer (@zzzeek)

from sqlalchemy import Integer, Column, ForeignKey
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)

class AAbs(A):
__abstract__ = True

class B1(A):
__tablename__ = 'b1'
id = Column(ForeignKey('a.id'), primary_key=True)

class B2(AAbs):
__tablename__ = 'b2'
id = Column(ForeignKey('a.id'), primary_key=True)

assert B1.__mapper__.inherits is A.__mapper__ # passes

assert B2.__mapper__.inherits is A.__mapper__ # fails

Issue 2:
Migrated issue, originally created by David Lord (@davidism)

I have the following models:

Device

DeviceSource has a foreign key and relationship to Device

LDAPDeviceSource is a joined-table inheritance of DeviceSource

In order to make defining new DeviceSource subclasses easier, I created DeviceSourceMixin, which inherits from DeviceSource and provides declared attrs for __tablename__ and the foreign primary id. DeviceSourceMixin is __abstract__ so that it doesn't create a table of its own.

The issue is that this intermediate __abstract__ seems to break the declarative model. The foreign key and relationship in DeviceSource do not get inherited by LDAPDeviceSource when subclassing DeviceSourceMixin.

This code demonstrates the issue:

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr, as_declarative
from sqlalchemy.orm import Session, relationship

engine = sa.create_engine('sqlite:///:memory:', echo=True)
session = Session(bind=engine)

@as_declarative(bind=engine)
class Base(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()

id = sa.Column(sa.Integer, primary_key=True)

class Device(Base):
pass

class DeviceSource(Base):
type = sa.Column(sa.String, nullable=False)
device_id = sa.Column(sa.Integer, sa.ForeignKey(Device.id), nullable=False)

device = relationship(Device, backref='sources')

__mapper_args__ = {
'polymorphic_on': type
}

class DeviceSourceMixin(DeviceSource):
__abstract__ = True

@declared_attr
def __tablename__(cls):
return cls.__name__.lower()

@declared_attr
def id(cls):
return sa.Column(sa.Integer, sa.ForeignKey(DeviceSource.id), primary_key=True)

class LDAPDeviceSource(DeviceSourceMixin):
name = sa.Column(sa.String, nullable=False)

__mapper_args__ = {
'polymorphic_identity': 'ldap'
}

Base.metadata.create_all()
d1 = Device()
s1 = LDAPDeviceSource(device=d1, name='s1')
session.add(s1)
session.commit()

It produces the following error:

Traceback (most recent call last):
File "/home/david/Projects/cedar/example2.py", line 62, in <module>
s1 = LDAPDeviceSource(device=d1, name='s1')
File "<string>", line 4, in __init__
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/state.py", line 260, in _initialize_instance
return manager.original_init(*mixed[1:], **kwargs)
File "<string>", line 6, in __init__
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 526, in _declarative_constructor
setattr(self, k, kwargs[k])
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 226, in __set__
instance_dict(instance), value, None)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 812, in set
value = self.fire_replace_event(state, dict_, value, old, initiator)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 832, in fire_replace_event
state, value, previous, initiator or self._replace_token)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 1148, in emit_backref_from_scalar_set_event
passive=PASSIVE_NO_FETCH)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 980, in append
collection.append_with_event(value, initiator)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/collections.py", line 653, in append_with_event
self._data()._sa_appender(item, _sa_initiator=initiator)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/collections.py", line 1047, in append
item = __set(self, item, _sa_initiator)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/collections.py", line 1019, in __set
item = executor.fire_append_event(item, _sa_initiator)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/collections.py", line 716, in fire_append_event
item, initiator)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 929, in fire_append_event
value = fn(state, value, initiator or self._append_token)
File "/home/david/.virtualenvs/cedar/lib/python3.4/site-packages/sqlalchemy/orm/attributes.py", line 1157, in emit_backref_from_collection_append_event
child_impl = child_state.manager[key].impl
KeyError: 'device'