Untitled

 avatar
unknown
plain_text
22 days ago
5.5 kB
2
Indexable
#!/usr/bin/env python3

import os
import re
import sys
import xml.etree.ElementTree as ET

def extract_special_msgs(log_xml_path):
    """
    Parse the given Robot Framework log XML file and return a list of tuples:
        [(keyword_name, special_message), ... ]
    where `special_message` is the content from <msg> that contained '--- SPECIAL ---'.
    """
    tree = ET.parse(log_xml_path)
    root = tree.getroot()

    # Robot Framework log.xml for version 7.1.1 typically has a top-level <robot> element
    # containing <suite> / <test> / <kw> trees, etc.
    namespace = ''  # For simplicity, we assume no XML namespace is used.

    special_entries = []

    # We can iterate all 'kw' nodes. Each <kw> can have <msg> children
    for kw in root.iter('kw'):
        # Attempt to get the "name" attribute of the keyword
        # or fallback to type if name is missing.
        keyword_name = kw.get('name') or kw.get('type', 'UNKNOWN_KEYWORD')

        # For each msg in this kw, check if it contains '--- SPECIAL ---'
        for msg in kw.findall('msg'):
            msg_text = (msg.text or "").strip()
            if '--- SPECIAL ---' in msg_text:
                # Store the entire <msg> text along with the parent kw name
                special_entries.append((keyword_name, msg_text))

    return special_entries

def insert_msgs_into_robot(robot_file_path, special_entries):
    """
    Open the .robot file, locate lines that define the keywords in `special_entries`,
    and insert the messages right after the keyword definition line.
    
    `special_entries` is a list of (keyword_name, special_message).
    """
    # Read .robot file as list of lines:
    with open(robot_file_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    # We’ll keep a new list of lines to write out.
    new_lines = []
    
    # Regex that might match a keyword definition in the *** Keywords *** section,
    # e.g. a line like:  "My Keyword Name"
    # This is simplistic. In real usage, you might account for indentation, resource usage, etc.
    keyword_header_pattern = re.compile(r'^\s*([\w\s]+?)\s{2,}|\s*([\w\s]+?):$')
    # Explanation:
    #  - Robot typically has two or more spaces or a colon after the keyword name.
    #  - This pattern might not cover all variations, so adjust as needed.

    # Convert special_entries into a dict of keyword -> list of messages
    # so we can handle multiple messages for the same keyword.
    from collections import defaultdict
    keyword_msgs = defaultdict(list)
    for kw_name, msg in special_entries:
        keyword_msgs[kw_name].append(msg)

    in_keywords_section = False
    for line in lines:
        stripped_line = line.strip()

        # Are we entering the Keywords section?
        if stripped_line.upper().startswith('*** KEYWORDS ***'):
            in_keywords_section = True
            new_lines.append(line)
            continue

        if in_keywords_section:
            # If we see another *** Section *** or *** Test Cases ***,
            # that means we've exited the Keywords section.
            if re.match(r'^\*{3}\s*\w+\s*\*{3}$', stripped_line):
                # We are leaving the Keywords section
                in_keywords_section = False
                new_lines.append(line)
                continue

            # Check if this line starts a new keyword definition
            match = keyword_header_pattern.match(stripped_line)
            if match:
                # The "keyword_name" could appear in group(1) or group(2)
                possible_kw_name = match.group(1) or match.group(2)
                if possible_kw_name:
                    # Clean up multiple spaces or trailing spaces
                    possible_kw_name = re.sub(r'\s+', ' ', possible_kw_name).strip()

                new_lines.append(line)

                # If this line's keyword name matches something in our dict, insert the messages
                if possible_kw_name in keyword_msgs:
                    for msg_text in keyword_msgs[possible_kw_name]:
                        # Insert as a comment or a new line
                        # E.g., we can do something like a Robot comment line:
                        inserted_line = f"    # Inserted from log.xml: {msg_text}\n"
                        new_lines.append(inserted_line)

                    # Once inserted, you might choose to remove them from the dict 
                    # (to avoid re-inserting) if you only do so once per file:
                    del keyword_msgs[possible_kw_name]
                continue

        # Default case: just keep the original line
        new_lines.append(line)

    # Write the updated lines back to the file
    # (Optionally rename the original and create a new file, or back up first)
    with open(robot_file_path, 'w', encoding='utf-8') as f:
        f.writelines(new_lines)

def main():
    if len(sys.argv) < 3:
        print(f"Usage: {os.path.basename(sys.argv[0])} <path_to_log_xml> <path_to_robot_file>")
        sys.exit(1)

    log_xml = sys.argv[1]
    robot_file = sys.argv[2]

    # 1) Extract the special messages from the log.xml
    special_entries = extract_special_msgs(log_xml)

    if not special_entries:
        print("No '--- SPECIAL ---' messages found in the XML.")
        sys.exit(0)

    # 2) Insert the extracted messages into the .robot file
    insert_msgs_into_robot(robot_file, special_entries)
    print("Messages have been inserted into the .robot file.")

if __name__ == "__main__":
    main()
Leave a Comment