nerdocs / pydifact

A python EDIFACT library.
MIT License
156 stars 45 forks source link

Implement high-level containers (Message & Interchange) #19

Closed JocelynDelalande closed 4 years ago

JocelynDelalande commented 4 years ago

In terms of high-level design and rough API, what do you think about :


# Former Message, made abstract class
class AbstractSegmentsContainer:
    @classmethod
    def from_str():
        pass
    @classmethod
    def from_file():
        pass
    @classmethod
    def from_segments():
        pass

    def get_segments():
        pass
    def get_segment():
        pass
    def add_segment():
        pass
    def serialize():
        pass

class Interchange(AbstractSegmentsContainer):
    def __init__(
            delimiters,
            timestamp,
            interchange_control_numbers,
            password_and_application_reference=None
            …
    ):
        pass

    def get_messages(msg_type=None):
        """
        Iterate through messages, optionaly filtering by msg_type
        """
    def get_message(msg_type=None):
        """ Same logic as get_segment"""

class Message(AbstractSegmentsContainer):
    def __init__(
            message_reference_number,
            message_identifier,
            common_access_reference_number=None,
            status_of_the_transfer=None,
    ):
        pass

It would allow to iterate over the segments as pydifact already does, or to go more semantically, digging Interchange−>Message->Segment.

Il let appart the functional groups for now, as they are optional, but they would fit easily in this model.

nerdoc commented 4 years ago

A Message, a Group and even an Interchange technically (in EDI terms) is an "Envelope", has a beginning segment and an ending one (UNB/UNZ etc.). AbstractSegmentsContainer even could be named Envelope? Even if this envelope should be an abstract class. But yes, I think this is a good start for a high level API.

and I would put from_file into Interchange as no message could/should be saved in a file. Interchange would be special too because it has a start/end tag (UNB/UNZ) and an (optional) UNA header...

But yes, this looks fine to me - but would be a bit of an overhaul ;-)

JocelynDelalande commented 4 years ago

A Message, a Group and even an Interchange technically (in EDI terms) is an "Envelope", has a beginning segment and an ending one (UNB/UNZ etc.). AbstractSegmentsContainer even could be named Envelope? Even if this envelope should be an abstract class.

Why not, but note the following : the term Envelope is used extensively in the doc I linked before (pdf « edifact tutorial »)… But rarely inside UN docs. It is not to be considered as a "well-known term" in EDIFACT world.

nerdoc commented 4 years ago

I don't know. ATM we have a str/file that is read into tokens, which is converted into Segments by the parser. in the next step I would create classes for each high-level API element (like FTX, DOC, etc.) and a map like

{
    "DTM": DateTimeSegment, 
    # ...
}

These classes represent each special Segment and contain logic, validation etc.

class DateTimeSegment(Segment):
    def __init__(function_code_qualifier, value, format_code):
        pass

    def __str__(self):
        pass

    def __eq__(self, other):
        pass

enhance the parser (or especially, the SegmentFactory) to create a DateTimeSegment whenever it detects a DTM segment in the string.

This way it is the most clear and readable structure I can think of. The only problem that are not that easy are groups, envelopes - everything with an opening/closing tag. The parser must be capable of that too and keep track of opened segments.

nerdoc commented 4 years ago

Oh, sorry, now I get the point. I kind of mix up SegmentCollection (former Message) and your SegmentContainer (which the real Message inherits). DateTimeElement is good, but a part of it then. So: AbstractSegmentsContainer is ok for me. I'll ty to implement that, with a few changes:

nerdoc commented 4 years ago

Idea for high level api, how it could be creating a message easily:

m = Message(...)
m.add_segment(DTXSegment(...))
m.add_segment(NADSegment(...))
# ...
g = FunctionalGroup(...)
g.add_message(m)
g.add_message(...)

interchange = Interchange(...)
interchange.add_group(g)

Correct?

JocelynDelalande commented 4 years ago

OK, let me know if I can help.

JocelynDelalande commented 4 years ago

I think there really are two possibly independent changes to be carried in current codebase/API :

Do you see it the same way or do you think that this is a work to be done at the same time ?