Exemple #1
0
    def register_change(self, key, left_value, right_value, change_type):
        """Assuming that left_value is the base state and the right value is the value to be set, we assure that
        
        - Modifications
          + Modified values will be passed on to the resolver, which will merge them or pick a side
        - Deletions
          + right values which are missing will be missing in the value we produce
        - Additions
          + right values which are where added will be added to the data structure unchecked
        - Unchanged
          + Unchanged values will be taken right away.
          
        We will copy right values to assure they are independent.
        """
        value_to_set = NoValue
        if change_type is self.added:
            value_to_set = self._handle_added(key, left_value, right_value)
        elif change_type is self.modified:
            value_to_set = self._resolve_conflict(key, left_value, right_value)
        elif change_type is self.unchanged:
            value_to_set = self._handle_unchanged(key, right_value)
        elif change_type is self.deleted:
            # If there was no change made to our current merge_value (tree) yet, we might have it still 
            # at the initial value, NoValue.
            # However, the _handle_deleted method requires parent_tree to be a tree-like objects, and asserts for it
            # We assure this now
            parent_tree = self._merged_value
            if parent_tree is NoValue:
                parent_tree = self.DictType()
            # handle possiblity of having NoValue as merged_value
            self._handle_deleted(key, parent_tree, left_value)
        #end handle change type

        if value_to_set is not NoValue:
            self._set_merged_value(key, smart_deepcopy(value_to_set))
Exemple #2
0
    def register_change(self, key, left_value, right_value, change_type):
        """Pick either a default value (right-hand side value) or the stored value (left-hand side)
        @note handles AnyKey"""
        if isinstance(key, type) and issubclass(key, AnyKey):
            # AnyKeys and their values are ignored if we get to the point where were are supposed to merge
            # them. This happens if it is indirectly removed or added, when whole branches are missing
            # in our data.
            # In that case, we just don't want to see it, the one who usees AnyKey needs to handle no keys
            # underneath AnyKeys parent tree anyway.
            
            # Change instance attribute, now AnyKey will map to an empty dict, which needs to be kept
            # to help clients to deal with it nicely
            self.delete_empty_trees = False
            return
        #end ignore everything underneath AnyKeys
        
        actual_value = NoValue
        qkey = self._qualified_key(self._to_string_key(key))
        
        # assure we have an instance for our assignments
        right_value_inst = right_value
        if isinstance(right_value, type) and right_value not in (TreeItem, NoValue):
            right_value_inst = right_value()
        # assure we have an instance for our assignments

        if change_type is self.added:
            actual_value = right_value_inst
        elif change_type is self.deleted:
            if self.keep_values_not_in_schema:
                # msg_prefix = 'Using'
                actual_value = left_value
            else:
                # msg_prefix = 'Dropped'
                actual_value = NoValue
            # end handle schema
        elif change_type is self.modified:
            try:
                if left_value is NoValue:
                    raise TypeError("NoValue is not a valid value")
                #end handle missing keys in storage
                # In case of a type conversion, we must assure the value is already 
                # 'final' and substituted. Otherwise the type conversion can fail prematurely.

                if right_value is None:
                    actual_value = left_value
                elif left_value is None:
                    actual_value = right_value_inst
                else:

                    if isinstance(right_value_inst, list) and not isinstance(left_value, list):
                        if self.should_resolve_values():
                            # have to assure we copy the nested value, otherwise the resolved value
                            # shows up in our source date-structure. We do this here, just to prevent
                            # unnecessary work in the resolver
                            right_value_inst = self._resolve_value(key, smart_deepcopy(right_value_inst))
                        actual_value = type(right_value_inst)()
                        actual_value.append(left_value)
                    elif isinstance(right_value, type):
                        # handle types
                        if self.should_resolve_values():
                            left_value = self._resolve_value(key, smart_deepcopy(left_value))
                        actual_value = right_value(left_value)
                    else:
                        # handle instances - only convert the type if this is necesary.
                        # Not all types are primitive, and invoking their constructor might just not work
                        if isinstance(left_value, type(right_value)):
                            actual_value = left_value
                        else:
                            if self.should_resolve_values():
                                left_value = self._resolve_value(key, left_value)
                            actual_value = type(right_value)(left_value)
                    # end handle list packing
                # handle value type - special handling for None
            except Exception, err:
                # Assure we have a real value for error printing and value handling
                actual_value = right_value_inst
                
                if self.should_resolve_values():
                    msg = "Could not convert value type %s of value '%s' at key '%s' "
                    msg += "to the desired type %s one of the default value with error: %s"
                    msg += ", using default value instead"
                    self._log.warn(msg, type(left_value), str(left_value), qkey, type(right_value_inst), str(err))
Exemple #3
0
                if self.should_resolve_values():
                    msg = "Could not convert value type %s of value '%s' at key '%s' "
                    msg += "to the desired type %s one of the default value with error: %s"
                    msg += ", using default value instead"
                    self._log.warn(msg, type(left_value), str(left_value), qkey, type(right_value_inst), str(err))
                # end handle logging
            #end handle type conversion
        else:
            # both values are equal - just use it
            assert change_type is self.unchanged
            actual_value = left_value
        #end handle change type

        # always perform a smart-copy here, value could be a nested list with mutable values
        if actual_value is not NoValue:
            self._set_merged_value(key, smart_deepcopy(actual_value))

    def _resolve_scalar_value(self, key, value):
        """@return a resolved single scalar string value"""
        # Actually, all of the values we see should be strings
        # however, the caller is and may be 'stupid', so we handle it here
        if not isinstance(value, basestring):
            return value
        # end ignore non-string types

        formatter = self.StringFormatterType()
        try:
            last_value = ''
            count = 0
            while last_value != value:
                count += 1