Ejemplo n.º 1
0
 def test_with_separator_identity(self):
     one = Characters()
     other = Characters()
     # a copy of a characters object must be equal, but not the same
     self.assertTrue(one == other,
                     'Objects differ: "{}", "{}"'.format(one, other))
     self.assertFalse(one is other)
Ejemplo n.º 2
0
def setup():
    setup = Setup()
    unb_segment = "UNB+UNOA:4+APIS*ABE+USADHS+070429:0900+000000001++USADHS'"
    cc = Characters()
    setup.cc = cc.with_control_character("decimal_point", ".")
    setup.collection = SegmentCollection.from_str(unb_segment)
    return setup
Ejemplo n.º 3
0
    def get_control_characters(message, characters=None):
        u"""Read the UNA segment from the passed string.

        :param message: a valid EDI message string, or UNA segment string,
                        to extract the control characters from
        :param characters: the control characters to use, if none found in
                           the message
        :rtype: str or None
        :return: the control characters
        """

        if not characters:
            characters = Characters()

        # First, try to read the UNA segment ("Service String Advice",
        # conditional). This segment and the UNB segment (Interchange Header)
        # must always be written in ASCII, even if after the BGM the files
        # continues with cyrillic or UTF-16.

        # If it does not exist, return a default.
        if not message[:3] == u"UNA":
            return characters

        # Get the character definitions
        chars = message[3:9]
        characters.is_extracted_from_message = True

        characters.component_separator = chars[0]
        characters.data_separator = chars[1]
        characters.decimal_point = chars[2]
        characters.escape_character = chars[3]
        characters.reserved_character = chars[4]
        characters.segment_terminator = chars[5]

        return characters
Ejemplo n.º 4
0
    def parse(self, message, characters=None):
        u"""Parse the message into a list of segments.

        :param characters: the control characters to use, if there is no
                UNA segment present
        :param message: The EDI message
        :rtype:
        """

        # FIXME: DRY: use get_control_characters here?
        tokens = []
        # If there is a UNA token, take the following 6 characters
        # unconditionally, save them as token and use it as control characters
        # for further parsing
        if message[0:3] == u'UNA':
            control_chars = message[3:9]
            tokens.append(Token(Token.Type.CONTENT, u'UNA'))
            tokens.append(Token(Token.Type.CTRL_CHARS, control_chars))

            # remove the UNA segment from the string
            message = message[9:].lstrip(u"\r\n")
            self.characters = Characters.from_str(u'UNA' + control_chars)

        else:
            # if no UNA header present, use default control characters
            if characters is not None:
                self.characters = characters

        tokenizer = Tokenizer()
        tokens += tokenizer.get_tokens(message, self.characters)
        segments = self.convert_tokens_to_segments(tokens, self.characters)
        return segments
Ejemplo n.º 5
0
    def parse(self,
              message: str,
              characters: Characters = None) -> Generator[Segment, Any, None]:
        """Parse the message into a list of segments.

        :param characters: the control characters to use, if there is no
                UNA segment present
        :param message: The EDI message
        :rtype:
        """

        # If there is a UNA, take the following 6 characters
        # unconditionally, save them, strip them, and make control Characters()
        # for further parsing
        if message[0:3] == "UNA":
            self.characters = Characters.from_str("UNA" + message[3:9])

            # remove the UNA segment from the string
            message = message[9:].lstrip("\r\n")

        else:
            # if no UNA header present, use default control characters
            if characters is not None:
                self.characters = characters

        tokenizer = Tokenizer()
        return self.convert_tokens_to_segments(
            tokenizer.get_tokens(message, self.characters), self.characters)
Ejemplo n.º 6
0
    def from_segments(cls, segments: list
                      or collections.Iterable) -> "Interchange":
        segments = iter(segments)

        first_segment = next(segments)
        if first_segment.tag == 'UNA':
            unb = next(segments)
        elif first_segment.tag == 'UNB':
            unb = first_segment
        else:
            raise EDISyntaxError(
                'An interchange must start with UNB or UNA and UNB')
        # Loosy syntax check :
        if len(unb.elements) < 4:
            raise EDISyntaxError('Missing elements in UNB header')

        datetime_str = '-'.join(unb.elements[3])
        timestamp = datetime.datetime.strptime(datetime_str, '%y%m%d-%H%M')
        interchange = Interchange(
            syntax_identifier=unb.elements[0],
            sender=unb.elements[1],
            recipient=unb.elements[2],
            timestamp=timestamp,
            control_reference=unb.elements[4],
        )

        if first_segment.tag == 'UNA':
            interchange.has_una_segment = True
            interchange.characters = Characters.from_str(
                first_segment.elements[0])

        return interchange.add_segments(segment for segment in segments
                                        if segment.tag != 'UNZ')
Ejemplo n.º 7
0
    def from_segments(cls, segments: Union[list, Iterable]) -> "Interchange":
        segments = iter(segments)

        first_segment = next(segments)
        if first_segment.tag == "UNA":
            unb = next(segments)
        elif first_segment.tag == "UNB":
            unb = first_segment
        else:
            raise EDISyntaxError(
                "An interchange must start with UNB or UNA and UNB")
        # Loosy syntax check :
        if len(unb.elements) < 4:
            raise EDISyntaxError("Missing elements in UNB header")

        datetime_str = "-".join(unb.elements[3])
        timestamp = datetime.datetime.strptime(datetime_str, "%y%m%d-%H%M")
        interchange = Interchange(
            syntax_identifier=unb.elements[0],
            sender=unb.elements[1],
            recipient=unb.elements[2],
            timestamp=timestamp,
            control_reference=unb.elements[4],
        )

        if first_segment.tag == "UNA":
            interchange.has_una_segment = True
            interchange.characters = Characters.from_str(
                first_segment.elements[0])

        return interchange.add_segments(segments)
Ejemplo n.º 8
0
    def __init__(self):

        # The segments that make up this message
        self.segments = []
        self.characters = Characters()

        # Flag whether the UNA header is present
        self.has_una_segment = False
Ejemplo n.º 9
0
class TestControlCharacters(unittest.TestCase):

    def setUp(self):
        self.cc = Characters()

    def test_wrong_attribute(self):
        self.assertRaises(AttributeError,
                          self.cc.with_control_character, 'wrongtype', '+')

    def test_wrong_character_size(self):
        self.assertRaises(ValueError,
                          self.cc.with_control_character, 'decimal_point', ',.')

    def test_correct_parameters(self):

        d = self.cc.with_control_character('component_separator', '/')

        self.assertEqual(self.cc.with_control_character(
            'component_separator', '/').component_separator, '/')

        self.assertEqual(self.cc.with_control_character(
            'data_separator', '/').data_separator, '/')

        self.assertEqual(self.cc.with_control_character(
            'decimal_point', '/').decimal_point, '/')

        self.assertEqual(self.cc.with_control_character(
            'escape_character', '/').escape_character, '/')

        self.assertEqual(self.cc.with_control_character(
            'reserved_character', '/').reserved_character, '/')


        self.assertEqual(self.cc.with_control_character(
            'segment_terminator', '/').segment_terminator, '/')
Ejemplo n.º 10
0
    def add_segment(self, segment: Segment) -> "Message":
        """Append a segment to the message.

        :param segment: The segment to add
        """
        if segment.tag == "UNA":
            self.has_una_segment = True
            self.characters = Characters.from_str(segment.elements[0])
        self.segments.append(segment)
        return self
Ejemplo n.º 11
0
    def create_segment(name: str, *elements: list) -> Segment:
        """Create a new instance of the relevant class type.

        :param name: The name of the segment
        :param elements: The data elements for this segment
        """
        if not SegmentFactory.characters:
            SegmentFactory.characters = Characters()

        # FIXME: characters is not used!
        return Segment(name, *elements)
Ejemplo n.º 12
0
    def add_segment(self, segment: Segment) -> "UNAHandlingMixin":
        """Append a segment to the collection. Passing a UNA segment means setting/overriding the control
        characters and setting the serializer to output the Service String Advice. If you wish to change the control
        characters from the default and not output the Service String Advice, change self.characters instead,
        without passing a UNA Segment.

        :param segment: The segment to add
        """
        if segment.tag == "UNA":
            self.has_una_segment = True
            self.characters = Characters.from_str(segment.elements[0])
            return self
        return super().add_segment(segment)
Ejemplo n.º 13
0
    def __init__(self,
                 extra_header_elements: List[Union[str, List[str]]] = []):
        """
        :param extra_header_elements: a list of elements to be appended at the end
          of the header segment (same format as Segment() constructor *elements).
        """

        # The segments that make up this message
        self.segments = []
        self.characters = Characters()

        self.extra_header_elements = extra_header_elements

        # Flag whether the UNA header is present
        self.has_una_segment = False
Ejemplo n.º 14
0
 def __init__(self,
              sender: str,
              recipient: str,
              control_reference: str,
              syntax_identifier: Tuple[str, int],
              delimiters: Characters = Characters(),
              timestamp: datetime.datetime = None,
              *args,
              **kwargs):
     super().__init__(*args, **kwargs)
     self.sender = sender
     self.recipient = recipient
     self.control_reference = control_reference
     self.syntax_identifier = syntax_identifier
     self.delimiters = delimiters
     self.timestamp = timestamp or datetime.datetime.now()
Ejemplo n.º 15
0
class TestControlCharacters(unittest.TestCase):
    def setUp(self):
        self.cc = Characters()

    def test_wrong_attribute(self):
        self.assertRaises(AttributeError, self.cc.with_control_character,
                          "wrongtype", "+")

    def test_wrong_character_size(self):
        self.assertRaises(ValueError, self.cc.with_control_character,
                          "decimal_point", ",.")

    def test_correct_parameters(self):

        d = self.cc.with_control_character("component_separator", "/")

        self.assertEqual(
            self.cc.with_control_character("component_separator",
                                           "/").component_separator,
            "/",
        )

        self.assertEqual(
            self.cc.with_control_character("data_separator",
                                           "/").data_separator, "/")

        self.assertEqual(
            self.cc.with_control_character("decimal_point", "/").decimal_point,
            "/")

        self.assertEqual(
            self.cc.with_control_character("escape_character",
                                           "/").escape_character,
            "/",
        )

        self.assertEqual(
            self.cc.with_control_character("reserved_character",
                                           "/").reserved_character,
            "/",
        )

        self.assertEqual(
            self.cc.with_control_character("segment_terminator",
                                           "/").segment_terminator,
            "/",
        )
Ejemplo n.º 16
0
    def create_segment(name: str,
                       *elements: Union[str, List[str]],
                       validate: bool = True) -> Segment:
        """Create a new instance of the relevant class type.

        :param name: The name of the segment
        :param elements: The data elements for this segment
        :param validate: bool if True, the created segment is validated before return
        """
        if not SegmentFactory.characters:
            SegmentFactory.characters = Characters()

        # Basic segment type validation is done here.
        # The more special validation must be done in the corresponding Segment

        if not name:
            raise EDISyntaxError("The tag of a segment must not be empty.")

        if type(name) != str:
            raise EDISyntaxError(
                "The tag name of a segment must be a str, but is a {}: {}".
                format(type(name), name))

        if not name.isalnum():
            raise EDISyntaxError(
                "Tag '{}': A tag name must only contain alphanumeric characters."
                .format(name))

        for Plugin in SegmentProvider.plugins:
            if Plugin().tag == name:
                s = Plugin(name, *elements)
        else:
            # we don't support this kind of EDIFACT segment (yet), so
            # just create a generic Segment()
            s = Segment(name, *elements)

        if validate:
            if not s.validate():
                raise EDISyntaxError(
                    "could not create '{}' Segment. Validation failed.".format(
                        name))

        # FIXME: characters is not used!
        return Segment(name, *elements)
Ejemplo n.º 17
0
    def __init__(self, factory: SegmentFactory = None):
        if factory is None:
            factory = SegmentFactory()

        self.factory = factory
        self.characters = Characters()
Ejemplo n.º 18
0
def test_with_separator_identity():
    one = Characters()
    other = Characters()
    # a copy of a characters object must be equal, but not the same
    assert one == other, 'Objects differ: "{}", "{}"'.format(one, other)
    assert one is not other
Ejemplo n.º 19
0
 def setUp(self):
     self.cc = Characters()
Ejemplo n.º 20
0
def test_cc_assigning():
    one = Characters()
    one.component_separator = "x"
    assert one.component_separator == "x"
    assert one == "x+,? '"
Ejemplo n.º 21
0
def test_wrong_cc_assigning():
    with pytest.raises(ValueError):
        Characters().with_control_character("component_separator", "xd")

    with pytest.raises(AttributeError):
        Characters().with_control_character("notexisting", ":")
Ejemplo n.º 22
0
def setup():
    setup = Setup()
    una_segment = "UNA:+.? '"
    setup.cc = Characters.from_str(una_segment)
    return setup
Ejemplo n.º 23
0
 def test_cc_assigning(self):
     one = Characters()
     one.component_separator = 'x'
     self.assertEqual(one.component_separator, 'x')
     self.assertEqual(str(one), "x+,? '")
Ejemplo n.º 24
0
 def test_no_terminator(self):
     with self.assertRaises(RuntimeError) as cm:
         self._tokenizer.get_tokens("TEST", Characters())
     self.assertEqual(str(cm.exception), "Unexpected end of EDI message")
Ejemplo n.º 25
0
 def _assert_tokens(self, message, expected=None):
     if expected is None:
         expected = []
     tokens = self._tokenizer.get_tokens("{}'".format(message), Characters())
     expected.append(Token(Token.Type.TERMINATOR, "'"))
     self.assertEqual(expected, tokens)
Ejemplo n.º 26
0
def test_no_terminator():
    with pytest.raises(RuntimeError):
        Tokenizer().get_tokens("TEST", Characters())
        pytest.fail("Unexpected end of EDI message")