Re: [sqlalchemy] Re: Custom type does not seem to honour is_mutable

2010-08-13 Thread Michael Bayer

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

2010-08-13 Thread Michael Bayer

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

2010-08-13 Thread Michael Bayer
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.