def index_tag(tag, data, start=0): """ Finds a tag in an encoded message byte string. :param tag: The tag number to find. :param data: The encoded FIX message data to search. :param start: Optimization: position at which to start the search. :return: A tuple consisting of the tag value, the index at which the tag was found, and the index that denotes the end of the field in the byte string. :raises: TagNotFound if the tag could not be found in the encoded message data. """ search_bytes = encode(tag) + b"=" if data.startswith(search_bytes): start_of_field = 0 else: # Ensure that the tag is prefixed by SOH to avoid partial matches. search_bytes = settings.SOH + search_bytes try: start_of_field = data.index(search_bytes, start) except ValueError as e: raise TagNotFound(tag, data) from e end_of_field = data.find(settings.SOH, start_of_field + 1) return ( data[start_of_field + len(search_bytes):end_of_field], start_of_field, end_of_field, )
def __getattr__(self, name): """ Convenience method for retrieving fields using the field name (e.g. field.MsgType will try to retrieve tag number 35). :param name: The tag name. :return: The Field in this FieldMap with name. :raises UnknownTag if name is not defined in one of the available FIX specifications. :raises TagNotFound if the tag name is valid, but no Field for that tag exists in the FieldMap. """ try: # First, try to get the tag number associated with 'name'. tag = connection.protocol.Tag.get_tag(name) except UnknownTag as e: # Not a known tag, ignore. raise AttributeError( f"{type(self).__name__} instance has no attribute '{name}'." ) from e try: # Then, see if a Field with that tag number is available in this FieldMap. return self[tag] except KeyError as e: raise TagNotFound(tag, self, f"Tag {tag} not found in {self!r}.") from e
def __getitem__(self, tag: int) -> Union[Field, list]: items = [field for field in self.data if field.tag == tag] if len(items) == 0: raise TagNotFound(tag, self) if len(items) == 1: return items[0] # Return Field instead of a list of one. return items
def __delitem__(self, tag: int): count = self.count(tag) if count > 1: raise DuplicateTags( tag, self.values(), message=f"Cannot delete Field by tag reference: " f"FieldMap contains {count} occurrences of '{tag}'. " f"Delete the Field(s) manually from 'data' instead.", ) idx = 0 for field in self._data: if field.tag == tag: del self._data[idx] return idx += 1 raise TagNotFound(tag, self)
def rindex_tag(tag, data, start=0): """ Finds a tag in an encoded message byte string, searching from right to left. :param tag: The tag number to find. :param data: The encoded FIX message data to search. :param start: Optimization: position at which to start the search. :return: A tuple consisting of the tag value, the index at which the tag was found, and the index that denotes the end of the field in the byte string. :raises: TagNotFound if the tag could not be found in the encoded message data. """ search_bytes = encode(tag) + b"=" try: start_of_field = data.rindex(search_bytes, start) except ValueError as e: raise TagNotFound(tag, data) from e end_of_field = data.find(settings.SOH, start_of_field + 1) return ( data[start_of_field + len(search_bytes):end_of_field], start_of_field, end_of_field, )
def __delitem__(self, tag: int): try: del self._data[tag] except KeyError: raise TagNotFound(tag, self)
def __getitem__(self, tag: int): try: return self._data[tag] # Shortcut: lookup Field by tag except KeyError: raise TagNotFound(tag, self)