feat: add Excel export functionality with support for metadata and customizable sheets
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime, timezone
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
from typing import Any, Iterable
|
||||
|
||||
import pytest
|
||||
@@ -10,15 +11,19 @@ import pytest
|
||||
from services.export_serializers import (
|
||||
CSVExportColumn,
|
||||
CSVExporter,
|
||||
ExcelExporter,
|
||||
default_formatter,
|
||||
default_project_columns,
|
||||
default_scenario_columns,
|
||||
export_projects_to_excel,
|
||||
export_scenarios_to_excel,
|
||||
format_date_iso,
|
||||
format_datetime_utc,
|
||||
format_decimal,
|
||||
stream_projects_to_csv,
|
||||
stream_scenarios_to_csv,
|
||||
)
|
||||
from openpyxl import load_workbook
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -50,6 +55,11 @@ def collect_csv_bytes(chunks: Iterable[bytes]) -> list[str]:
|
||||
return [chunk.decode("utf-8") for chunk in chunks]
|
||||
|
||||
|
||||
def load_workbook_bytes(data: bytes):
|
||||
buffer = BytesIO(data)
|
||||
return load_workbook(buffer, read_only=True, data_only=True)
|
||||
|
||||
|
||||
def test_csv_exporter_writes_header_and_rows() -> None:
|
||||
exporter = CSVExporter(
|
||||
[
|
||||
@@ -66,6 +76,64 @@ def test_csv_exporter_writes_header_and_rows() -> None:
|
||||
assert chunks[1] == "Alpha,Nevada\n"
|
||||
|
||||
|
||||
def test_excel_exporter_basic_workbook() -> None:
|
||||
exporter = ExcelExporter(default_project_columns(), sheet_name="Projects")
|
||||
project = DummyProject(name="Alpha", location="Nevada")
|
||||
|
||||
data = exporter.export([project])
|
||||
workbook = load_workbook_bytes(data)
|
||||
sheet = workbook["Projects"]
|
||||
rows = list(sheet.rows)
|
||||
|
||||
assert [cell.value for cell in rows[0]] == [
|
||||
"name",
|
||||
"location",
|
||||
"operation_type",
|
||||
"description",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
assert rows[1][0].value == "Alpha"
|
||||
|
||||
|
||||
def test_excel_export_projects_helper_with_metadata() -> None:
|
||||
project = DummyProject(name="Alpha", location="Nevada")
|
||||
data = export_projects_to_excel(
|
||||
[project], metadata={"rows": 1}, workbook_title="Project Export")
|
||||
|
||||
workbook = load_workbook_bytes(data)
|
||||
assert workbook.properties.title == "Project Export"
|
||||
assert "Projects" in workbook.sheetnames
|
||||
assert any(sheet.title.startswith("Metadata")
|
||||
for sheet in workbook.worksheets)
|
||||
|
||||
|
||||
def test_excel_export_scenarios_helper_projects_resolved() -> None:
|
||||
project = DummyProject(name="Alpha")
|
||||
scenario = DummyScenario(project=project, name="Scenario 1")
|
||||
data = export_scenarios_to_excel([scenario])
|
||||
|
||||
workbook = load_workbook_bytes(data)
|
||||
sheet = workbook["Scenarios"]
|
||||
rows = list(sheet.rows)
|
||||
|
||||
assert rows[1][0].value == "Alpha"
|
||||
assert rows[1][1].value == "Scenario 1"
|
||||
exporter = CSVExporter(
|
||||
[
|
||||
CSVExportColumn("Name", "name"),
|
||||
CSVExportColumn("Location", "location"),
|
||||
]
|
||||
)
|
||||
|
||||
project = DummyProject(name="Alpha", location="Nevada")
|
||||
|
||||
chunks = collect_csv_bytes(exporter.iter_bytes([project]))
|
||||
|
||||
assert chunks[0] == "Name,Location\n"
|
||||
assert chunks[1] == "Alpha,Nevada\n"
|
||||
|
||||
|
||||
def test_csv_exporter_handles_optional_values_and_default_formatter() -> None:
|
||||
exporter = CSVExporter(
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user