Chapter 36 Quiz: Automated Report Generation

Instructions: Answer all 20 questions. Multiple choice questions have one correct answer unless otherwise noted. The answer key is at the bottom.


Section A — Multiple Choice (Questions 1–12)

1. In Jinja2, which delimiter is used to output a variable's value into the rendered document?

a) {% variable %} b) {{ variable }} c) {# variable #} d) << variable >>


2. You want to apply a custom Python function as a Jinja2 filter so you can write {{ revenue | currency }} in your templates. What is the correct way to register it?

a) env.add_filter("currency", currency_function) b) env.globals["currency"] = currency_function c) env.filters["currency"] = currency_function d) env.register("currency", currency_function)


3. When embedding a matplotlib chart in an HTML report so the report is fully self-contained (no external image files), you should:

a) Save the chart as a .png file and reference it with a relative <img src> path b) Convert the chart to a base64-encoded data URI and embed it directly in the <img src> attribute c) Use JavaScript's Canvas API to re-draw the chart in the browser d) Save the chart to a CDN and reference it with an absolute URL


4. Which Python library converts HTML/CSS to PDF?

a) reportlab b) fpdf c) weasyprint d) pdfminer


5. In Jinja2 template inheritance, which tag marks a section that child templates can override?

a) {% section %} b) {% override %} c) {% block %} d) {% extends %}


6. You are building an Excel report with openpyxl. Which object do you create to set a cell's background color?

a) CellColor(hex="FF0000") b) PatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid") c) BackgroundFill(color="red") d) FillStyle(background="FF0000")


7. A colleague complains that the monthly report script takes 45 seconds to run because it loads 300,000 transaction rows from the database to compute totals. What is the best fix?

a) Use a faster Python CSV parser b) Add more RAM to the server c) Move the aggregation into the SQL query so Python only receives the summary totals d) Use multithreading to process 10 batches of 30,000 rows simultaneously


8. In a Jinja2 template loop, which variable gives you the current iteration number starting from 1?

a) loop.count b) loop.index c) loop.number d) loop.iter


9. You want a CSS rule that forces a page break before a section when the HTML is rendered as a PDF. Which CSS property does this?

a) break-before: page b) page-break-before: always c) print-break: new-page d) Both a and b are correct


10. What does matplotlib.use("Agg") do, and why is it important for automated report generation?

a) Sets chart colors to an "Agg" color scheme b) Enables high-resolution (aggregated) chart output c) Switches matplotlib to a non-interactive backend that doesn't require a display, making it safe to run on servers and in scheduled jobs d) Enables anti-aliasing for smoother chart lines


11. In the context of parameterized reports, what is the main advantage of separating ReportParameters from ReportBuilder?

a) It makes the code run faster b) The same template and rendering logic can serve many different reports just by changing the parameters, without modifying the template c) It is required by the Jinja2 library d) It prevents SQL injection attacks


12. You want to schedule a Python report script to run on the first of every month at 2:00 AM on a Linux server. Which is the most standard approach?

a) Use the schedule Python library running in a persistent process b) Write a cron job: 0 2 1 * * python3 /path/to/report.py c) Set up a systemd timer d) Both b and c are valid standard approaches


Section B — True / False (Questions 13–17)

13. Jinja2's {# comment #} syntax renders the comment text into the output document for readers to see.

14. When using weasyprint, the @page CSS rule allows you to add automatic page numbers, headers, and footers to your PDF output.

15. openpyxl can only write new Excel files; it cannot open and modify existing .xlsx files.

16. Template inheritance in Jinja2 is useful when you want multiple reports to share the same layout and header/footer while having different content sections.

17. A base64-encoded image embedded in an HTML file makes the file completely self-contained, but it increases the file size compared to referencing an external image file.


Section C — Short Answer (Questions 18–20)

18. Explain the difference between these two Jinja2 delimiters and give one use case for each: - {{ expression }} - {% statement %}


19. A business analyst asks why the automated monthly report sometimes shows the wrong month's data. You inspect the code and find this function:

def get_report_month():
    today = date.today()
    return date(today.year, today.month, 1)

Identify the bug and explain how to fix it. The report is supposed to cover the prior month's data, not the current month.


20. You are designing a report delivery system for Acme Corp. Sandra Chen (VP Sales) wants the report as a PDF attachment in an email. Marcus Webb (IT) wants the raw Excel file so he can load it into the data warehouse. Priya Okonkwo wants an interactive HTML version she can open in her browser. Describe how you would structure the report generation pipeline to satisfy all three requirements from a single data fetch. What are the key design decisions?


Answer Key

1. b{{ variable }} is the output delimiter. {% %} is for statements, {# #} is for comments.

2. cenv.filters["name"] = function is the correct way to register custom Jinja2 filters.

3. b — Converting to base64 and embedding in the src attribute (data:image/png;base64,...) creates a self-contained HTML file with no external dependencies.

4. c — WeasyPrint is the library for HTML-to-PDF conversion. ReportLab and fpdf generate PDFs programmatically from scratch; pdfminer reads PDFs.

5. c{% block name %}...{% endblock %} marks overridable sections. {% extends %} declares which template to inherit from.

6. bPatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid") is the correct openpyxl fill object.

7. c — The correct solution is to push aggregation to the database using SQL GROUP BY. Pulling hundreds of thousands of rows into Python when you only need the totals is wasteful regardless of other optimizations.

8. bloop.index is 1-based. loop.index0 is 0-based. There is no loop.count or loop.number.

9. d — Both page-break-before: always (the older CSS2 property) and break-before: page (the newer CSS3 property) are correct. WeasyPrint supports page-break-before: always.

10. cmatplotlib.use("Agg") selects the Agg backend, which renders to in-memory bitmaps without needing a GUI display. This is essential for server-side and scheduled execution where no screen is available.

11. b — Separation of parameters from rendering logic means the same render() function can generate January's report, the Northeast region's report, or a YTD summary report simply by passing different ReportParameters objects.

12. d — Both a cron job and a systemd timer are valid, standard approaches. Cron is simpler and more common; systemd timers offer more control and better logging integration. The schedule library in option a also works but requires a persistent running process.

13. False{# comment #} is a template comment that is removed from the output. It never appears in the rendered document.

14. True — WeasyPrint supports the CSS @page rule including @top-center, @bottom-right, and the counter(page) / counter(pages) functions for automatic page numbering.

15. False — openpyxl can both read and write .xlsx files. Use openpyxl.load_workbook("file.xlsx") to open an existing file for modification.

16. True — Template inheritance is specifically designed for this: the base template defines the shared structure (header, footer, CSS), and child templates fill in the unique content blocks.

17. True — Base64 encoding increases the data size by approximately 33% compared to the binary image file. The tradeoff is self-containment vs. file size efficiency.

18. - {{ expression }} outputs the value of an expression into the rendered document. Use it to display data: {{ company_name }}, {{ revenue | currency }}, {{ regions | length }}. The expression is evaluated and its string representation is inserted at that position. - {% statement %} controls the template's logic and structure without producing output itself. Use it for loops ({% for item in items %}), conditionals ({% if value > 0 %}), variable assignment ({% set total = 0 %}), and inheritance ({% extends "base.html" %}, {% block content %}).

19. The bug: date(today.year, today.month, 1) returns the first day of the current month, not the prior month. If today is February 10, 2025, this returns February 1, 2025, and the query would pull February data (which is incomplete) rather than January's closed data.

Fix:

def get_prior_month_start() -> date:
    """Return the first day of the prior month."""
    today = date.today()
    # Subtract one day from the 1st to get the last day of the prior month
    last_day_prior = date(today.year, today.month, 1) - timedelta(days=1)
    # Then get the first day of that month
    return date(last_day_prior.year, last_day_prior.month, 1)

20. The key design principle is fetch once, render multiple times. The pipeline should:

  1. Single data fetch: Query the database once and store the result as a Python dictionary (or dataframe). This is the source of truth for all three outputs.

  2. Three independent renderers: Write separate functions for render_pdf(), render_excel(), and render_html() — each takes the same data dictionary and produces its format-specific output.

  3. Shared business logic: Calculations (revenue totals, YoY percentages, executive summary generation) happen before rendering, so all three outputs show identical numbers.

  4. Delivery routing: After generation, route each output to the appropriate recipient: email PDF to Sandra, FTP or share Excel to Marcus's data pipeline, and place HTML in Priya's shared folder or web server.

Key design decisions: - Never recalculate metrics separately for each format — one calculation, shared data - Use the same Jinja2 template system for HTML/PDF (they share the same template or the PDF uses a print-optimized variant) - Make each renderer independently testable - Log all generated files for auditability