Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

collection_class=set is not supported #100

Open
ptallada opened this issue Oct 16, 2015 · 2 comments
Open

collection_class=set is not supported #100

ptallada opened this issue Oct 16, 2015 · 2 comments
Labels
Milestone

Comments

@ptallada
Copy link

Hi!

I have a model with some relationships configured with collection_class=set.
But when I try to insert a new record it tries to call the constructor with the collection as a list, and that fails with following error.

A workaround is to override the class constructor. But maybe it is better if pyramid_sacrud could cast the iterable to the collection_class type.

Traceback (most recent call last):
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/pyramid_sacrud/views/CRUD.py", line 140, in sa_add
obj = self.crud.create(data)
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sacrud/action.py", line 66, in create
return self._add(obj, data, **kwargs)
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sacrud/action.py", line 183, in _add
.add(self.session, data, self.table)
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sacrud/preprocessing.py", line 206, in add
return self.obj(**params)
File "", line 4, in init
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/orm/state.py", line 269, in _initialize_instance
return manager.original_init(_mixed[1:], *_kwargs)
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 526, in _declarative_constructor
setattr(self, k, kwargs[k])
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 226, in set
instance_dict(instance), value, None)
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 1009, in set
lambda adapter, i: adapter.adapt_like_to_iterable(i))
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 1025, in _set_iterable
new_values = list(adapter(new_collection, iterable))
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 1009, in
lambda adapter, i: adapter.adapt_like_to_iterable(i))
File "/home/tallada/Projectes/env/cosmohub_v5/local/lib/python2.7/site-packages/sqlalchemy/orm/collections.py", line 646, in adapt_like_to_iterable
given, wanted))
TypeError: Incompatible collection type: list is not set-like

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@ptallada
Copy link
Author

Quick fix in preprocessing.py, checking if the collection_class attribute is defined and using it to wrap the list.

Lines 55-58:

if relation.property.collection_class:
    return relation.property.collection_class(objs.all())
else:
    return objs.all()

@uralbash
Copy link
Member

@ptallada Thanks!
This is a very special case, it works quite as shown below:

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Item(Base):
    __tablename__ = 'item'
    id = Column(Integer, primary_key=True)
    notes = relationship("Note",
                collection_class=set,
                cascade="all, delete-orphan")


class Note(Base):
    __tablename__ = 'note'
    id = Column(Integer, primary_key=True)
    item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
    keyword = Column(String)
    text = Column(String)

    def __init__(self, keyword, text):
        self.keyword = keyword
        self.text = text

item = Item()
note = Note("foo", "bar")
Item.notes.property.collection_class([note, ])  # OK

But I can use other Classes, for example (http://docs.sqlalchemy.org/en/rel_0_9/orm/collections.html#dictionary-collections):

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Item(Base):
    __tablename__ = 'item'
    id = Column(Integer, primary_key=True)
    notes = relationship("Note",
                collection_class=attribute_mapped_collection('keyword'),
                cascade="all, delete-orphan")


class Note(Base):
    __tablename__ = 'note'
    id = Column(Integer, primary_key=True)
    item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
    keyword = Column(String)
    text = Column(String)

    def __init__(self, keyword, text):
        self.keyword = keyword
        self.text = text

item = Item()
note = Note("foo", "bar")
Item.notes.property.collection_class([note, ])

And it raises error:

Traceback (most recent call last):
  File "foofoo.py", line 30, in <module>
    Item.notes.property.collection_class([note, ])
TypeError: <lambda>() takes 0 positional arguments but 1 was given

This is most likely a bug in sacrud, but I don't know how it to best solve at the moment

@uralbash uralbash added the bug label Oct 17, 2015
@uralbash uralbash added this to the 0.1.4 milestone Oct 17, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants