Re: [sqlalchemy] Re: Custom type does not seem to honour is_mutable
On Aug 13, 2010, at 10:24 AM, Dan wrote: On Aug 13, 3:17 pm, Michael Bayer mike...@zzzcomputing.com wrote: On Aug 13, 2010, at 10:01 AM, Dan wrote: I have created a custom type in order to store denormalized PKs in a TEXT field. The idea is that the text is converted back and forth from a set of integers: http://paste.pocoo.org/show/249784/ this is unrelated, but the code is incorrect there, should be def process(value): if value is not None: items = [str(item).strip() for item in value] value = self.separator.join(item for item in items if item) otherwise, you must implement copy_value() on your type. Here, the value isn't being copied so there's nothing to compare to. Yes, sorry for the typo. Realized myself once I'd posted. Usually you're supposed to mixin MutableType which will raise notimplemented for copy_value(). I guess still more docs are needed since you were misled by the is_mutable() method. I've tried the same thing with the MutableType mixin with the same result, i.e: class DenormalizedText(types.TypeDecorator, types.MutableType): MutableType would be first. But again this only just so the NotImplementedError lets you know copy_value() is needed.I could make the default copy_value() raise if is_mutable() is true...though it pains me to add more method calls... from sqlalchemy import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import * Base = declarative_base() metadata = Base.metadata engine = create_engine('sqlite://', echo=True) from sqlalchemy import types class DenormalizedText(types.TypeDecorator): Stores denormalized primary keys that can be accessed as a set. :param coerce: coercion function that ensures correct type is returned :param separator: separator character impl = types.Text def __init__(self, coerce=int, separator= , **kwargs): self.coerce = coerce self.separator = separator super(DenormalizedText, self).__init__(**kwargs) def bind_processor(self, dialect): def process(value): if value is not None: items = [str(item).strip() for item in value] value = self.separator.join(item for item in items if item) return value return process def result_processor(self, dialect, coltype): def process(value): if not value: return set() return set(self.coerce(item) \ for item in value.split(self.separator)) return process def copy_value(self, value): return set(value) def is_mutable(self): return True class Post(Base): __tablename__ = posts id = Column(Integer, primary_key=True) votes = Column(DenormalizedText) def __init__(self, *args, **kwargs): super(Post, self).__init__(*args, **kwargs) self.votes = self.votes or set() Base.metadata.create_all(engine) session = sessionmaker(engine)() post = Post() post.votes.add(3) session.add(post) session.commit() print --- post.votes.add(5) session.commit() -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
Re: [sqlalchemy] Re: Custom type does not seem to honour is_mutable
On Aug 13, 2010, at 10:45 AM, Dan wrote: Unfortunately still getting the same result: http://paste.pocoo.org/show/249801/ The test snippet shows that the modified set is not actually saved to the database. that code snippet is not complete (doesn't create a Session, doesn't add Post to it, doesn't commit() or flush() the session but then removes it so I guess maybe its a scoped_session, don't know) so I don't actually know what you're doing. The test case below adds your assertion, uses the Session properly, and works fine. The previous test I pasted also works (if I bothered to write out a full test for it, you can be sure I ran it). from sqlalchemy import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import * Base = declarative_base() metadata = Base.metadata engine = create_engine('sqlite://', echo=True) from sqlalchemy import types class DenormalizedText(types.TypeDecorator): Stores denormalized primary keys that can be accessed as a set. :param coerce: coercion function that ensures correct type is returned :param separator: separator character impl = types.Text def __init__(self, coerce=int, separator= , **kwargs): self.coerce = coerce self.separator = separator super(DenormalizedText, self).__init__(**kwargs) def bind_processor(self, dialect): def process(value): if value is not None: items = [str(item).strip() for item in value] value = self.separator.join(item for item in items if item) return value return process def result_processor(self, dialect, coltype): def process(value): if not value: return set() return set(self.coerce(item) \ for item in value.split(self.separator)) return process def copy_value(self, value): return set(value) def is_mutable(self): return True class Post(Base): __tablename__ = posts id = Column(Integer, primary_key=True) votes = Column(DenormalizedText) def __init__(self, *args, **kwargs): super(Post, self).__init__(*args, **kwargs) self.votes = self.votes or set() Base.metadata.create_all(engine) session = sessionmaker(engine)() post = Post() assert post.votes == set([]) session.add(post) session.commit() post.votes.add(1) assert 1 in post.votes session.commit() post_id = post.id # close out transaction, session entirely, even # though commit expires everything anyway session.close() post = session.query(Post).get(post_id) assert 1 in post.votes On Aug 13, 3:29 pm, Michael Bayer mike...@zzzcomputing.com wrote: On Aug 13, 2010, at 10:24 AM, Dan wrote: On Aug 13, 3:17 pm, Michael Bayer mike...@zzzcomputing.com wrote: On Aug 13, 2010, at 10:01 AM, Dan wrote: I have created a custom type in order to store denormalized PKs in a TEXT field. The idea is that the text is converted back and forth from a set of integers: http://paste.pocoo.org/show/249784/ this is unrelated, but the code is incorrect there, should be def process(value): if value is not None: items = [str(item).strip() for item in value] value = self.separator.join(item for item in items if item) otherwise, you must implement copy_value() on your type. Here, the value isn't being copied so there's nothing to compare to. Yes, sorry for the typo. Realized myself once I'd posted. Usually you're supposed to mixin MutableType which will raise notimplemented for copy_value(). I guess still more docs are needed since you were misled by the is_mutable() method. I've tried the same thing with the MutableType mixin with the same result, i.e: class DenormalizedText(types.TypeDecorator, types.MutableType): MutableType would be first. But again this only just so the NotImplementedError lets you know copy_value() is needed.I could make the default copy_value() raise if is_mutable() is true...though it pains me to add more method calls... from sqlalchemy import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import * Base = declarative_base() metadata = Base.metadata engine = create_engine('sqlite://', echo=True) from sqlalchemy import types class DenormalizedText(types.TypeDecorator): Stores denormalized primary keys that can be accessed as a set. :param coerce: coercion function that ensures correct type is returned :param separator: separator character impl = types.Text def __init__(self, coerce=int, separator= , **kwargs): self.coerce = coerce self.separator = separator super(DenormalizedText, self).__init__(**kwargs) def bind_processor(self, dialect):
Re: [sqlalchemy] Re: Custom type does not seem to honour is_mutable
hey no problem glad you're back in business. On Aug 13, 2010, at 11:35 AM, Dan wrote: The issue appeared to be removing the session instance (session.remove()) - I was trying to get a clean session for testing. Anyway, works fine now - thanks for your help and sorry for wasting your time. On Aug 13, 4:21 pm, Dan danjac...@gmail.com wrote: that code snippet is not complete (doesn't create a Session, doesn't add Post to it, doesn't commit() or flush() the session but then removes it so I guess maybe its a scoped_session, don't know) so I don't actually know what you're doing. The test case below adds your assertion, uses the Session properly, and works fine. The previous test I pasted also works (if I bothered to write out a full test for it, you can be sure I ran it). Sorry for lack of context - had to strip out test from a whole lot of other code - not an excuse I know. There must be some other issue here, I'll investigate further and let you know. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.