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