{"record":{"id":"39822a7ce623e26c","repo":"ocrmypdf/OCRmyPDF","slug":"this-ocrengine-does-not-implement-generate-ocr","errorCode":null,"errorMessage":"This OcrEngine does not implement generate_ocr()","messagePattern":"This OcrEngine does not implement generate_ocr\\(\\)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"info","filePath":"src/ocrmypdf/pluginspec.py","lineNumber":544,"sourceCode":"        This function executes in a worker thread or worker process. OCRmyPDF\n        automatically parallelizes OCR over pages. The OCR engine should not\n        introduce more parallelism.\n\n        Args:\n            input_file: A page image on which to perform OCR.\n            options: The command line options.\n            page_number: Zero-indexed page number (for multi-page context).\n\n        Returns:\n            A tuple of (OcrElement tree for the page, plain text content).\n            The OcrElement should have ocr_class=OcrClass.PAGE as its root.\n\n        Note:\n            This method is optional. Engines that don't implement it should\n            leave the default implementation, and the pipeline will fall back to\n            generate_hocr() or generate_pdf().\n        \"\"\"\n        raise NotImplementedError(\"This OcrEngine does not implement generate_ocr()\")\n\n\n@hookspec(firstresult=True)\ndef get_ocr_engine(options: OcrOptions | None) -> OcrEngine:  # type: ignore[return-value]\n    \"\"\"Returns an OcrEngine to use for processing this file.\n\n    The OcrEngine may be instantiated multiple times, by both the main process\n    and child process.\n\n    When multiple OCR engine plugins are installed, plugins should check\n    ``options.ocr_engine`` and return ``None`` if they are not the selected\n    engine. The hook caller will then try the next plugin.\n\n    Args:\n        options: The current OcrOptions, used to determine which engine\n            to select. May be None for backward compatibility with external\n            plugins.\n","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/ocrmypdf/OCRmyPDF/blob/5074a0b0e109362422b768fd271ed84bf717c4ec/src/ocrmypdf/pluginspec.py#L526-L562","documentation":"OcrEngine.generate_ocr() is optional; the base class raises NotImplementedError by design. The pipeline is expected to call generate_hocr() or generate_pdf() instead when an engine does not implement the direct OCR text path.","triggerScenarios":"Calling engine.generate_ocr() on an engine subclass that only implements generate_hocr() or generate_pdf(), or a plugin engine that hasn't overridden the optional method.","commonSituations":"Custom OCR engine plugin authors testing their engine directly; code that assumes all engines support the direct-text API.","solutions":["Implement generate_ocr() in your OcrEngine subclass if you want the direct path","Otherwise call/let the pipeline fall back to generate_hocr() or generate_pdf()","Guard with hasattr or try NotImplementedError before calling directly"],"exampleFix":"// before\ntext = engine.generate_ocr(image, options)\n// after\ntext = engine.generate_ocr(image, options) if hasattr(type(engine), 'generate_ocr') and OcrEngine.generate_ocr is not type(engine).generate_ocr else engine.generate_hocr(image, options)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def supports_generate_ocr(engine: OcrEngine) -> bool:\\n    return type(engine).generate_ocr is not OcrEngine.generate_ocr","tryCatchPattern":"try:\\n    result = engine.generate_ocr(image, options)\\nexcept NotImplementedError:\\n    result = engine.generate_hocr(image, options)","preventionTips":["Check which optional methods an engine implements before calling","Let the pipeline choose the code path instead of calling engines directly","Document which of generate_ocr/generate_hocr/generate_pdf your plugin implements"],"tags":["plugin-api","ocr-engine","not-implemented","extension-point"],"backgroundTag":"optional-interface-method-not-implemented","analyzedSha":"5074a0b0e109362422b768fd271ed84bf717c4ec","analyzedAt":"2026-08-27T11:57:38.523Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}