Esempio n. 1
0
    def test_parse_fields_fields_mixed(self, fieldmap_class):
        fm = fieldmap_class(Field(1, "a"), (2, "b"))

        assert len(fm) == 2
        assert all([tag in fm for tag in [1, 2]])
        assert all([field in fm.values() for field in [(1, "a"), (2, "b")]])
        assert all(type(field) is Field for field in fm)
Esempio n. 2
0
    def _parse_fields(cls, fields, **kwargs):
        """
        Creates a list of Fields from the provided (tag, value) pairs.

        :param fields: Any combination of (tag, value) pairs or other Field objects.
        :return: An list of Fields.
        """
        parsed_fields = []

        for field in fields:
            # For each field in the FieldMap
            if isinstance(field, Field) or isinstance(field, Group):
                # Add field as-is
                parsed_fields.append(field)
                continue

            try:
                # Add new field
                parsed_fields.append(
                    Field(
                        *field
                    )  # Make sure that this is an actual, well-formed Field.
                )
            except TypeError:
                raise ParsingError(
                    f"Invalid Field: '{field}' mut be a (tag, value) tuple.")

        return parsed_fields
Esempio n. 3
0
    def _parse_group_fields(self, fields, group_index, message_type):
        parsed_fields = []

        # Retrieve the template for this repeating group
        group_identifier = Field(fields[group_index][0],
                                 fields[group_index][1])
        templates = self.get_group_templates(group_identifier.tag,
                                             message_type=message_type)
        if len(templates) != 1:
            # Cannot have more than one template defined for a group_identifier / message_type pair
            raise ParsingError(
                f"Could not determine template for tag {group_identifier.tag}."
            )

        instance_template = templates[0]
        idx = group_index + 1

        while idx < len(fields):
            field = fields[idx]

            if not isinstance(fields[idx], Field):
                try:
                    field = Field(*fields[idx])
                except TypeError:
                    raise ParsingError(
                        f"Invalid Field: '{field}' mut be a (tag, value) tuple."
                    )

            if field.tag not in instance_template:
                # No more group fields to process - done.
                break

            if field.tag in self.group_templates:
                # Tag denotes the start of a new repeating group.
                group = self._parse_group_fields(fields, idx, message_type)

                parsed_fields.append(group)
                # Skip over all of the fields that were processed as part of the group.
                idx += len(group)
                continue

            parsed_fields.append(field)
            idx += 1

        return Group(group_identifier,
                     *parsed_fields,
                     template=instance_template)
Esempio n. 4
0
    def _parse_fields(self, fields, **kwargs):
        """
        Parses the list of field tuples recursively into Field instances.

        :param fields: A list of (tag, value) tuples
        :return: A list of parsed Field and repeating Group objects.
        :raises: DuplicateTags if 'fields' contain repeating Fields for which no group_template has been provided.
        """
        parsed_fields = collections.OrderedDict()

        idx = 0
        tags_seen = set()

        while idx < len(fields):
            field = fields[idx]

            if not isinstance(fields[idx], Field):
                try:
                    field = Field(*fields[idx])
                except TypeError:
                    raise ParsingError(
                        f"Invalid Field: '{field}' mut be a (tag, value) tuple."
                    )

            if field.tag in tags_seen:
                raise DuplicateTags(
                    field.tag,
                    fields[idx],
                    f"No repeating group template defined for duplicate tag {field.tag} in {fields}.",
                )

            else:
                # Busy parsing a non-group tag.
                tags_seen.add(field.tag)

            if field.tag in self.group_templates:
                # Tag denotes the start of a new repeating group.
                try:
                    message_type = str(
                        parsed_fields[connection.protocol.Tag.MsgType])
                except KeyError:
                    # Message type not yet determined!
                    raise ParsingError(
                        f"Cannot parse repeating group as MsgType tag ({connection.protocol.Tag.MsgType}) has not "
                        "been seen yet!")

                group = self._parse_group_fields(fields, idx, message_type)
                parsed_fields[group.tag] = group

                # Skip over all of the fields that were processed as part of the group.
                idx += len(group)
                continue

            parsed_fields[field.tag] = field
            idx += 1

        return parsed_fields
Esempio n. 5
0
    def __setitem__(self, tag: int, value: any):
        if isinstance(value, Group):
            # Also add group templates when a new group is set.
            self.add_group_templates({tag: {"*": value.template}})

        elif not (isinstance(value, Field)):
            # Create a new Field if value is not a Field or Group already.
            value = Field(tag, value)

        self._data[tag] = value
Esempio n. 6
0
    async def on_receive(self, message: RawMessage) -> FIXMessage:
        fields = (
            message.BeginString,
            message.BodyLength,
            message.MsgType,
            message.MsgSeqNum,
            *Field.fields_frombytes(message.encoded_body),
            message.CheckSum,
        )

        message = generic_message_factory(*fields, group_templates=self.group_templates)

        return message
Esempio n. 7
0
    def _parse_instance_fields(self, identifier_tag, fields, template):

        instances = []
        parsed_fields = []
        instance_tags_remaining = set(template)

        for field in fields:  # Loop over group instances
            if not isinstance(field, Field) and not isinstance(field, Group):
                try:
                    field = Field(*field)
                except TypeError:
                    raise ParsingError(
                        f"Invalid Field: '{field}' mut be a (tag, value) tuple."
                    )

            if field.tag == identifier_tag:
                continue  # Skip over identifier tags

            if field.tag not in instance_tags_remaining:
                if field.tag in template:
                    # Tag belongs to the next instance. Append the current instance to this group.
                    instances.append(FieldList(*parsed_fields))

                    instance_tags_remaining = set(
                        template)  # Reset group filter
                    parsed_fields.clear()  # Start parsing the next instance

                else:
                    raise ParsingError(
                        f"Unknown tag {field.tag} found while parsing group fields {template}."
                    )

            instance_tags_remaining.remove(field.tag)
            parsed_fields.append(field)

        if parsed_fields:
            # Append final instance that was parsed
            instances.append(FieldList(*parsed_fields))

        return instances
Esempio n. 8
0
    def __setitem__(self, tag: int, value: any):
        count = self.count(tag)
        if count > 1:
            raise DuplicateTags(
                tag,
                self.values(),
                message=
                f"Cannot set value: FieldMap contains {count} occurrence(s) of '{tag}'.",
            )

        if not (isinstance(value, Field) or isinstance(value, Group)):
            # Create a new Field if value is not a Field or Group already.
            value = Field(tag, value)

        if tag in self:
            # Update value, retaining the Field's position in the list
            self._data = [
                value if field.tag == tag else field for field in self.data
            ]
        else:
            # Add a new Field
            self.data.append(value)
Esempio n. 9
0
    def __init__(self, identifier, *fields, template=None, message_type="*"):
        """
        :param identifier: A Field that identifies the repeating Group. The value of the 'identifier' Field
        indicates the number of times that GroupInstance repeats in this Group.
        :param fields: A FieldMap or list of (tag, value) tuples.
        :param template: Optional. The list of tags that this repeating group consists of. If no template is
        provided then tries to find a template corresponding to identifier.tag in the default GROUP_TEMPLATES setting.
        :param message_type: Optional. The message type that this repeating group is for (used to retrieve the correct
        default template).
        :raises: ParsingError if no template is specified and no template could be found in settings.
        """
        group_identifier = Field(
            *identifier
        )  # First, make sure the group identifier is a valid Field.

        if template is None:
            templates = self.get_group_templates(group_identifier.tag,
                                                 message_type=message_type)
            if len(templates) != 1:
                # FieldDicts are not message-type aware, so can only handle a single template per identifier tag
                raise ParsingError(
                    f"Could not determine template for tag {group_identifier.tag}."
                )

            template = templates[0]

        self.identifier = group_identifier
        self._instance_template = template
        self._instances = self._parse_fields(group_identifier,
                                             fields,
                                             template=template)

        if len(self._instances) != self.size:
            raise ParsingError(
                self.tag,
                fields,
                f"Cannot make {self.size} instances of {template} with {fields}.",
            )
Esempio n. 10
0
    def clear(self):
        for instance in self.instances:
            instance.clear()

        self.identifier = Field(self.identifier.tag, 0)
Esempio n. 11
0
 def __delitem__(self, index: int):
     del self._instances[index]
     self.identifier = Field(self.tag, int(self.value) - 1)
Esempio n. 12
0
 def test_eq_list_of_fields(self, fieldmap_class, fieldmap_impl_abc_123):
     assert fieldmap_impl_abc_123 == [Field(1, "abc"), Field(2, 123)]
Esempio n. 13
0
 def test_add_field(self, routing_id_group):
     fm = routing_id_group + Field(216, "z")
     assert (
         repr(fm) ==
         "Group(Field(215, '3'), Field(216, 'a'), Field(217, 'b'), Field(216, 'c'), Field(217, 'd'), Field(216, 'z'))"  # noqa
     )
Esempio n. 14
0
 def test_add_sequence_of_fields(self, fieldmap_impl_abc_123):
     fm = fieldmap_impl_abc_123 + (Field(3, "ccc"), Field(4, "dddd"))
     assert len(fm) == 4
     assert fm[3] == "ccc"
     assert fm[4] == "dddd"
Esempio n. 15
0
 def test_add_field(self, fieldmap_impl_abc_123):
     fm = fieldmap_impl_abc_123 + Field(3, "ccc")
     assert len(fm) == 3
     assert fm[3] == "ccc"