markitdown-pro 1.1.2__tar.gz → 1.2.2__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 (53) hide show
  1. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/PKG-INFO +1 -1
  2. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/azure_doc_intel_wrapper.py +6 -1
  3. markitdown_pro-1.2.2/markitdown_pro/converters/tabular_wrapper.py +31 -0
  4. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/markup_handler.py +1 -1
  5. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/office_handler.py +7 -3
  6. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/pdf_handler.py +3 -3
  7. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/text_handler.py +1 -1
  8. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/services/azure_doc_intelligence.py +3 -3
  9. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro.egg-info/PKG-INFO +1 -1
  10. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro.egg-info/SOURCES.txt +1 -2
  11. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/setup.py +1 -1
  12. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/tests/handlers/test_markup_handler.py +2 -12
  13. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/tests/handlers/test_text_handler.py +4 -4
  14. markitdown_pro-1.1.2/tests/handlers/test_office_handler.py +0 -26
  15. markitdown_pro-1.1.2/tests/handlers/test_pdf_handler.py +0 -26
  16. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/README.md +0 -0
  17. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/__init__.py +0 -0
  18. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/common/__init__.py +0 -0
  19. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/common/isolated_worker.py +0 -0
  20. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/common/logger.py +0 -0
  21. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/common/schemas.py +0 -0
  22. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/common/utils.py +0 -0
  23. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/conversion_pipeline.py +0 -0
  24. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/__init__.py +0 -0
  25. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/azure_speech_wrapper.py +0 -0
  26. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/base.py +0 -0
  27. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/gpt_vision_wrapper.py +0 -0
  28. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/markitdown_wrapper.py +0 -0
  29. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/pymupdf_wrapper.py +0 -0
  30. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/unstructured_wrapper.py +0 -0
  31. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/converters/youtube_wrapper.py +0 -0
  32. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/__init__.py +0 -0
  33. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/audio_handler.py +0 -0
  34. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/base_handler.py +0 -0
  35. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/email_handler.py +0 -0
  36. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/epub_handler.py +0 -0
  37. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/image_handler.py +0 -0
  38. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/ipynb_handler.py +0 -0
  39. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/markitdown_handler.py +0 -0
  40. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/pst_handler.py +0 -0
  41. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/handlers/tabular_handler.py +0 -0
  42. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/services/__init__.py +0 -0
  43. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/services/azure_speech.py +0 -0
  44. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro/services/openai_services.py +0 -0
  45. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro.egg-info/dependency_links.txt +0 -0
  46. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro.egg-info/requires.txt +0 -0
  47. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/markitdown_pro.egg-info/top_level.txt +0 -0
  48. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/pyproject.toml +0 -0
  49. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/setup.cfg +0 -0
  50. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/tests/handlers/__init__.py +0 -0
  51. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/tests/handlers/test_email_handler.py +0 -0
  52. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/tests/handlers/test_pst_handler.py +0 -0
  53. {markitdown_pro-1.1.2 → markitdown_pro-1.2.2}/tests/test_conversion_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markitdown-pro
3
- Version: 1.1.2
3
+ Version: 1.2.2
4
4
  Summary: A package that converts almost any file format to Markdown.
5
5
  Author: Developer
6
6
  Classifier: Programming Language :: Python :: 3
@@ -5,9 +5,14 @@ from .base import ConverterWrapper
5
5
 
6
6
 
7
7
  class DocIntelligenceWrapper(ConverterWrapper):
8
+
9
+ SUPPORTED_EXTENSIONS = DocumentIntelligenceHandler.SUPPORTED_EXTENSIONS
10
+
8
11
  def __init__(self):
9
12
  super().__init__("Azure Document Intelligence")
10
13
  self.converter = DocumentIntelligenceHandler()
11
14
 
12
15
  async def convert(self, file_path: str) -> Optional[str]:
13
- return await self.converter.convert_to_md(file_path)
16
+ markdown = await self.converter.convert_to_md(file_path)
17
+ await self.converter.aclose()
18
+ return markdown
@@ -0,0 +1,31 @@
1
+ from typing import Optional
2
+
3
+ from ..common.logger import logger
4
+ from ..common.utils import clean_markdown
5
+ from ..handlers.tabular_handler import TabularHandler
6
+ from .base import ConverterWrapper
7
+
8
+
9
+ class TabularWrapper(ConverterWrapper):
10
+ SUPPORTED_FORMATS = (
11
+ "csv",
12
+ "tsv",
13
+ "xls",
14
+ "xlsx",
15
+ )
16
+
17
+ def __init__(self):
18
+ super().__init__("TabularHandler")
19
+ self.tabular_handler = TabularHandler()
20
+
21
+ async def convert(self, file_path: str) -> Optional[str]:
22
+ logger.debug(f"TabularWrapper: Converting {file_path} to markdown")
23
+ file_extension = file_path.split(".")[-1].lower()
24
+
25
+ if file_extension not in self.SUPPORTED_FORMATS:
26
+ logger.warning(f"TabularWrapper: Unsupported file format: {file_extension}")
27
+ return None
28
+
29
+ markdown = await self.tabular_handler.handle(file_path)
30
+ markdown = clean_markdown(markdown) if markdown else None
31
+ return markdown
@@ -18,7 +18,7 @@ from .base_handler import BaseHandler
18
18
  class MarkupHandler(BaseHandler):
19
19
  """Handler for .html, .xml, .json, .ndjson, .yaml, .yml files."""
20
20
 
21
- extensions = frozenset([".html", ".htm", ".xml", ".json", ".ndjson", ".yaml", ".yml"])
21
+ SUPPORTED_EXTENSIONS = frozenset([".html", ".htm", ".xml", ".json", ".ndjson", ".yaml", ".yml"])
22
22
 
23
23
  async def handle(self, file_path: str, *args, **kwargs) -> Optional[str]:
24
24
  logger.info(f"Processing markup file: {file_path}")
@@ -5,6 +5,7 @@ from ..common.utils import ensure_minimum_content
5
5
  from ..converters.azure_doc_intel_wrapper import DocIntelligenceWrapper
6
6
  from ..converters.base import ConverterWrapper
7
7
  from ..converters.markitdown_wrapper import MarkItDownWrapper
8
+ from ..converters.tabular_wrapper import TabularWrapper
8
9
  from ..converters.unstructured_wrapper import UnstructuredWrapper
9
10
  from .base_handler import BaseHandler
10
11
 
@@ -13,9 +14,10 @@ class OfficeHandler(BaseHandler):
13
14
  """
14
15
  Convert Office documents to Markdown by trying a series of converters in order:
15
16
 
16
- 1) MarkItDown (fast, local parsing for Office formats)
17
- 2) Azure Document Intelligence (cloud extraction + OCR for embedded images)
18
- 3) Unstructured (robust fallback parser)
17
+ 1) TabularHandler (specialized handler for tabular data)
18
+ 2) MarkItDown (fast, local parsing for Office formats)
19
+ 3) Azure Document Intelligence (cloud extraction + OCR for embedded images)
20
+ 4) Unstructured (robust fallback parser)
19
21
 
20
22
  The first converter that returns non-trivial Markdown (as judged by
21
23
  `ensure_minimum_content`) wins. If all fail, `None` is returned.
@@ -34,12 +36,14 @@ class OfficeHandler(BaseHandler):
34
36
  super().__init__(*args, **kwargs)
35
37
 
36
38
  # Ordered, fastest → most comprehensive
39
+ self.tabular = TabularWrapper()
37
40
  self.markitdown = MarkItDownWrapper()
38
41
  self.doc_intelligence = DocIntelligenceWrapper()
39
42
  self.unstructured = UnstructuredWrapper()
40
43
 
41
44
  # (converter, human_readable_name) in the exact order to try
42
45
  self._pipeline: list[tuple[ConverterWrapper, str]] = [
46
+ (self.tabular, "TabularHandler"),
43
47
  (self.markitdown, "MarkItDown"),
44
48
  (self.doc_intelligence, "Azure Document Intelligence"),
45
49
  (self.unstructured, "Unstructured"),
@@ -89,10 +89,10 @@ class PDFHandler(BaseHandler):
89
89
  # Choose pipeline based on detected content type
90
90
  if pdf_type == PDFType.TEXT_ONLY:
91
91
  pipeline = self.text_pipeline
92
- elif pdf_type == PDFType.ALL_IMAGES:
92
+ elif pdf_type == PDFType.ALL_IMAGES or pdf_type == PDFType.TEXT_PLUS_IMAGES:
93
93
  pipeline = self.image_pipeline
94
- elif pdf_type == PDFType.TEXT_PLUS_IMAGES:
95
- pipeline = self.text_pipeline + self.image_pipeline
94
+ # elif pdf_type == PDFType.TEXT_PLUS_IMAGES:
95
+ # pipeline = self.text_pipeline + self.image_pipeline
96
96
  else:
97
97
  # Fallback to text pipeline if detection returned an unexpected value
98
98
  pipeline = self.text_pipeline
@@ -11,7 +11,7 @@ from .base_handler import BaseHandler
11
11
  class TextHandler(BaseHandler):
12
12
  """Handler for .txt, .md, .py, .go, and other text/code files."""
13
13
 
14
- extensions = frozenset([".txt", ".md", ".py", ".go"])
14
+ SUPPORTED_EXTENSIONS = frozenset([".txt", ".md", ".py", ".go"])
15
15
 
16
16
  async def handle(self, file_path: str, *args, **kwargs) -> Optional[str]:
17
17
  logger.info(f"Processing text file: {file_path}")
@@ -59,7 +59,7 @@ class DocumentIntelligenceHandler:
59
59
  ".heic",
60
60
  }
61
61
  )
62
- extensions: frozenset[str] = frozenset(
62
+ SUPPORTED_EXTENSIONS: frozenset[str] = frozenset(
63
63
  list(pdf_extensions) + list(office_extensions) + list(image_extensions)
64
64
  )
65
65
 
@@ -112,7 +112,7 @@ class DocumentIntelligenceHandler:
112
112
  return None
113
113
 
114
114
  ext = file_path.suffix.lower()
115
- if ext not in self.extensions:
115
+ if ext not in self.SUPPORTED_EXTENSIONS:
116
116
  logger.warning(f"DocumentIntelligenceHandler: unsupported extension '{ext}'.")
117
117
  return None
118
118
 
@@ -178,4 +178,4 @@ class DocumentIntelligenceHandler:
178
178
  @classmethod
179
179
  def supports(cls, path: str | Path) -> bool:
180
180
  """Return True if the file extension is supported by this handler."""
181
- return Path(path).suffix.lower() in cls.extensions
181
+ return Path(path).suffix.lower() in cls.SUPPORTED_EXTENSIONS
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markitdown-pro
3
- Version: 1.1.2
3
+ Version: 1.2.2
4
4
  Summary: A package that converts almost any file format to Markdown.
5
5
  Author: Developer
6
6
  Classifier: Programming Language :: Python :: 3
@@ -21,6 +21,7 @@ markitdown_pro/converters/base.py
21
21
  markitdown_pro/converters/gpt_vision_wrapper.py
22
22
  markitdown_pro/converters/markitdown_wrapper.py
23
23
  markitdown_pro/converters/pymupdf_wrapper.py
24
+ markitdown_pro/converters/tabular_wrapper.py
24
25
  markitdown_pro/converters/unstructured_wrapper.py
25
26
  markitdown_pro/converters/youtube_wrapper.py
26
27
  markitdown_pro/handlers/__init__.py
@@ -45,7 +46,5 @@ tests/test_conversion_pipeline.py
45
46
  tests/handlers/__init__.py
46
47
  tests/handlers/test_email_handler.py
47
48
  tests/handlers/test_markup_handler.py
48
- tests/handlers/test_office_handler.py
49
- tests/handlers/test_pdf_handler.py
50
49
  tests/handlers/test_pst_handler.py
51
50
  tests/handlers/test_text_handler.py
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="markitdown-pro",
5
- version="1.1.2",
5
+ version="1.2.2",
6
6
  author="Developer",
7
7
  description="A package that converts almost any file format to Markdown.",
8
8
  long_description=open("README.md").read(),
@@ -9,25 +9,15 @@ from tests.utils import list_files
9
9
 
10
10
  log = logging.getLogger(__name__)
11
11
 
12
- INCLUDE_EXTENSIONS = [
13
- ".html",
14
- ".htm",
15
- ".xml",
16
- ".json",
17
- ".ndjson",
18
- ".yaml",
19
- ".yml",
20
- ]
21
-
22
12
  TEST_FILES_PATH = data_path()
23
- ALL_FILES = list_files(TEST_FILES_PATH, include_ext=INCLUDE_EXTENSIONS, recursive=True)
13
+ ALL_FILES = list_files(TEST_FILES_PATH, include_ext=MarkupHandler.extensions, recursive=True)
24
14
  log.info(f"Found {len(ALL_FILES)} test files in {TEST_FILES_PATH}.")
25
15
 
26
16
 
27
17
  @pytest.mark.asyncio
28
18
  @pytest.mark.parametrize("file_path", ALL_FILES, ids=[pretty_id(p) for p in ALL_FILES])
29
19
  async def test_files(file_path: Path, markup_handler: MarkupHandler):
30
- log.info(f"Testing file: {file_path}")
20
+ log.info(f"{MarkupHandler.__name__}: Testing file {file_path}")
31
21
 
32
22
  markdown_text = await markup_handler.handle(str(file_path))
33
23
  assert markdown_text is not None, f"Conversion returned None for {file_path.name}"
@@ -9,17 +9,17 @@ from tests.utils import list_files
9
9
 
10
10
  log = logging.getLogger(__name__)
11
11
 
12
- INCLUDE_EXTENSIONS = [".txt", ".md", ".py", ".go"]
13
-
14
12
  TEST_FILES_PATH = data_path()
15
- ALL_FILES = list_files(TEST_FILES_PATH, include_ext=INCLUDE_EXTENSIONS, recursive=True)
13
+ ALL_FILES = list_files(
14
+ TEST_FILES_PATH, include_ext=TextHandler.SUPPORTED_EXTENSIONS, recursive=True
15
+ )
16
16
  log.info(f"Found {len(ALL_FILES)} test files in {TEST_FILES_PATH}.")
17
17
 
18
18
 
19
19
  @pytest.mark.asyncio
20
20
  @pytest.mark.parametrize("file_path", ALL_FILES, ids=[pretty_id(p) for p in ALL_FILES])
21
21
  async def test_files(file_path: Path, text_handler: TextHandler):
22
- log.info(f"Testing file: {file_path}")
22
+ log.info(f"{TextHandler.__name__}: Testing file {file_path}")
23
23
 
24
24
  markdown_text = await text_handler.handle(str(file_path))
25
25
  assert markdown_text is not None, f"Conversion returned None for {file_path.name}"
@@ -1,26 +0,0 @@
1
- import logging
2
- from pathlib import Path
3
-
4
- import pytest
5
-
6
- from markitdown_pro.handlers.office_handler import OfficeHandler
7
- from tests.fixtures import data_path, pretty_id
8
- from tests.utils import list_files
9
-
10
- log = logging.getLogger(__name__)
11
-
12
- INCLUDE_EXTENSIONS = [".docx", ".xlsx", ".pptx"]
13
-
14
- TEST_FILES_PATH = data_path()
15
- ALL_FILES = list_files(TEST_FILES_PATH, include_ext=INCLUDE_EXTENSIONS, recursive=True)
16
- log.info(f"Found {len(ALL_FILES)} test files in {TEST_FILES_PATH}.")
17
-
18
-
19
- @pytest.mark.asyncio
20
- @pytest.mark.parametrize("file_path", ALL_FILES, ids=[pretty_id(p) for p in ALL_FILES])
21
- async def test_files(file_path: Path, office_handler: OfficeHandler):
22
- log.info(f"Testing file: {file_path}")
23
-
24
- markdown_text = await office_handler.handle(str(file_path))
25
- assert markdown_text is not None, f"Conversion returned None for {file_path.name}"
26
- assert isinstance(markdown_text, str), f"Output type is not str for {file_path.name}"
@@ -1,26 +0,0 @@
1
- import logging
2
- from pathlib import Path
3
-
4
- import pytest
5
-
6
- from markitdown_pro.handlers.pdf_handler import PDFHandler
7
- from tests.fixtures import data_path, pretty_id
8
- from tests.utils import list_files
9
-
10
- log = logging.getLogger(__name__)
11
-
12
- INCLUDE_EXTENSIONS = [".pdf"]
13
-
14
- TEST_FILES_PATH = data_path()
15
- ALL_FILES = list_files(TEST_FILES_PATH, include_ext=INCLUDE_EXTENSIONS, recursive=True)
16
- log.info(f"Found {len(ALL_FILES)} test files in {TEST_FILES_PATH}.")
17
-
18
-
19
- @pytest.mark.asyncio
20
- @pytest.mark.parametrize("file_path", ALL_FILES, ids=[pretty_id(p) for p in ALL_FILES])
21
- async def test_files(file_path: Path, pdf_handler: PDFHandler):
22
- log.info(f"Testing file: {file_path}")
23
-
24
- markdown_text = await pdf_handler.handle(str(file_path))
25
- assert markdown_text is not None, f"Conversion returned None for {file_path.name}"
26
- assert isinstance(markdown_text, str), f"Output type is not str for {file_path.name}"
File without changes
File without changes