[Python] How to create a new line in pylatex

Discussão em 'Python' iniciado por Stack, Março 27, 2025.

  1. Stack

    Stack Membro Participativo

    I am having issues with my pylatex code could anyone give guidance. Its not test wrapping( I would prefer if a new line is created as well) and and Im having issues handing the # sign in the code.

    Currently the output looks like a straight line that runs out of the table dimensions. every # is seen as /#.

    My code is:

    import json
    import subprocess
    from datetime import datetime
    from pylatex import Document, Section, Subsection, Command, Tabular, NewPage, Itemize, Tabularx
    from pylatex.utils import NoEscape, bold

    class ReportGenerator:
    def __init__(self, json_path, output_name):
    self.json_path = json_path
    self.output_name = output_name
    self.doc = Document(output_name)
    self.load_data()
    self.add_preamble()

    def load_data(self):
    with open(self.json_path, "r") as f:
    self.data = json.load(f)

    def add_preamble(self):
    """Configure document preamble and styling"""
    self.doc.preamble.append(Command('usepackage', 'textcomp'))
    self.doc.preamble.append(Command('usepackage', 'lastpage'))
    self.doc.preamble.append(NoEscape(r'\usepackage{makecell}'))
    self.doc.preamble.append(NoEscape(r'\usepackage{parskip}'))
    self.doc.preamble.append(NoEscape(r'\usepackage{xcolor}'))
    self.doc.preamble.append(NoEscape(r'\usepackage{tabularx}'))
    self.doc.preamble.append(NoEscape(r'\setlength{\parindent}{0pt}'))
    self.doc.preamble.append(NoEscape(r'\setlength{\parskip}{1em}'))
    self.doc.preamble.append(Command('title', 'Test Report'))
    self.doc.preamble.append(Command('author', 'Automated Test System'))
    self.doc.preamble.append(Command('date', datetime.now().strftime("%Y-%m-%d")))
    self.doc.append(NoEscape(r'\maketitle'))

    def sanitize_text(self, text):
    """Escape special LaTeX characters"""
    replacements = {
    '#': r'\#',
    '_': r'\_',
    '%': r'\%',
    '{': r'\{',
    '}': r'\}',
    '[': r'\[',
    ']': r'\]',
    '@': r'\@',
    '&': r'\&',
    '~': r'\textasciitilde{}',
    '^': r'\textasciicircum{}',
    '\\': r'\textbackslash{}'
    }
    return ''.join([replacements.get(c, c) for c in str(text)])

    def format_measurement(self, value):
    """Format measurement values with units"""
    if isinstance(value, dict):
    if 'Units' in value:
    return f"{value['Measurement']} {self.sanitize_text(value['Units'])}"
    return ', '.join([f"{self.sanitize_text(k)}: {self.sanitize_text(v)}"
    for k, v in value.items()])
    return self.sanitize_text(value)


    def create_test_table(self, data, section_name):
    """Create a table for test results with nested measurements"""

    with self.doc.create(Section(self.sanitize_text(section_name))):
    content = self.data[section_name]
    headers=('Property', 'Value')

    if section_name in ["Introduction", "Conclusion"]:
    if isinstance(content, dict):
    # Convert dict to formatted text
    text_content = '\n\n'.join([f"{bold(k)}: {v}" for k, v in content.items()])
    self.doc.append(NoEscape(text_content))
    else:
    self.doc.append(NoEscape(content.replace('\n', '\par\n')))
    elif section_name == "Result":
    for test_name, test_data in content.items():
    with self.doc.create(Subsection(test_name)):
    with self.doc.create(Tabular('|l|l|')) as table:
    table.add_hline()
    table.add_row([bold(headers[0]), bold(headers[1])])
    table.add_hline()
    for key, value in data.items():
    formatted_value = str(value).replace('\n', r' \\ ')
    table.add_row([key, NoEscape(r'\makecell[l]{' + formatted_value + '}')])
    table.add_hline()

    else:
    with self.doc.create(Tabular('|l|l|')) as table:
    table.add_hline()
    table.add_row([bold('Parameter'), bold('Value')])
    table.add_hline()

    for param, value in data.items():
    if param == 'Pass/Fail':
    continue

    safe_param = self.sanitize_text(param)
    formatted_value = self.format_measurement(value)

    # Handle special cases for complex parameters
    if '[N]' in param:
    formatted_value = formatted_value.replace('(', r'\(').replace(')', r'\)')

    table.add_row([safe_param, NoEscape(r'\makecell[l]{' + formatted_value + '}')])
    table.add_hline()

    if 'Pass/Fail' in data:
    pf_value = data['Pass/Fail']
    color = r'\textcolor{green}{Pass}' if pf_value == 'Pass' else r'\textcolor{red}{Fail}'
    table.add_row([bold('Pass/Fail'), NoEscape(color)])
    table.add_hline()

    def handle_test_info(self):
    """Special handler for complex Test Info section"""
    test_info = self.data.get("Test Info", {})
    line_delimiter = " • "
    with self.doc.create(Tabular('|p{4cm}|p{10cm}|')) as table:
    table.add_hline()
    table.add_row([bold('Field'), bold('Value')])
    table.add_hline()

    for field, value in test_info.items():
    if field == 'Notes':
    continue # Handle notes separately

    safe_field = self.sanitize_text(field)
    if isinstance(value, dict):
    sub_values = '\n'.join(
    [f"{self.sanitize_text(k)}: {self.sanitize_text(v)}"
    for k, v in value.items()]
    )
    table.add_row([safe_field, NoEscape(r'\makecell[l]{' + sub_values + '}')])
    else:
    table.add_row([safe_field, self.sanitize_text(value)])
    table.add_hline()

    # Handle Notes with proper LaTeX list formatting
    if 'Notes' in test_info:
    notes = test_info['Notes']
    items = '\n'.join([r'\item ' + self.sanitize_text(v) for v in notes.values()])
    notes_latex = (
    r'\begin{minipage}[t]{0.9\textwidth}'
    r'\begin{itemize}' + '\n' +
    items + '\n' +
    r'\end{itemize}' +
    r'\end{minipage}'
    )
    table.add_row([bold('Notes'), NoEscape(notes_latex)])
    table.add_hline()

    # Rest of the class remains the same as previous version...

    def generate_report(self):
    """Main report generation workflow"""
    # Add Test Info section
    self.handle_test_info()
    self.doc.append(NewPage())

    # Add Table of Contents
    self.doc.append(Command('tableofcontents'))
    self.doc.append(NewPage())

    # Process all test sections
    test_sections = [k for k in self.data.keys() if k != "Test Info"]
    for section in test_sections:
    self.create_test_table(self.data[section], section)

    # Generate output files
    self.generate_tex()
    self.compile_pdf()

    def generate_tex(self):
    """Generate LaTeX source file"""
    try:
    self.doc.generate_tex(self.output_name)
    print(f"Generated LaTeX file: {self.output_name}.tex")
    except Exception as e:
    print(f"Error generating LaTeX: {str(e)}")

    def compile_pdf(self):
    """Compile LaTeX to PDF with multiple runs for TOC"""
    try:
    for _ in range(2): # Run twice to generate TOC
    subprocess.run(['pdflatex', f"{self.output_name}.tex"], check=True)
    print(f"PDF generated successfully: {self.output_name}.pdf")
    except subprocess.CalledProcessError as e:
    print(f"PDF compilation failed: {str(e)}")
    except FileNotFoundError:
    print("Error: pdflatex not found. Ensure LaTeX is installed.")

    if __name__ == "__main__":
    # Configuration
    JSON_PATH = r"C:\Users\Ariela\Desktop\draft\test2.json"
    OUTPUT_NAME = 'test_report2'

    # Generate report
    report = ReportGenerator(JSON_PATH, OUTPUT_NAME)
    report.generate_report()

    Continue reading...

Compartilhe esta Página