def set_size(self, new_value=None, attr_index=None, **context): ''' Raises DescEditError when called. Unions must have a fixed size and thus the SIZE value in their descriptor must be an int. Setting fixed sizes is disallowed because of the possibility of unintended descriptor modification. ''' raise DescEditError('Union sizes are int literals and cannot be set ' + 'using set_size. Make a new descriptor instead.')
def __delattr__(self, attr_name): try: object.__delattr__(self, attr_name) except AttributeError: desc = object.__getattribute__(self, "desc") if attr_name in desc['NAME_MAP']: # set the size of the node to 0 since it's being deleted try: self.set_size(0, attr_name) except (NotImplementedError, AttributeError): pass self.__delitem__(desc['NAME_MAP'][attr_name]) elif attr_name in desc: raise DescEditError( "Deleting entries from a descriptor is not " + "supported. Make a new descriptor instead.") else: raise AttributeError( "'%s' of type %s has no attribute '%s'" % (desc.get('NAME', UNNAMED), type(self), attr_name))
def __setattr__(self, attr_name, new_value): try: object.__setattr__(self, attr_name, new_value) except AttributeError: desc = object.__getattribute__(self, "desc") if attr_name in desc['NAME_MAP']: assert not self.assert_is_valid_field_value( desc['NAME_MAP'][attr_name], new_value) self[desc['NAME_MAP'][attr_name]] = new_value elif attr_name in desc: raise DescEditError( "Setting entries in a descriptor in this way is not " + "supported. Make a new descriptor instead.") else: raise AttributeError( "'%s' of type %s has no attribute '%s'" % (desc.get('NAME', UNNAMED), type(self), attr_name)) # if the object being placed in the Block is itself # a Block, set its parent attribute to this Block. if attr_name != "parent" and isinstance(new_value, Block): new_value.parent = self
def set_size(self, new_value=None, attr_index=None, **context): ''' Sets the size of the 'attr_index' element in this Block to 'new_value' using the SIZE entry in self.desc[attr_index]. If the attribute itself has a descriptor, uses its descriptor instead of the one in self.desc[attr_index] If 'new_value' isnt supplied, calculates it using the sizecalc method of the 'TYPE' entry in the descriptor. If the SIZE entry is a string, the size will be set using self.set_neighbor and providing the SIZE entry as the nodepath. If the SIZE entry is a function, the size will be set by doing: size_setter(attr_index=attr_index, new_value=new_value, parent=self, node=node, **context) where size_setter is the function under the descriptors SIZE key, new_value is the calculated or provided value to set the size to, context is a dictionary of the remaining supplied keyword arguments, node is the attribute whose size is being set, and attr_index is the provided attr_index argument. If attr_index is an int, sets the size of self[attr_index]. If attr_index is a str, sets the size of self.__getattr__(attr_index). If attr_index is None, this method will do nothing. This is because WhileBlocks are designed to express data which doesnt store a size. Raises DescEditError if the descriptor 'SIZE' entry is an int and the value the size is being set to is greater than what is currently in the descriptor. Raises DescKeyError if 'SIZE' doesnt exist in the descriptor. Raises TypeError if the 'SIZE' entry isnt an int, string, or function. ''' self_desc = object.__getattribute__(self, 'desc') if isinstance(attr_index, str): attr_index = self_desc['NAME_MAP'][attr_index] elif not isinstance(attr_index, int): # cant set size of WhileArrays return node = self[attr_index] # try to get the size directly from the node try: desc = node.desc size = self_desc['SIZE'] error_num = 0 except Exception: # if that fails, try to get it from the desc of the parent desc = self_desc[attr_index] try: size = desc['SIZE'] error_num = 0 except Exception: # its parent cant tell us the size, raise this error error_num = 1 if 'TYPE' in desc and not desc['TYPE'].is_var_size: # the size is not variable so it cant be set # without changing the type. raise this error error_num = 2 if error_num: f_type = desc['TYPE'] if error_num == 1: raise DescKeyError("Could not locate size for " + "attribute '%s' in block '%s'." % (desc.get('NAME', UNNAMED), self_desc.get('NAME', UNNAMED))) raise DescKeyError(("Can not set size for attribute " + "'%s' in block '%s'.\n'%s' has a " + "fixed size of '%s'.\nTo change its " + "size you must change its FieldType.") % (desc.get('NAME', attr_index), self_desc.get('NAME', UNNAMED), f_type, f_type.size)) if isinstance(size, int): # Because literal descriptor sizes are supposed to be static # (unless you're changing the structure), we don't even try to # change the size if the new size is less than the current one. if new_value is None and newsize <= size: return raise DescEditError("Changing a size statically defined in a " + "descriptor is not supported through " + "set_size. Make a new descriptor instead.") # if a new size wasnt provided then it needs to be calculated if new_value is not None: newsize = new_value else: newsize = desc['TYPE'].sizecalc(node, parent=self, attr_index=attr_index, **context) if isinstance(size, str): # set size by traversing the tag structure # along the path specified by the string self.set_neighbor(size, newsize, node) elif hasattr(size, "__call__"): # set size by calling the provided function size(attr_index=attr_index, new_value=newsize, parent=self, node=node, **context) else: raise TypeError(("Size specified in '%s' is not a valid type." + "Expected int, str, or function. Got %s.\n") % (desc.get('NAME', attr_index), type(size)) + "Cannot determine how to set the size.")
def set_size(self, new_value=None, attr_index=None, **context): ''' Sets the size of this Block to 'new_value' using the SIZE entry in the descriptor. If 'attr_index' is not None, uses the descriptor of the attribute 'attr_index'. If the attribute has a descriptor, uses its descriptor instead of the one in self.desc[attr_index] If new_value isnt supplied, uses the value returned by the sizecalc method of the TYPE entry in the descriptor. If attr_index is None, calculates the size of this Block, otherwise calculates the size of the specified attribute. If the SIZE entry is a string, the size will be set with: self.set_neighbor(nodepath, new_value, node) where 'node' is this Block(or its attribute if attr_index is not None), and nodepath is the value in the descriptor under 'SIZE'. If the SIZE entry is a function, If attr_index is an int, sets the size of self[attr_index]. If attr_index is a str, sets the size of self.__getattr__(attr_index). Raises a DescEditError if the descriptor 'SIZE' entry is an int FINISH WRITING THIS DOCSTRING Size units are dependent on the data type being measured. Variables and structs will be measured in bytes and arrays and containers will be measured in entries. The descriptor may specify size in terms of already parsed fields. ''' self_desc = object.__getattribute__(self, 'desc') if isinstance(attr_index, int): node = self[attr_index] # try to get the size directly from the node or the parent try: desc = node.desc except AttributeError: desc = self_desc[attr_index] size = desc.get('SIZE') elif isinstance(attr_index, str): node = self.__getattr__(attr_index) error_num = 0 # try to get the size directly from the node try: desc = node.desc size = desc['SIZE'] except Exception: # if that fails, try to get it from the desc of the parent try: desc = self_desc[self_desc['NAME_MAP'][attr_index]] except Exception: desc = self_desc[attr_index] try: size = desc['SIZE'] except Exception: # its parent cant tell us the size, raise this error error_num = 1 if 'TYPE' in desc and not desc['TYPE'].is_var_size: # the size is not variable so it cant be set # without changing the type. raise this error error_num = 2 if error_num: attr_name = desc.get('NAME', UNNAMED) if isinstance(attr_index, (int, str)): attr_name = attr_index if error_num == 1: raise DescKeyError( "Could not determine size for attribute " + "'%s' in block '%s'." % (attr_name, self_desc['NAME'])) elif error_num == 2: raise DescKeyError( ("Can not set size for attribute '%s' in block '%s'." + "\n'%s' has a fixed size of '%s'.\nTo change the " + "size of '%s' you must change its FieldType.") % (attr_name, self_desc['NAME'], desc['TYPE'], desc['TYPE'].size, attr_name)) else: node = self desc = self_desc size = desc.get('SIZE') # raise exception if the size is None if size is None: attr_name = desc.get('NAME', UNNAMED) if isinstance(attr_index, (int, str)): attr_name = attr_index raise DescKeyError("'SIZE' does not exist in '%s'." % attr_name) # if a new size wasnt provided then it needs to be calculated if new_value is not None: newsize = new_value elif hasattr(node, 'parent'): newsize = desc['TYPE'].sizecalc(parent=node.parent, node=node, attr_index=attr_index, **context) else: newsize = desc['TYPE'].sizecalc(parent=self, node=node, attr_index=attr_index, **context) if isinstance(size, int): # Because literal descriptor sizes are supposed to be static # (unless you're changing the structure), we don't even try to # change the size if the new size is less than the current one. if new_value is None and newsize <= size: return raise DescEditError("Changing a size statically defined in a " + "descriptor is not supported through " + "set_size. Make a new descriptor instead.") elif isinstance(size, str): # set size by traversing the tag structure # along the path specified by the string self.set_neighbor(size, newsize, node) return elif hasattr(size, '__call__'): # set size by calling the provided function if hasattr(node, 'parent'): size(attr_index=attr_index, new_value=newsize, parent=node.parent, node=node, **context) else: size(attr_index=attr_index, new_value=newsize, parent=self, node=node, **context) return self_name = self_desc['NAME'] if isinstance(attr_index, (int, str)): self_name = attr_index raise TypeError(("size specified in '%s' is not a valid type." + "\nExpected int, str, or function. Got %s.\n") % (self_name, type(size)))
def __delitem__(self, index): raise DescEditError("ListBlocks do not support deletion of fields.")