-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpdf_generator.py
More file actions
89 lines (79 loc) · 4.71 KB
/
pdf_generator.py
File metadata and controls
89 lines (79 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# pdf_generator.py
import random
import streamlit as st
from config import QUESTION_TYPE_MC
# WeasyPrint import and availability check
try:
from weasyprint import HTML, CSS
WEASYPRINT_AVAILABLE = True
except ImportError:
WEASYPRINT_AVAILABLE = False
except OSError as e:
st.error(f"WeasyPrint import error (likely missing Pango/Cairo dependencies): {e}")
WEASYPRINT_AVAILABLE = False
def generate_pdf_data(tests_data_lists, subject_name, status_callback, pdf_strings):
"""
Generate PDF data. Calls status_callback only for WeasyPrint errors.
"""
if not WEASYPRINT_AVAILABLE:
status_callback("error", "PG_WEASYPRINT_UNAVAILABLE")
return None
css_style = """
@page { size: A4; margin: 2cm; }
body { font-family: Verdana, sans-serif; font-size: 11pt; line-height: 1.4; }
.test-container { }
.page-break { page-break-before: always; }
h2 { margin-bottom: 0.8em; font-size: 1.6em; color: #000; font-weight: bold; text-align: center; }
.pdf-header-info { margin-bottom: 2.5em; font-size: 1em; font-weight: normal; line-height: 1.6; }
.header-line { display: flex; align-items: baseline; width: 100%; margin-bottom: 0.6em; }
.header-label { white-space: nowrap; margin-right: 0.5em; flex-shrink: 0; }
.header-underline { flex-grow: 1; border-bottom: 1px solid black; position: relative; top: -2px; min-width: 40px; }
.class-label { margin-left: 2.5em; }
.question { margin-top: 1.8em; margin-bottom: 0.4em; font-weight: bold; }
.answer { display: flex; align-items: baseline; margin-left: 2.5em; margin-top: 0.1em; margin-bottom: 0.3em; padding-left: 0; text-indent: 0; }
.checkbox { flex-shrink: 0; margin-right: 0.6em; font-family: 'DejaVu Sans', sans-serif; }
.answer-text { }
"""
html_parts = []
checkbox_char = "\u2610"
safe_subject_name = subject_name.replace('<', '<').replace('>', '>') if subject_name else "Materia Non Specificata"
title_format = pdf_strings.get("title_format", "Test for {subject_name}")
name_label = pdf_strings.get("name_label", "Name:")
date_label = pdf_strings.get("date_label", "Date:")
class_label = pdf_strings.get("class_label", "Class:")
missing_question_text = pdf_strings.get("missing_question", "MISSING QUESTION")
no_options_text = pdf_strings.get("no_options", "<em>(No answer options provided)</em>")
for index, single_test_data in enumerate(tests_data_lists):
test_title = title_format.format(subject_name=safe_subject_name)
test_html = f'<h2>{test_title}</h2>\n<div class="pdf-header-info">\n'
test_html += f' <div class="header-line"><span class="header-label">{name_label}</span><span class="header-underline"></span></div>\n'
test_html += f' <div class="header-line"><span class="header-label">{date_label}</span><span class="header-underline date-line"></span><span class="header-label class-label">{class_label}</span><span class="header-underline class-line"></span></div>\n</div>\n'
q_counter = 1
for question_data in single_test_data:
q_text = question_data.get('question', missing_question_text).strip().replace('\r', '').replace('<', '<').replace('>', '>')
q_type = question_data.get('type', QUESTION_TYPE_MC)
nbsp = " "
test_html += f'<p class="question">{q_counter}.{nbsp}{q_text}</p>\n'
if q_type == QUESTION_TYPE_MC:
answers = question_data.get('answers', []).copy()
random.shuffle(answers)
if not answers:
test_html += f'<p class="answer">{no_options_text}</p>\n'
else:
for answer in answers:
ans_text = str(answer).strip().replace('\r', '').replace('<', '<').replace('>', '>')
test_html += f'<p class="answer"><span class="checkbox">{checkbox_char}</span><span class="answer-text">{ans_text}</span></p>\n'
q_counter += 1
page_break_class = " page-break" if index > 0 else ""
html_parts.append(f'<div class="test-container{page_break_class}">\n{test_html}\n</div>')
final_html_content = f'<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Verifiche Generate</title><style>{css_style}</style></head><body>{"".join(html_parts)}</body></html>'
try:
html_doc = HTML(string=final_html_content)
pdf_bytes = html_doc.write_pdf()
return pdf_bytes
except FileNotFoundError as e:
status_callback("error", "PG_WEASYPRINT_DEPENDENCY_ERROR", error=e)
return None
except Exception as e:
status_callback("error", "PG_WEASYPRINT_OTHER_ERROR", error=e)
return None