markitdown-pro 2.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/.github/workflows/test.yml +4 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/.gitignore +1 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/PKG-INFO +1 -1
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/conversion_pipeline.py +21 -2
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/gotenberg_converter.py +40 -11
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/office_handler.py +32 -1
- markitdown_pro-2.1.0/tests/data/powerpoint-legacy/geometry-colors.ppt +0 -0
- markitdown_pro-2.1.0/tests/data/powerpoint-legacy/lorem-ipsum-only-text.ppt +0 -0
- markitdown_pro-2.1.0/tests/data/powerpoint-legacy/lorem-ipsum-scanned-text.ppt +0 -0
- markitdown_pro-2.1.0/tests/data/powerpoint-legacy/lorem-ipsum-text-with-image.ppt +0 -0
- markitdown_pro-2.1.0/tests/data/powerpoint-legacy/lorem-ipsum-text-with-scanned-text.ppt +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/test_expectations.yaml +56 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/geometry-colors.doc +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/geometry-colors.odt +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/geometry-colors.rtf +2197 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-only-text.doc +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-only-text.odt +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-only-text.rtf +258 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-scanned-text.doc +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-scanned-text.odt +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-scanned-text.rtf +18373 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-text-with-image.doc +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-text-with-image.odt +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-text-with-image.rtf +2204 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.doc +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.odt +0 -0
- markitdown_pro-2.1.0/tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.rtf +7208 -0
- markitdown_pro-2.1.0/tests/integration/test_legacy_office_formats.py +108 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_conversion_pipeline.py +74 -2
- markitdown_pro-2.1.0/tests/unit/test_gotenberg_converter.py +69 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_office_handler.py +62 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/uv.lock +0 -1
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/.github/workflows/lint.yaml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/.github/workflows/publish.yaml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/.vscode/settings.json +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/README.md +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/common/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/common/config.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/common/isolated_worker.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/common/logger.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/common/schemas.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/common/utils.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/base.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/doc_intel_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/gpt_vision_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/markitdown_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/pymupdf_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/speech_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/tabular_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/unstructured_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/youtube_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/audio_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/base_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/email_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/epub_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/image_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/ipynb_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/markup_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/page_pdf_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/pdf_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/pst_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/tabular_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/handlers/text_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/services/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/services/azure_doc_intelligence.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/services/azure_speech.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/services/openai_services.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/pyproject.toml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/common/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/common/test_config.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/conftest.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/conversion_pipeline/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/conversion_pipeline/test_conversion_pipeline.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_azure_doc_intel_wrapper.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_azure_speech_wrapper.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_doc_intel_lifecycle.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_gpt_vision_config.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_gpt_vision_wrapper.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_pymupdf_wrapper.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_pymupdf_wrapper_async.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/converters/test_unstructured_io_wrapper.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_cn.wav +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_en.mp3 +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_en.wav +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_es.mp3 +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_es.wav +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_it.wav +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_jp.mp3 +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/audio/the-power-of-small-steps_jp.wav +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/eml/email-with-image.eml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/eml/mime-different-plain-html.eml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/epub/sample1.epub +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/images/flower.jpg +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/images/geometry_colors.bmp +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/images/handwriting.jpg +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/images/scanned_text.heic +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/images/scanned_text.png +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/images/text_with_image.jpg +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/markup/blog.html +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/markup/factbook.xml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/markup/simple.json +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/markup/simple.yaml +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/msg/fake-email-multiple-attachments.msg +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/msg/fake-email.msg +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/pdf/geometry-colors.pdf +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/pdf/lorem-ipsum-only-images.pdf +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/pdf/lorem-ipsum-only-text.pdf +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/pdf/lorem-ipsum-scanned-text.pdf +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/pdf/lorem-ipsum-text-with-image.pdf +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/powerpoint/geometry-colors.pptx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/powerpoint/lorem-ipsum-only-text.pptx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/powerpoint/lorem-ipsum-scanned-text.pptx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/powerpoint/lorem-ipsum-text-with-image.pptx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/powerpoint/lorem-ipsum-text-with-scanned-text.pptx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/tabular/2023-half-year-analyses-by-segment.xlsx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/tabular/stanley-cups.csv +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/tabular/stanley-cups.tsv +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/tabular/stanley-cups.xlsx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/text/book-war-and-peace-1p.txt +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/text/fake-email.txt +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/text/logger.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/word/geometry-colors.docx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/word/lorem-ipsum-only-text.docx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/word/lorem-ipsum-scanned-text.docx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/word/lorem-ipsum-text-with-image.docx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/data/word/lorem-ipsum-text-with-scanned-text.docx +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/fixtures.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_email_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_epub_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_image_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_ipynb_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_markitdown_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_markitdown_validation.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_markup_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_page_pdf_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_pdf_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_pst_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_tabular_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/handlers/test_text_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/cheat_sheet.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/runner.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_audio_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_doc_intelligence_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_email_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_gotenberg_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_gpt_vision_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_markitdown_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_markup_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_pdf_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_pymupdf_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_tabular_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/integration/test_text_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/page_count/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/page_count/test_pdf_page_count.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/__init__.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_audio_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_base_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_doc_intel_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_gpt_vision_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_image_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_markitdown_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_page_pdf_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_pdf_handler.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_pymupdf_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/unit/test_speech_converter.py +0 -0
- {markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/tests/utils.py +0 -0
|
@@ -152,21 +152,40 @@ class ConversionPipeline:
|
|
|
152
152
|
".pdf": self.pdf_handler,
|
|
153
153
|
".xls": self.tabular_handler,
|
|
154
154
|
".xlsx": self.tabular_handler,
|
|
155
|
-
".docx": self.office_handler,
|
|
156
|
-
".pptx": self.office_handler,
|
|
157
155
|
},
|
|
158
156
|
}
|
|
159
157
|
|
|
158
|
+
# Register Office extensions dynamically — the handler decides which
|
|
159
|
+
# legacy formats it supports based on Gotenberg availability. This
|
|
160
|
+
# keeps ``handlers_mapping`` (what consumers read) truthful at runtime.
|
|
161
|
+
for ext in self.office_handler.supported_extensions:
|
|
162
|
+
self.handlers_categories[ExtensionCategory.FORMATTED_DOCS][ext] = self.office_handler
|
|
163
|
+
|
|
160
164
|
# Normalize map of extensions to handlers
|
|
161
165
|
self.handlers_mapping: dict[str, BaseHandler] = {}
|
|
162
166
|
for handlers in self.handlers_categories.values():
|
|
163
167
|
for ext, handler in handlers.items():
|
|
164
168
|
self.handlers_mapping[ext] = handler
|
|
165
169
|
|
|
170
|
+
# Cache the read-only view so consumers get a stable object (and we
|
|
171
|
+
# don't rebuild the frozenset on every ``.supported_extensions`` access).
|
|
172
|
+
# ``handlers_mapping`` is read-only by convention.
|
|
173
|
+
self._supported_extensions: frozenset[str] = frozenset(self.handlers_mapping)
|
|
174
|
+
|
|
166
175
|
# ---------------------------------------------------------------------
|
|
167
176
|
# Public APIs
|
|
168
177
|
# ---------------------------------------------------------------------
|
|
169
178
|
|
|
179
|
+
@property
|
|
180
|
+
def supported_extensions(self) -> frozenset[str]:
|
|
181
|
+
"""Canonical set of extensions this pipeline can route.
|
|
182
|
+
|
|
183
|
+
This is the source of truth for consumers advertising supported
|
|
184
|
+
formats (e.g., a ``/extensions`` endpoint). ``handlers_mapping`` is
|
|
185
|
+
the routing table; ``supported_extensions`` is its read-only view.
|
|
186
|
+
"""
|
|
187
|
+
return self._supported_extensions
|
|
188
|
+
|
|
170
189
|
async def convert_document_to_md(
|
|
171
190
|
self,
|
|
172
191
|
file_path: str | Path,
|
{markitdown_pro-2.0.0 → markitdown_pro-2.1.0}/markitdown_pro/converters/gotenberg_converter.py
RENAMED
|
@@ -5,11 +5,14 @@ Gotenberg (https://gotenberg.dev) is a Docker-based API that wraps LibreOffice
|
|
|
5
5
|
for document-to-PDF conversion. It handles concurrency internally and scales
|
|
6
6
|
horizontally via container replicas.
|
|
7
7
|
|
|
8
|
-
Configure via environment variable
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
Configure via the ``GOTENBERG_URL`` environment variable or pass
|
|
9
|
+
``gotenberg_url=...`` explicitly. If neither is provided, the converter is
|
|
10
|
+
disabled and ``convert()`` returns ``None`` without any network I/O — this lets
|
|
11
|
+
downstream consumers advertise supported formats accurately.
|
|
12
|
+
|
|
13
|
+
If the Gotenberg service is configured but unreachable at call time,
|
|
14
|
+
``convert()`` returns ``None`` and the caller should fall through to the next
|
|
15
|
+
converter.
|
|
13
16
|
"""
|
|
14
17
|
|
|
15
18
|
import contextlib
|
|
@@ -23,7 +26,6 @@ from ..common.logger import logger
|
|
|
23
26
|
from .base import Converter
|
|
24
27
|
|
|
25
28
|
_COMPONENT = "GotenbergConverter"
|
|
26
|
-
_DEFAULT_URL = "http://gotenberg:3000"
|
|
27
29
|
_CONVERT_ENDPOINT = "/forms/libreoffice/convert"
|
|
28
30
|
|
|
29
31
|
|
|
@@ -36,21 +38,48 @@ class GotenbergConverter(Converter):
|
|
|
36
38
|
DocIntelligence can extract from Office files directly.
|
|
37
39
|
|
|
38
40
|
Requires a running Gotenberg instance. Gracefully returns None if
|
|
39
|
-
the service is unavailable
|
|
41
|
+
the service is unavailable or if the converter is disabled, allowing
|
|
42
|
+
fallback to other converters.
|
|
40
43
|
"""
|
|
41
44
|
|
|
42
45
|
SUPPORTED_EXTENSIONS = frozenset({".docx", ".pptx", ".doc", ".ppt", ".odt", ".rtf"})
|
|
43
46
|
|
|
44
47
|
def __init__(self, gotenberg_url: str | None = None) -> None:
|
|
45
48
|
super().__init__(_COMPONENT)
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
# gotenberg_url is the single source of truth; ``enabled`` derives from it.
|
|
50
|
+
# Treat empty/whitespace values as unconfigured to catch a common
|
|
51
|
+
# ``docker-compose`` misconfiguration (``environment: GOTENBERG_URL=``).
|
|
52
|
+
raw = (gotenberg_url if gotenberg_url is not None else os.getenv("GOTENBERG_URL")) or ""
|
|
53
|
+
self.gotenberg_url: str | None = raw.strip() or None
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def enabled(self) -> bool:
|
|
57
|
+
return bool(self.gotenberg_url)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def _convert_url(self) -> str:
|
|
61
|
+
"""The fully-qualified Gotenberg endpoint URL.
|
|
62
|
+
|
|
63
|
+
Only safe to access when ``self.enabled`` is True. Callers in this
|
|
64
|
+
class are already guarded by the ``if not self.enabled`` short-circuit
|
|
65
|
+
in ``convert()``; raising here makes the invariant explicit instead
|
|
66
|
+
of letting a ``None`` propagate into ``httpx`` or the format string.
|
|
67
|
+
"""
|
|
68
|
+
if not self.gotenberg_url:
|
|
69
|
+
raise RuntimeError(
|
|
70
|
+
"GotenbergConverter is not configured (set GOTENBERG_URL "
|
|
71
|
+
"or pass gotenberg_url=...). Check ``enabled`` before calling."
|
|
72
|
+
)
|
|
73
|
+
return f"{self.gotenberg_url.rstrip('/')}{_CONVERT_ENDPOINT}"
|
|
48
74
|
|
|
49
75
|
async def convert(self, file_path: str) -> str | None:
|
|
76
|
+
if not self.enabled:
|
|
77
|
+
return None
|
|
78
|
+
|
|
50
79
|
file_name = Path(file_path).name
|
|
51
80
|
tag = f"{_COMPONENT} | {file_name}"
|
|
52
81
|
|
|
53
|
-
logger.info(f"{tag} | converting to PDF via Gotenberg ({self.
|
|
82
|
+
logger.info(f"{tag} | converting to PDF via Gotenberg ({self.gotenberg_url})")
|
|
54
83
|
|
|
55
84
|
pdf_bytes = await self._convert_to_pdf(file_path, tag)
|
|
56
85
|
if not pdf_bytes:
|
|
@@ -108,7 +137,7 @@ class GotenbergConverter(Converter):
|
|
|
108
137
|
return None
|
|
109
138
|
|
|
110
139
|
except httpx.ConnectError:
|
|
111
|
-
logger.info(f"{tag} | Gotenberg not reachable at {self.
|
|
140
|
+
logger.info(f"{tag} | Gotenberg not reachable at {self.gotenberg_url}, skipping")
|
|
112
141
|
return None
|
|
113
142
|
except httpx.TimeoutException:
|
|
114
143
|
logger.warning(f"{tag} | Gotenberg timed out after 120s")
|
|
@@ -38,11 +38,22 @@ class OfficeHandler(BaseHandler):
|
|
|
38
38
|
the pipeline order when initializing the handler.
|
|
39
39
|
|
|
40
40
|
Supported formats: .docx, .pptx (modern Office XML formats).
|
|
41
|
-
|
|
41
|
+
Legacy binary formats (.doc, .ppt, .odt, .rtf) are supported at runtime
|
|
42
|
+
only when the configured pipeline contains an enabled ``GotenbergConverter``.
|
|
43
|
+
Callers should inspect the instance attribute ``supported_extensions`` (not
|
|
44
|
+
the class constant) to learn which formats this handler will actually
|
|
45
|
+
process.
|
|
42
46
|
"""
|
|
43
47
|
|
|
48
|
+
# Class constant stays narrow (the always-supported modern formats) so that
|
|
49
|
+
# ``BaseHandler.is_valid`` and any class-level introspection never falsely
|
|
50
|
+
# advertise legacy formats that would fail without Gotenberg. Dynamic
|
|
51
|
+
# runtime capability lives on the instance attribute ``supported_extensions``
|
|
52
|
+
# set in ``__init__``.
|
|
44
53
|
SUPPORTED_EXTENSIONS = frozenset({".docx", ".pptx"})
|
|
45
54
|
|
|
55
|
+
_GOTENBERG_ONLY_EXTS = frozenset({".doc", ".ppt", ".odt", ".rtf"})
|
|
56
|
+
|
|
46
57
|
def __init__(
|
|
47
58
|
self,
|
|
48
59
|
pipeline: list[tuple[Converter, str]] | None = None,
|
|
@@ -62,6 +73,26 @@ class OfficeHandler(BaseHandler):
|
|
|
62
73
|
(self.markitdown, "MarkItDown"),
|
|
63
74
|
]
|
|
64
75
|
|
|
76
|
+
# isinstance catches subclasses/proxies users might pass in custom
|
|
77
|
+
# pipelines. We explicitly check that the imported ``GotenbergConverter``
|
|
78
|
+
# is still a real class before using it as an isinstance second arg —
|
|
79
|
+
# if tests patch the name to a MagicMock *instance* (not a class),
|
|
80
|
+
# we fall back to ``gotenberg_enabled = False`` instead of wrapping
|
|
81
|
+
# the whole generator in try/except TypeError, which would otherwise
|
|
82
|
+
# silently swallow a real bug inside an ``enabled`` property.
|
|
83
|
+
if isinstance(GotenbergConverter, type):
|
|
84
|
+
gotenberg_enabled = any(
|
|
85
|
+
isinstance(c, GotenbergConverter) and getattr(c, "enabled", False)
|
|
86
|
+
for c, _ in self._pipeline
|
|
87
|
+
)
|
|
88
|
+
else:
|
|
89
|
+
gotenberg_enabled = False
|
|
90
|
+
self.supported_extensions: frozenset[str] = (
|
|
91
|
+
self.SUPPORTED_EXTENSIONS | self._GOTENBERG_ONLY_EXTS
|
|
92
|
+
if gotenberg_enabled
|
|
93
|
+
else self.SUPPORTED_EXTENSIONS
|
|
94
|
+
)
|
|
95
|
+
|
|
65
96
|
async def handle(self, file_path: str, *args, **kwargs) -> str | None:
|
|
66
97
|
"""
|
|
67
98
|
Convert an Office document to Markdown by trying the configured pipeline in order.
|
|
Binary file
|
|
Binary file
|
|
@@ -74,6 +74,62 @@ gotenberg_converter:
|
|
|
74
74
|
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
# =============================================================================
|
|
78
|
+
# LEGACY OFFICE FORMATS — Gotenberg-gated (.doc / .ppt / .odt / .rtf)
|
|
79
|
+
# Same fixtures as above re-saved / pandoc-converted into legacy formats.
|
|
80
|
+
# Routed through OfficeHandler → Gotenberg → PDF → PDFHandler per-page OCR.
|
|
81
|
+
# Only available iff GOTENBERG_URL is configured on the pipeline.
|
|
82
|
+
# =============================================================================
|
|
83
|
+
legacy_office_formats:
|
|
84
|
+
# .doc (re-saved from .docx via Word)
|
|
85
|
+
- file: tests/data/word-legacy/lorem-ipsum-only-text.doc
|
|
86
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
87
|
+
- file: tests/data/word-legacy/lorem-ipsum-text-with-image.doc
|
|
88
|
+
expect: ["what is lorem ipsum?", "red", "green", "blue"]
|
|
89
|
+
- file: tests/data/word-legacy/geometry-colors.doc
|
|
90
|
+
expect: ["red", "green", "blue"]
|
|
91
|
+
- file: tests/data/word-legacy/lorem-ipsum-scanned-text.doc
|
|
92
|
+
expect: ["what is lorem ipsum?", "why do we use it?"]
|
|
93
|
+
- file: tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.doc
|
|
94
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
95
|
+
|
|
96
|
+
# .ppt (re-saved from .pptx via PowerPoint)
|
|
97
|
+
- file: tests/data/powerpoint-legacy/lorem-ipsum-only-text.ppt
|
|
98
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
99
|
+
- file: tests/data/powerpoint-legacy/lorem-ipsum-text-with-image.ppt
|
|
100
|
+
expect: ["what is lorem ipsum", "red", "green", "blue"]
|
|
101
|
+
- file: tests/data/powerpoint-legacy/geometry-colors.ppt
|
|
102
|
+
expect: ["red", "green", "blue"]
|
|
103
|
+
- file: tests/data/powerpoint-legacy/lorem-ipsum-scanned-text.ppt
|
|
104
|
+
expect: ["what is lorem ipsum", "why do we use it"]
|
|
105
|
+
- file: tests/data/powerpoint-legacy/lorem-ipsum-text-with-scanned-text.ppt
|
|
106
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
107
|
+
|
|
108
|
+
# .odt (re-saved from .docx via Word)
|
|
109
|
+
- file: tests/data/word-legacy/lorem-ipsum-only-text.odt
|
|
110
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
111
|
+
- file: tests/data/word-legacy/lorem-ipsum-text-with-image.odt
|
|
112
|
+
expect: ["what is lorem ipsum?", "red", "green", "blue"]
|
|
113
|
+
- file: tests/data/word-legacy/geometry-colors.odt
|
|
114
|
+
expect: ["red", "green", "blue"]
|
|
115
|
+
- file: tests/data/word-legacy/lorem-ipsum-scanned-text.odt
|
|
116
|
+
expect: ["what is lorem ipsum?", "why do we use it?"]
|
|
117
|
+
- file: tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.odt
|
|
118
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
119
|
+
|
|
120
|
+
# .rtf (re-saved from .docx via Word)
|
|
121
|
+
- file: tests/data/word-legacy/lorem-ipsum-only-text.rtf
|
|
122
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
123
|
+
- file: tests/data/word-legacy/lorem-ipsum-text-with-image.rtf
|
|
124
|
+
expect: ["what is lorem ipsum?", "red", "green", "blue"]
|
|
125
|
+
- file: tests/data/word-legacy/geometry-colors.rtf
|
|
126
|
+
expect: ["red", "green", "blue"]
|
|
127
|
+
- file: tests/data/word-legacy/lorem-ipsum-scanned-text.rtf
|
|
128
|
+
expect: ["what is lorem ipsum?", "why do we use it?"]
|
|
129
|
+
- file: tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.rtf
|
|
130
|
+
expect: ["what is lorem ipsum?", "where does it come from"]
|
|
131
|
+
|
|
132
|
+
|
|
77
133
|
# =============================================================================
|
|
78
134
|
# MARKITDOWN CONVERTER — text extraction only, NO OCR, NO image content
|
|
79
135
|
# =============================================================================
|
|
Binary file
|
|
Binary file
|