On Dec 26, 2011, at 1:50 PM, Kent wrote: > Yes, a nice simplification. > I'm using it to lazyload attributes for objects that aren't in a > session. I'm not sure if you pointed me there, I think I found it > myself, but you helped work out the later details... > Our app lives inside a webserver framework that, very appropriately, > in my opinion, only has one session for any given web request. So, > for our framework, I can safely lazyload related attributes for > transient or detached objects by temporarily setting state.session_id:
heh yes this is exactly what things used to do between like version 0.2 and 0.4 :) - if there was no session, it would look in the "threadlocal" context which somehow was associated with things. This was one of many implicit decisions/surprises we took out in favor of a behavioral model that's transparent. For awhile there we also had this crazy "session lookup" logic that was quasi-optional, nobody knew what it was, and I had similar endless threads with a few interested folks like yourself trying to explain/rationalize it, as well as try to decide how this could be an "optional" hook. The library only improved as I took out all kinds of tricks like this which were leftovers from the original 0.1 model that followed the "magic everything, everywhere" pattern. various things come to mind in terms of re-enabling this pattern. One is that the "session registry" would be extensible. Technically it is right now if you were to override orm.session._state_session(). Then the lazyloaders would treat the parent object as though it were inside of whatever session you had it returning here. You could even hardwire it to the contextual session itself - then even sharing objects among threads would be selecting the current thread's session. I could barely consider what level of surprise side effects might/might not occur from this practice, but it is how things used to work. If you want to play with it, I can re-add some kind of event for this. I have a name like "detached session" in my mind, maybe an event that's only called if there's no session_id, maybe it's just a session registry you stick onto a mapper, though I suppose the event hook is a good place here. The other is that the "loader callable" here is a lot like an event and we could put a hook here that you'd just listen() for. That wouldn't be very difficult to do, though determining when it's invoked would be tricky. When the value is locally present in __dict__, I wouldn't want even one function call of latency there checking for a possible event handler. When the value isn't present, would the event be before callable_() is invoked, or only if callable_() is not present, etc. Also i played around with how the "load_lazy" function could be exposed such that the Session could be supplied, but it's not very nice for a public API - some loader callables populate the attribute, others return the function and the AttributeImpl does the population. Exposing this publicly would mean I can't adjust that without the risk of breaking existing apps. So see what happens if you, for the moment, just monkeypatch over orm.session._state_session to do a lookup in a global context if state.session_id isn't set. If that solves the problem of "I want detached objects to load stuff", for you and everyone else who wants this feature, then whatever - I'm not at all thrilled about this use case but if it's just one trivial hook that I don't need to encourage, then there you go. > > def configure_attribute(class_, attr, inst): > """ > Set up function to be invoked when relations are 'get'ed on > possibly > transient objects, so we can automatically query these related > objects > """ > if isinstance(inst.property, RelationshipProperty): > default_loader = inst.impl.callable_ > def load_value(state, passive): > if state.session_id is not None: > # this is persistent or pending, so > # return default sqla functionality > return default_loader(state, passive) > if passive is attributes.PASSIVE_NO_FETCH: > return attributes.PASSIVE_NO_RESULT > # session_id is currently None > state.session_id = DBSession().hash_key > retval = default_loader(state, passive) > state.session_id = None > return retval > inst.impl.callable_ = load_value > > .. > .. > event.listen(DBEntity, 'attribute_instrument', configure_attribute) > > > On Dec 26, 12:26 pm, Michael Bayer <mike...@zzzcomputing.com> wrote: >> On Dec 26, 2011, at 9:07 AM, Kent wrote: >> >>> Documentation for AttributeImpl.callable_ still reads >>> "optional function which generates a callable based on a parent >>> instance, which produces the "default" values for a scalar or >>> collection attribute when it's first accessed, if not present >>> already." >>> But it seems it is no longer the function which generates a callable, but >>> rather is the callable itself now, accepting both the state and the passive >>> parameters. >> >>> It used to be two stages, first callable_ accepts a state and then that >>> returns a callable which accepted the passive parameter. >> >> yes that was a fabulous simplification of things I'm still very happy about. >> >> >> >>> Can you briefly summarize how this is meant to work now? (I think the doc >>> string is wrong now??) >> >> docstring is wrong yes. the callable just receives a state and a passive >> flag, then loads something for the attribute. It's just one less level of >> "callable" and the two that we have in use are LoadDeferredColumns and >> LoadLazyAttribute in strategies.py. This also isn't very public API and >> if I pointed you to this for some previous issue, I'd be curious if I >> remembered to mention that..... >> >> >> >> >> >> >> >> >> >>> On 12/25/2011 10:31 AM, Michael Bayer wrote: >> >>>> yes a few change names, reconstruct_instance, init_instance, init_failed. >> >>>> On Dec 24, 2011, at 7:42 PM, Kent Bower wrote: >> >>>>> Right. And reconstruct_instance() was renamed load()? >> >>>>> On 12/24/2011 5:56 PM, Michael Bayer wrote: >>>>>> On Dec 24, 2011, at 10:04 AM, Kent wrote: >> >>>>>>> As the migration guide suggests, I'd like to embrace the events API. >>>>>>> Is mapper event load() invoked at exactly the same place as the >>>>>>> deprecated reconstruct_instance() ? >>>>>> yeah nothing has been moved. All the places where the internals would >>>>>> call XXXExtension.xxx_event() were just replaced with >>>>>> self.dispatch.xxx_event(), and the old Extension classes are invoked via >>>>>> an adapter to the new system. All unit tests for the extension system >>>>>> remain in place and haven't been modified. >> >>>>>>> -- >>>>>>> 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 >>>>>>> sqlalchemy+unsubscr...@googlegroups.com. >>>>>>> For more options, visit this group >>>>>>> athttp://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 sqlalchemy@googlegroups.com. >>>>> To unsubscribe from this group, send email to >>>>> sqlalchemy+unsubscr...@googlegroups.com. >>>>> For more options, visit this group >>>>> athttp://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 sqlalchemy@googlegroups.com. >>> To unsubscribe from this group, send email to >>> sqlalchemy+unsubscr...@googlegroups.com. >>> For more options, visit this group >>> athttp://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 sqlalchemy@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 sqlalchemy@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.