nerdocs / pydifact

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

running the example outputs nothing #62

Closed juliusjunghans closed 1 year ago

juliusjunghans commented 1 year ago

Hi,

this is the example, changed sligtly, it shows the input message as output. But the for loop outputs nothing? Do i maybe need a older python for this?

cat first.py from pydifact.segmentcollection import Interchange

interchange = Interchange.from_file("./tests/data/order.edi")

interchange2 = Interchange.from_str( "UNA:+,? 'UNB+UNOC:1+1234+3333+200102:2212+42'UNH+42z42+PAORES:93:1:IA'UNT+2+42z42'UNZ+2+42'" ) for message in interchange2.get_messages(): print(message) print(message.segments) for segment in message.segments: print('Segment tag: {}, content: {}'.format( segment.tag, segment.elements))

juliusjunghans commented 1 year ago

python-3.11.4

mj0nez commented 1 year ago

Hey, CI tests against the latest 3.11, therefore 3.11.4 should be fine. Could you format your snippet - I will try to take a look at this, tomorrow.

juliusjunghans commented 1 year ago

Yes sorry for the formatting, the code is here https://github.com/nerdocs/pydifact under usage. The first example. you have to comment out the order.edi line.

mj0nez commented 1 year ago

No worries.... :) So, your python 3.11.4 should work with pydifact but the example is a bit misleading:

A message is enclosed by a UNH-segment as header and a UNT-segment as footer, the segments of a message are all the segments in between those two (see the Message class. Therefore, the EDI in the string has no segments.

You could verify this by replacing it with the following:

from pydifact.segmentcollection import Interchange

interchange = Interchange.from_str(
    "UNA:+,? 'UNB+UNOC:1+1234+3333+200102:2212+42'UNH+42z42+PAORES:93:1:IA'MSG+1:45'IFT+3+XYZCOMPANY AVAILABILITY'ERC+A7V:1:AMD'UNT+5+42z42'UNZ+2+42'"
)
for message in interchange.get_messages():
    for segment in message.segments:
        print("Segment tag: {}, content: {}".format(segment.tag, segment.elements))

This would output:

Segment tag: MSG, content: [['1', '45']]
Segment tag: IFT, content: ['3', 'XYZCOMPANY AVAILABILITY']
Segment tag: ERC, content: [['A7V', '1', 'AMD']]

This is unfavorable first example so I have put up a PR to fix this. Thank you for pointing this out!

juliusjunghans commented 1 year ago

Thank you. Apparently there are some syntax checks, just one UNH per message for example. But what about DTM:137999 Segments - they are parsed as well. Is there a way to provide a shema file? The 123999 is probably not a allowed value.

And what about min/max values for DTM :137 fields (dont know the specifications for EAN007). But lets assume its allowed one time - can pydifact catch that and throw an error on a second match?

Test Message: UNA:+,? ' UNB+UNOC:1+1234+3333+200102:2212+42' UNH+ME000001+DESADV:D:01B:UN:EAN007' BGM+351+DES587441+9' DTM+137999:20020401:102' DTM+11:20020403:102' DTM+358:20020403:102' RFF+ON:12332' DTM+171:20020325:102' NAD+SU+5411234512309::9' RFF+VA:6558774' NAD+BY+5412345000013::9' RFF+VA:7002474' NAD+DP+5412345123453::9' RFF+VA:800800' NAD+SH+5412345000105::9' CPS+1' PAC+2++201::9' CPS+2+1' PAC+1++201::9' MEA+PD+AAB+KGM:263.2' MEA+PD+WD+MMT:800’ MEA+PD+LN+MMT:1200’ PCI+33E' GIN+BJ+354107380000001051' PAC+20++CT' LIN+1++5410738000152:SRV' QTY+12:20' CPS+3+1' PAC+1++201::9' MEA+PD+AAB+KGM:305.1' PCI+33E' GIN+BJ+354107380000001068' PAC+20++CT' LIN+2++5410738000169:SRV' QTY+12:5' LIN+3++5410738000176:SRV' QTY+12:3' LIN+4++5410738000183:SRV' QTY+12:12' CNT+2:4' UNT+40+ME000001'

mj0nez commented 1 year ago

The current checks only verify that objects (segments, messages and interchanges…) can be correctly constructed. As a UNH-segment indicates the beginning of a message, pydifact expects that the previous message is closed with a UNT-footer. So you can think of the current checks as general syntax assurances. A nested validation like is-this-a-valid-datetime or for formats and schemas is currently not implemented. Although there is a PR #37 where others tried to add a mapping-feature.

Another solution could be implementing your own schema validator or/and Segments. Pydifact provides some basic validators and a PluginMount to automatically parse segments to instances of your custom classes, which would invoke your own validation during parsing. E.g.:

class CustomDTM(Segment):

    tag = "DTM"

    __omitted__ = False

    def validate(self) -> bool:
        # add your business logic here
        #       
        # is a valid date etc. ..

See the implementations of API and Segment

But be aware that now all segments with the DTM-tag are going to be instances of CustomDTM.. Therefore, all DTM-segments in your string have to comply to your validation rule.