pydifact

repository·master·Indexed 41 days ago

https://github.com/nerdocs/pydifact

A Python library for reading and writing EDIFACT files. It provides a Parser for converting raw EDIFACT strings into structured data, a Serializer for converting Segment objects back to strings, and a hierarchy of containers including Interchange and Message to manage EDIFACT documents. The library includes a Plugin API via PluginMount for extensibility and a generator for managing directory/source files from providers like UNECE and GEFEG.

Tokens
6.4K
Snippets
27
Records
35
Agent score
52%

What's inside pydifact

  1. What is Pydifact?

    master
    Pydifact is a Python library designed to provide complete support for reading and writing EDIFACT files. It is intended for handling the EDIFACT standard, which is used in various business sectors (such as medical report transfers in Austria) for data exchange.
  2. Extend pydifact using the Plugin API

    master

    Pydifact provides a framework for extending its functionality via plugins, following the Simple Plugin Framework pattern. To create a plugin, you can use the PluginMount metaclass.

    Specifically, the SegmentProvider class in pydifact.segments uses PluginMount, meaning it is designed to be extensible through plugins.

  3. Locate and prepare source files in the Zips directory

    master

    The pydifact-generator requires specific source files to function. These files must be placed in the Zips directory, which is the location where the generator searches for its data sources.

    Because these sources are hosted externally, they are not bundled with the pydifact package. You must manually download the necessary ZIP files from the following providers:

    Note: The generator validates the presence of these files. If a required ZIP file for a specific release is missing from the Zips directory, the generator will throw an error.

  4. Implement a custom Segment subclass

    master

    The Segment class is a low-level internal class. To implement specialized EDIFACT segments, you should subclass Segment.

    When subclassing, you must:

    1. Provide a tag attribute (the 3-letter uppercase alphanumeric segment code).
    2. Implement a validate() method to handle segment-specific validation logic.

    If you do not set __omitted__ = True in your subclass, it will be automatically registered in the Segment.plugins list, making it available via the SegmentFactory.

    from pydifact.segments import Segment
    
    class MyCustomSegment(Segment):
        tag = "ABC"
        
        def validate(self, syntax_version: str, directory: str) -> None:
            # Custom validation logic here
            pass
  5. How segment containers work in pydifact

    master

    Pydifact uses a hierarchy of segment containers to represent EDIFACT data structures. All containers inherit from AbstractSegmentsContainer, which provides common methods for managing a collection of Segment objects.

    There are three main types of containers:

    1. Interchange: Represents the highest level of an EDIFACT document. It includes a header (UNB) and a footer (UNZ) and can contain one or more Message objects.
    2. Message: Represents a single message within an interchange, bounded by a header (UNH) and a footer (UNT).
    3. RawSegmentCollection: A lightweight container for analyzing arbitrary groups of segments without the overhead of header/footer validation or specific EDIFACT structure requirements.

    When using Interchange or Message, the container automatically manages the envelope segments (header and footer) separately from the internal segments list.

    from pydifact.segmentcollection import Interchange
    
    # An interchange can be created from a string
    interchange = Interchange.from_str("UNB+UNOA:1+SENDER+RECIPIENT+...\n...UNT+1+REF\nUNZ+1+REF")
    
    # Or from a file
    interchange = Interchange.from_file("path/to/edi_file.txt")
  6. Create an Interchange from a string or file

    master

    The Interchange class provides factory methods to instantiate an EDIFACT interchange from raw data.

    • Interchange.from_str(string, parser=None, characters=None): Parses an EDIFACT string into an Interchange instance.
    • Interchange.from_file(file, encoding='iso8859-1', parser=None): Reads an EDIFACT file from disk using the specified encoding and parses it.

    Note: If the input contains a UNA segment, the Interchange will automatically update its control characters and set the has_una_segment flag.

    from pydifact.segmentcollection import Interchange
    
    # From string
    interchange = Interchange.from_str("UNB+...\n...UNZ+...")
    
    # From file
    interchange = Interchange.from_file("data.edi", encoding="utf-8")
  7. Extract messages from an Interchange

    master

    An Interchange can contain multiple messages. Use get_messages() to iterate through them. This method parses the segments between UNH (header) and UNT (footer) tags into Message objects.

    If the interchange structure is invalid (e.g., a UNH is not closed by a UNT), an EDISyntaxError will be raised.

    for message in interchange.get_messages():
        print(f"Message Type: {message.type}, Version: {message.version}")
        # Process message segments...
  8. Extract control characters from a UNA segment

    master

    The Parser.get_control_characters static method allows you to extract the EDI control characters from a message string (specifically looking for the UNA segment) without performing a full parse.

    This is useful if you need to know the delimiters used in a file before deciding how to process it. If the message does not start with UNA, it returns the provided characters object (which defaults to standard EDIFACT characters if none are provided).

    from pydifact.parser import Parser
    from pydifact.control import Characters
    
    # Example message starting with UNA
    message = "UNA:+.? '"
    
    # Extract characters
    chars = Parser.get_control_characters(message)
    print(chars.segment_terminator) # Output depends on the UNA content
  9. Initialize the Parser with custom configuration

    master

    You can customize the Parser behavior during initialization using the following parameters:

    • factory: A SegmentFactory instance used to create segment objects. Defaults to a new SegmentFactory().
    • characters: A Characters instance defining the control characters (separators, terminators, etc.). Defaults to a new Characters() instance.
    • directory: A string representing the directory used for looking up segment definitions. Defaults to an empty string.

    Note: If you provide characters during the parse() call, those will take precedence over the parser's initialized characters if no UNA segment is found in the message.

    from pydifact.parser import Parser
    from pydifact.segments import SegmentFactory
    from pydifact.control import Characters
    
    custom_factory = SegmentFactory()
    custom_chars = Characters()
    
    parser = Parser(
        factory=custom_factory,
        characters=custom_chars,
        directory="/path/to/segments"
    )
  10. Serialize a container to an EDIFACT string

    master

    To convert an Interchange or Message back into a raw EDIFACT string, use the serialize() method. This method automatically includes the header and footer segments.

    • serialize(break_lines=False): Returns the string representation. If break_lines is True, a line break is inserted after each segment terminator (note: this is common in practice but technically forbidden in some EDIFACT specs).
    • __str__(): Calling str(container) is equivalent to calling serialize().
    edi_string = interchange.serialize(break_lines=True)
  11. Work with EDIFACT Segments and Tokens

    master

    The core data structures in pydifact are:

    • Segment: Represents a single EDIFACT segment (a group of elements).
    • Token: Represents the smallest unit of data within a segment.
    • Tokenizer: Used for breaking down raw text into Token objects.
    • Characters: Handles EDIFACT-specific character sets and control characters.
  12. Validate a Segment against an EDIFACT directory

    master

    You can manually trigger validation for a Segment instance using the validate() method. This checks the segment's elements against an XML schema definition located in the pydifact syntax directories.

    Parameters:

    • syntax_version (str): The EDIFACT syntax version (e.g., "1", "300", "402"). The correct release is determined automatically.
    • directory (str): The directory name to validate against (e.g., "d00a", "d96a").

    Validation Logic:

    • Checks if the number of elements matches the XML definition (required vs. optional).
    • Validates mandatory elements are not empty.
    • Validates data element types (an for alphanumeric, n for numeric, a for alphabetic) and length constraints (length or maxlength).

    Raises:

    • ValidationError: If the segment does not conform to the schema.
    # Assuming 'segment' is an instance of a Segment subclass
    try:
        segment.validate(syntax_version="402", directory="d96a")
    except ValidationError as e:
        print(f"Validation failed: {e}")