[sqlalchemy] Re: overriding collection methods

2007-08-20 Thread sdobrev
sorry, fixed patch

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

Index: orm/collections.py
===
--- orm/collections.py	(revision )
+++ orm/collections.py	(working copy)
@@ -647,35 +648,32 @@
 # ensure all roles are present, and apply implicit instrumentation if
 # needed
-if 'appender' not in roles or not hasattr(cls, roles['appender']):
+for rolename,eventname in dict(
+appender='fire_append_event',
+remover ='fire_remove_event',
+iterator=None,
+).iteritems():
+roler = roles.get( rolename, None)
+if not rolename or not hasattr(cls, roler):
+typename = cls.__name__
 raise exceptions.ArgumentError(
-Type %s must elect an appender method to be 
-a collection class % cls.__name__)
-elif (roles['appender'] not in methods and
-  not hasattr(getattr(cls, roles['appender']), '_sa_instrumented')):
-methods[roles['appender']] = ('fire_append_event', 1, None)
-
-if 'remover' not in roles or not hasattr(cls, roles['remover']):
-raise exceptions.ArgumentError(
-Type %s must elect a remover method to be 
-a collection class % cls.__name__)
-elif (roles['remover'] not in methods and
-  not hasattr(getattr(cls, roles['remover']), '_sa_instrumented')):
-methods[roles['remover']] = ('fire_remove_event', 1, None)
-
-if 'iterator' not in roles or not hasattr(cls, roles['iterator']):
-raise exceptions.ArgumentError(
-Type %s must elect an iterator method to be 
-a collection class % cls.__name__)
+Type %(typename)s must elect an %(role)s method to be 
+a collection class % locals() )
+elif (eventname and
+roler not in methods and
+not hasattr(getattr(cls, roler), '_sa_instrumented')):
+methods[ roler] = ( eventname, 1, None)
 
 # apply ad-hoc instrumentation from decorators, class-level defaults
 # and implicit role declarations


[sqlalchemy] Re: overriding collection methods

2007-08-20 Thread svilen

another thing noted, the collections instrumentation fails over old 
python classes (not inheriting object), e.g. 
class myX: ...whatever...

it fails at _instrument_class(), because type(myX()) being 
type 'instance' is recognized as builtin, and apart of that the 
util.duck_type_collection() may fail because issubclass does not work 
just straighforward, e.g. must be 
import types
isa = isinstance(specimen, (type, types.ClassType)) and issubclass 
or isinstance

neither types.ClassType (type 'clasobj' or the above mentioned 
type 'instance' are otherwise accesible as some predefined python 
type - but only as type(someclass) or type(someclass()).

ciao
svil

--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread svilen

a suggestion about _list_decorators() and similar.
they can be easily made into classes, i.e. non dynamic (and 
overloadable/patchable :-).

class _list_decorators( object):  #instead of def _list_decorators()
  all contents/decorators stays same...
 
_funcs = _get_decorators( locals() )

def __new__( klas):
return klas._funcs

def _get_decorators( d):
skip = '__module__', '__doc__',
if 1:   #Whichever way preferred
r = dict( (k,v) for k,v in d.iteritems() if k not in skip)
or:
r = d.copy()
for s in skip: r.pop(s)
return r

_def _tidy(fn): ... #becomes global

the only prerequisite for this is to rename __del() and __set() into 
_del /_set or else they get looked up as private-named identifiers 
(?? no idea why).

ciao
svilen


--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread svilen
a patch, it got even tidier ;-) - 
no more _tidy() calls, all automated.

On Monday 20 August 2007 16:41:30 svilen wrote:
 a suggestion about _list_decorators() and similar.
 they can be easily made into classes, i.e. non dynamic (and
 overloadable/patchable :-).

 class _list_decorators( object):  

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

Index: sqlalchemy/orm/collections.py
===
--- sqlalchemy/orm/collections.py	(revision 3375)
+++ sqlalchemy/orm/collections.py	(working copy)
@@ -746,7 +749,7 @@
 pass
 return wrapper
 
-def __set(collection, item, _sa_initiator=None):
+def _set(collection, item, _sa_initiator=None):
 Run set events, may eventually be inlined into decorators.
 
 if _sa_initiator is not False and item is not None:
@@ -754,7 +757,7 @@
 if executor:
 getattr(executor, 'fire_append_event')(item, _sa_initiator)
   
-def __del(collection, item, _sa_initiator=None):
+def _del(collection, item, _sa_initiator=None):
 Run del events, may eventually be inlined into decorators.
 
 if _sa_initiator is not False and item is not None:
@@ -762,17 +765,28 @@
 if executor:
 getattr(executor, 'fire_remove_event')(item, _sa_initiator)
 
-def _list_decorators():
+def _tidy_(fn, base):
+fn._sa_instrumented = True
+fn.__doc__ = getattr( base, fn.__name__).__doc__
+return fn
+
+def _tider( func, base):
+def f( fn): return _tidy_( func(fn), base)
+return f
+
+def _get_decorators( d, base):
+skip = '__module__', '__doc__',
+return dict( (k,_tider(v,base)) for k,v in d.iteritems() if k not in skip )
+
+
+class _list_decorators( object):#def _list_decorators():
 Hand-turned instrumentation wrappers that can decorate any list-like
 class.
 
-def _tidy(fn):
-setattr(fn, '_sa_instrumented', True)
-fn.__doc__ = getattr(getattr(list, fn.__name__), '__doc__')
 
 def append(fn):
 def append(self, item, _sa_initiator=None):
-# FIXME: example of fully inlining __set and adapter.fire
+# FIXME: example of fully inlining _set and adapter.fire
 # for critical path
 if _sa_initiator is not False and item is not None:
 executor = getattr(self, '_sa_adapter', None)
@@ -780,21 +794,18 @@
 executor.attr.fire_append_event(executor._owner(),
 item, _sa_initiator)
 fn(self, item)
-_tidy(append)
 return append
 
 def remove(fn):
 def remove(self, value, _sa_initiator=None):
 fn(self, value)
-__del(self, value, _sa_initiator)
-_tidy(remove)
+_del(self, value, _sa_initiator)
 return remove
 
 def insert(fn):
 def insert(self, index, value):
-__set(self, value)
+_set(self, value)
 fn(self, index, value)
-_tidy(insert)
 return insert
 
 def __setitem__(fn):
@@ -802,8 +813,8 @@
 if not isinstance(index, slice):
 existing = self[index]
 if existing is not None:
-__del(self, existing)
-__set(self, value)
+_del(self, existing)
+_set(self, value)
 fn(self, index, value)
 else:
 # slice assignment requires __delitem__, insert, __len__
@@ -830,114 +841,101 @@
len(rng)))
 for i, item in zip(rng, value):
 self.__setitem__(i, item)
-_tidy(__setitem__)
 return __setitem__
 
 def __delitem__(fn):
 def __delitem__(self, index):
 if not isinstance(index, slice):
 item = self[index]
-__del(self, item)
+_del(self, item)
 fn(self, index)
 else:
 # slice deletion requires __getslice__ and a slice-groking
 # __getitem__ for stepped deletion
 # note: not breaking this into atomic dels
 for item in self[index]:
-__del(self, item)
+_del(self, item)
 fn(self, index)
-_tidy(__delitem__)
 return __delitem__
 
 def __setslice__(fn):
 def __setslice__(self, start, end, values):
 for value in self[start:end]:
-

[sqlalchemy] Re: overriding collection methods

2007-08-20 Thread svilen

and no need for that __new__ replacement either - just use 
_list_decorators._funcs instead of _list_decorators()

On Monday 20 August 2007 17:05:32 svilen wrote:
 a patch, it got even tidier ;-) -
 no more _tidy() calls, all automated.

 On Monday 20 August 2007 16:41:30 svilen wrote:
  a suggestion about _list_decorators() and similar.
  they can be easily made into classes, i.e. non dynamic (and
  overloadable/patchable :-).
 
  class _list_decorators( object):

--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread svilen

On Monday 20 August 2007 17:29:52 jason kirtland wrote:
 [EMAIL PROTECTED] wrote:
  hi
  i need to have a list collection with list.appender (in SA 0.4
  terms) that accepts either one positional arg as the value, or
  keyword args which it uses to create the value. Each collection
  instance knows what type of values to create.
 
   [...]
   Any idea to fix/enhance this, letting **kwargs through to my
   function? The dynamic wrapper() can do this, while these preset
   ones cannot... while they should be equaly powerful.

 Hi Svil,

 @collections.appender
 @collections.internally_instrumented
 def append(self, obj=_NOTSET, **kargs):
...

  There are 2 (different) uses of an appender, one is the SA
  itself, but the other is the programmer. SA will always use
  single
  arg/positionals, while i could use this or that or combination.

 SQLAlchemy's appender doesn't have to be the programmer's appender.
  You can add a method solely for the orm's use if you like.  That's
 one of the points of the decorator syntax, divorcing function names
 from the interface.  If you want to keep 'append' for your own use,
 just tag another method as the @appender.
thanks for suggestion. 

This would work if the default decorators were not force wrapped 
anyway, in that ABC decoration part. i'm looking now to see why is 
it so. 

And anyway i need to first create the object and just then append it 
(the decorators will first fire event on the object and just then 
append(), that is call me), so may have to look further/deeper. 
Maybe i can make my append create objects first and then call the 
actual appender - so yes, this is the way.


--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread jason kirtland

svilen wrote:
 a suggestion about _list_decorators() and similar.
 they can be easily made into classes, i.e. non dynamic (and 
 overloadable/patchable :-).

The stdlib decorators end up in a static, module-level dictionary that 
can be manipulated if you want to.  Wouldn't this be replacing a dict 
with some_cls.__dict__?


--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread svilen

On Monday 20 August 2007 18:01:49 jason kirtland wrote:
 svilen wrote:
  a suggestion about _list_decorators() and similar.
  they can be easily made into classes, i.e. non dynamic (and
  overloadable/patchable :-).

 The stdlib decorators end up in a static, module-level dictionary
 that can be manipulated if you want to.  Wouldn't this be replacing
 a dict with some_cls.__dict__?

well, more or less...
i use similar function-made locals() namespaces a _lot_, and maybe 
thats why i avoid using them whenever i can - their contents is not 
easily changeable/inheritable/splitable... programaticaly, 
piece-by-piece.
whatever.

--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread jason kirtland

svilen wrote:
 And anyway i need to first create the object and just then append it 
 (the decorators will first fire event on the object and just then 
 append(), that is call me), so may have to look further/deeper. 
 Maybe i can make my append create objects first and then call the 
 actual appender - so yes, this is the way.

Either way.  The @internally_instrumented is there exactly for that 
flexibility on ORM interface methods like 'append' and as an override 
for ABC decoration on python interface methods.  (The regular recipes 
also override ABC decoration.)   Or you can do you work elsewhere and 
forward to an instrumented method for event service.



--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread sdobrev

On Monday 20 August 2007 18:09:41 jason kirtland wrote:
 svilen wrote:
  And anyway i need to first create the object and just then append
  it (the decorators will first fire event on the object and just
  then append(), that is call me), so may have to look
  further/deeper. Maybe i can make my append create objects first
  and then call the actual appender - so yes, this is the way.

 Either way.  The @internally_instrumented is there exactly for that
 flexibility on ORM interface methods like 'append' and as an
 override for ABC decoration on python interface methods.  (The
 regular recipes also override ABC decoration.)   Or you can do you
 work elsewhere and forward to an instrumented method for event
 service.
an example on this? i can't figure it out, whatever i do, that 
ABC-auto-decorators loop kicks in and byebye my nice append - even if 
the appender is not append() at all. Why should append() be 
instrumented regardless of it being or not the used appender?

@internally_instrumented - u mean my append() to do everything, even 
firing of events? uhm. ugly, for my simple case. 
and are there some fire-this-event() funcs? those __del()/__set() do 
not seem like very exposed...


class _NotSet: pass 
class MyCollection( list):
factory = None
def append( me, obj =_NotSet, **kwargs):
if obj is _NotSet: 
print 'success!', kwargs
obj = factory(**kwargs)
me._append( obj)
return obj
@sqlalchemy.orm.collections.collection.appender
def _append( me, *a,**k): return list.append(me, *a,**k)

m = mapper( A, .., rel = relation( collection_class = 
MyCollection)... )

a=A()
a.rel.append( key1=val1, key2=val2)
#this always fails/TypeError, as the append called is not mine, but an 
wrapped/instrumented one and that one has no kwargs.


btw, i noted the sequence fire-event() / original-func-call() is not 
same/consistent in those auto-decorators, e.g. for remove() and del() 
etc.


--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread sdobrev

On Monday 20 August 2007 20:58:45 [EMAIL PROTECTED] wrote:
 On Monday 20 August 2007 18:09:41 jason kirtland wrote:
  svilen wrote:
   And anyway i need to first create the object and just then
   append it (the decorators will first fire event on the object
   and just then append(), that is call me), so may have to look
   further/deeper. Maybe i can make my append create objects first
   and then call the actual appender - so yes, this is the way.
 
  Either way.  The @internally_instrumented is there exactly for
  that flexibility on ORM interface methods like 'append' and as an
  override for ABC decoration on python interface methods.  (The
  regular recipes also override ABC decoration.)   Or you can do
  you work elsewhere and forward to an instrumented method for
  event service.

 an example on this? i can't figure it out, whatever i do, that
 ABC-auto-decorators loop kicks in and byebye my nice append - even
 if the appender is not append() at all. Why should append() be
 instrumented regardless of it being or not the used appender?

so @internally_instrumented prevents any automatic wrapping, ok i got 
it. (The docstrings in collections.py should make their way to the 
normal docs...)
it is not at all obvious why, if there is a choosen appender, the 
default one (append() or whatever) has to be instrumented too...

--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread jason kirtland

[EMAIL PROTECTED] wrote:

 On Monday 20 August 2007 18:09:41 jason kirtland wrote:
 svilen wrote:
  And anyway i need to first create the object and just then
  append it (the decorators will first fire event on the object
  and just then append(), that is call me), so may have to look
  further/deeper. Maybe i can make my append create objects first
  and then call the actual appender - so yes, this is the way.

 Either way.  The @internally_instrumented is there exactly for
 that flexibility on ORM interface methods like 'append' and as an
 override for ABC decoration on python interface methods.  (The
 regular recipes also override ABC decoration.)   Or you can do
 you work elsewhere and forward to an instrumented method for
 event service.
 an example on this? i can't figure it out, whatever i do, that
 ABC-auto-decorators loop kicks in and byebye my nice append -
 even if  the appender is not append() at all.

For your example, something like:

class MyCollection(list):
@collection.internally_instrumented
def append(self, options, **kw):
# do factory stuff, forward to _append
new_obj = factory_stuff(options, **kw)
# forward to _append, which will fire events
self._append(new_obj)
@collection.appender
def _append(self, item):
   ...

But tacking a factory method onto a regular Python list is much 
simpler with a separation of concerns:

class FactoryCollection(list):
   def create(self, options, **kw):
  obj = factory_stuff(options, **kw)
  self.append(obj)
  return obj

No decorators needed.

For a while there was a no-op decorator that did the same job as 
@internally_instrumented in the first example, just a different 
name for clarity.  It could easily come back if this pattern 
becomes common- I yanked it after working with the collections for 
a while and finding the second form much more common in my work.

 Why should append() be instrumented regardless of it being or
 not the used appender?

If you use an object with a Python list interface, all the list 
interface methods will be instrumented so that relation collections 
have natural Pythonic behavior.  If you don't want automatic 
instrumentation on list methods you don't have to have it- see the 
0.4 docs for how to opt out via __emulates__.


--~--~-~--~~~---~--~~
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: overriding collection methods

2007-08-20 Thread sdobrev

 But tacking a factory method onto a regular Python list is much
 simpler with a separation of concerns:

 class FactoryCollection(list):
def create(self, options, **kw):
eh sorry, i want it the hard way.. 
now as i think of it, its just me being lazy and fancy - preferring 
implicitness and less method names to remember.

 For a while there was a no-op decorator that did the same job as
 @internally_instrumented in the first example, just a different
 name for clarity.  It could easily come back if this pattern
 becomes common- I yanked it after working with the collections for
 a while and finding the second form much more common in my work.
@do_not_instrument might a be better name -- but regardless the name, 
if the opting-out concept is not not advertised, one does not know 
what to look 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
-~--~~~~--~~--~--~---