extract-python 0.10.4__py3-none-any.whl → 0.11.1__py3-none-any.whl

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.
@@ -5,20 +5,20 @@ logger = logging.getLogger(__name__)
5
5
  try:
6
6
  from .docling_ import DOCLING_DEFAULT_ARTIFACTS_PATH, DoclingPipeline
7
7
  except ModuleNotFoundError:
8
- logger.exception("docling is not available, might be optional...")
8
+ logger.warning("docling is not available, might be optional...")
9
9
  DOCKING_DEFAULT_ARTIFACTS_PATH, DoclingPipeline = None, None
10
10
 
11
11
  try:
12
12
  from .marker_ import MarkerPipeline
13
13
  except ModuleNotFoundError:
14
- logger.exception("marker is not available, might be optional...")
14
+ logger.warning("marker is not available, might be optional...")
15
15
  MarkerPipeline = None
16
16
 
17
17
 
18
18
  try:
19
19
  from .miner_u import MinerUPipeline
20
20
  except ModuleNotFoundError:
21
- logger.exception("mineru is not available, might be optional...")
21
+ logger.warning("mineru is not available, might be optional...")
22
22
  MinerUPipeline = None
23
23
 
24
24
 
@@ -0,0 +1,9 @@
1
+ from .cli import cli_app
2
+
3
+
4
+ def main() -> None:
5
+ cli_app()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,50 @@
1
+ import importlib
2
+ import logging
3
+ import os
4
+ from typing import Annotated
5
+
6
+ import typer
7
+ from icij_common.logging_utils import setup_loggers
8
+
9
+ import extract_python
10
+
11
+ from .doc import configs_app
12
+ from .utils import AsyncTyper
13
+
14
+ cli_app = AsyncTyper(
15
+ context_settings={"help_option_names": ["-h", "--help"]},
16
+ pretty_exceptions_enable=False,
17
+ )
18
+ cli_app.add_typer(configs_app)
19
+
20
+
21
+ def version_callback(value: bool) -> None: # noqa: FBT001
22
+ if value:
23
+ package_version = importlib.metadata.version(extract_python.__name__)
24
+ print(package_version)
25
+ raise typer.Exit()
26
+
27
+
28
+ def pretty_exc_callback(value: bool) -> None: # noqa: FBT001
29
+ if not value:
30
+ os.environ["TYPER_STANDARD_TRACEBACK"] = "1"
31
+
32
+
33
+ @cli_app.callback()
34
+ def main(
35
+ version: Annotated[ # noqa: ARG001
36
+ bool | None,
37
+ typer.Option("--version", callback=version_callback, is_eager=True),
38
+ ] = None,
39
+ *,
40
+ pretty_exceptions: Annotated[ # noqa: ARG001
41
+ bool,
42
+ typer.Option(
43
+ "--pretty-exceptions", callback=pretty_exc_callback, is_eager=True
44
+ ),
45
+ ] = False,
46
+ ) -> None:
47
+ setup_loggers(
48
+ ["__main__", extract_python.__name__, "docling", "mineru", "marker"],
49
+ level=logging.DEBUG,
50
+ )
@@ -0,0 +1,78 @@
1
+ import logging
2
+ import os
3
+ from pathlib import Path
4
+ from typing import Annotated, Never
5
+
6
+ import typer
7
+ from extract_core import (
8
+ Device,
9
+ InputDoc,
10
+ OutputFormat,
11
+ Pipeline,
12
+ PipelineConfig,
13
+ PipelineSize,
14
+ PipelineType,
15
+ )
16
+ from extract_core.default_config import default_config
17
+ from pydantic import TypeAdapter
18
+
19
+ from .utils import AsyncTyper
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ _DOC = "doc"
24
+
25
+ _DOC_CONVERT_HELP = "Converts documents to the provided output format"
26
+ _DOC_CONVERT_DOCS_HELP = "input documents (can be file or directories)"
27
+ _DOC_CONVERT_OUTPUT_PATH_HELP = "directory where the converted documents will be saved"
28
+ _DOC_CONVERT_DEVICE_HELP = "device used to run inference"
29
+ _DOC_CONVERT_OUTPUT_FMT_HELP = "output format"
30
+ _DOC_CONVERT_PIPELINE_CONFIG = "path to a JSON pipeline configuration"
31
+
32
+
33
+ configs_app = AsyncTyper(name=_DOC)
34
+
35
+
36
+ @configs_app.async_command(help=_DOC_CONVERT_HELP)
37
+ async def convert(
38
+ docs: Annotated[list[Path], typer.Argument(help=_DOC_CONVERT_DOCS_HELP)],
39
+ output_path: Annotated[Path, typer.Argument(help=_DOC_CONVERT_OUTPUT_PATH_HELP)],
40
+ output_format: Annotated[
41
+ OutputFormat, typer.Option(help=_DOC_CONVERT_OUTPUT_FMT_HELP)
42
+ ] = OutputFormat.MARKDOWN,
43
+ config: Annotated[
44
+ Path | None,
45
+ typer.Option("-c", "--config", help=_DOC_CONVERT_PIPELINE_CONFIG),
46
+ ] = None,
47
+ ) -> None:
48
+ if config is not None:
49
+ config = TypeAdapter(PipelineConfig).validate_json(config.read_text())
50
+ else:
51
+ config = default_config(
52
+ pipeline_type=PipelineType.DOCLING,
53
+ device=Device.CPU,
54
+ size=PipelineSize.SMALL,
55
+ )
56
+ config = config.to_device()
57
+ docs = [InputDoc.from_path(d, n_pages=1) for p in docs for d in _walkdir(p)]
58
+ pipeline = Pipeline.from_config(config)
59
+ output_paths = []
60
+ async for res in pipeline.extract_content(docs, output_format, output_path):
61
+ output_path = res.output.path
62
+ logger.info("converted %s to %s", res.input.path, output_path / output_path)
63
+ output_paths.append(output_path / output_path)
64
+ print("\n".join(output_paths))
65
+
66
+
67
+ def _raise(exc: OSError) -> Never:
68
+ raise exc
69
+
70
+
71
+ def _walkdir(path: Path) -> list[Path]:
72
+ if path.is_file():
73
+ return [path]
74
+ paths = []
75
+ for root, _, files in os.walk(path, onerror=_raise):
76
+ root = Path(root) # noqa: PLW2901
77
+ paths.extend(root / f for f in files)
78
+ return paths
@@ -0,0 +1,25 @@
1
+ import asyncio
2
+ import sys
3
+ from collections.abc import Callable
4
+ from functools import wraps
5
+ from typing import Any
6
+
7
+ import typer
8
+
9
+
10
+ class AsyncTyper(typer.Typer):
11
+ def async_command(self, *args, **kwargs) -> Callable[[Callable], Callable]:
12
+ def decorator(async_func: Callable) -> Callable:
13
+ @wraps(async_func)
14
+ def sync_func(*_args, **_kwargs) -> Any:
15
+ res = asyncio.run(async_func(*_args, **_kwargs))
16
+ return res
17
+
18
+ self.command(*args, **kwargs)(sync_func)
19
+ return async_func
20
+
21
+ return decorator
22
+
23
+
24
+ def eprint(*args, **kwargs) -> None:
25
+ print(*args, file=sys.stderr, **kwargs)
@@ -59,8 +59,7 @@ class DoclingPipeline(Pipeline):
59
59
  def __init__(self, config: DoclingPipelineConfig):
60
60
  super().__init__(config)
61
61
  format_options = {
62
- k: v.to_docling(self._device)
63
- for k, v in self._config.format_options.items()
62
+ k: v.to_docling() for k, v in self._config.format_options.items()
64
63
  }
65
64
  logger.info(
66
65
  "resolved format options to: %s",
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: extract-python
3
- Version: 0.10.4
3
+ Version: 0.11.1
4
4
  Summary: Structured content extraction
5
5
  Project-URL: Homepage, https://github.com/ICIJ/extract-python
6
6
  Project-URL: Repository, https://github.com/ICIJ/extract-python
7
7
  Project-URL: Issues, https://github.com/ICIJ/extract-python/issues
8
8
  Author-email: Clément Doumouro <cdoumouro@icij.org>
9
9
  Requires-Python: <3.15,>=3.13
10
- Requires-Dist: extract-core~=0.10.4
10
+ Requires-Dist: extract-core~=0.11.0
11
11
  Requires-Dist: icij-common~=0.8.2
12
12
  Requires-Dist: pympler~=1.1
13
13
  Provides-Extra: benches
@@ -15,6 +15,8 @@ Requires-Dist: html2image~=2.0.7; extra == 'benches'
15
15
  Requires-Dist: markdown2>=2.5.4; extra == 'benches'
16
16
  Requires-Dist: notebook>=7.4.5; extra == 'benches'
17
17
  Requires-Dist: pypdfium2>=4.30.0; extra == 'benches'
18
+ Provides-Extra: cli
19
+ Requires-Dist: typer~=0.21.2; extra == 'cli'
18
20
  Provides-Extra: docling
19
21
  Requires-Dist: docling-slim[feat-ocr-easyocr,feat-ocr-mac,feat-ocr-rapidocr,feat-ocr-tesserocr,standard]~=2.127; extra == 'docling'
20
22
  Provides-Extra: docling-gpu
@@ -0,0 +1,14 @@
1
+ extract_python/__init__.py,sha256=mUWwAYj8dRhM79J_Ns_yNM3WG2GDqWRNXZd3XVkkUaY,753
2
+ extract_python/__main__.py,sha256=g-fvS46zl9umKmGrSpl-OG-8PSuZgjqvTCqjpsZtSps,101
3
+ extract_python/constants.py,sha256=659V40LcTWJhX3IbuJLSSvI5AsGJh9ciMrGCfzJn2zA,98
4
+ extract_python/docling_.py,sha256=iZha9zh6uyFo67RVB0YqHMJt9auzJJV0kJ1OCPTOan8,10030
5
+ extract_python/marker_.py,sha256=bb0DJXrSWOznIuPnw4-adR5_R9QiwtFGGBh5KlXFxjM,3323
6
+ extract_python/miner_u.py,sha256=sEU1PhPpfPVo4jP7flNlbGO9PfsLFLz973-ufZEd0ws,3966
7
+ extract_python/utils.py,sha256=LrR1tlOgpWEri6TLDlYYPRBmlka-AjOepWnbySf2Haw,9974
8
+ extract_python/cli/__init__.py,sha256=Xt3MB74fO8cimm0Xas8dIMmXu62O0dV-4o3-OUzZggo,1245
9
+ extract_python/cli/doc.py,sha256=SMwRs-7-u_lw3wpHO6m3vFYnbjYCn_qIVC-q2TIxcbg,2435
10
+ extract_python/cli/utils.py,sha256=Png7oGKKxDeStn27k-o4Hxlzl-G-u-QDSH6IfJqUk1I,667
11
+ extract_python-0.11.1.dist-info/METADATA,sha256=B4sG_uDFLruPQE3ytKMq5o7ODQOKGRlYGgvyuFiBmkE,1429
12
+ extract_python-0.11.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
13
+ extract_python-0.11.1.dist-info/entry_points.txt,sha256=noSkCWA0LRm0V7WbmYDPBnJrKeiYdpvXynAW6y72Z4M,64
14
+ extract_python-0.11.1.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ extract_python = extract_python.__main__:main
@@ -1,9 +0,0 @@
1
- extract_python/__init__.py,sha256=DA2LUro6vMjfS8fb2MsqO95FbJEZHyZ7kFyn42q02Wk,759
2
- extract_python/constants.py,sha256=659V40LcTWJhX3IbuJLSSvI5AsGJh9ciMrGCfzJn2zA,98
3
- extract_python/docling_.py,sha256=zD5rIXV1pAQBNGZc0RliP9buHjttz4CdSOj21Z4FbFo,10054
4
- extract_python/marker_.py,sha256=bb0DJXrSWOznIuPnw4-adR5_R9QiwtFGGBh5KlXFxjM,3323
5
- extract_python/miner_u.py,sha256=sEU1PhPpfPVo4jP7flNlbGO9PfsLFLz973-ufZEd0ws,3966
6
- extract_python/utils.py,sha256=LrR1tlOgpWEri6TLDlYYPRBmlka-AjOepWnbySf2Haw,9974
7
- extract_python-0.10.4.dist-info/METADATA,sha256=5UcF7UU0SgfLmsb-oSXbCfZWzUBOKSYSvZFUILttM4o,1364
8
- extract_python-0.10.4.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
9
- extract_python-0.10.4.dist-info/RECORD,,