[Subversion] / PEAK / src / peak / binding / _once.pyx |
No default branch
Bookmark a link to HEAD:
(view)
(download)
Drop another module from initial load requirements, by using the Python/C API for 'threads.get_ident()' instead of importing a Python version from 'peak.util.threads'. (This may also slightly speed up the initial computation of attribute bindings, but it's unlikely to be measurable.)
Got rid of bogus equivalance between NOT_FOUND and AttributeError. We never used it before, it's counterintuitive, and it makes it impossible to use the 'subject' attribute in 'peak.web.TraversalContext' when the target object is NOT_FOUND.
All 'peak.binding' APIs now only accept positional parameters for items unique to that API. Items common to multiple APIs (such as 'offerAs', 'doc', 'attrName', etc.) should now be supplied as keyword arguments. Bindings also now automatically "suggest" the containing object as a parent component for the contained object, whenever a value is assigned to them or computed. If a non-None 'adaptTo' is set on the binding, the value assigned or computed will be adapted to the specified protocol before the parent component is suggested. 'binding.New()' no longer relies on the 'IComponentFactory' interface, but instead uses the new adapt/suggest mechanisms. Previously, parent components were only "suggested" when a binding was set via component constructor keyword arguments. Now, this is done at any time bindings are set, but *not* for non-binding keyword arguments. In other words, ordinary attributes of a component do not receive "suggested parent" notices, even when set via constructor keyword arguments. If you want an attribute to do this, you must define the attribute with the binding API; e.g. via 'requireBinding()' or 'binding.Constant()'.
Fixed up error checking; bindings now can tell again if they're used with the wrong name in a class that doesn't support them. But, now they should also be usable at multiple metalevels without conflict, since the usage checking only occurs when used in non-supporting classes. (Don't know what that means? Me, either! It's one of those things that you don't expect to be a problem, but is. Or was, now. I think. Need to add some tests.)
First phase of descriptor refactoring. Once bindings now place a proxy for themselves in a class when activated in that class. This avoids the need for Once-derivatives to "copy" themselves when they are found under more than one name (e.g in the same class or when they are created without a name initially). Eventually this will let us do something similar with model.StructuralFeature objects. Added hooks to the Once class family to allow an 'onSet()' method to be called that can alter a value being setattr'd. This will let us do automatic 'adapt()' and 'setParentComponent()' when attributes are set or looked up. Also, simplified the structure of the Pyrex OnceDescriptor base, using Pyrex 0.7.2's ability to declare C-level attributes visible from Python. (Previously, we used a custom descriptor to deal with this.) NOTE: Error checking of bindings is partly BROKEN right now; bindings do not verify that they haven't been placed in a class that doesn't support them; they only verify that they have been told what name to use. This needs a little review, and the tutorial may need to be adjusted as well.
Normalized whitespace.
Updated to use Pyrex version 0.6.1, which now handles descriptor methods correctly and can build pure-C source that works with the mingw32 distutils compiler. PEAK's Pyrex source files can now be built by 0.6.1 without special patches to either PEAK or Pyrex. Hurray for Pyrex, and its author, Greg Ewing!
Made Once attributes thread-safe, to a point. While a "once" attribute is being calculated, a special "lock" object is placed in the object's dictionary. This object just holds the thread ID of the calculating thread. If a re-entrant access to the attribute is made, the lock's ID is checked for whether it's the same thread. If it's the same thread, an error is raised indicating that the attribute has a circular definition. If it's not the same thread, the current thread pretends the value hasn't been computed yet, and tries to compute it. Note that in cases where the underlying once function and object are properly constructed, this may occasionally result in two threads doing the same work to calculate the attribute, but the results are always the same. In cases where the once function actually refers back to itself, it's possible for competing threads to keep stealing the lock from each other and thus never terminate. Well, actually, you'll get a recursion depth error on both threads, eventually. So the limitations of this guard technique should be quite acceptable for the intended uses of once bindings, especially since this protection is really intended for class attributes such as 'peak.model' metadata, not instance attributes. Classes *have* to be sharable between threads; instances rarely need to be.
Retrieving an already-computed Once binding is now only 15% slower than access to a regular Python new-style attribute or slot, at least on my Windows machine. I think Once is now tuned enough; next it needs thread safety for the actual computation, and variant versions to be used for structural feature computations.
Fixed a performance problem with binding.Once introduced by my correctness fix. Apparently, if speed is your aim, you should not use module-level variables in Pyrex to hold imported items. Instead, define 'cdef' global variables for them, and then assign the imported items to them. 'cdef' vars don't require a dictionary lookup for access.
Change to binding.Once: if the object's dict contains 'NOT_FOUND' as the bound attribute's value, 'AttributeError' is raised upon access. This lets you override a bound attribute value and declare it non-existent, and it also ensures that a circularly defined attribute will result in an error message. Unfortunately, an error will also result if two threads attempt to access and compute the bound attribute "at the same time". But this is a slight improvement over the situation prior to this change, where a race condition would cause the "losing" thread to silently return 'NOT_FOUND', possibly causing the problem to lurk awhile. The existence of this race condition is a potentially serious problem with the use of lazy attribute bindings in class objects (which are shared between threads), and it may be that we will need to require some type of locking for such bindings. :(
Completed conversion to C of the base class descriptor methods for 'Once' attributes. Due to constraints in how Pyrex creates extension types, it was not possible to continue support for the (deprecated anyway) 'OnceClass' and 'AutoCreatable' metaclasses. This is now cleaned up pretty decently and runs the tests at least as fast as before I began the metadata refactoring yesterday (~4.1 seconds on my Windows PC). Note that if you want to build from Pyrex source or have Pyrex installed, you *must* patch Pyrex.Compiler.TypeSlots so that these two lines: descrgetfunc = Signature("TOO", "O") # typedef ... descrsetfunc = Signature("TOO", "O") # typedef ... Look like *this* instead: descrgetfunc = Signature("Tpp", "O") # typedef ... descrsetfunc = Signature("TOp", "i") # typedef ... This is a work-around for improper generation of descriptor __get__/__set__ code by Pyrex.
cvs-admin@eby-sarna.com Powered by ViewCVS 1.0-dev |
ViewCVS and CVS Help |