markitdown-pro 2.1.0__tar.gz → 2.1.1__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.
Files changed (173) hide show
  1. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/.github/workflows/test.yml +1 -7
  2. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/.gitignore +1 -0
  3. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/PKG-INFO +1 -1
  4. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/gotenberg_converter.py +59 -6
  5. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/gpt_vision_converter.py +3 -0
  6. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/page_pdf_converter.py +1 -0
  7. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/services/openai_services.py +10 -2
  8. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/.github/workflows/lint.yaml +0 -0
  9. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/.github/workflows/publish.yaml +0 -0
  10. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/.vscode/settings.json +0 -0
  11. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/README.md +0 -0
  12. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/__init__.py +0 -0
  13. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/__init__.py +0 -0
  14. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/common/__init__.py +0 -0
  15. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/common/config.py +0 -0
  16. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/common/isolated_worker.py +0 -0
  17. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/common/logger.py +0 -0
  18. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/common/schemas.py +0 -0
  19. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/common/utils.py +0 -0
  20. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/conversion_pipeline.py +0 -0
  21. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/__init__.py +0 -0
  22. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/base.py +0 -0
  23. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/doc_intel_converter.py +0 -0
  24. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/markitdown_converter.py +0 -0
  25. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/pymupdf_converter.py +0 -0
  26. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/speech_converter.py +0 -0
  27. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/tabular_converter.py +0 -0
  28. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/unstructured_converter.py +0 -0
  29. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/converters/youtube_converter.py +0 -0
  30. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/__init__.py +0 -0
  31. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/audio_handler.py +0 -0
  32. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/base_handler.py +0 -0
  33. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/email_handler.py +0 -0
  34. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/epub_handler.py +0 -0
  35. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/image_handler.py +0 -0
  36. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/ipynb_handler.py +0 -0
  37. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/markup_handler.py +0 -0
  38. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/office_handler.py +0 -0
  39. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/pdf_handler.py +0 -0
  40. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/pst_handler.py +0 -0
  41. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/tabular_handler.py +0 -0
  42. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/handlers/text_handler.py +0 -0
  43. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/services/__init__.py +0 -0
  44. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/services/azure_doc_intelligence.py +0 -0
  45. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/markitdown_pro/services/azure_speech.py +0 -0
  46. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/pyproject.toml +0 -0
  47. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/__init__.py +0 -0
  48. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/common/__init__.py +0 -0
  49. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/common/test_config.py +0 -0
  50. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/conftest.py +0 -0
  51. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/conversion_pipeline/__init__.py +0 -0
  52. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/conversion_pipeline/test_conversion_pipeline.py +0 -0
  53. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_azure_doc_intel_wrapper.py +0 -0
  54. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_azure_speech_wrapper.py +0 -0
  55. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_doc_intel_lifecycle.py +0 -0
  56. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_gpt_vision_config.py +0 -0
  57. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_gpt_vision_wrapper.py +0 -0
  58. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_pymupdf_wrapper.py +0 -0
  59. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_pymupdf_wrapper_async.py +0 -0
  60. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/converters/test_unstructured_io_wrapper.py +0 -0
  61. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_cn.wav +0 -0
  62. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_en.mp3 +0 -0
  63. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_en.wav +0 -0
  64. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_es.mp3 +0 -0
  65. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_es.wav +0 -0
  66. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_it.wav +0 -0
  67. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_jp.mp3 +0 -0
  68. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/audio/the-power-of-small-steps_jp.wav +0 -0
  69. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/eml/email-with-image.eml +0 -0
  70. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/eml/mime-different-plain-html.eml +0 -0
  71. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/epub/sample1.epub +0 -0
  72. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/images/flower.jpg +0 -0
  73. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/images/geometry_colors.bmp +0 -0
  74. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/images/handwriting.jpg +0 -0
  75. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/images/scanned_text.heic +0 -0
  76. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/images/scanned_text.png +0 -0
  77. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/images/text_with_image.jpg +0 -0
  78. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/markup/blog.html +0 -0
  79. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/markup/factbook.xml +0 -0
  80. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/markup/simple.json +0 -0
  81. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/markup/simple.yaml +0 -0
  82. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/msg/fake-email-multiple-attachments.msg +0 -0
  83. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/msg/fake-email.msg +0 -0
  84. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/pdf/geometry-colors.pdf +0 -0
  85. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/pdf/lorem-ipsum-only-images.pdf +0 -0
  86. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/pdf/lorem-ipsum-only-text.pdf +0 -0
  87. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/pdf/lorem-ipsum-scanned-text.pdf +0 -0
  88. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/pdf/lorem-ipsum-text-with-image.pdf +0 -0
  89. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint/geometry-colors.pptx +0 -0
  90. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint/lorem-ipsum-only-text.pptx +0 -0
  91. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint/lorem-ipsum-scanned-text.pptx +0 -0
  92. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint/lorem-ipsum-text-with-image.pptx +0 -0
  93. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint/lorem-ipsum-text-with-scanned-text.pptx +0 -0
  94. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint-legacy/geometry-colors.ppt +0 -0
  95. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint-legacy/lorem-ipsum-only-text.ppt +0 -0
  96. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint-legacy/lorem-ipsum-scanned-text.ppt +0 -0
  97. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint-legacy/lorem-ipsum-text-with-image.ppt +0 -0
  98. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/powerpoint-legacy/lorem-ipsum-text-with-scanned-text.ppt +0 -0
  99. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/tabular/2023-half-year-analyses-by-segment.xlsx +0 -0
  100. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/tabular/stanley-cups.csv +0 -0
  101. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/tabular/stanley-cups.tsv +0 -0
  102. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/tabular/stanley-cups.xlsx +0 -0
  103. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/test_expectations.yaml +0 -0
  104. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/text/book-war-and-peace-1p.txt +0 -0
  105. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/text/fake-email.txt +0 -0
  106. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/text/logger.py +0 -0
  107. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word/geometry-colors.docx +0 -0
  108. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word/lorem-ipsum-only-text.docx +0 -0
  109. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word/lorem-ipsum-scanned-text.docx +0 -0
  110. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word/lorem-ipsum-text-with-image.docx +0 -0
  111. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word/lorem-ipsum-text-with-scanned-text.docx +0 -0
  112. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/geometry-colors.doc +0 -0
  113. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/geometry-colors.odt +0 -0
  114. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/geometry-colors.rtf +0 -0
  115. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-only-text.doc +0 -0
  116. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-only-text.odt +0 -0
  117. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-only-text.rtf +0 -0
  118. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-scanned-text.doc +0 -0
  119. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-scanned-text.odt +0 -0
  120. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-scanned-text.rtf +0 -0
  121. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-text-with-image.doc +0 -0
  122. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-text-with-image.odt +0 -0
  123. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-text-with-image.rtf +0 -0
  124. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.doc +0 -0
  125. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.odt +0 -0
  126. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/data/word-legacy/lorem-ipsum-text-with-scanned-text.rtf +0 -0
  127. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/fixtures.py +0 -0
  128. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/__init__.py +0 -0
  129. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_email_handler.py +0 -0
  130. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_epub_handler.py +0 -0
  131. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_image_handler.py +0 -0
  132. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_ipynb_handler.py +0 -0
  133. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_markitdown_handler.py +0 -0
  134. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_markitdown_validation.py +0 -0
  135. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_markup_handler.py +0 -0
  136. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_page_pdf_converter.py +0 -0
  137. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_pdf_handler.py +0 -0
  138. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_pst_handler.py +0 -0
  139. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_tabular_handler.py +0 -0
  140. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/handlers/test_text_handler.py +0 -0
  141. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/__init__.py +0 -0
  142. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/cheat_sheet.py +0 -0
  143. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/runner.py +0 -0
  144. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_audio_handler.py +0 -0
  145. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_doc_intelligence_converter.py +0 -0
  146. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_email_handler.py +0 -0
  147. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_gotenberg_converter.py +0 -0
  148. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_gpt_vision_converter.py +0 -0
  149. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_legacy_office_formats.py +0 -0
  150. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_markitdown_converter.py +0 -0
  151. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_markup_handler.py +0 -0
  152. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_pdf_handler.py +0 -0
  153. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_pymupdf_converter.py +0 -0
  154. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_tabular_handler.py +0 -0
  155. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/integration/test_text_handler.py +0 -0
  156. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/page_count/__init__.py +0 -0
  157. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/page_count/test_pdf_page_count.py +0 -0
  158. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/__init__.py +0 -0
  159. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_audio_handler.py +0 -0
  160. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_base_converter.py +0 -0
  161. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_conversion_pipeline.py +0 -0
  162. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_doc_intel_converter.py +0 -0
  163. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_gotenberg_converter.py +0 -0
  164. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_gpt_vision_converter.py +0 -0
  165. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_image_handler.py +0 -0
  166. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_markitdown_converter.py +0 -0
  167. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_office_handler.py +0 -0
  168. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_page_pdf_converter.py +0 -0
  169. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_pdf_handler.py +0 -0
  170. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_pymupdf_converter.py +0 -0
  171. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/unit/test_speech_converter.py +0 -0
  172. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/tests/utils.py +0 -0
  173. {markitdown_pro-2.1.0 → markitdown_pro-2.1.1}/uv.lock +0 -0
@@ -1,13 +1,6 @@
1
1
  name: '🧪 Test package'
2
2
 
3
3
  on:
4
- push:
5
- branches:
6
- - main
7
- paths:
8
- - 'markitdown_pro/**'
9
- - 'tests/**'
10
- - 'pyproject.toml'
11
4
  pull_request:
12
5
  branches:
13
6
  - main
@@ -15,6 +8,7 @@ on:
15
8
  - 'markitdown_pro/**'
16
9
  - 'tests/**'
17
10
  - 'pyproject.toml'
11
+ workflow_dispatch:
18
12
 
19
13
  permissions:
20
14
  contents: read
@@ -25,3 +25,4 @@ docs/
25
25
  **/CONTINUITY.md
26
26
  **/CHANGELOG.md
27
27
  .mcp.json
28
+ .worktrees/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markitdown-pro
3
- Version: 2.1.0
3
+ Version: 2.1.1
4
4
  Summary: A package that converts almost any file format to Markdown.
5
5
  Author: Developer
6
6
  License-Expression: MIT
@@ -15,10 +15,14 @@ If the Gotenberg service is configured but unreachable at call time,
15
15
  converter.
16
16
  """
17
17
 
18
+ import asyncio
18
19
  import contextlib
20
+ import functools
19
21
  import os
20
22
  import tempfile
23
+ from collections.abc import Awaitable, Callable
21
24
  from pathlib import Path
25
+ from typing import TypeVar
22
26
 
23
27
  import httpx
24
28
 
@@ -28,6 +32,49 @@ from .base import Converter
28
32
  _COMPONENT = "GotenbergConverter"
29
33
  _CONVERT_ENDPOINT = "/forms/libreoffice/convert"
30
34
 
35
+ # Transient failures worth retrying. ConnectError is intentionally excluded —
36
+ # "service unreachable" is handled as a graceful skip, not a retry.
37
+ _RETRYABLE_EXC: tuple[type[BaseException], ...] = (
38
+ httpx.TimeoutException,
39
+ httpx.RemoteProtocolError,
40
+ httpx.ReadError,
41
+ httpx.WriteError,
42
+ )
43
+
44
+ T = TypeVar("T")
45
+
46
+
47
+ def _retry_transient(
48
+ attempts: int = 3, delays: tuple[float, ...] = (1.0, 3.0)
49
+ ) -> Callable[[Callable[..., Awaitable[T | None]]], Callable[..., Awaitable[T | None]]]:
50
+ """Retry an async method on transient httpx errors. Sleeps between attempts
51
+ are taken from ``delays`` (short, fixed backoff — enough to ride out a
52
+ worker restart or a brief connection hiccup)."""
53
+
54
+ def decorator(
55
+ fn: Callable[..., Awaitable[T | None]],
56
+ ) -> Callable[..., Awaitable[T | None]]:
57
+ @functools.wraps(fn)
58
+ async def wrapper(self, *args, **kwargs) -> T | None:
59
+ tag = args[1] if len(args) >= 2 else kwargs.get("tag", _COMPONENT)
60
+ for i in range(attempts):
61
+ try:
62
+ return await fn(self, *args, **kwargs)
63
+ except _RETRYABLE_EXC as e:
64
+ if i == attempts - 1:
65
+ raise
66
+ sleep_for = delays[min(i, len(delays) - 1)]
67
+ logger.warning(
68
+ f"{tag} | transient {type(e).__name__}: {e}; "
69
+ f"retry {i + 1}/{attempts - 1} in {sleep_for:.1f}s"
70
+ )
71
+ await asyncio.sleep(sleep_for)
72
+ return None
73
+
74
+ return wrapper
75
+
76
+ return decorator
77
+
31
78
 
32
79
  class GotenbergConverter(Converter):
33
80
  """
@@ -81,7 +128,11 @@ class GotenbergConverter(Converter):
81
128
 
82
129
  logger.info(f"{tag} | converting to PDF via Gotenberg ({self.gotenberg_url})")
83
130
 
84
- pdf_bytes = await self._convert_to_pdf(file_path, tag)
131
+ try:
132
+ pdf_bytes = await self._convert_to_pdf(file_path, tag)
133
+ except _RETRYABLE_EXC as e:
134
+ logger.error(f"{tag} | Gotenberg error after retries: {type(e).__name__}: {e}")
135
+ return None
85
136
  if not pdf_bytes:
86
137
  return None
87
138
 
@@ -114,6 +165,7 @@ class GotenbergConverter(Converter):
114
165
  with contextlib.suppress(Exception):
115
166
  os.unlink(tmp_pdf)
116
167
 
168
+ @_retry_transient(attempts=3, delays=(1.0, 3.0))
117
169
  async def _convert_to_pdf(self, file_path: str, tag: str) -> bytes | None:
118
170
  """Send file to Gotenberg and return PDF bytes."""
119
171
  try:
@@ -131,7 +183,7 @@ class GotenbergConverter(Converter):
131
183
  if response.status_code == 200:
132
184
  return response.content
133
185
 
134
- logger.warning(
186
+ logger.error(
135
187
  f"{tag} | Gotenberg returned {response.status_code}: {response.text[:200]}"
136
188
  )
137
189
  return None
@@ -139,9 +191,10 @@ class GotenbergConverter(Converter):
139
191
  except httpx.ConnectError:
140
192
  logger.info(f"{tag} | Gotenberg not reachable at {self.gotenberg_url}, skipping")
141
193
  return None
142
- except httpx.TimeoutException:
143
- logger.warning(f"{tag} | Gotenberg timed out after 120s")
144
- return None
194
+ except _RETRYABLE_EXC:
195
+ # Let the retry decorator handle transient errors. If retries are
196
+ # exhausted it re-raises, and the caller in ``convert()`` logs.
197
+ raise
145
198
  except Exception as e:
146
- logger.warning(f"{tag} | Gotenberg error: {e}")
199
+ logger.error(f"{tag} | Gotenberg error: {e}")
147
200
  return None
@@ -11,6 +11,8 @@ Returns Markdown when successful, or `None` if conversion produced
11
11
  insufficient content (as determined by `ensure_minimum_content` in the service).
12
12
  """
13
13
 
14
+ from pathlib import Path
15
+
14
16
  from ..common import config
15
17
  from ..common.utils import is_pdf
16
18
  from ..services.openai_services import GPTVision
@@ -115,6 +117,7 @@ class GPTVisionConverter(Converter):
115
117
  max_retries=_retries,
116
118
  base_delay=base_delay,
117
119
  max_delay=max_delay,
120
+ context_label=Path(file_path).name,
118
121
  )
119
122
 
120
123
  async def aclose(self) -> None:
@@ -158,6 +158,7 @@ class PagePDFConverter:
158
158
  png_path = await asyncio.to_thread(self._render_page_to_png, file_path, page_idx)
159
159
  content = await self.gpt_vision.gpt_vision.process_image(
160
160
  file_or_url=png_path,
161
+ context_label=f"{Path(file_path).name} page {page_idx + 1}",
161
162
  )
162
163
  if content:
163
164
  logger.info(f"{tag} | succeeded ({len(content)} chars)")
@@ -240,6 +240,7 @@ class GPTVision:
240
240
  base_delay: float = 0.5,
241
241
  max_delay: float = 20.0,
242
242
  retry_http_statuses: tuple[int, ...] = _RETRY_HTTP_STATUSES,
243
+ context_label: str | None = None,
243
244
  ):
244
245
  """
245
246
  Call self.lang_client.ainvoke with:
@@ -275,8 +276,9 @@ class GPTVision:
275
276
  raise last_err
276
277
  cap = min(max_delay, base_delay * (2 ** (attempt - 1)))
277
278
  sleep_for = random.uniform(0, cap)
279
+ label = context_label or file_or_url
278
280
  logger.warning(
279
- f"GPTVision: ainvoke transient error {file_or_url}: attempt {attempt}/{max_retries}: "
281
+ f"GPTVision: ainvoke transient error {label}: attempt {attempt}/{max_retries}: "
280
282
  f"{type(last_err).__name__}: {last_err}. Retrying in {sleep_for:.2f}s"
281
283
  )
282
284
  await asyncio.sleep(sleep_for)
@@ -331,6 +333,7 @@ class GPTVision:
331
333
  max_retries: int = 6,
332
334
  base_delay: float = 0.5,
333
335
  max_delay: float = 20.0,
336
+ context_label: str | None = None,
334
337
  ) -> str | None:
335
338
  """
336
339
  OCR a single image (local path or URL) with the vision model.
@@ -373,6 +376,7 @@ class GPTVision:
373
376
  max_retries=max_retries,
374
377
  base_delay=base_delay,
375
378
  max_delay=max_delay,
379
+ context_label=context_label,
376
380
  )
377
381
  finally:
378
382
  with suppress(Exception):
@@ -469,7 +473,11 @@ class GPTVision:
469
473
  # Per-page hard timeout so one slow page cannot stall the run
470
474
  try:
471
475
  partial_md = await asyncio.wait_for(
472
- self.process_image(png_path), timeout=self.page_timeout_s
476
+ self.process_image(
477
+ png_path,
478
+ context_label=f"{file_stem} page {page_index + 1}/{num_pages}",
479
+ ),
480
+ timeout=self.page_timeout_s,
473
481
  )
474
482
  except TimeoutError:
475
483
  logger.error(
File without changes
File without changes