Fix package structure and lazy-import ODT formatter
Add missing __init__.py to formatters/ so setuptools.find_packages includes the subpackage in wheel/sdist builds (#16). Move ODTFormatter import from top-level to lazy import inside get_formatter_by_extension() so missing odfpy no longer crashes module load before main() runs. Remove dead except ImportError handler in cli.py save() block; surface a clear 'odfpy is not installed' message when the formatter factory returns None for .odt (#25). Closes #16, closes #25
This commit is contained in:
@@ -107,25 +107,23 @@ def main(argv: Optional[List[str]] = None) -> int:
|
||||
)
|
||||
|
||||
if not formatter:
|
||||
known_exts = ", ".join([".odt", ".csv", ".md", ".html"])
|
||||
print(
|
||||
f"❌ Неизвестный формат файла: {output_ext!r}. Поддерживаются: {known_exts}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
try:
|
||||
formatter.save(rows, args.output)
|
||||
print(f"✅ Report saved to {args.output}")
|
||||
except ImportError as e:
|
||||
if output_ext == ".odt":
|
||||
print(
|
||||
"❌ odfpy is not installed. Install with: pip install odfpy",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(f"❌ Import error: {e}", file=sys.stderr)
|
||||
known_exts = ", ".join([".odt", ".csv", ".md", ".html"])
|
||||
print(
|
||||
f"❌ Неизвестный формат файла: {output_ext!r}. "
|
||||
f"Поддерживаются: {known_exts}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
try:
|
||||
formatter.save(rows, args.output)
|
||||
print(f"✅ Report saved to {args.output}")
|
||||
except Exception as e:
|
||||
fmt = output_ext.lstrip(".").upper()
|
||||
print(f"❌ {fmt} export error: {e}", file=sys.stderr)
|
||||
|
||||
0
redmine_reporter/formatters/__init__.py
Normal file
0
redmine_reporter/formatters/__init__.py
Normal file
@@ -5,11 +5,11 @@ from .console import CompactFormatter, TableFormatter
|
||||
from .csv import CSVFormatter
|
||||
from .html import HTMLFormatter
|
||||
from .markdown import MarkdownFormatter
|
||||
from .odt import ODTFormatter
|
||||
|
||||
# Словарь для сопоставления расширений файлов с классами форматтеров
|
||||
# Словарь для сопоставления расширений файлов с классами форматтеров.
|
||||
# ODT намеренно отсутствует — его импорт отложен (ленивый), так как odfpy
|
||||
# может быть не установлен. См. get_formatter_by_extension.
|
||||
FORMATTER_MAP: Dict[str, Type[Formatter]] = {
|
||||
".odt": ODTFormatter,
|
||||
".csv": CSVFormatter,
|
||||
".md": MarkdownFormatter,
|
||||
".html": HTMLFormatter,
|
||||
@@ -27,10 +27,23 @@ def get_formatter_by_extension(extension: str, **kwargs) -> Optional[Formatter]:
|
||||
"""
|
||||
Возвращает экземпляр форматтера по расширению файла.
|
||||
Ключевые аргументы (**kwargs) передаются в конструктор форматтера.
|
||||
Возвращает None для .odt, если odfpy не установлен.
|
||||
"""
|
||||
formatter_class = FORMATTER_MAP.get(extension.lower())
|
||||
ext = extension.lower()
|
||||
|
||||
formatter_class = FORMATTER_MAP.get(ext)
|
||||
if formatter_class:
|
||||
return formatter_class(**kwargs)
|
||||
|
||||
# ODT требует odfpy — ленивый импорт, чтобы отсутствие зависимости
|
||||
# не ломало загрузку модуля и другие форматтеры.
|
||||
if ext == ".odt":
|
||||
try:
|
||||
from .odt import ODTFormatter
|
||||
except ImportError:
|
||||
return None
|
||||
return ODTFormatter(**kwargs)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user