[sqlalchemy] Re: Modification tracking

2013-08-23 Thread Jonathan Vanasco
I had to do this last week.

I posted a recipe in this thread:

https://groups.google.com/forum/#!topic/sqlalchemy/Xr1llnf5tzQ


tracked objects inherit from RevisionObject, which adds 2 columns to the 
database:
   revision_id (INT)
   revision_history (HSTORE) 
  
it also adds 2 methods:
generate_snapshot
generate_diff

i only track changes on certain elements, so I added a revision_columns 
attribute to the object.  ( which should be a list of the attributes ).

if you wanted all columns, you could just iterate over:

sqlalchemy_orm.class_mapper(self.__class__).mapped_table.c


If you want to go over the relationships, there's another attribute of the 
`mapped_table` that handles that.  OR you could just have both objects 
inherit from something like this and then call generate_diff() on the sub 
objects.

one last note:

I only store data on the first access, on the edits I first store a 
snapshot as r0 , then store a diff as r1.  that cuts down on duplication.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


[sqlalchemy] testing for an association proxy (possible bug and patch included)

2013-08-23 Thread Jonathan Vanasco
I have this general structure:

class Person:
 # orm relationships are preceded by (o)ne or (l)ist  
 o_Person2Address_ActiveShipping = sa.orm.relationship( 
Person2Address, primaryjoin=and_( Person2Address.person_id==Person.id , 
Person2Address.role_id=='active-shipping' ), uselist=False ) 
active_shipping_address = association_proxy('
o_Person2Address_ActiveShipping', 'address')

class Person2Address:
address = sa.orm.relationship(Address, 
primaryjoin=Person2Address.address_id==Address.id)

class Address:
   pass

this works perfect when i have a Person2Address and address .  I'd imagine 
it works fine if the proxy is for an empty list too.

the problem is when o_Person2Address_ActiveShipping is an empty scalar 
(from the uselist=False argument).

   jim = dbSession.query( Person )
   active_shipping = jim.o_Person2Address_ActiveShipping 
   type(active_shipping)
None

   # this will raise an error
   if jim.active_shipping_address :

  # this will raise an error too
   if jim.active_shipping_address 
and jim.active_shipping_address.address :

  print jim.active_shipping_address

that raises an error on the .active_shipping_address

File 
/Users/jvanasco/webserver/environments/project-2.7.5/lib/python2.7/site-packages/sqlalchemy/ext/associationproxy.py,
 line 241, in __get__
return self._scalar_get(getattr(obj, self.target_collection))
AttributeError: 'NoneType' object has no attribute 'media_asset'



i think a simple fix could be something like this ( line 240, 
sqlalchemy/ext/associationproxy.py 
)

if self.scalar:
-if not getattr(obj, self.target_collection)
-return self._scalar_get(getattr(obj, self.target_collection))
else:

if self.scalar:
+proxied = getattr(obj, self.target_collection)
+if not proxied :
+return None
+return self._scalar_get(proxied)
  else:







-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Feedback appreciated

2013-08-23 Thread Konsta Vesterinen


On Friday, August 23, 2013 1:52:41 AM UTC+3, Michael Bayer wrote:



 wow that is quite a compliment, I of course have heard of Doctrine and met 
 many PHP users who use it extensively.   This is really amazing that you're 
 A. using Python now B. using SQLAlchemy and C. writing full blown software 
 for it, wow !


Thanks!

 

 These are all really interesting projects and I had a lot of thoughts 
 looking at all of them just briefly.   I also wonder at what points within 
 here should/can some of this be part of SQLA itself, or not.  Here's my 
 notes:

 wtforms:

 1. in all cases, use inspect(cls) to get at a Mapper.  if on 0.7, use 
 class_mapper(cls).   but it would be great if you could target 0.8 and up 
 as a lot of functions were added for exactly these kinds of use cases (See 
 http://docs.sqlalchemy.org/en/rel_0_8/faq.html#how-do-i-get-a-list-of-all-columns-relationships-mapped-attributes-etc-given-a-mapped-class
 )

 2. ClassManager.values() is not terrible, but again isn't super public. 
  you can use mapper.attrs as well as mapper.column_attrs and others as of 
 0.8.


These are both valid points and I fully agree with you.

 

 versioning:

 2. unit_of_work.py: you can tell if a statement is an INSERT/DELETE 
 usually by looking at context.isinsert/context.isdelete, and also the table 
 name 
 you can get from context.statement.table (something like that).  Similar 
 things can be done where I see you're regexping the DELETE
 later on.   Digging into the string is fine but once you're targeting the 
 broad spectrum of scenarios, like users that are adding SQL comments and 
 such to their SQL, backends that don't actually use SQL, you want to stick 
 with inspecting the expression trees as much as possible.

 3. make schema object names configurable, i.e. transaction_id


Good points. I created issues for both.

 

 4. This code looks great but I'd still be scared to use it, because 
 versioning is such a particular thing, not to mention
 interactions with other schema complexities.But I don't say that to be 
 discouraging, just to state how non-trivial a problem 
 this is.   When i do versioning for real, there's always weird quirks and 
 things 
 specific to the app, which are easier to hardcode in my versioning code 
 rather than having to configure a 3rd party library to do it.
 it's why i kept it as just an example in SQLA itself, it's a huge job... 
   but if you can make this extension successful,
 that'll be very impressive.   In the docs it would be nice if I could see 
 immediately what happens to the SQL schema when I use this.


I will add this in the docs and I agree the whole thing is a little bit 
scary. :) I think we can make it a great tool though. One of the things I 
don't like about Hibernate Envers is its API. With Continuum I tried to get 
ideas for the API from the best versioning Ruby world has (especially 
papertrail). 

The schema Continuum generates is basically the same as the one Hibernate 
Envers generates (with a little bit different naming conventions).

 

 sqlalchemy_utils:

 1. have coercion_listener configure itself?   
 coercion_listener.configure().  since it's global usually,
 and you could always pass a target base class to configure() as an option.


Good idea.
 

 2. ScalarListType vs. Postgresql ARRAY ?   same/better?  should SLT use 
 ARRAY on a PG backend ?


Hmm I'm not sure about this yet. Its definately not better than using 
PostgreSQL ARRAY. ARRAY is better in many ways but its PostgreSQL specific. 
Maybe we could make ScalarListType use ARRAY on PostgreSQL by default (as 
you suggested).

 

 3. operators for types!   I see these are mostly string storage but you 
 can start adding special operations as
 needed using TypeEngine.Comparator: 
 http://docs.sqlalchemy.org/en/rel_0_8/core/types.html#types-operators e.g. 
 look at all the operations that pg.ARRAY has (contains, indexed 
 access, concatenation, etc.). then you can make all these types *really* 
 slick.


EmailType already uses CaseInsensitiveComparator. I will add more of these 
as you suggested once I figure out what kind of operators each type needs. 
:)
 

 4a. batch_fetch - h.  I see the idea is avoid JOIN by just 
 feeding the keys into an IN (caveat there, IN works well for small lists, 
 but less so for large - Oracle at least limits their size to 1000, when I 
 have to use batch IN I will actually batch within the IN itself in groups 
 of 500 or so).   You know you could build this as a loader strategy.  an 
 API overhaul of that system
 is coming up but the LoaderStrategy API shouldn't change much.   Then you 
 could just say query.options(batch_load_all(a.b.c)) like
 any other option.   LoaderStrategy isn't an API that people use often but 
 it is extensible, and 0.9 it's even nicer already, with more to come.   I 
 recently posted about it on the development list, if you want to check out 
 sqlalchemy-devel (it's a pretty dead list but I'd value 

[sqlalchemy] problems with temporary tables and commits

2013-08-23 Thread Tim Tisdall
I'll try to make this succinct...

I'm creating a temporary table and then doing a query with it that takes a 
good length of time.  I found that the source tables going into the 
temporary table were being locked after the temporary table was created 
even though they were no longer needed for the second much longer query. 
 Apparently create temporary table in MySQL doesn't autocommit and so the 
transaction is locking a lot more than needed.  So...  I tried committing 
right after creating the temporary table, but now I randomly lose the 
temporary table because SQLAlchemy sees the commit as a reason to return 
the connection back to the connection pool and then get back another 
connection on the next query.  So, as the temporary table is persistent 
only on that connection I usually lose the table as I usually don't get the 
very same connection back from the pool.

I'd like to be able to tell MySQL to commit after creating the temporary 
table so I can drop the locks used to fill that table, but I want to make 
sure SQLAlchemy doesn't let go of the connection and return it to the pool.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] testing for an association proxy (possible bug and patch included)

2013-08-23 Thread Gombas, Gabor (IT)
On Fri, Aug 23, 2013 at 12:11:39PM -0700, Jonathan Vanasco wrote:

 i think a simple fix could be something like this ( line 240, 
 sqlalchemy/ext/associationproxy.py 
 )
 
 if self.scalar:
 -if not getattr(obj, self.target_collection)
 -return self._scalar_get(getattr(obj, self.target_collection))
 else:
 
 if self.scalar:
 +proxied = getattr(obj, self.target_collection)
 +if not proxied :
 +return None
 +return self._scalar_get(proxied)
   else:

We're monkey-patching AssociationProxy.__get__ with the same change
since SQLA 0.5.x, so it would be nice to get it applied upstream...
Maybe in 0.9?

Gabor

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


[sqlalchemy] OrderingList not updating position as expected

2013-08-23 Thread Kyle Marek-Spartz
Hello,

I've ran into a potential issue with OrderingList. When we are creating a 
new child, we'd like to be able to simply specify child.parent (or 
child.parent_id), and have child.position be updated appropriately when 
committed. This saves querying for the parent object, and then appending 
the child to the list.

Here's a gist of what I'd like to be able to do: 
https://gist.github.com/zeckalpha/6324142

I'm on 0.8.2.

Thanks,

kms

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] testing for an association proxy (possible bug and patch included)

2013-08-23 Thread jason kirtland
On Fri, Aug 23, 2013 at 2:31 PM, Gombas, Gabor (IT) 
gabor.gom...@morganstanley.com wrote:

 On Fri, Aug 23, 2013 at 12:11:39PM -0700, Jonathan Vanasco wrote:

  i think a simple fix could be something like this ( line 240,
 sqlalchemy/ext/associationproxy.py
  )
 
  if self.scalar:
  -if not getattr(obj, self.target_collection)
  -return self._scalar_get(getattr(obj,
 self.target_collection))
  else:
 
  if self.scalar:
  +proxied = getattr(obj, self.target_collection)
  +if not proxied :
  +return None
  +return self._scalar_get(proxied)
else:

 We're monkey-patching AssociationProxy.__get__ with the same change
 since SQLA 0.5.x, so it would be nice to get it applied upstream...
 Maybe in 0.9?


The patch seems like surprising Python behavior to me. Traversing across a
None is almost certainly a bug in regular code, and quashing that error by
default feels dangerous. I would want this to raise by default (and I have
found bugs because it did.)  I think you could opt into this behavior by
supplying an alternate, custom getter function that quashed None when
creating the proxy.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] problems with temporary tables and commits

2013-08-23 Thread Michael Bayer

well a CREATE TABLE will autocommit but only if it's on an Engine that's not 
already in a transactionand when you use a Session it sets up a transaction 
that stays open until you say commit().

I can see the problem here, one way around is to actually bind the Session to a 
connection like this:

conn = engine.connect()

sess = Session(bind=conn)

otherwise, just sending through the commit on the DBAPI connection directly 
might not be so terrible.  If you said, 
session.connection().connection.commit() that should have the same effect.






On Aug 23, 2013, at 4:32 PM, Tim Tisdall tisd...@gmail.com wrote:

 I knew I'd find a possible solution right after asking...  Isn't that always 
 the way?
 
 I found that I can do DBSession.execute(COMMIT) to get MySQL to commit the 
 temporary table but SQLAlchemy/transaction doesn't seem to pick up on it and 
 I don't lose the connection to the threadpool.
 
 This seems kind of a hack, but does anyone have a better solution?
 
 
 On Fri, Aug 23, 2013 at 4:12 PM, Tim Tisdall tisd...@gmail.com wrote:
 I'll try to make this succinct...
 
 I'm creating a temporary table and then doing a query with it that takes a 
 good length of time.  I found that the source tables going into the temporary 
 table were being locked after the temporary table was created even though 
 they were no longer needed for the second much longer query.  Apparently 
 create temporary table in MySQL doesn't autocommit and so the transaction 
 is locking a lot more than needed.  So...  I tried committing right after 
 creating the temporary table, but now I randomly lose the temporary table 
 because SQLAlchemy sees the commit as a reason to return the connection back 
 to the connection pool and then get back another connection on the next 
 query.  So, as the temporary table is persistent only on that connection I 
 usually lose the table as I usually don't get the very same connection back 
 from the pool.
 
 I'd like to be able to tell MySQL to commit after creating the temporary 
 table so I can drop the locks used to fill that table, but I want to make 
 sure SQLAlchemy doesn't let go of the connection and return it to the pool.
 
 -- 
 You received this message because you are subscribed to a topic in the Google 
 Groups sqlalchemy group.
 To unsubscribe from this topic, visit 
 https://groups.google.com/d/topic/sqlalchemy/9dfigjQt1Bw/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to 
 sqlalchemy+unsubscr...@googlegroups.com.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/groups/opt_out.
 
 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to sqlalchemy+unsubscr...@googlegroups.com.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/groups/opt_out.



signature.asc
Description: Message signed with OpenPGP using GPGMail


Re: [sqlalchemy] OrderingList not updating position as expected

2013-08-23 Thread Michael Bayer

On Aug 23, 2013, at 6:07 PM, Kyle Marek-Spartz zeckal...@gmail.com wrote:

 Hello,
 
 I've ran into a potential issue with OrderingList. When we are creating a new 
 child, we'd like to be able to simply specify child.parent (or 
 child.parent_id), and have child.position be updated appropriately when 
 committed. This saves querying for the parent object, and then appending the 
 child to the list.

well in the first case, say we have this:

s = Session.query(Slide).get(1)
b = Bullet()
b.slide = s

when we load Slide, slide.bullets is unloaded.  The orderinglist can't do its 
job here without emitting a SELECT for slide.bullets first.  As it turns out, 
this doesn't occur in this case.  Setting b.slide = someslide was optimized a 
long time ago to not emit a usually wasteful SELECT of the other side of the 
collection.

If you were to say this:

s = Session.query(Slide).get(1)
s.bullets
b = Bullet()
b.slide = s

then it sets position, because b.slide = s emits the backref to 
s.bullets.append and you get the ordering behavior.   

So when you say, this saves querying for the parent object, if you're looking 
for saving on the performance of a SELECT, you're not going to get that.  If 
you're looking for that it should just work without any explicit code, then 
yes we need some extra help here.   I'm not sure what we should do to 
orderinglist directly, this should at least be documented, but here is how you 
can make sure s.bullets is present:

from sqlalchemy import event

@event.listens_for(Bullet.slide, set)
def ping_slide_bullets(target, value, oldvalue, initiator):
value.bullets
return value

of course in your example, you need to keep that Slide object attached to the 
Session (don't keep closing the session and creating new ones) otherwise it 
can't emit the lazyload for bullets.

For the second part of the example, that's a totally different thing, that's 
the I want to set bar.foo_id = 7 and have it act like bar.foo = 
Session.query(Foo).get(7)There's an FAQ entry which also refers to a wiki 
recipe that, using more events, can approximate this behavior for the typical 
case:  
http://docs.sqlalchemy.org/en/rel_0_8/faq.html#i-set-the-foo-id-attribute-on-my-instance-to-7-but-the-foo-attribute-is-still-none-shouldn-t-it-have-loaded-foo-with-id-7
 .


signature.asc
Description: Message signed with OpenPGP using GPGMail