import csv import re import argparse from fpdf import FPDF def is_number(s): try: float(s) return True except ValueError: return False def ensure_colon(heading: str) -> str: heading = heading.strip() # If it already ends with a colon, don't add another one if not heading.endswith(":"): heading += ":" return heading def main(): parser = argparse.ArgumentParser(description="Generate a PDF report from a TSV input.") parser.add_argument("-i", "--input_tsv", required=True, help="Path to the input TSV file.") parser.add_argument("-o", "--output_pdf", required=True, help="Path to the output PDF file.") args = parser.parse_args() input_tsv = args.input_tsv output_pdf = args.output_pdf # Read the TSV data with open(input_tsv, 'r', encoding='utf-8-sig') as f: reader = csv.DictReader(f, delimiter='\t') rows = list(reader) rows = sorted(rows, key=lambda r: r.get("Sending locality:", "").strip()) pdf = FPDF(format='Letter', unit='pt') pdf.set_auto_page_break(auto=True, margin=50) # Add all required font styles pdf.add_font("DejaVu", "", "DejaVuSansCondensed.ttf") pdf.add_font("DejaVu", "B", "DejaVuSansCondensed-Bold.ttf") pdf.add_font("DejaVu", "I", "DejaVuSansCondensed-Oblique.ttf") pdf.add_font("DejaVu", "BI", "DejaVuSansCondensed-BoldOblique.ttf") pdf.set_font("DejaVu", size=12) skip_cols = {'Timestamp', 'Email Address', 'Name (last, first):', 'Sending locality:'} for row in rows: pdf.add_page() name = row.get('Name (last, first):', '').strip() sending_locality = row.get('Sending locality:', '').strip() # Header section pdf.set_font("DejaVu", '', 14) pdf.cell(0, 20, name, new_x="LMARGIN", new_y="NEXT") pdf.set_font("DejaVu", '', 12) pdf.cell(0, 20, f"Sending Locality: {sending_locality}", new_x="LMARGIN", new_y="NEXT") for col in row.keys(): if col in skip_cols: continue col_title = col.strip() value = row[col].strip() if not value: continue comment_match = re.match(r'^Comments\s\d+$', col_title, re.IGNORECASE) if comment_match: # Comments pdf.set_font("DejaVu", 'I', 12) pdf.write(16, "Comments: ") pdf.set_font("DejaVu", '', 12) pdf.multi_cell(0, 16, value, new_x="LMARGIN", new_y="NEXT") pdf.ln(10) continue # Non-comment columns pdf.set_font("DejaVu", 'B', 12) if is_number(value): # Numeric value col_title = ensure_colon(col_title) pdf.multi_cell(0, 16, f"{col_title} {value}", new_x="LMARGIN", new_y="NEXT") pdf.ln(10) else: # Non-numeric value col_title = ensure_colon(col_title) pdf.multi_cell(0, 16, col_title, new_x="LMARGIN", new_y="NEXT") pdf.set_font("DejaVu", '', 12) pdf.multi_cell(0, 16, value, new_x="LMARGIN", new_y="NEXT") pdf.ln(10) pdf.set_font("DejaVu", 'B', 12) pdf.output(output_pdf) if __name__ == "__main__": main()