[18.0][IMP] report_py3o: improve error observability in LO conversion chain#1166
[18.0][IMP] report_py3o: improve error observability in LO conversion chain#1166rrebollo wants to merge 2 commits into
Conversation
_convert_single_report: add try/except around subprocess.check_output, capture LO stdout+stderr, verify output file exists after conversion. Raise UserError instead of RuntimeError for user-facing failures. Controller: add logger.exception() before serializing error to JSON, so the real traceback appears in Odoo logs instead of being silently swallowed by except Exception. Follows OCA patterns from report_csv, report_xlsx, report_xml controllers for consistent error logging across the reporting-engine ecosystem.
test_convert_single_report_called_process_error: verify _convert_single_report raises UserError when subprocess.check_output raises CalledProcessError. TestReportPy3oController.test_report_download_error_logging: verify controller logs the exception before serializing the error, using HttpCase + assertLogs pattern from report_csv. Fix existing test_py3o_report_availability: RuntimeError -> UserError to match the change in _convert_single_report_cmd. Fix indentation in test_report_template_configs: _render call was incorrectly de-indented outside the with temporary_copy block, causing TemplateNotFound.
fsmw
left a comment
There was a problem hiding this comment.
Thanks @rrebollo for the reciprocal review opportunity — happy to return the favor on #1165.
Solid PR. Confirmed the controller pattern matches report_csv (line 107) and report_xlsx (line 101) exactly: logger.exception before serialize_exception. Good catch on the missing os.path.exists check — that's the real root cause of the silent LO exit-0-with-no-output chain (we hit a similar issue once with HTML content in templates).
The RuntimeError → UserError change is also correct and the existing test_py3o_report_availability already covers that path at line 264.
CI all green (pre-commit, Odoo, OCB, codecov, runboat), tests are appropriately focused (TransactionCase for the model path, HttpCase + assertLogs for the controller), and the localized error messages + stderr context in logger.error are exactly what admins need for postmortem.
Approved ✅
Problem
When LibreOffice fails to convert a rendered ODT to the target format,
FileNotFoundErrorpropagates unhandled, the controller catches it without logging, and debugging is impossible.Actual production traceback (anonymized):
The
FileNotFoundErroris not the root cause — it is the last symptom of a silent failure chain:--headless --convert-to→ exit code 0 → but silently produces no output file (e.g. because the rendered ODT contains HTML content LO cannot handle)_convert_single_reporthas zero error handling —subprocess.check_outputsucceeds, code computes the expected output path, never verifies the file existscreate_reporttriesopen(result_path, "r+b")→FileNotFoundErrorpropagatesexcept Exceptiondoes not log — the entire traceback is silently swallowed, returned as JSON to the browser, and lost on page refreshFix
Two minimal changes following OCA patterns already used by sibling addons (
report_csv,report_xlsx,report_xml):py3o_report.py— Model-level error handling:subprocess.check_output(..., stderr=subprocess.STDOUT)try/except FileNotFoundError→UserErrortry/except CalledProcessError→logger.error(details)+UserErroros.path.exists(result_path)→logger.error(stderr)+UserErrorif missing_convert_single_report_cmd:RuntimeError→UserErrorcontrollers/main.py— Controller-level logging (one line):logger.exception("Error while generating py3o report: %s", reportname)beforeserialize_exceptionreport_csv,report_xlsx,report_xmlcontrollers exactlyTesting
Two new tests added:
test_convert_single_report_called_process_errorTransactionCase+mock.patch("subprocess.check_output")_convert_single_reportraisesUserErroron LO failureTestReportPy3oController.test_report_download_error_loggingHttpCase+mock.patch.object(ReportController, "report_routes")+assertLogs@BinhexTeam T18747