Re: [sqlalchemy] Mapping dictionaries with string keys and record values

2010-04-26 Thread Torsten Landschoff
Hi Michael.

On Sun, 2010-04-25 at 22:32 -0400, Michael Bayer wrote:

   You should be able to roll this yourself as a custom dictlike
   collection class . 

That's what I did :-) I wrote mostly to share my code and to suggest
that this should be available out of the box.

  sorry, it seems you've done that already.  I'm surprised the
  existing attribute_mapped_collection doesn't do this already ?

I was surprised as well.

 well, it doesn't.  It should, and maybe should raise an error if the
 two values don't match.  It doesn't make much sense to add another
 collection class to do what the first one should.

Agreed.

 I'm sure you noticed that you can remove the repetition by working the
 other way, i.e.:
 
 item.note.set(Note(key=color, value=blue, desc=This should be
 blue because))
 item.note.set(Note(key=shape, value=rectangular))

Indeed, although I find it unintuitive that set actually does an
append/insert/add operation. Apart from that, I try to keep the mapping
code and the data objects (which carry application logic) separate in
case we ever want to use a non-SQL data backend (NoSQL DB, ZODB, ...).
So usually, there is no set method on item.notes and there is no key
property in the Note class (it's added by the mapper as _key).

 also, never do this:

 
 class Note(object):
 def __init__(self, **args): 
 self.__dict__.update(args)

That's not production code. I just added it to get initialization in one
line.

 you bypass all of SQLAlchemy's history tracking logic.  do this
 instead:
 
 
 class Note(object):
 def __init__(self, **args): 
 for k, v in args.items():
 setattr(self, k, v)

I usually name the possible keyword arguments explicitly as the output
of help(Note) is otherwise quite unhelpful.

Thanks for your reply and the remarks! Do you plan to extend
attribute_mapped_collection to update the key like in my example?

Be aware that this approach also has it's downside. For example,
assigning 

item2 = Item()
item2.notes['color'] = item.notes['color']

will not work contrary to what one might expect (it generated a conflict
on the id column). The solution is to have the target collection copy
the assigned object if it has a key already. But that might be too much
magic to be easy to understand.

So I think, the automatic key update should be an option.

Greetings, Torsten

-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landsch...@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

-- 
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] Mapping dictionaries with string keys and record values

2010-04-26 Thread Michael Bayer
Torsten Landschoff wrote:

 Thanks for your reply and the remarks! Do you plan to extend
 attribute_mapped_collection to update the key like in my example?

here's some things to note on that:

1. I'm not sure why it wasn't that way already, and I'd want to hear from
Jason Kirtland, its author, on if we are missing something or otherwise
whats up.   I have a vague notion that there was a reason for this, or
maybe not.

2. I wonder if there's a way to make this happen more deeply than within
setattr().   Like the collection internals would include an event to
operate upon the target object that includes the other args from the
collection decorator.

3. corresponding delete() event.  Set the attribute on the replaced object
to None ?   that seems potentially surprising ?


 Be aware that this approach also has it's downside. For example,
 assigning

 item2 = Item()
 item2.notes['color'] = item.notes['color']

 will not work contrary to what one might expect (it generated a conflict
 on the id column). The solution is to have the target collection copy
 the assigned object if it has a key already. But that might be too much
 magic to be easy to understand.

the target can only be in one collection at a time so I would think
item2's id wins.  its a primary key switch.



-- 
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] Mapping dictionaries with string keys and record values

2010-04-26 Thread jason kirtland
On Mon, Apr 26, 2010 at 8:24 AM, Michael Bayer mike...@zzzcomputing.com wrote:
 Torsten Landschoff wrote:

 Thanks for your reply and the remarks! Do you plan to extend
 attribute_mapped_collection to update the key like in my example?

 here's some things to note on that:

 1. I'm not sure why it wasn't that way already, and I'd want to hear from
 Jason Kirtland, its author, on if we are missing something or otherwise
 whats up.   I have a vague notion that there was a reason for this, or
 maybe not.

It's not something that can be easily solved in the general case with
the current API. The mapped collections use a 'keyfunc' to figure out
the dictionary key for loaded instances, for example
'operator.attrgetter(name)' for attribute_mapped_collection(name).
 Mechanically reversing that logic in a setting operation sounds
pretty hard to me, but perhaps if we allowed an 'assignfunc' function
to be supplied that would do the trick.  Internally, the collection
code would call it during a dict['key'] = instance assignment
operation, maybe passing just the key value and the instance:

  def assignfunc(key, instance):
  instance.name = key

For highly constrained types like the attribute- and column-mapped
collections, these functions would be easy to generate.

A good test for the feature would be a mapped collection that maps a
tuple of attributes, such as one created by
attribute_mapped_collection(('x', 'y')).  Assigning collection[1,
2] = instance should assign both instance.x and instance.y in that
case.

 2. I wonder if there's a way to make this happen more deeply than within
 setattr().   Like the collection internals would include an event to
 operate upon the target object that includes the other args from the
 collection decorator.

I have a hunch this is only meaningful for mapped collections-
mutations like list_collection[2:5] would be difficult to translate
and I'm not sure what information one would want to capture there.
Worth a look though.

-- 
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] Mapping dictionaries with string keys and record values

2010-04-26 Thread Torsten Landschoff
On Mon, 2010-04-26 at 11:24 -0400, Michael Bayer wrote:

 2. I wonder if there's a way to make this happen more deeply than within
 setattr().   Like the collection internals would include an event to
 operate upon the target object that includes the other args from the
 collection decorator.

Sorry, I was unable to follow you here. You think there should be an
event generated to be handled by the collection internals? What
arguments of the decorator are you talking about?

 3. corresponding delete() event.  Set the attribute on the replaced object
 to None ?   that seems potentially surprising ?

In my case it did not matter much since the object is owned by the
mapped collection. So after the delete, it is garbage collected anyway.
As the client code does not know about the key attribute, it would not
notice the change anyway even if it still has a pointer.

For me this is the same as some code still having a reference to a value
that was stored in a dict. If you remove it from the dictionary, you may
still keep a reference but it is not reachable anymore from the dict. To
make this match with the database, I am using cascade=delete-orphan.

  item2 = Item()
  item2.notes['color'] = item.notes['color']
 
  will not work contrary to what one might expect (it generated a conflict
  on the id column). The solution is to have the target collection copy
  the assigned object if it has a key already. But that might be too much
  magic to be easy to understand.
 
 the target can only be in one collection at a time so I would think
 item2's id wins.  its a primary key switch.

Can't it belong to two collections if there is a secondary join?
In plain Python code, both mappings would have a reference to the same
object.

Greetings, Torsten

-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landsch...@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

-- 
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] Mapping dictionaries with string keys and record values

2010-04-26 Thread Torsten Landschoff
On Mon, 2010-04-26 at 11:08 -0700, jason kirtland wrote:

  1. I'm not sure why it wasn't that way already, and I'd want to hear from
  Jason Kirtland, its author, on if we are missing something or otherwise
  whats up.   I have a vague notion that there was a reason for this, or
  maybe not.
 
 It's not something that can be easily solved in the general case with
 the current API. The mapped collections use a 'keyfunc' to figure out
 the dictionary key for loaded instances, for example
 'operator.attrgetter(name)' for attribute_mapped_collection(name).
  Mechanically reversing that logic in a setting operation sounds
 pretty hard to me, but perhaps if we allowed an 'assignfunc' function
 to be supplied that would do the trick.  Internally, the collection

I agree. The idea of an assignfunc crossed my mind as well.

Greetings, Torsten

-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landsch...@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

-- 
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.



[sqlalchemy] Mapping dictionaries with string keys and record values

2010-04-25 Thread Torsten Landschoff
Hi everybody.

After reading the documentation on dictionary based collections at
http://www.sqlalchemy.org/docs/mappers.html#dictionary-based-collections, I 
am wondering if I am the only one who things that this code is intuitive:

item = Item()
item.notes['color'] = Note('color', 'blue')
print item.notes['color']

I'd rather write

item.notes['color'] = Note('blue')

That the key is stored  with the value should be an implementation
detail I think.
I extended sqlalchemy.orm.collections.MappedCollection with a few lines
to implement this (attached).

Shouldn't something like this be included with SQLAlchemy? Or is this a
bad idea?

Greetings, Torsten


-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landsch...@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

-- 
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.

import operator
import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy.orm.collections import MappedCollection

class MyMappedCollection(MappedCollection):
def __init__(self, key_attr):
super(MyMappedCollection, self).__init__(operator.attrgetter(key_attr))
self._key_attr = key_attr

def __setitem__(self, key, value):
setattr(value, self._key_attr, key)
if key in self:
del self[key]
super(MappedCollection, self).__setitem__(key, value)

def map_on(attr):
return lambda: MyMappedCollection(attr)

metadata = sa.MetaData()
item_table = sa.Table(item, metadata,
sa.Column(id, sa.Integer, primary_key=True))

note_table = sa.Table(note, metadata,
sa.Column(id, sa.Integer, sa.ForeignKey(item_table.c.id), primary_key=True, index=True),
sa.Column(key, sa.String, primary_key=True),
sa.Column(value, sa.String),
sa.Column(desc, sa.String))

class Item(object): pass
class Note(object):
def __init__(self, **args): self.__dict__.update(args)

orm.mapper(Note, note_table)
orm.mapper(Item, item_table, properties=dict(
note=orm.relation(Note, cascade=all,delete-orphan, collection_class=map_on(key

engine = sa.create_engine(sqlite:///)
metadata.create_all(engine)
session = orm.sessionmaker(bind=engine)()

item = Item()
item.note[color] = Note(value=blue, desc=This should be blue because)
item.note[shape] = Note(value=rectangular)
session.add(item)
session.commit()




Re: [sqlalchemy] Mapping dictionaries with string keys and record values

2010-04-25 Thread Michael Bayer

On Apr 25, 2010, at 7:31 PM, Michael Bayer wrote:

 
 
 
 
 On Apr 25, 2010, at 1:38 PM, Torsten Landschoff 
 torsten.landsch...@dynamore.de wrote:
 
 Hi everybody.
 
 After reading the documentation on dictionary based collections at 
 http://www.sqlalchemy.org/docs/mappers.html#dictionary-based-collections, 
 I am wondering if I am the only one who things that this code is intuitive:
 item = Item()
 item.notes['color'] = Note('color', 'blue')
 print item.notes['color']
 I'd rather write
 item.notes['color'] = Note('blue')
 That the key is stored  with the value should be an implementation detail I 
 think.
 I extended sqlalchemy.orm.collections.MappedCollection with a few lines to 
 implement this (attached).
 
 Shouldn't something like is be included with SQLAlchemy? Or is this a bad id
 
 You should be able to roll this yourself as a custom dictlike collection 
 class . 

sorry, it seems you've done that already.  I'm surprised the existing 
attribute_mapped_collection doesn't do this already ?





 
 
 Greetings, Torsten
 
 -- 
 DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
 Torsten Landschoff
 
 Office Dresden
 Tel: +49-(0)351-4519587
 Fax: +49-(0)351-4519561
 
 mailto:torsten.landsch...@dynamore.de
 http://www.dynamore.de
 
 Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
 Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz
 
 -- 
 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.
 dictmapping.py
 
 
 -- 
 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] Mapping dictionaries with string keys and record values

2010-04-25 Thread Michael Bayer

On Apr 25, 2010, at 10:18 PM, Michael Bayer wrote:

 
 On Apr 25, 2010, at 7:31 PM, Michael Bayer wrote:
 
 
 
 
 
 On Apr 25, 2010, at 1:38 PM, Torsten Landschoff 
 torsten.landsch...@dynamore.de wrote:
 
 Hi everybody.
 
 After reading the documentation on dictionary based collections at 
 http://www.sqlalchemy.org/docs/mappers.html#dictionary-based-collections, 
 I am wondering if I am the only one who things that this code is intuitive:
 item = Item()
 item.notes['color'] = Note('color', 'blue')
 print item.notes['color']
 I'd rather write
 item.notes['color'] = Note('blue')
 That the key is stored  with the value should be an implementation detail I 
 think.
 I extended sqlalchemy.orm.collections.MappedCollection with a few lines to 
 implement this (attached).
 
 Shouldn't something like is be included with SQLAlchemy? Or is this a bad id
 
 You should be able to roll this yourself as a custom dictlike collection 
 class . 
 
 sorry, it seems you've done that already.  I'm surprised the existing 
 attribute_mapped_collection doesn't do this already ?

well, it doesn't.  It should, and maybe should raise an error if the two values 
don't match.  It doesn't make much sense to add another collection class to do 
what the first one should.

I'm sure you noticed that you can remove the repetition by working the other 
way, i.e.:

item.note.set(Note(key=color, value=blue, desc=This should be blue 
because))
item.note.set(Note(key=shape, value=rectangular))

also, never do this:

class Note(object):
def __init__(self, **args): 
self.__dict__.update(args)

you bypass all of SQLAlchemy's history tracking logic.  do this instead:

class Note(object):
def __init__(self, **args): 
for k, v in args.items():
setattr(self, k, v)




 
 
 
 
 
 
 
 Greetings, Torsten
 
 -- 
 DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
 Torsten Landschoff
 
 Office Dresden
 Tel: +49-(0)351-4519587
 Fax: +49-(0)351-4519561
 
 mailto:torsten.landsch...@dynamore.de
 http://www.dynamore.de
 
 Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
 Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz
 
 -- 
 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.
 dictmapping.py
 
 
 -- 
 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.

-- 
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.