[sqlalchemy] Re: Use of new_instance() in the user-defined-state branch?

2008-03-28 Thread Phillip J. Eby

At 09:45 AM 3/28/2008 -0400, Michael Bayer wrote:
On Mar 28, 2008, at 12:55 AM, Phillip J. Eby wrote:
  Sadly, about the only way for me to implement that without code
  duplication will be to temporarily change the item's __class__ to a
  subclass with an empty __init__ method.  Unless there's a way to
  change the generated __init__ method to take an extra flag or check a
  per-thread variable to skip the bits you don't want?  What are the
  bits you don't want run, anyway?  That is, what specifically mustn't
  happen?

an end-user's __init__ method is not run when the object is loaded
from the DB since the ORM is going to populate its state explicitly.
its for similar reasons that pickle.loads() doesn't call __init__.
Its a common use case that someone's class needs to be constructed
differently when it is newly created vs. when it is re-populated from
the DB.

The usual method we have of modifying this behavior is to use a
MapperExtension where you implement create_instance().  Then you can
build the object any way you want, using __init__, whatever.   Why is
that not an option here ?  ( or has it just not been mentioned ?)

Because Jason said this:

At 06:08 PM 3/27/2008 -0700, jason kirtland wrote:
Phillip J. Eby wrote:
  At 02:26 PM 3/27/2008 -0700, jason kirtland wrote:
  new_instance creates an instance without invoking __init__.  The ORM
  uses it to recreate instances when loading from the database.
  new_instance can be added to InstrumentationManager as an extension
  method... The ORM doesn't care how empty instances are manufactured so
  long as they can be created without initialization arguments, e.g. a
  no-arg constructor.
  Does that mean that no attributes must be set from 
 new_instance(), either?
  You should be able to set whatever you like there.
 
  So...  new_instance() could literally just be a call to
  'self.class_()', with no other behavior, as long as the constructor
  requires no arguments?  The modified __init__ that SA inserts won't
  be a problem there?

Sorry, I should have included more detail.  You don't want to trigger
the logic in SA's __init__ decorator or call the user's __init__.  The
ORM policy is not to __init__ on load, and will soon support a symmetric
__on_load__ type of hook that the ORM can call post-__new__ when
reconstituting instances.

So, which one of you is right?  :)


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Use of new_instance() in the user-defined-state branch?

2008-03-28 Thread Phillip J. Eby

So you're still disagreeing with Jason, who's quite explicitly saying 
that SA's __init__ will blow up if it gets called.  Which of you is right?  :)

At 11:38 AM 3/28/2008 -0400, Michael Bayer wrote:
On Mar 28, 2008, at 10:58 AM, Phillip J. Eby wrote:

 
  Sorry, I should have included more detail.  You don't want to trigger
  the logic in SA's __init__ decorator or call the user's __init__.
  The
  ORM policy is not to __init__ on load, and will soon support a
  symmetric
  __on_load__ type of hook that the ORM can call post-__new__ when
  reconstituting instances.
 
  So, which one of you is right?  :)

Well, I'm not entirely sure how your users will be using their
objects.  If they just want to take any old application and enable
trellis + sqlalchemy, if they are accustomed to writing for SA then it
would be a surprise for their __init__() method to be called.   Like,
if I wrote a class like this:

class MyClass(object):
  def __init__(self, a, b):
  self.a = a
  self.b = b


then I mapped it to Trellis + SQLA, we *can't* call MyClass() upon
load from the database - we dont have the constructor arguments
available and TypeError will be thrown.

If OTOH, using Trellis implies that you must already have an
__init__() that is compatible with a no-arg calling style and that
they should expect population of attributes to occur after it's
called, then theres no issue with configuring the SA mappings to call
__init__().

I think you mentioned earlier that Trellis doesn't care what the
user does with __init__()neither does SQLAlchemy, and thats why we
never call it by default with no args, since we make no assumptions
about what it expects or what it does.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Use of new_instance() in the user-defined-state branch?

2008-03-27 Thread Phillip J. Eby

I just noticed that in the latest version of the branch, there's a 
new_instance() call that is using a class' __new__ method in order to 
create a new instance, rather than using 'class()'.  What I'd like to 
find out is how to get around this, because Trellis objects will not 
be properly initialized unless the 'class()' is called, with any 
initialization taking place inside __new__ and/or __init__.   Trellis 
doesn't override __new__ or __init__, and doesn't care what they 
do.  But the creation of an instance *must* be wrapped by the class' 
__call__ (i.e. class()), as there is a try/finally involved that must execute.

Any thoughts on how this might be refactored?  What is new_instance() used for?


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Use of new_instance() in the user-defined-state branch?

2008-03-27 Thread Phillip J. Eby

At 02:26 PM 3/27/2008 -0700, jason kirtland wrote:
  new_instance creates an instance without invoking __init__.  The ORM
  uses it to recreate instances when loading from the database.
  new_instance can be added to InstrumentationManager as an extension
  method... The ORM doesn't care how empty instances are manufactured so
  long as they can be created without initialization arguments, e.g. a
  no-arg constructor.
 
  Does that mean that no attributes must be set from new_instance(), either?

You should be able to set whatever you like there.

So...  new_instance() could literally just be a call to 
'self.class_()', with no other behavior, as long as the constructor 
requires no arguments?  The modified __init__ that SA inserts won't 
be a problem there?


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Integrating the ORM with Trellis

2008-03-04 Thread Phillip J. Eby

At 02:04 PM 3/3/2008 -0500, Michael Bayer wrote:

the bug is that unregister_attribute() is not working, which the test
suite is using to remove and re-register new instrumentation:

 class Foo(object):
 pass

  attributes.register_attribute(Foo, collection,
uselist=True, typecallable=set, useobject=True)
  assert
attributes.get_class_state(Foo).is_instrumented(collection)
  attributes.unregister_attribute(Foo, collection)
  assert not
attributes.get_class_state(Foo).is_instrumented(collection)

seems like unregister_attribute() is still doing the old thing of just
del class.attr, so we'd just need to stick a hook similar to
instrument_attribute for this on ClassState which will take over the
job.

looks good !

Okay, so I did a matching uninstrument_attribute and 
pre_uninstrument_attribute, which look like really dumb names at this 
point.  I propose the following name changes (in addition to the ones 
in my previous patch):

pre_instrument_attribute - install_descriptor
pre_uninstrument_attribute - uninstall_descriptor

That okay?  instrument_attribute will then call install_descriptor to 
do the actual installing.  And of course the hooks on the adapted 
thingy from the class would work the same way.

If that's okay with you, then after I'm done I'll post a patch for 
review before checkin.  After that, I'll start work on the 
Trellis-side support for this, and then eventually dig into  collections stuff.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Integrating the ORM with Trellis

2008-03-03 Thread Phillip J. Eby
At 04:04 PM 2/27/2008 -0500, Michael Bayer wrote:
do you have any interest in committing changes to the branch
yourself ?  as long as the unit tests keep running whatever you'd want
is most likely fine with meotherwise I will at least experiment
with doing away with __mro__ searching and possibly doing away with
pre_instrument_attribute.

Okay, I've run into an interesting hitch on the branch -- I think 
it's a test coverage issue.  The definition of 
'ClassState.is_instrumented' is different from that of 
_ClassStateAdapter, in a way that appears to *matter*.  That is, if 
you change ClassState.is_instrumented to work in roughly the same way 
as _ClassStateAdapter.is_instrumented, the standard tests 
fail.  Specifically, with this rather unhelpful error...  :)

Traceback (most recent call last):
   File test/orm/attributes.py, line 397, in test_collectionclasses
 assert False
AssertionError

This would appear to indicate that there is some kind of hidden 
dependency between collections support, and the presence of SA 
descriptors on a class.

Further investigation reveals that the problem comes from 
register_attribute() checking to see if an attribute is already 
instrumented, and if so, returns immediately.  It would appear that 
this really wants to know if there is actually an instrumented 
descriptor, rather than whether one has merely been registered with 
the class state, per these comments::

# this currently only occurs if two primary mappers are made for the 
same class.
# TODO:  possibly have InstrumentedAttribute check entity_name when 
searching for impl.
# raise an error if two attrs attached simultaneously otherwise

I'm pretty much stumped at this point.  Essentially, even though the 
tests don't cover this point for custom instrumentation, it means 
that this problem *will* occur with custom instrumentation, even 
without my changes.

Now, the *good* news is, the other 1190 tests all pass with my changes.  :)

I've attached my current diff against the user_defined_state 
branch.  Note that this bit is the part that makes the one test break:

  def is_instrumented(self, key, search=False):
  if search:
-return hasattr(self.class_, key) and 
isinstance(getattr(self.class_, key), InstrumentedAttribute)
+return key in self
  else:
-return key in self.class_.__dict__ and 
isinstance(self.class_.__dict__[key], InstrumentedAttribute)
+return key in self.local_attrs

In other words, it's only the change to ClassState.is_instrumented 
that breaks the test, showing that there's a meaningful difference 
here between what gets registered in the state, and what's actually 
on the class.  Which is going to be a problem for anybody rerouting 
the descriptors (the way the Trellis library will be).

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



classstate_dict.patch
Description: Binary data