docling-core 2.97.1__tar.gz → 2.97.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 (152) hide show
  1. {docling_core-2.97.1 → docling_core-2.97.2}/PKG-INFO +1 -1
  2. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/deserializer/doclang.py +40 -9
  3. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/common.py +19 -1
  4. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/markdown.py +15 -9
  5. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core.egg-info/PKG-INFO +1 -1
  6. {docling_core-2.97.1 → docling_core-2.97.2}/pyproject.toml +1 -1
  7. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_deserializer_doclang.py +47 -0
  8. {docling_core-2.97.1 → docling_core-2.97.2}/LICENSE +0 -0
  9. {docling_core-2.97.1 → docling_core-2.97.2}/README.md +0 -0
  10. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/__init__.py +0 -0
  11. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/cli/__init__.py +0 -0
  12. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/cli/serialize.py +0 -0
  13. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/cli/view.py +0 -0
  14. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/compat.py +0 -0
  15. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/experimental/__init__.py +0 -0
  16. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/experimental/serializer/__init__.py +0 -0
  17. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/experimental/serializer/outline.py +0 -0
  18. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/py.typed +0 -0
  19. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/search/__init__.py +0 -0
  20. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/search/package.py +0 -0
  21. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/__init__.py +0 -0
  22. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/__init__.py +0 -0
  23. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/base.py +0 -0
  24. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/chunk_expander.py +0 -0
  25. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/code_chunking/__init__.py +0 -0
  26. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/code_chunking/_language_code_chunkers.py +0 -0
  27. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/code_chunking/_utils.py +0 -0
  28. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/code_chunking/base_code_chunking_strategy.py +0 -0
  29. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/code_chunking/code_chunk.py +0 -0
  30. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/code_chunking/standard_code_chunking_strategy.py +0 -0
  31. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/doc_chunk.py +0 -0
  32. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/hierarchical_chunker.py +0 -0
  33. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/hybrid_chunker.py +0 -0
  34. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/line_chunker.py +0 -0
  35. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/page_chunker.py +0 -0
  36. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/tokenizer/__init__.py +0 -0
  37. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/tokenizer/base.py +0 -0
  38. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/tokenizer/huggingface.py +0 -0
  39. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/chunker/tokenizer/openai.py +0 -0
  40. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/deserializer/__init__.py +0 -0
  41. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/deserializer/base.py +0 -0
  42. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/deserializer/doclang_source_mapping.py +0 -0
  43. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/profiler/__init__.py +0 -0
  44. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/profiler/doc_profiler.py +0 -0
  45. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/__init__.py +0 -0
  46. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/_doclang_utils.py +0 -0
  47. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/azure.py +0 -0
  48. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/base.py +0 -0
  49. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/doclang.py +0 -0
  50. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/doctags.py +0 -0
  51. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/html.py +0 -0
  52. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/html_styles.py +0 -0
  53. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/latex.py +0 -0
  54. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/markdown_excel.py +0 -0
  55. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/plain_text.py +0 -0
  56. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/serializer/webvtt.py +0 -0
  57. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/visualizer/__init__.py +0 -0
  58. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/visualizer/base.py +0 -0
  59. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/visualizer/key_value_visualizer.py +0 -0
  60. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/visualizer/layout_visualizer.py +0 -0
  61. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/visualizer/reading_order_visualizer.py +0 -0
  62. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/transforms/visualizer/table_visualizer.py +0 -0
  63. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/__init__.py +0 -0
  64. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/base.py +0 -0
  65. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/__init__.py +0 -0
  66. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/base.py +0 -0
  67. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/__init__.py +0 -0
  68. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/annotations.py +0 -0
  69. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/constants.py +0 -0
  70. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/content_layer.py +0 -0
  71. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/formatting.py +0 -0
  72. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/meta.py +0 -0
  73. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/origin.py +0 -0
  74. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/reference.py +0 -0
  75. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/scalars.py +0 -0
  76. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/common/source.py +0 -0
  77. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/doctags.py +0 -0
  78. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/document.py +0 -0
  79. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/__init__.py +0 -0
  80. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/code.py +0 -0
  81. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/content.py +0 -0
  82. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/form.py +0 -0
  83. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/group.py +0 -0
  84. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/key_value.py +0 -0
  85. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/node.py +0 -0
  86. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/picture/__init__.py +0 -0
  87. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/picture/charts.py +0 -0
  88. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/picture/classification.py +0 -0
  89. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/picture/meta.py +0 -0
  90. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/picture/molecule.py +0 -0
  91. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/picture/picture.py +0 -0
  92. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/table/__init__.py +0 -0
  93. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/table/table.py +0 -0
  94. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/table/table_data.py +0 -0
  95. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/items/text.py +0 -0
  96. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/labels.py +0 -0
  97. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/page.py +0 -0
  98. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/tokens.py +0 -0
  99. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/utils.py +0 -0
  100. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/doc/webvtt.py +0 -0
  101. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/io/__init__.py +0 -0
  102. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/legacy_doc/__init__.py +0 -0
  103. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/legacy_doc/base.py +0 -0
  104. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/types/legacy_doc/document.py +0 -0
  105. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/__init__.py +0 -0
  106. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/alias.py +0 -0
  107. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/file.py +0 -0
  108. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/generate_docs.py +0 -0
  109. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/generate_jsonschema.py +0 -0
  110. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/legacy.py +0 -0
  111. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/settings.py +0 -0
  112. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core/utils/validators.py +0 -0
  113. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core.egg-info/SOURCES.txt +0 -0
  114. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core.egg-info/dependency_links.txt +0 -0
  115. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core.egg-info/entry_points.txt +0 -0
  116. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core.egg-info/requires.txt +0 -0
  117. {docling_core-2.97.1 → docling_core-2.97.2}/docling_core.egg-info/top_level.txt +0 -0
  118. {docling_core-2.97.1 → docling_core-2.97.2}/setup.cfg +0 -0
  119. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_azure_serializer.py +0 -0
  120. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_base.py +0 -0
  121. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_chunk_expander.py +0 -0
  122. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_cli_serialize.py +0 -0
  123. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_code_chunker.py +0 -0
  124. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_code_chunking_strategy.py +0 -0
  125. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_compat.py +0 -0
  126. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_data_gen_flag.py +0 -0
  127. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_deserializer_doclang_source_mapping.py +0 -0
  128. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_doc_base.py +0 -0
  129. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_doclang_archive.py +0 -0
  130. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_docling_doc.py +0 -0
  131. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_doctags_load.py +0 -0
  132. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_hierarchical_chunker.py +0 -0
  133. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_hierarchy.py +0 -0
  134. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_hybrid_chunker.py +0 -0
  135. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_latex_serialization.py +0 -0
  136. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_line_chunker.py +0 -0
  137. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_metadata.py +0 -0
  138. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_otsl_table_export.py +0 -0
  139. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_page.py +0 -0
  140. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_page_chunker.py +0 -0
  141. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_plain_text_serialization.py +0 -0
  142. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_profiler.py +0 -0
  143. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_regions_to_table.py +0 -0
  144. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_serialization.py +0 -0
  145. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_serialization_doclang.py +0 -0
  146. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_serialization_doctag.py +0 -0
  147. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_serialization_outline.py +0 -0
  148. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_tokens.py +0 -0
  149. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_upath_support.py +0 -0
  150. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_utils.py +0 -0
  151. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_visualization.py +0 -0
  152. {docling_core-2.97.1 → docling_core-2.97.2}/tests/test_webvtt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docling-core
3
- Version: 2.97.1
3
+ Version: 2.97.2
4
4
  Summary: A python library to define and validate data types in Docling.
5
5
  Author-email: Cesar Berrospi Ramis <ceb@zurich.ibm.com>, Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>
6
6
  Maintainer-email: Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>, Cesar Berrospi Ramis <ceb@zurich.ibm.com>
@@ -137,6 +137,8 @@ class DocLangDocDeserializer(BaseDocDeserializer, BaseModel):
137
137
  # Internal state used while walking the tree (private instance attributes)
138
138
  _page_no: int = PrivateAttr(default=1)
139
139
  _default_resolution: int = PrivateAttr(default=DOCLANG_DFLT_RESOLUTION)
140
+ _default_page_width: int = PrivateAttr(default=DOCLANG_DFLT_RESOLUTION)
141
+ _default_page_height: int = PrivateAttr(default=DOCLANG_DFLT_RESOLUTION)
140
142
  _thread_registry: dict[tuple[str, str], NodeItem] = PrivateAttr(default_factory=dict)
141
143
  _media_root: Path | None = PrivateAttr(default=None)
142
144
  _max_xml_bytes: int = PrivateAttr(default=settings.max_doclang_xml_bytes)
@@ -205,8 +207,11 @@ class DocLangDocDeserializer(BaseDocDeserializer, BaseModel):
205
207
  doc = DoclingDocument(name="Document")
206
208
  self._page_no = page_no
207
209
  self._default_resolution = DOCLANG_DFLT_RESOLUTION
210
+ self._default_page_width = DOCLANG_DFLT_RESOLUTION
211
+ self._default_page_height = DOCLANG_DFLT_RESOLUTION
212
+ self._apply_default_resolution(root)
208
213
  self._thread_registry = {}
209
- self._ensure_page_exists(doc=doc, page_no=self._page_no, resolution=self._default_resolution)
214
+ self._ensure_page_exists(doc=doc, page_no=self._page_no)
210
215
  self._parse_document_root(doc=doc, root=root)
211
216
  return doc
212
217
 
@@ -232,7 +237,7 @@ class DocLangDocDeserializer(BaseDocDeserializer, BaseModel):
232
237
 
233
238
  def _advance_page_break(self, *, doc: DoclingDocument) -> None:
234
239
  self._page_no += 1
235
- self._ensure_page_exists(doc=doc, page_no=self._page_no, resolution=self._default_resolution)
240
+ self._ensure_page_exists(doc=doc, page_no=self._page_no)
236
241
 
237
242
  def _provenance_from_nodes_with_page_breaks(
238
243
  self,
@@ -320,9 +325,9 @@ class DocLangDocDeserializer(BaseDocDeserializer, BaseModel):
320
325
  }:
321
326
  self._parse_text_like(doc=doc, el=el, parent=parent)
322
327
  elif name == DocLangToken.PAGE_BREAK.value:
323
- # Start a new page; keep a default square page using the configured resolution
328
+ # Start a new page using the document's declared default resolution
324
329
  self._page_no += 1
325
- self._ensure_page_exists(doc=doc, page_no=self._page_no, resolution=self._default_resolution)
330
+ self._ensure_page_exists(doc=doc, page_no=self._page_no)
326
331
  self._source_recorder.bind_page(el, self._page_no)
327
332
  elif name == DocLangToken.HEADING.value:
328
333
  self._parse_heading(doc=doc, el=el, parent=parent)
@@ -1291,7 +1296,7 @@ class DocLangDocDeserializer(BaseDocDeserializer, BaseModel):
1291
1296
 
1292
1297
  is_virtual_text = self._is_list_item_virtual_text(all_content_nodes)
1293
1298
 
1294
- if not all_content_nodes:
1299
+ if self._first_non_whitespace_node(all_content_nodes) is None:
1295
1300
  # Empty list item (just ldiv, no content)
1296
1301
  doc.add_list_item(
1297
1302
  text="",
@@ -2183,10 +2188,36 @@ class DocLangDocDeserializer(BaseDocDeserializer, BaseModel):
2183
2188
  return "".join(out)
2184
2189
 
2185
2190
  # --------- Location helpers ---------
2186
- def _ensure_page_exists(self, *, doc: DoclingDocument, page_no: int, resolution: int) -> None:
2187
- # If the page already exists, do nothing; otherwise add with a square size based on resolution
2188
- if page_no not in doc.pages:
2189
- doc.add_page(page_no=page_no, size=Size(width=resolution, height=resolution))
2191
+ def _ensure_page_exists(self, *, doc: DoclingDocument, page_no: int, resolution: int | None = None) -> None:
2192
+ # If the page already exists, do nothing. A per-<location> resolution attribute
2193
+ # (rare/legacy) forces a square page; otherwise use the document default size,
2194
+ # which honours a non-square <default_resolution>.
2195
+ if page_no in doc.pages:
2196
+ return
2197
+ if resolution is not None:
2198
+ size = Size(width=resolution, height=resolution)
2199
+ else:
2200
+ size = Size(width=self._default_page_width, height=self._default_page_height)
2201
+ doc.add_page(page_no=page_no, size=size)
2202
+
2203
+ def _apply_default_resolution(self, root: Element) -> None:
2204
+ """Read <default_resolution width height/> so pages use the declared coordinate space."""
2205
+ elems = root.getElementsByTagName("default_resolution")
2206
+ if not elems:
2207
+ return
2208
+ el = cast(Element, elems[0])
2209
+ try:
2210
+ width = int(el.getAttribute("width") or 0)
2211
+ height = int(el.getAttribute("height") or 0)
2212
+ except ValueError:
2213
+ return
2214
+ if width > 0:
2215
+ self._default_page_width = width
2216
+ if height > 0:
2217
+ self._default_page_height = height
2218
+ # Scalar fallback for <location resolution="..."> value space (square docs only).
2219
+ if width > 0:
2220
+ self._default_resolution = width
2190
2221
 
2191
2222
  def _extract_provenance(self, *, doc: DoclingDocument, el: Element) -> list[ProvenanceItem]:
2192
2223
  head_nodes, _ = self._split_element_children_head_body(el)
@@ -52,6 +52,7 @@ from docling_core.types.doc import (
52
52
  PictureDataType,
53
53
  PictureItem,
54
54
  PictureMoleculeData,
55
+ RichTableCell,
55
56
  Script,
56
57
  TableAnnotationType,
57
58
  TableItem,
@@ -188,7 +189,8 @@ class CommonParams(BaseModel):
188
189
  """Common serialization parameters."""
189
190
 
190
191
  # allowlists with non-recursive semantics, i.e. if a list group node is outside the
191
- # range and some of its children items are within, they will be serialized
192
+ # range and some of its children items are within, they will be serialized.
193
+ # Table cell subtrees are content of their table and are excluded with it.
192
194
  labels: set[DocItemLabel] = _DEFAULT_LABELS
193
195
  layers: set[ContentLayer] = _DEFAULT_LAYERS
194
196
  pages: set[int] | None = None # None means all pages are allowed
@@ -313,6 +315,22 @@ class DocSerializer(BaseModel, BaseDocSerializer):
313
315
  )
314
316
  )
315
317
  }
318
+ # Rich cells own subtrees, unlike plain cells whose content lives in data.
319
+ # Exclude both representations with the table; leave captions independent.
320
+ for table in self.doc.tables:
321
+ if table.self_ref in refs or table.content_layer not in params.layers:
322
+ refs.add(table.self_ref)
323
+ for cell in table.data.table_cells:
324
+ if isinstance(cell, RichTableCell):
325
+ refs.update(
326
+ node.self_ref
327
+ for node, _ in self.doc.iterate_items(
328
+ root=cell.ref.resolve(self.doc),
329
+ with_groups=True,
330
+ traverse_pictures=True,
331
+ included_content_layers=set(ContentLayer),
332
+ )
333
+ )
316
334
  self._excluded_refs_cache[params_json] = refs
317
335
  return refs
318
336
 
@@ -107,33 +107,39 @@ def _mark_subtree_visited(
107
107
  _mark_subtree_visited(child_ref.resolve(doc=doc), doc, visited)
108
108
 
109
109
 
110
- def _collect_subtree_text(item: NodeItem, doc: DoclingDocument) -> str:
110
+ def _collect_subtree_text(item: NodeItem, doc: DoclingDocument, excluded_refs: set[str]) -> str:
111
111
  """Collect all text from *item*'s subtree, flattening nested tables.
112
112
 
113
113
  Returns a space-joined string of every piece of text found so that the
114
114
  content of a nested table is preserved in a flat, readable form.
115
115
 
116
116
  For TableItems the text is pulled from ``data.grid`` cells directly;
117
- children are *not* recursed into because they duplicate the grid content
118
- for RichTableCells. For all other items, ``.text`` is collected and
119
- children are visited recursively.
117
+ RichTableCells are resolved through their references, without visiting the
118
+ table children again. Exclusions apply during flattening just as they do
119
+ during normal serialization.
120
120
  """
121
121
  parts: list[str] = []
122
122
 
123
123
  if isinstance(item, TableItem):
124
+ if item.self_ref in excluded_refs:
125
+ return ""
124
126
  for row in item.data.grid:
125
127
  for cell in row:
126
- if cell.text:
127
- parts.append(cell.text)
128
+ if isinstance(cell, RichTableCell):
129
+ cell_text = _collect_subtree_text(cell.ref.resolve(doc), doc, excluded_refs)
130
+ else:
131
+ cell_text = cell.text
132
+ if cell_text:
133
+ parts.append(cell_text)
128
134
  return " ".join(parts)
129
135
 
130
- if isinstance(item, TextItem) and item.text:
136
+ if isinstance(item, TextItem) and item.self_ref not in excluded_refs and item.text:
131
137
  parts.append(item.text)
132
138
 
133
139
  if isinstance(item, NodeItem):
134
140
  for child_ref in item.children:
135
141
  child = child_ref.resolve(doc=doc)
136
- child_text = _collect_subtree_text(child, doc)
142
+ child_text = _collect_subtree_text(child, doc, excluded_refs)
137
143
  if child_text:
138
144
  parts.append(child_text)
139
145
 
@@ -715,7 +721,7 @@ class MarkdownTableSerializer(BaseTableSerializer):
715
721
  visited: set[str] = kwargs.get("visited") or set()
716
722
  _mark_subtree_visited(item, doc, visited)
717
723
  return create_ser_result(
718
- text=_collect_subtree_text(item, doc),
724
+ text=_collect_subtree_text(item, doc, doc_serializer.get_excluded_refs(**kwargs)),
719
725
  span_source=item,
720
726
  )
721
727
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docling-core
3
- Version: 2.97.1
3
+ Version: 2.97.2
4
4
  Summary: A python library to define and validate data types in Docling.
5
5
  Author-email: Cesar Berrospi Ramis <ceb@zurich.ibm.com>, Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>
6
6
  Maintainer-email: Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>, Cesar Berrospi Ramis <ceb@zurich.ibm.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "docling-core"
3
- version = "2.97.1" # DO NOT EDIT, updated automatically
3
+ version = "2.97.2" # DO NOT EDIT, updated automatically
4
4
  description = "A python library to define and validate data types in Docling."
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]
@@ -795,6 +795,27 @@ def test_roundtrip_nested_list_unordered_in_unordered():
795
795
  assert dt2 == dt
796
796
 
797
797
 
798
+ def test_deserialize_locationless_list_with_empty_item_and_formula():
799
+ doc = _deserialize(
800
+ """
801
+ <doclang>
802
+ <list>
803
+ <ldiv/>
804
+ <ldiv/>
805
+ A.
806
+ <formula>f(x)</formula>
807
+ is odd
808
+ </list>
809
+ </doclang>
810
+ """
811
+ )
812
+
813
+ assert [item.text for item in doc.texts] == ["", "", "A.", "f(x)", "is odd"]
814
+ assert doc.texts[3].label == DocItemLabel.FORMULA
815
+ assert all(not item.prov for item in doc.texts)
816
+ assert "<location" not in _serialize(doc)
817
+
818
+
798
819
  def test_roundtrip_nested_list_ordered_in_ordered():
799
820
  """Test nested ordered list within ordered list."""
800
821
  doc = DoclingDocument(name="t")
@@ -2410,3 +2431,29 @@ def test_unnamed_group_markup_still_wraps_floats() -> None:
2410
2431
  doc = _deserialize(xml, validate=False)
2411
2432
  assert doc.groups == []
2412
2433
  assert len(doc.pictures) == 1
2434
+
2435
+
2436
+ def test_default_resolution_sets_page_coordinate_space():
2437
+ """<default_resolution> establishes the page size so locations are not clamped."""
2438
+ import warnings
2439
+
2440
+ xml = (
2441
+ '<doclang version="0.7">'
2442
+ '<head><default_resolution width="2048" height="2048"/></head>'
2443
+ "<text>"
2444
+ '<location value="27"/><location value="14"/>'
2445
+ '<location value="1316"/><location value="1900"/>'
2446
+ "<content>Hello</content></text>"
2447
+ "</doclang>"
2448
+ )
2449
+ doc = _deserialize(xml, validate=False)
2450
+
2451
+ assert doc.pages[1].size.width == 2048
2452
+ assert doc.pages[1].size.height == 2048
2453
+ bbox = doc.texts[0].prov[0].bbox
2454
+ assert (bbox.l, bbox.t, bbox.r, bbox.b) == (27, 14, 1316, 1900)
2455
+
2456
+ with warnings.catch_warnings(record=True) as caught:
2457
+ warnings.simplefilter("always")
2458
+ DoclingDocument.validate_document(doc)
2459
+ assert [w for w in caught if "clamping" in str(w.message)] == []
File without changes
File without changes
File without changes