Example #1
0
def merge_context_modified_events(a, b):
    ''' Merge ContextModified event 'b' into ContextModified event 'a'.

        Assumes that 'b' is an event generated immediately after event 'a'.
        This entails, for example, that 'a.added' and 'b.added' are disjoint,
        since it doesn't make sense for the same name to be added twice in
        succession.
    '''
    assert disjoint(set(a.added), set(a.modified), set(a.removed))
    assert disjoint(set(b.added), set(b.modified), set(b.removed))

    for x in b.added:
        if x in a.added:
            assert False
        elif x in a.modified:
            assert False
        elif x in a.removed:
            a.removed.remove(x)
            a.added.append(x)
        else:
            a.added.append(x)

    for x in b.modified:
        if x in a.added:
            pass # 'a.added' is already correct
        elif x in a.modified:
            pass # 'a.modified' is already correct
        elif x in a.removed:
            assert False
        else:
            a.modified.append(x)

    for x in b.removed:
        if x in a.added:
            a.added.remove(x)
        elif x in a.modified:
            a.modified.remove(x)
            a.removed.append(x)
        elif x in a.removed:
            assert False
        else:
            a.removed.append(x)

    # 'changed' gives us little information, so this is the best we can do
    a.changed = list(set(a.changed + b.changed))

    a.reset |= b.reset

    assert disjoint(set(a.added), set(a.modified), set(a.removed))
Example #2
0
def merge_trait_dict_events(a, b, dict_):
    ''' Merge TraitDictEvent 'b' into TraitDictEvent 'a'.

        ``dict_`` should be a mapping object that gives the current value of
        'changed' items in the events.

        Assumes that 'b' is an event generated immediately after event 'a'.
        This entails, for example, that 'a.added.keys()' and
        'b.added.keys()' are disjoint, since it doesn't make sense for the
        same name to be added twice in succession.
    '''
    assert disjoint(set(a.added), set(a.changed), set(a.removed))
    assert disjoint(set(b.added), set(b.changed), set(b.removed))

    for k,v in b.added.iteritems():
        if k in a.added:
            assert False
        elif k in a.changed:
            assert False
        elif k in a.removed:
            if v is a.removed[k]:
                del a.removed[k]
            else:
                a.changed[k] = a.removed.pop(k)
        else:
            a.added[k] = v

    for k,v in b.changed.iteritems():
        if k in a.added:
            a.added[k] = dict_[k]
        elif k in a.changed:
            pass # 'a.added[k]' is already the correct value
        elif k in a.removed:
            assert False
        else:
            a.changed[k] = v

    for k,v in b.removed.iteritems():
        if k in a.added:
            del a.added[k]
        elif k in a.changed:
            a.removed[k] = a.changed[k]
            del a.changed[k]
        elif k in a.removed:
            assert False
        else:
            a.removed[k] = v

    assert disjoint(set(a.added), set(a.changed), set(a.removed))
Example #3
0
def merge_context_modified_events(a, b):
    ''' Merge ContextModified event 'b' into ContextModified event 'a'.

        Assumes that 'b' is an event generated immediately after event 'a'.
        This entails, for example, that 'a.added' and 'b.added' are disjoint,
        since it doesn't make sense for the same name to be added twice in
        succession.
    '''
    assert disjoint(set(a.added), set(a.modified), set(a.removed))
    assert disjoint(set(b.added), set(b.modified), set(b.removed))

    for x in b.added:
        if x in a.added:
            assert False
        elif x in a.modified:
            assert False
        elif x in a.removed:
            a.removed.remove(x)
            a.added.append(x)
        else:
            a.added.append(x)

    for x in b.modified:
        if x in a.added:
            pass  # 'a.added' is already correct
        elif x in a.modified:
            pass  # 'a.modified' is already correct
        elif x in a.removed:
            assert False
        else:
            a.modified.append(x)

    for x in b.removed:
        if x in a.added:
            a.added.remove(x)
        elif x in a.modified:
            a.modified.remove(x)
            a.removed.append(x)
        elif x in a.removed:
            assert False
        else:
            a.removed.append(x)

    # 'changed' gives us little information, so this is the best we can do
    a.changed = list(set(a.changed + b.changed))

    a.reset |= b.reset

    assert disjoint(set(a.added), set(a.modified), set(a.removed))
Example #4
0
def merge_trait_dict_events(a, b, dict_):
    ''' Merge TraitDictEvent 'b' into TraitDictEvent 'a'.

        ``dict_`` should be a mapping object that gives the current value of
        'changed' items in the events.

        Assumes that 'b' is an event generated immediately after event 'a'.
        This entails, for example, that 'a.added.keys()' and
        'b.added.keys()' are disjoint, since it doesn't make sense for the
        same name to be added twice in succession.
    '''
    assert disjoint(set(a.added), set(a.changed), set(a.removed))
    assert disjoint(set(b.added), set(b.changed), set(b.removed))

    for k, v in b.added.iteritems():
        if k in a.added:
            assert False
        elif k in a.changed:
            assert False
        elif k in a.removed:
            if v is a.removed[k]:
                del a.removed[k]
            else:
                a.changed[k] = a.removed.pop(k)
        else:
            a.added[k] = v

    for k, v in b.changed.iteritems():
        if k in a.added:
            a.added[k] = dict_[k]
        elif k in a.changed:
            pass  # 'a.added[k]' is already the correct value
        elif k in a.removed:
            assert False
        else:
            a.changed[k] = v

    for k, v in b.removed.iteritems():
        if k in a.added:
            del a.added[k]
        elif k in a.changed:
            a.removed[k] = a.changed[k]
            del a.changed[k]
        elif k in a.removed:
            assert False
        else:
            a.removed[k] = v

    assert disjoint(set(a.added), set(a.changed), set(a.removed))
Example #5
0
    def _bind(self, names):

        # Local bindings shadow global names and replace conditional locals
        self.locals |= set(names)
        self.globals -= set(names)
        self.conditional_locals -= set(names)

        assert disjoint(self.globals, self.locals, self.conditional_locals)
Example #6
0
    def _bind_conditional(self, names):

        # Conditional bindings shadow global names, but are precluded by
        # existing unconditional bindings
        self.conditional_locals |= set(names) - self.locals
        self.globals -= set(names)

        assert disjoint(self.globals, self.locals, self.conditional_locals)
Example #7
0
    def _bind_conditional(self, names):

        # Conditional bindings shadow global names, but are precluded by
        # existing unconditional bindings
        self.conditional_locals |= set(names) - self.locals
        self.globals -= set(names)

        assert disjoint(self.globals, self.locals, self.conditional_locals)
Example #8
0
    def _bind(self, names):

        # Local bindings shadow global names and replace conditional locals
        self.locals |= set(names)
        self.globals -= set(names)
        self.conditional_locals -= set(names)

        assert disjoint(self.globals, self.locals, self.conditional_locals)
Example #9
0
    def _dict_is_modified( self, event ):
        """ Fires when 'context_data' fires 'dict_modified'.
        """
        assert disjoint( event.added, event.changed, event.removed )

        # How much can we optimize this while keeping it maintainable?

        # If the dictionary has changed, then we are dirty. (I think this is
        # the only place we have to do this...)
        self.dirty = True

        # These become attributes on a ContextModified event we create below.
        # Leave them as normal sets until the end to avoid excessive trait
        # validation.
        added    = set()
        modified = set()
        removed  = set()
        changed  = set()

        # The following three loops duplicate code: the body of 'changed' is
        # simply the body of 'removed' followed by the body of 'added',
        # followed by some logic for group maintenance. It would be better to
        # abstract out the two shared chunks, but I keep waiting for a higher
        # level insight that will greatly simplify this logic and eliminate the
        # need to repeat code in the first place.

        for name, new in event.added.iteritems():

            # Rebind renamed dynamic bindings
            if hashable( new ) and new in self._dynamic_bindings:
                self._rebind_dynamic( new, name )

            # Add new data
            if self.is_valid_array( new ):
                added.update(
                    self._add_context_items( ContextItem( name = name ) )
                )
            elif isinstance( new, ANumericContext ):
                added.update( self._add_sub_context( name, new ) )
                changed.add( name )
            else:
                changed.add( name )

        for name, old in event.changed.iteritems():
            new = self.context_data[ name ]

            # Short-circuit if possible
            if new is old:
                continue

            # Unbind dynamic bindings
            if hashable( old ) and old in self._dynamic_bindings:
                d = self._dynamic_bindings[ old ]
                self._unbind_dynamic( old, d['trait_name'], remove=False )

            # Remove old data
            if name in self._context_items:
                removed.update(
                    self._remove_context_items( self._context_items[ name ],
                                                delete = False )
                )
            elif isinstance( old, ANumericContext ):
                removed.update( self._remove_sub_context( name, old ) )
                changed.add( name )
            else:
                changed.add( name )

            # Rebind dynamic bindings
            if hashable( new ) and new in self._dynamic_bindings:
                self._rebind_dynamic( new, name )

            # Add new data
            if self.is_valid_array( new ):
                added.update(
                    self._add_context_items( ContextItem( name = name ) )
                )
            elif isinstance( new, ANumericContext ):
                added.update( self._add_sub_context( name, new ) )
                changed.add( name )
            else:
                changed.add( name )

            # Update an item's group if it changes shape
            if ( self.is_valid_array( new ) and self.is_valid_array( old ) and
                    new.shape != old.shape ):

                context_groups = self._context_groups
                item           = self._context_items[ name ]

                for group in item.groups:
                    n, names = context_groups[ group ]
                    names.remove( name )
                    if len( names ) == 0:
                        del context_groups[ group ]

                group       = new.shape
                item.groups = [ group ]
                context_groups.setdefault(
                    group, ( group, [] ) )[1].append( name )

        for name, old in event.removed.iteritems():

            # Unbind dynamic bindings
            if hashable( old ) and old in self._dynamic_bindings:
                d = self._dynamic_bindings[ old ]
                self._unbind_dynamic( old, d['trait_name'], remove=False )

            # Remove old data
            if name in self._context_items:
                removed.update(
                    self._remove_context_items( self._context_items[ name ],
                                                delete = False )
                )
            elif isinstance( old, ANumericContext ):
                removed.update( self._remove_sub_context( name, old ) )
                changed.add( name )
            else:
                changed.add( name )

        # Calculate context event
        modified |= added & removed
        added    -= modified
        removed  -= modified
        cm = ContextModified(
            added    = list( added ),
            modified = list( modified ),
            removed  = list( removed ),
            changed  = list( changed ),
        )

        # Fire events
        self.post_dict_modified( event )
        self.post_context_modified( cm )
Example #10
0
 def test_disjoint(self):
     self.assertTrue(disjoint(set([1,2]), set([3])))
     self.assertFalse(disjoint(set('abc'), set('xy'), set('z'), set('cde')))
     self.assertTrue(disjoint())
Example #11
0
 def test_disjoint(self):
     self.assertTrue(disjoint(set([1, 2]), set([3])))
     self.assertFalse(disjoint(set('abc'), set('xy'), set('z'), set('cde')))
     self.assertTrue(disjoint())