Tighten configuration and export handling
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, List
|
||||
|
||||
from ..types import ReportRow
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from typing import List
|
||||
|
||||
from tabulate import tabulate
|
||||
from .base import Formatter
|
||||
|
||||
from ..types import ReportRow
|
||||
from .base import Formatter
|
||||
|
||||
|
||||
class TableFormatter(Formatter):
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import csv
|
||||
import io
|
||||
from typing import List
|
||||
from .base import Formatter
|
||||
|
||||
from ..types import ReportRow
|
||||
from .base import Formatter
|
||||
|
||||
|
||||
class CSVFormatter(Formatter):
|
||||
@@ -14,9 +15,7 @@ class CSVFormatter(Formatter):
|
||||
def format(self, rows: List[ReportRow]) -> str:
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output, dialect="excel")
|
||||
writer.writerow(
|
||||
["Project", "Version", "Issue ID", "Subject", "Status", "Spent Time"]
|
||||
)
|
||||
writer.writerow(["Project", "Version", "Issue ID", "Subject", "Status", "Spent Time"])
|
||||
for r in rows:
|
||||
writer.writerow(
|
||||
[
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from typing import Dict, Type, Optional
|
||||
from typing import Dict, Optional, Type
|
||||
|
||||
from .base import Formatter
|
||||
from .console import TableFormatter, CompactFormatter
|
||||
from .console import CompactFormatter, TableFormatter
|
||||
from .csv import CSVFormatter
|
||||
from .html import HTMLFormatter
|
||||
from .markdown import MarkdownFormatter
|
||||
from .odt import ODTFormatter
|
||||
from .html import HTMLFormatter
|
||||
|
||||
# Словарь для сопоставления расширений файлов с классами форматтеров
|
||||
FORMATTER_MAP: Dict[str, Type[Formatter]] = {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from html import escape
|
||||
from typing import Dict, List
|
||||
from .base import Formatter
|
||||
|
||||
from ..types import ReportRow
|
||||
from .base import Formatter
|
||||
|
||||
|
||||
class HTMLFormatter(Formatter):
|
||||
@@ -36,34 +38,38 @@ class HTMLFormatter(Formatter):
|
||||
]
|
||||
|
||||
for project, versions in projects.items():
|
||||
project_text = escape(project)
|
||||
total_project_rows = sum(len(tasks) for tasks in versions.values())
|
||||
first_version_in_project = True
|
||||
|
||||
for version, task_rows in versions.items():
|
||||
version_text = escape(version)
|
||||
row_span_version = len(task_rows)
|
||||
first_row_in_version = True
|
||||
|
||||
for r in task_rows:
|
||||
task_cell = escape(f"{r['issue_id']}. {r['subject']}")
|
||||
status_text = escape(r["status_ru"])
|
||||
time_text = escape(r["time_text"])
|
||||
lines.append(" <tr>")
|
||||
|
||||
# Ячейка "Проект" - только в первой строке проекта
|
||||
if first_version_in_project and first_row_in_version:
|
||||
lines.append(
|
||||
f' <td rowspan="{total_project_rows}" style="vertical-align: top;">{project}</td>'
|
||||
f' <td rowspan="{total_project_rows}" style="vertical-align: top;">{project_text}</td>'
|
||||
)
|
||||
|
||||
# Ячейка "Версия" - только в первой строке версии
|
||||
if first_row_in_version:
|
||||
lines.append(
|
||||
f' <td rowspan="{row_span_version}" style="vertical-align: top;">{version}</td>'
|
||||
f' <td rowspan="{row_span_version}" style="vertical-align: top;">{version_text}</td>'
|
||||
)
|
||||
first_row_in_version = False
|
||||
|
||||
# Остальные колонки
|
||||
task_cell = f"{r['issue_id']}. {r['subject']}"
|
||||
lines.append(f" <td>{task_cell}</td>")
|
||||
lines.append(f" <td>{r['status_ru']}</td>")
|
||||
lines.append(f" <td>{r['time_text']}</td>")
|
||||
lines.append(f" <td>{status_text}</td>")
|
||||
lines.append(f" <td>{time_text}</td>")
|
||||
|
||||
lines.append(" </tr>")
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
from typing import List
|
||||
from .base import Formatter
|
||||
|
||||
from ..types import ReportRow
|
||||
from .base import Formatter
|
||||
|
||||
|
||||
def _escape_markdown_table_cell(value: object) -> str:
|
||||
return str(value).replace("\\", "\\\\").replace("|", "\\|").replace("\n", "<br>")
|
||||
|
||||
|
||||
class MarkdownFormatter(Formatter):
|
||||
@@ -15,10 +20,13 @@ class MarkdownFormatter(Formatter):
|
||||
"|--------|--------|--------|--------|-----------|",
|
||||
]
|
||||
for r in rows:
|
||||
task_cell = f"{r['issue_id']}. {r['subject']}"
|
||||
task_cell = _escape_markdown_table_cell(f"{r['issue_id']}. {r['subject']}")
|
||||
lines.append(
|
||||
f"| {r['display_project']} | {r['display_version']} "
|
||||
f"| {task_cell} | {r['status_ru']} | {r['time_text']} |"
|
||||
f"| {_escape_markdown_table_cell(r['display_project'])} "
|
||||
f"| {_escape_markdown_table_cell(r['display_version'])} "
|
||||
f"| {task_cell} "
|
||||
f"| {_escape_markdown_table_cell(r['status_ru'])} "
|
||||
f"| {_escape_markdown_table_cell(r['time_text'])} |"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from importlib import resources
|
||||
from typing import List
|
||||
from typing import Dict, List
|
||||
|
||||
from odf.opendocument import OpenDocument, load
|
||||
from odf.style import Style, TableCellProperties, TableColumnProperties
|
||||
from odf.table import Table, TableCell, TableColumn, TableRow
|
||||
from odf.text import P
|
||||
from odf.table import Table, TableColumn, TableRow, TableCell
|
||||
from odf.style import Style, TableColumnProperties, TableCellProperties
|
||||
from .base import Formatter
|
||||
|
||||
from ..types import ReportRow
|
||||
from ..utils import get_month_name_from_range
|
||||
from .base import Formatter
|
||||
|
||||
|
||||
class ODTFormatter(Formatter):
|
||||
@@ -25,11 +27,7 @@ class ODTFormatter(Formatter):
|
||||
Форматирует данные в объект OpenDocument.
|
||||
"""
|
||||
|
||||
with (
|
||||
resources.files("redmine_reporter")
|
||||
.joinpath("templates", "template.odt")
|
||||
.open("rb") as f
|
||||
):
|
||||
with resources.files("redmine_reporter").joinpath("templates/template.odt").open("rb") as f:
|
||||
doc = load(f)
|
||||
|
||||
para_style_name = "Standard"
|
||||
@@ -43,9 +41,7 @@ class ODTFormatter(Formatter):
|
||||
# Стиль ячеек
|
||||
cell_style_name = "TableCellStyle"
|
||||
cell_style = Style(name=cell_style_name, family="table-cell")
|
||||
cell_props = TableCellProperties(
|
||||
padding="0.04in", border="0.05pt solid #000000"
|
||||
)
|
||||
cell_props = TableCellProperties(padding="0.04in", border="0.05pt solid #000000")
|
||||
cell_style.addElement(cell_props)
|
||||
doc.automaticstyles.addElement(cell_style)
|
||||
|
||||
@@ -73,7 +69,7 @@ class ODTFormatter(Formatter):
|
||||
header_row.addElement(cell)
|
||||
table.addElement(header_row)
|
||||
|
||||
projects = {}
|
||||
projects: Dict[str, Dict[str, List[ReportRow]]] = {}
|
||||
for r in rows:
|
||||
project = r["project"]
|
||||
version = r["version"]
|
||||
@@ -103,9 +99,7 @@ class ODTFormatter(Formatter):
|
||||
# Ячейка "Проект" - только в первой строке всего проекта
|
||||
if first_version_in_project and first_row_in_version:
|
||||
cell_project = TableCell(stylename=cell_style_name)
|
||||
cell_project.setAttribute(
|
||||
"numberrowsspanned", str(total_project_rows)
|
||||
)
|
||||
cell_project.setAttribute("numberrowsspanned", str(total_project_rows))
|
||||
p = P(stylename=para_style_name, text=project)
|
||||
cell_project.addElement(p)
|
||||
row.addElement(cell_project)
|
||||
@@ -113,9 +107,7 @@ class ODTFormatter(Formatter):
|
||||
# Ячейка "Версия" - только в первой строке каждой версии
|
||||
if first_row_in_version:
|
||||
cell_version = TableCell(stylename=cell_style_name)
|
||||
cell_version.setAttribute(
|
||||
"numberrowsspanned", str(row_span_version)
|
||||
)
|
||||
cell_version.setAttribute("numberrowsspanned", str(row_span_version))
|
||||
p = P(stylename=para_style_name, text=version)
|
||||
cell_version.addElement(p)
|
||||
row.addElement(cell_version)
|
||||
|
||||
Reference in New Issue
Block a user