def func_turn_into_waldo_var( self,val,force_copy,active_event, host_uuid,new_peered, ext_args_array,new_multi_threaded): ''' turn_into_waldo_var works for all non-function types. function-types require additional information (which arguments are and are not external) to populate their ext_args_array. This is passed in in this function. ''' if isinstance(val,wVariables.WaldoFunctionVariable): if force_copy: # means that it was a WaldoVariable: just call its copy # method return val.copy(active_event,new_peered,new_multi_threaded) # otherwise, just return val return val elif hasattr(val,'__call__'): # python function pass #### DEBUG else: util.logger_assert( 'incorrect type passed into func_turn_into_waldo_var') #### END DEBUG waldo_func = wVariables.WaldoFunctionVariable( 'garbage', host_uuid, new_peered, val).set_external_args_array(ext_args_array) return waldo_func
def var_type(): ''' @returns {String} --- Each subtype of _ReferenceBase has a unique name. ''' util.logger_assert( 'var_type is pure virtual in _ReferenceBase.')
def update_val_of_key_during_deserialize( self,invalid_listener,key,val): ''' @param {Text,Number,TrueFalse} key --- The index of the internal map or list (if list, then key is just a number) @param {Anything} val --- Can be a python value or pointers to additional Waldo variables. Called when deserializing nested maps/lists. See case 4 in the comments for the method waldoNetworkSerializer.deserialize_peered_object_into_variables. ''' #### DEBUG # note only should be serializing and deserializing peered data if not self.peered: util.logger_assert( 'Should not be updating value and version for a ' + 'non-peered data item.') #### END DEBUG self._lock() self._add_invalid_listener(invalid_listener) dirty_element = self._dirty_map[invalid_listener.uuid] dirty_element.val[key] = val self._unlock()
def is_value_type(self): ''' @returns {bool} --- True if the reference base points at a value type (Text, Bool, Number). False otherwise. ''' util.logger_assert( 'is_value_type is pure virtual in _ReferenceBase.')
def call_func_obj( self,active_event,func_obj,*args): ''' @param {wVariable.WaldoFunctionVariable} func_obj --- The wrapped function that we are calling. @param {*args} --- The actual arguments that get passed to the function. ''' # {list} external_arg_list --- Each element is a number. # If a number is in this list, then that means that the # corresponding argument to func_obj is external and therefore # should not be de_waldo-ified. If an argument does not have # its corresponding index in the array, then dewaldo-ify it. external_arg_list = func_obj.ext_args_array if external_arg_list == None: util.logger_assert( 'No external arg array for function object') call_arg_list = [] for counter in range(0,len(args)): to_append = args[counter] if counter not in external_arg_list: to_append = self.de_waldoify(to_append,active_event) call_arg_list.append(to_append) internal_func = func_obj.get_val(active_event) return internal_func( active_event.local_endpoint,*call_arg_list)
def create_new_variable_wrapper_from_serialized( host_uuid,serial_obj_named_tuple): ''' @param {collections.namedtuple} serial_obj_named_tuple --- @see util._generate_serialization_named_tuple. Should have elements var_name, var_type,var_data, version_obj_data. When we are deserializing sequence local objects from messages sent from partner endpoint, we may not already have a waldoVariable to deserialize the variable into using deserialize_peered_object_into_variable. In this case, we should first create a new _WaldoVariable to serialize into. This function takes a serial_obj_named_tuple, and returns a new variable with corresponding type to its var_type ''' var_name = serial_obj_named_tuple.var_name var_type = serial_obj_named_tuple.var_type #### DEBUG: Testing whether got a valid type if var_type not in ReferenceTypeConstructorDict: util.logger_assert( 'Error when in waldoNetworkSerializer.create_new_variable_' + 'wrapper_from_serialized. ' + 'Unknown Waldo type requested for deserialization.') #### END DEBUG var_constructor = ReferenceTypeConstructorDict[var_type] if var_type == wVariables.WaldoUserStructVariable.var_type(): # user structs require dict initializers. for the time being, # it's okay to just write in an empt dict because we know we # will overwrite it anyways. return var_constructor(var_name,host_uuid,True,{}) return var_constructor(var_name,host_uuid,True)
def __init__(self, filename, name, host_uuid, peered=False, init_val=None): self.filename = filename if peered: util.logger_assert("Cannot peer a file") WaldoTextVariable.__init__(self, name, host_uuid, False, init_val) self.flush_file(self.val)
def de_waldoify(self,invalid_listener): ''' Returns a Python-ized version of this object accessed by the current invalid listener. Eg., if it was a Waldo number that wrapped 2, then it just returns 2. Lists, maps and strings are more complex. ''' util.logger_assert( 'de_waldoify is pure virtual in _ReferenceBase.')
def copy(self,invalid_listener,peered): ''' Returns a deep copy of this object. Useful when assigning to/from a peered variable. Eg., if have a peered map of lists, any list that we assign into the map should be copied as peered first. This way, avoid problem of sharing references. ''' util.logger_assert( 'copy is pure virtual in _ReferenceBase.')
def add_to_delta_list(self,delta_to_add_to,current_internal_val,action_event): ''' @param delta_to_add_to --- Either varStoreDeltas.SingleMapDelta or varStoreDeltas.SingleListDelta We log all operations on this variable ''' util.logger_assert( 'Pure virutal add_to_delta_list in waldoReferenceContainerBase')
def __init__(self, name, host_uuid, peered=False, init_val=None): """ @param {dict} init_val --- Required to be non-None. Contains a mapping of names to WaldoVariables. Each name corresponds to one of the variable fields in the struct. """ if not isinstance(init_val, dict): util.logger_assert("User structs must always have init_vals. " + "Otherwise, not initializing struct data") WaldoMapVariable.__init__(self, name, host_uuid, peered, init_val)
def _map_get_delete_key_incorporate_deltas(container_deleted_action): if container_deleted_action.HasField('deleted_key_text'): index_to_del_from = container_deleted_action.deleted_key_text elif container_deleted_action.HasField('deleted_key_num'): index_to_del_from = container_deleted_action.deleted_key_num elif container_deleted_action.HasField('deleted_key_tf'): index_to_del_from = container_deleted_action.deleted_key_tf #### DEBUG else: util.logger_assert('Error in delete: unknown key type.') #### END DEBUG return index_to_del_from
def _map_get_add_key_incorporate_deltas(container_added_action): if container_added_action.HasField('added_key_text'): index_to_add_to = container_added_action.added_key_text elif container_added_action.HasField('added_key_num'): index_to_add_to = container_added_action.added_key_num elif container_added_action.HasField('added_key_tf'): index_to_add_to = container_added_action.added_key_tf #### DEBUG else: util.logger_assert('Unknown map index') #### END DEBUG return index_to_add_to
def add_var(self,unique_name,waldo_variable): ''' @param {String} unique_name --- @param {_WaldoVariable} waldo_variable ''' #### DEBUG if self.get_var_if_exists(unique_name) != None: util.logger_assert( 'Already had an entry for variable trying to ' + 'insert into store.') #### END DEBUG self._name_to_var_map[unique_name] = waldo_variable
def serializable_var_tuple_for_network( self,parent_delta,var_name,invalid_listener,force): ''' @see waldoReferenceBase.serializable_var_tuple_for_network ''' self._lock() self._add_invalid_listener(invalid_listener) dirty_element = self._dirty_map[invalid_listener.uuid] self._unlock() version_obj = dirty_element.version_obj is_var_store = False if parent_delta.parent_type == VarStoreDeltas.VAR_STORE_DELTA: is_var_store = True struct_delta = parent_delta.struct_deltas.add() elif parent_delta.parent_type == VarStoreDeltas.CONTAINER_WRITTEN: struct_delta = parent_delta.what_written_map elif parent_delta.parent_type == VarStoreDeltas.CONTAINER_ADDED: struct_delta = parent_delta.added_what_map elif parent_delta.parent_type == VarStoreDeltas.SUB_ELEMENT_ACTION: struct_delta = parent_delta.struct_delta else: util.logger_assert('Unexpected parent container type when serializing map') struct_delta.parent_type = VarStoreDeltas.STRUCT_CONTAINER struct_delta.var_name = var_name struct_delta.has_been_written = version_obj.has_been_written_since_last_message # reset has been written to written_since_last_message = version_obj.has_been_written_since_last_message version_obj.has_been_written_since_last_message = False var_data = dirty_element.val internal_has_been_written = var_data.serializable_var_tuple_for_network( struct_delta,'',invalid_listener, # must force the write when we have written a new value over list force or written_since_last_message) # FIXME: check to ensure that second part of condition will # still hide elements that do not change if (not internal_has_been_written) and is_var_store and (not written_since_last_message): # remove the newly added map delta because there were no # changes that it encoded del parent_delta.struct_deltas[-1] return internal_has_been_written or written_since_last_message or force
def call_func_obj( self,active_event,func_obj,*args): ''' @param {wVariable.WaldoFunctionVariable} func_obj --- The wrapped function that we are calling. @param {*args} --- The actual arguments that get passed to the function. ''' # {list} external_arg_list --- Each element is a number. # If a number is in this list, then that means that the # corresponding argument to func_obj is external and therefore # should not be de_waldo-ified. If an argument does not have # its corresponding index in the array, then dewaldo-ify it. external_arg_list = func_obj.ext_args_array if external_arg_list == None: util.logger_assert( 'No external arg array for function object') call_arg_list = [] for counter in range(0,len(args)): to_append = args[counter] if counter not in external_arg_list: to_append = self.de_waldoify(to_append,active_event) call_arg_list.append(to_append) internal_func = func_obj.get_val(active_event) returned_val = internal_func( active_event.local_endpoint,*call_arg_list) if isinstance(returned_val,list): return wVariables.WaldoSingleThreadListVariable( 'garbage', # actual name of variable isn't important active_event.local_endpoint._host_uuid, False, # not peered returned_val# used as initial value ) elif isinstance(returned_val,dict): return wVariables.WaldoSingleThreadMapVariable( 'garbage', # actual name of variable isn't important active_event.local_endpoint._host_uuid, False, # not peered returned_val# used as initial value ) return returned_val
def update_version_obj_during_deserialize( self,invalid_listener,new_version_obj): ''' @see update_val_of_key_during_deserialize ''' #### DEBUG # note only should be serializing and deserializing peered data if not self.peered: util.logger_assert( 'Should not be updating value and version for a ' + 'non-peered data item.') #### END DEBUG self._lock() self._add_invalid_listener(invalid_listener) dirty_element = self._dirty_map[invalid_listener.uuid] dirty_element.version_obj = new_version_obj self._unlock()
def get_for_iter(self,to_iter_over,active_event): ''' When call for loop on Waldo variables, need to get item to iterate over ''' if (isinstance(to_iter_over,dict) or isinstance(to_iter_over,list) or util.is_string(to_iter_over)): return iter(to_iter_over) if wVariables.is_non_ext_text_var(to_iter_over): return iter(to_iter_over.get_val(active_event)) if wVariables.is_non_ext_map_var(to_iter_over): return iter(to_iter_over.get_val(active_event).get_keys(active_event)) if wVariables.is_non_ext_list_var(to_iter_over): # FIXME: This is an inefficient way of reading all values # over list. to_return = [] for i in range(0, to_iter_over.get_val(active_event).get_len(active_event)): to_append = to_iter_over.get_val(active_event).get_val_on_key(active_event,i) # The reason that we do this here is that in a for # loop, the operation we perform in the compiled code # immediately following the actual for header is # assign to another Waldo variable the variable being # held by to_append. (We do this through a write_val # call. write_val must take in InternalMaps or # InternalLists. Therefore, get_val on the # WaldoList/WaldoMap first. Note this is unnecessary # for all other for iterations because none of the # others possibly return a WaldoObject to iterate over. if (wVariables.is_non_ext_list_var(to_append) or wVariables.is_non_ext_map_var(to_append)): to_append = to_append.get_val(active_event) to_return.append(to_append) return iter(to_return) util.logger_assert( 'Calling get_for_iter on an object that does not support iteration')
def get_constructed_obj( var_type,var_name,host_uuid,peered,init_data,invalidation_listener): ''' @returns {WaldoReferenceObject} --- Either a wVariable or an InternalList or InternalMap. ''' #### DEBUG if var_type not in ReferenceTypeConstructorDict: util.logger_assert( 'Unknown variable type to deserialize') #### END DEBUG if var_type == wVariables.WaldoUserStructVariable.var_type(): # we are constructing a user struct: in this case, init_data # will be an internal map. can just deserialize the map into #### DEBUG if not isinstance(init_data,waldoInternalMap.InternalMap): util.logger_assert( 'Must initialize user struct data with internal map') #### END DEBUG # FIXME: it is unclear if we just created an internal map for # no reason here. maybe just serialize and deserialize # internal values of structs as dicts. # FIXME: it is gross that reaching into the internal map this # way. init_data._lock() if invalidation_listener.uuid not in init_data._dirty_map: new_init_data = init_data.val else: new_init_data = init_data._dirty_map[invalidation_listener.uuid].val init_data._unlock() init_data = new_init_data var_constructor = ReferenceTypeConstructorDict[var_type] if requires_name_arg_in_constructor(var_type): return var_constructor(var_name,host_uuid,peered,init_data) return var_constructor(host_uuid,peered,init_data)
def promote_multithreaded(self,peered): ''' Whenever we assign a single threaded variable, A, into a multithreaded variable, B, we need to "promote" the single threaded variable to be a multithreaded variable. This is so that reads/writes to A.B from multiple threads do not cause read-write conflicts. This method returns a multithreaded version of this variable containing the same data within it. Importantly, it does not genearte a new multithreaded version of itself each time. This is to account for assigning the same single threaded variable to more than one multithreaded connection. ''' util.logger_assert( 'In Waldo single threaded container, promote_multithreaded ' + 'is pure virtual. Must overload.')
def __init__(self, name, host_uuid, peered=False, init_val=None): if peered: util.logger_assert("Function variables may not be peered") def _default_helper_func(*args, **kwargs): pass if init_val == None: init_val = _default_helper_func _WaldoVariable.__init__(self, name, host_uuid, peered, init_val) # {Array} --- Each element is an int. When making a call to a # function object, the function object takes in arguments. # For non-externals, we de-waldoify these arguments. However, # for external arguments, we do not. If an argument is # supposed to be an external, then we just pass it through # directly self.ext_args_array = None
def handle_len(self,what_calling_len_on, active_event): ''' Can support python lists, dicts, strings, or waldo lists, waldo maps, waldo texts. @returns {int} ''' if (isinstance(what_calling_len_on, dict) or isinstance(what_calling_len_on, list) or util.is_string(what_calling_len_on)): return len(what_calling_len_on) if wVariables.is_non_ext_text_var(what_calling_len_on): return len(what_calling_len_on.get_val(active_event)) if (wVariables.is_non_ext_list_var(what_calling_len_on) or wVariables.is_non_ext_map_var(what_calling_len_on)): return what_calling_len_on.get_val(active_event).get_len(active_event) util.logger_assert( 'Calling len on an object that does not support the function')
def handle_in_check(self,lhs,rhs,active_event): ''' Call has form: lhs in rhs rhs can have three basic types: it can be a list, a map, or a string. That means that it can either be a WaldoMapVariable, a WaldoListVariable, a WaldoStringVariable, or a Python string. Instead of using static type inference at compile time to determine, for sake of development, just doing dynamic check to determine which type it is and do the in processing here. FIXME: it is faster to do the static checks with type inference, etc. at compile time rather than at run time. ''' lhs_val = self.get_val_if_waldo(lhs,active_event) # handles Python string case if util.is_string(rhs): # if isinstance(rhs,basestring): return lhs_val in rhs elif isinstance(rhs,wVariables.WaldoTextVariable): return lhs_val in rhs.get_val(active_event) elif isinstance(rhs,wVariables.WaldoMapVariable): return rhs.get_val(active_event).contains_key_called( active_event,lhs_val) elif isinstance(rhs,wVariables.WaldoListVariable): return rhs.get_val(active_event).contains_val_called( active_event,lhs_val) util.logger_assert( 'Error when calling in: unknown right hand side of expression')
def del_key(self, to_del): util.logger_assert("Cannot call del_key on list. Use del_key_list instead.")
def deserialize_peered_object_into_variable( host_uuid,serial_obj_named_tuple,invalidation_listener,waldo_reference): ''' @param {uuid} host_uuid --- The uuid of the host currently on. @param {collections.namedtuple} serial_obj_named_tuple --- @see util._generate_serialization_named_tuple. Should have elements var_name, var_type,var_data, version_obj_data. @param {_InvalidationListener} invalidation_listener --- The event that we are serializing to. @param {_ReferenceValue} waldo_reference --- We write the value and version found in serial_obj_named_tuple into the dirtymapelement corresponding to invalidation_listener in waldo_reference. (Put another way, we try to append any changes that have happened to waldo_reference on the other endpoint to waldo_reference on this endpoint.) @returns {Nothing} --- Changes will be propagated through arguments. ''' # FIXME: probably do not need "var_name" var_name = serial_obj_named_tuple.var_name serial_vobj = serial_obj_named_tuple.version_obj_data version_obj = RefVers.deserialize_version_obj_from_network_data( serial_vobj) var_type = serial_obj_named_tuple.var_type #### DEBUG: Testing whether got a valid type if var_type not in ReferenceTypeConstructorDict: util.logger_assert( 'Error when in waldoNetworkSerializer.deserialize_peered_object' + '. Unknown Waldo type requested for deserialization.') #### END DEBUG # var_data can either be a python value (string,bool,number) or a # python list/map or a SerializationHelperNamedTuple. If it is a # list or map, it either has elements that are python values or it # has elements that are SerializationHelperNamedTuple-s. # # CASE 1: We have python values # Put var_data directly into the dirty_map_element associated # with invalidation_listener in waldo_reference. Similarly copy # over the version object. (We cannot do this for # SerializationHelperNamedTuples because these represent # pointers to additional InternalMaps/Lists/Structs. If we just # copied over the values of these, then they would refer to # different objects on the endpoint than they initially did. # And we wouldn't be able to detect conflicts.) # # CASE 2: We have lists/maps of python values # Do same as in Case 1. # # CASE 3: We have a single SerializationHelperNamedTuple # This means that we are currently deserializing a # WaldoVariable. (One of the classes defined in wVariables.py.) # There can be two cases for what happens. # a: The WaldoVariable has not been written to. # We want the changes to point to the same variable that we # have been using. Get the associated Waldo reference that # waldo_reference points to and write the contents of the # SerializationHelperNamedTuple into its dirty map element's # val and version object. This ensures that the changes that # we are making will be made to the same waldo object on one # endpoint as they were being made to the waldo object on the # other endpoint. # b: The WaldoVariable has been written to. # What this means is that, at some point in this event, we # re-defined the Waldo object that the peered variable was # pointing to. (Ie, we assigned the peered variable to # another map/list/user struct.) In this case, we should # just do what we did in Case 1/Case 2. We do NOT want our # new changes to point to the same old reference. We want # them to point to a new reference. # # CASE 4: We have a map/list of SerializationHelperNamedTuple-s # # Here's why we need to keep track of whether each element was # written to or read from. Assume that we have a map of maps: # Map(from: Text, to: Map(from: Text, to: Text)) m # # It is important to distinguish: # m['a'] = { 'other_a': 'other_a'} # from # m['a']['other_a'] = 'other_a' (assuming m['a'] is already defined) # because if we have another operation # m['a']['b'] = 'b' # for the first case, there's a conflict, for the second they # can execute in parallel # To determine whether written to or read from, use version_obj, # which will have type # waldoReferenceContainerBase._ReferenceContainerVersion. For # each key within it that was written, added, or deleted, treat # the index similarly to 3b above. For others, treat as 3a above. var_data = serial_obj_named_tuple.var_data if not isinstance(var_data,util._SerializationHelperNamedTuple): case1_or_case2 = True if isinstance(var_data,list): if ((len(var_data) != 0) and # it's fine to treat empty # lists as a list of python # values (instead of an empty # list of # SerHelperNamedTuple-s. # This is because we aren't # over-writing any pointed to # references by copying over # it. (isinstance(var_data[0],util._SerializationHelperNamedTuple))): case1_or_case2 = False if isinstance(var_data,dict): if ((len(var_data) != 0) and # see len comment in if # statement above. (isinstance( next(iter(var_data.values())), # var_data.itervalues().next(), util._SerializationHelperNamedTuple))): case1_or_case2 = False if case1_or_case2: # CASE 1/2 above ... overwrite val and version object of # the variable's associated dirty map element. waldo_reference.update_version_and_val( invalidation_listener,version_obj,var_data) return else: # CASE 3 above: we have a single SerializationHelperNamedTuple # means that we must have a _ReferenceValue if not version_obj.has_been_written_to: # case 3a above nested_reference = waldo_reference.get_val( invalidation_listener) deserialize_peered_object_into_variable( host_uuid,var_data,invalidation_listener,nested_reference) else: # case 3b above # FIXME: It is correct to just create a new object here. # However, we do not necessarily need to create a new # object if we had written to the data object much earlier # in the event and have since updated both sides. Could # incur a performance penalty doing this. new_obj = new_obj_from_serialized( host_uuid,var_data,invalidation_listener) waldo_reference.update_version_and_val( invalidation_listener,version_obj,new_obj) return # CASE 4 above: list/map of SerializationHelperNamedTuple-s # make it able to handle maps or lists. all_keys = range(0,len(var_data)) if isinstance(var_data, dict): all_keys = list(var_data.keys()) for key in all_keys: if ((key in version_obj.written_values_keys) or (key in version_obj.added_keys) or (key in version_obj.deleted_keys)): # handle same as 3b above # waldo_reference is an InternalMap/InternalDict and we # must notify it that this object has been # deleted/written/added new_obj = new_obj_from_serialized( host_uuid,var_data[key],invalidation_listener) waldo_reference.update_val_of_key_during_deserialize( invalidation_listener,key,new_obj) elif key in version_obj.read_values_keys: # only add others if have been read. do not willy-nilly # add references. # handle same as 3a above...except getting val for target # key nested_reference = waldo_reference.get_val_on_key( invalidation_listener,key) # recurse deserialize_peered_object_into_variable( host_uuid,var_data[key],invalidation_listener, nested_reference) # remove any elements that may have been deleted by the other side if isinstance(var_data,dict): # it's a map. look for keys that are not in all keys local_keys = waldo_reference.get_keys(invalidation_listener) for key in local_keys: if key not in all_keys: waldo_reference.del_key_called(invalidation_listener,key) if isinstance(var_data,list): if len(local_keys) > len(all_keys): # FIXME: if do something more intelligent about sliding # elements in the list down when they are not modified, # then may have to do something more intelligent than just # deleting off the end. num_times_to_delete = len(all_keys) - len(local_keys) for i in range(0,num_times_to_delete): # keep deleting the spot just beyond how long the list # should be. waldo_reference.del_key_called( invalidation_listener,len(all_keys)) # either way, reset the version obj of overall internal list/map waldo_reference.update_version_obj_during_deserialize( invalidation_listener,version_obj)
def get_keys(self, invalid_listener): util.logger_assert("Cannot call get_keys on a list")
def contains_key(self, invalid_listener, key): util.logger_assert("Cannot call contains_key on list")
def serializable_var_tuple_for_network( self,parent_delta,var_name,invalid_listener,force): ''' The runtime automatically synchronizes data between both endpoints. When one side has updated a peered variable, the other side needs to attempt to apply those changes before doing further work. This method grabs the val and version object of the dirty element associated with invalid_listener. Using these data, plus var_name, it constructs a named tuple for serialization. (@see util._generate_serialization_named_tuple) Note: if the val of this object is another Reference object, then we recursively keep generating named tuples and embed them in the one we return. Note: we only serialize peered data. No other data gets sent over the network; therefore, it should not be serialized. @param {*Delta or VarStoreDeltas} parent_delta --- Append any message that we create here to this message. @param {String} var_name --- Both sides of the connection need to agree on a common name for the variable being serialized. This is to ensure that when the data are received by the other side we know which variable to put them into. This value is only really necessary for the outermost wrapping of the named type tuple, but we pass it through anyways. @param {bool} force --- True if regardless of whether modified or not we should serialize. False otherwise. (We migth want to force for instance the first time we send sequence data.) @returns {bool} --- True if some subelement was modified, False otherwise. ''' self._lock() self._add_invalid_listener(invalid_listener) dirty_element = self._dirty_map[invalid_listener.uuid] self._unlock() version_obj = dirty_element.version_obj # a val can either point to a waldo reference, a python value, # or a list/map of waldo references or a list/map of python # values. var_data = dirty_element.val if (not force) and (not version_obj.has_been_written_since_last_message): if (isinstance(var_data,numbers.Number) or util.is_string(var_data) or isinstance(var_data,bool)): # nothing to do because this value has not been # written. NOTE: for list/dict types, must actually # go through to ensure no subelements were written. return False sub_element_modified = False if self.py_val_serialize(parent_delta,var_data,var_name): sub_element_modified = True elif isinstance(var_data,list): list_delta = parent_delta.internal_list_delta list_delta.parent_type = VarStoreDeltas.INTERNAL_LIST_CONTAINER if force: # perform each operation as a write... version_obj.add_all_data_to_delta_list( list_delta,var_data,invalid_listener) sub_element_modified = True else: # if all subelements have not been modified, then we # do not need to keep track of these changes. # wVariable.waldoMap, wVariable.waldoList, or # wVariable.WaldoUserStruct will get rid of it later. sub_element_modified = version_obj.add_to_delta_list( list_delta,var_data,invalid_listener) elif isinstance(var_data,dict): map_delta = parent_delta.internal_map_delta map_delta.parent_type = VarStoreDeltas.INTERNAL_MAP_CONTAINER if force: # perform each operation as a write... version_obj.add_all_data_to_delta_list( map_delta,var_data,invalid_listener) sub_element_modified = True else: # if all subelements have not been modified, then we # do not need to keep track of these changes. # wVariable.waldoMap, wVariable.waldoList, or # wVariable.WaldoUserStruct will get rid of it later. sub_element_modified = version_obj.add_to_delta_list( map_delta,var_data,invalid_listener) else: # creating deltas for cases where internal data are waldo # references.... should have been overridden in # wVariables.py util.logger_assert('Serializing unknown type.') version_obj.has_been_written_since_last_message = False return sub_element_modified
def modified(self,invalidation_listener): ''' Returns True if the object has been modified, False otherwise. ''' util.logger_assert( 'modified is pure virtual in _ReferenceVersion class.')
def py_val_serialize(self,parent,var_data,var_name): ''' @param {} parent --- Either a ContainerAction a VarStoreDeltas. FIXME: unclear if actually need var_name for all elements py_serialize-ing, or just py variables that are in the top-level. @returns {bool} --- True if var_data was a python value type and we put it into parent. False otherwise. If is python value type, then adds a delta message to parent. Otherwise, does nothing. ''' is_value_type = False delta = None if isinstance(var_data, numbers.Number): # can only add a pure number to var store a holder or to # an added key if parent.parent_type == VarStoreDeltas.VAR_STORE_DELTA: delta = parent.num_deltas.add() elif parent.parent_type == VarStoreDeltas.CONTAINER_ADDED: parent.added_what_num = var_data elif parent.parent_type == VarStoreDeltas.CONTAINER_WRITTEN: parent.what_written_num = var_data #### DEBUG else: util.logger_assert('Unexpected parent type in py_serialize') #### END DEBUG is_value_type = True elif util.is_string(var_data): if parent.parent_type == VarStoreDeltas.VAR_STORE_DELTA: delta = parent.text_deltas.add() elif parent.parent_type == VarStoreDeltas.CONTAINER_ADDED: parent.added_what_text = var_data elif parent.parent_type == VarStoreDeltas.CONTAINER_WRITTEN: parent.what_written_text = var_data #### DEBUG else: util.logger_assert('Unexpected parent type in py_serialize') #### END DEBUG is_value_type = True elif isinstance(var_data,bool): if parent.parent_type == VarStoreDeltas.VAR_STORE_DELTA: delta = parent.true_false_deltas.add() elif parent.parent_type == VarStoreDeltas.CONTAINER_ADDED: parent.added_what_tf = var_data elif parent.parent_type == VarStoreDeltas.CONTAINER_WRITTEN: parent.what_written_tf = var_data #### DEBUG else: util.logger_assert('Unexpected parent type in py_serialize') #### END DEBUG is_value_type = True if delta != None: # all value types have same format delta.var_name = var_name delta.var_data = var_data return is_value_type