-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Closed
Labels
Milestone
Description
Migrated issue, originally created by Konsta Vesterinen (@kvesteri)
Before SA 1.0 I could have denormalized schemas where foreign keys pointed to unhashable types (let's say HSTORE). This was very common in same cases for me as I had for example denormalized translation columns using HSTORE as the underlying data type. Then foreign keys with onupdate='CASCADE' where used for automatic real-time denormalization when data changed. I created a simplified test case:
import sqlalchemy as sa
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import HSTORE
engine = sa.create_engine(
'postgres://postgres@localhost/sqlalchemy_utils_test'
)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
session.execute('CREATE EXTENSION IF NOT EXISTS hstore')
session.commit()
class Category(Base):
__tablename__ = 'category'
id = sa.Column(sa.Integer, primary_key=True)
data = sa.Column(HSTORE)
__table_args__ = (
sa.Index(
'some_index',
data,
id,
unique=True
),
)
class Article(Base):
__tablename__ = 'article'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String)
category_id = sa.Column(sa.Integer)
category_data = sa.Column(HSTORE)
category = sa.orm.relationship(Category)
__table_args__ = (
sa.ForeignKeyConstraint(
[category_data, category_id],
['category.data', 'category.id'],
onupdate='CASCADE'
),
)
Base.metadata.create_all(bind=session.bind)
article = Article(name='Some article', category=Category(data={'1': '2'}))
session.add(article)
session.commit()
category = Category(data={'2': '2'})
session.commit()
article.category = category
session.commit()
Base.metadata.drop_all(bind=session.bind)
throws Exception
...
elif orm_util._never_set.intersection(params.values()):
TypeError: unhashable type: 'dict'
The problem is even deeper than this as the following code block illustrates:
import sqlalchemy as sa
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import HSTORE
engine = sa.create_engine(
'postgres://postgres@localhost/sqlalchemy_utils_test'
)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
session.execute('CREATE EXTENSION IF NOT EXISTS hstore')
session.commit()
class Article(Base):
__tablename__ = 'article'
id = sa.Column(HSTORE, primary_key=True)
Base.metadata.create_all(bind=session.bind)
article = Article(id={'1': '2'})
session.add(article)
session.commit()
Base.metadata.drop_all(bind=session.bind)
Which throws exception:
Traceback (most recent call last):
File "sa_test.py", line 42, in <module>
session.commit()
File ".../sqlalchemy/orm/session.py", line 790, in commit
self.transaction.commit()
File ".../sqlalchemy/orm/session.py", line 392, in commit
self._prepare_impl()
File ".../sqlalchemy/orm/session.py", line 372, in _prepare_impl
self.session.flush()
File ".../sqlalchemy/orm/session.py", line 2004, in flush
self._flush(objects)
File ".../sqlalchemy/orm/session.py", line 2122, in _flush
transaction.rollback(_capture_exception=True)
File ".../sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File ".../sqlalchemy/util/compat.py", line 182, in reraise
raise value
File ".../sqlalchemy/orm/session.py", line 2086, in _flush
flush_context.execute()
File ".../sqlalchemy/orm/unitofwork.py", line 373, in execute
rec.execute(self)
File ".../sqlalchemy/orm/unitofwork.py", line 532, in execute
uow
File ".../sqlalchemy/orm/persistence.py", line 149, in save_obj
base_mapper, states, uowtransaction
File ".../sqlalchemy/orm/persistence.py", line 292, in _organize_states_for_save
instance_key in uowtransaction.session.identity_map:
File ".../sqlalchemy/orm/identity.py", line 96, in __contains__
if key in self._dict:
TypeError: unhashable type: 'dict'
The second issue is not critical for me but the first is. I have many projects using HSTORE based translations and denormalization.
Reactions are currently unavailable