The PEAK Developers' Center   Diff for "TrellisCollections" UserPreferences
 
HelpContents Search Diffs Info Edit Subscribe XML Print View
Ignore changes in the amount of whitespace

Differences between version dated 2008-01-07 15:55:17 and 2008-05-23 12:49:19 (spanning 2 versions)

Deletions are marked like this.
Additions are marked like this.

.. contents:: **Table of Contents**
 
 
 
SortedSet
---------
 

    >>> myIndex = collections.SortedSet(data=myItems)
 
    >>> class Viewer(trellis.Component):
    ... trellis.values(model = None)
    ... model = trellis.attr(None)
    ...
    ... @trellis.observer
    ... trellis.perform()
    ... def view_it(self):
    ... if self.model is not None:
    ... print self.model

    >>> view.model = None # quiet, please
 
    >>> class Watcher(trellis.Component):
    ... @trellis.observer
    ... trellis.perform()
    ... def dump(self):
    ... print myIndex.changes
 

that it's possible to have multiple slices if multiple items are added or
deleted::
 
    >>> @trellis.modifier
    ... def add_some():
    >>> def add_some():
    ... myItems.add(0)
    ... myItems.add(4)
 
    >>> add_some()
    >>> trellis.atomically(add_some)
    [(3, 3, 1), (0, 0, 1)]
    []
    >>> myIndex

 
Finally, note that adjacent operations may be merged into single slices::
 
    >>> @trellis.modifier
    ... def del_some():
    >>> def del_some():
    ... myItems.remove(2)
    ... myItems.remove(3)
 
    >>> del_some()
    >>> trellis.atomically(del_some)
    [(1, 3, 0)]
    []
    >>> myIndex

And that insertion+deletion at the same position can lead to change slices that
don't result in a net change to the number of rows::
 
    >>> @trellis.modifier
    ... def add_and_del():
    >>> def add_and_del():
    ... myItems.remove(1)
    ... myItems.add(2)
 
    >>> add_and_del()
    >>> trellis.atomically(add_and_del)
    [(1, 2, 1)]
    []
    >>> myIndex
    [4, 2, 0]
 
    >>> @trellis.modifier
    ... def add_and_del():
    >>> def add_and_del():
    ... myItems.remove(2)
    ... myItems.add(1)
 
    >>> add_and_del()
    >>> trellis.atomically(add_and_del)
    [(1, 2, 1)]
    []
    >>> myIndex

 
    >>> def show():
    ... print "Changes:", o.changes
    >>> c = trellis.ObserverCell(show)
    >>> c = trellis.Performer(show)
    Changes: {}
 
The ``changes`` attribute is a dictionary (a regular dictionary, not a

 
The basic idea for using an ``Observing`` object is to update the ``keys`` to
reflect the currently-visible row or column numbers (or other keys) of a data
structure being displayed in a GUI. Then, an ``@action`` rule that reads the
structure being displayed in a GUI. Then, a ``@perform`` rule that reads the
``changes`` can notify the GUI of any changes that happen to the underlying
data structure.
 

 
TODO: ``changes`` doesn't update if you initialize ``keys`` with a populated
set.
 
 
Hub (NEW in 0.7a2)
------------------
 
A ``collections.Hub`` is used for loosely-coupled many-to-many communications
with flexible pattern matching -- aka "publish/subscribe" or "pub/sub"
messaging::
 
    >>> hub = collections.Hub()
 
You can send messages into a hub by calling its ``put()`` method::
 
    >>> hub.put(1, 2, 3)
 
    
However, this does nothing unless there are rules using the hub's ``get()``
method to receive these messages::
 
    >>> def watch_3_3():
    ... for message in hub.get(None, None, 3):
    ... print message
    
    >>> watch_3_3 = trellis.Performer(watch_3_3)
 
    >>> hub.put(1, 2, 3)
    (1, 2, 3)
 
The ``put()`` and ``get()`` methods both accept an arbitrary number of
positional arguments, but ``get()`` will only match ``put()`` calls with
the same number of arguments::
 
    >>> hub.put('x', 'y')
 
    >>> hub.put(1, 2, 3, 4)
 
And then, only if the non-``None`` arguments to ``get()`` match the
corresponding arguments given to ``put``::
 
    >>> hub.put(1, 2, 4)
 
    >>> hub.put(5, 4, 3)
    (5, 4, 3)
 
You can of course have multiple rules monitoring the same hub::
 
    >>> def watch_2_4():
    ... for message in hub.get(2, 4, None):
    ... print "24:", message
    >>> watch_2_4 = trellis.Performer(watch_2_4)
 
    >>> hub.put(2,4,3)
    24: (2, 4, 3)
    (2, 4, 3)
 
    >>> hub.put(2, 4, 4)
    24: (2, 4, 4)
 
And you can send more than one value in a single recalculation or atomic
action, with the relative order of messages being preserved for each observer::
 
    >>> def send_many():
    ... hub.put(1, 2, 3)
    ... hub.put(2, 4, 4)
    ... hub.put(2, 4, 3)
 
    >>> trellis.atomically(send_many)
    24: (2, 4, 4)
    24: (2, 4, 3)
    (1, 2, 3)
    (2, 4, 3)
 
Note, however, that all arguments to ``put()`` and ``get()`` must be hashable::
 
    >>> hub.put(1, [])
    Traceback (most recent call last):
      ...
    TypeError: list objects are unhashable
 
    >>> hub.get(1, [])
    Traceback (most recent call last):
      ...
    TypeError: list objects are unhashable
 
This is because hubs use a dictionary-based indexing system, that avoids the
need to test every message against every observer's match pattern. Each
active ``get()`` pattern is saved under an index, keyed by its rightmost
non-``None`` value.
 
Each value in a message is then looked up in this index, and then tested
against that (hopefully small) subset of active patterns. For example, if we
look at the contents of our sample hub's index, we can see that the
``(None, None, 3)`` match pattern is indexed under "position 2, value 3", and
the ``(2, 4, None)`` pattern is indexed under "position 1, value 4"::
 
    >>> hub._index
    {(2, 3): {(None, None, 3): 1}, (1, 4): {(2, 4, None): 1}}
 
This means that ``(2, 4, None)`` will only be checked for messages with a 4
in the second position, and ``(None, None, 3)`` will only be checked for
messages with a 3 in the third position (which of course it will always match).
 
So, for best performance in high-volume applications, make sure you design your
messages to place "more distinct" fields further to the right. For example, if
you have a small number of distinct message types, you should probably make the
message type the first field, so that if a ``get()`` matches on both the
message type and some more-distinctive field, it will be indexed only on the
more-distinctive field, avoiding it being matched against every message of the
desired type. (Unless of course, the ``get()`` is *supposed* to return all
messages of the desired type!)
 
In contrast, if you placed the message type as the last field, then any
``get()`` targeting a particular message type would incur a match-time penalty
for *every* message of that type. Thus, you should place fields with fewer
possible values more to the left, and fields with a larger number of possible
values more to the right.
 

PythonPowered
ShowText of this page
EditText of this page
FindPage by browsing, title search , text search or an index
Or try one of these actions: AttachFile, DeletePage, LikePages, LocalSiteMap, SpellCheck