List open Redmine issues assigned to the current (or overridden) user, sorted by priority rank (P1..P5) then version due date with a stable id tie-break. Renders an OSC 8 hyperlinked console table on stdout and a counts/hours summary line on stderr; version due dates are fetched once per unique version, unavailable versions degrade to an empty due date. Also migrates the codebase to ruff 0.17.3 defaults (PEP 585/604 annotations, targeted noqa for intentional blind excepts and CLI root logging). Behavior-neutral: 408 tests pass with -W error.
33 lines
1.4 KiB
Python
33 lines
1.4 KiB
Python
from abc import ABC, abstractmethod
|
|
from typing import Any
|
|
|
|
from ..types import ReportRow
|
|
|
|
|
|
class Formatter(ABC):
|
|
"""
|
|
Абстрактный базовый класс для всех форматтеров.
|
|
Определяет общий интерфейс для форматирования отчета.
|
|
|
|
Контракт:
|
|
- format() возвращает строку для текстовых форматтеров (CSV, HTML, Markdown, console)
|
|
и объект OpenDocument для ODTFormatter.
|
|
- save() сохраняет результат в файл; консольные форматтеры бросают NotImplementedError.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def format(self, rows: list[ReportRow]) -> Any:
|
|
"""
|
|
Форматирует список строк отчета в нужный формат.
|
|
Для текстовых форматтеров возвращает str.
|
|
Для ODTFormatter возвращает объект OpenDocument.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def save(self, rows: list[ReportRow], output_path: str) -> None:
|
|
"""
|
|
Сохраняет отформатированный отчет в файл по указанному пути.
|
|
Для форматтеров, которые не поддерживают сохранение (например, консольные),
|
|
бросает NotImplementedError.
|
|
"""
|