You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.3 KiB
Python

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()