PyMuPDF 1.23.23__tar.gz → 1.23.25__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 (171) hide show
  1. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/PKG-INFO +1 -1
  2. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/changes.txt +27 -0
  3. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/pipcl.py +40 -35
  4. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/scripts/sysinstall.py +98 -49
  5. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/scripts/test.py +3 -2
  6. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/setup.py +1 -1
  7. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src/__init__.py +10 -9
  8. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src/table.py +90 -46
  9. PyMuPDF-1.23.25/src_classic/version.i +7 -0
  10. PyMuPDF-1.23.25/tests/resources/test_3179.pdf +0 -0
  11. PyMuPDF-1.23.25/tests/resources/test_3186.pdf +0 -0
  12. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_geometry.py +7 -0
  13. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_optional_content.py +65 -0
  14. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_tables.py +37 -0
  15. PyMuPDF-1.23.25/tests/test_textextract.py +241 -0
  16. PyMuPDF-1.23.23/src_classic/version.i +0 -7
  17. PyMuPDF-1.23.23/tests/test_textextract.py +0 -218
  18. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/COPYING +0 -0
  19. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/MANIFEST.in +0 -0
  20. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/README.md +0 -0
  21. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/READMErb.md +0 -0
  22. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/mupdf.tgz +0 -0
  23. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/pyproject.toml +0 -0
  24. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/pytest.ini +0 -0
  25. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/scripts/gh_release.py +0 -0
  26. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src/__main__.py +0 -0
  27. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src/extra.i +0 -0
  28. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src/fitz.py +0 -0
  29. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src/utils.py +0 -0
  30. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/__init__.py +0 -0
  31. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/__main__.py +0 -0
  32. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/_config.h +0 -0
  33. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/fitz_old.i +0 -0
  34. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-annot.i +0 -0
  35. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-convert.i +0 -0
  36. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-defines.i +0 -0
  37. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-devices.i +0 -0
  38. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-fields.i +0 -0
  39. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-fileobj.i +0 -0
  40. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-geo-c.i +0 -0
  41. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-geo-py.i +0 -0
  42. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-globals.i +0 -0
  43. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-other.i +0 -0
  44. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-pdfinfo.i +0 -0
  45. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-pixmap.i +0 -0
  46. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-portfolio.i +0 -0
  47. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-python.i +0 -0
  48. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-select.i +0 -0
  49. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-stext.i +0 -0
  50. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/helper-xobject.i +0 -0
  51. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/src_classic/utils.py +0 -0
  52. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/README.md +0 -0
  53. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/001003ED.pdf +0 -0
  54. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/1.pdf +0 -0
  55. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/2.pdf +0 -0
  56. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/2201.00069.pdf +0 -0
  57. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/3.pdf +0 -0
  58. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/4.pdf +0 -0
  59. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/Bezier.epub +0 -0
  60. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/PragmaticaC.otf +0 -0
  61. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/bug1945.pdf +0 -0
  62. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/bug1971.pdf +0 -0
  63. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/chinese-tables.pdf +0 -0
  64. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/chinese-tables.pickle +0 -0
  65. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/circular-toc.pdf +0 -0
  66. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/cython.pdf +0 -0
  67. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/cython.pickle +0 -0
  68. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/full_toc.txt +0 -0
  69. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/full_toc2.txt +0 -0
  70. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/github_sample.pdf +0 -0
  71. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/has-bad-fonts.pdf +0 -0
  72. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/image-file1.pdf +0 -0
  73. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/img-transparent.png +0 -0
  74. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/joined.pdf +0 -0
  75. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/metadata.txt +0 -0
  76. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/mupdf_explored.pdf +0 -0
  77. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/nur-ruhig.jpg +0 -0
  78. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/quad-calc-0.pdf +0 -0
  79. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/simple_toc.txt +0 -0
  80. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/small-table.pdf +0 -0
  81. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/strict-yes-no.pdf +0 -0
  82. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/symbol-list.pdf +0 -0
  83. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/symbols.txt +0 -0
  84. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test-2333.pdf +0 -0
  85. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test-2462.pdf +0 -0
  86. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test-3143.pdf +0 -0
  87. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test-3150.pdf +0 -0
  88. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test2093.pdf +0 -0
  89. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test2182.pdf +0 -0
  90. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test2238.pdf +0 -0
  91. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_1645_expected.pdf +0 -0
  92. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_1645_expected_1.22.pdf +0 -0
  93. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_1645_expected_1.24.pdf +0 -0
  94. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_1824.pdf +0 -0
  95. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2108.pdf +0 -0
  96. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2270.pdf +0 -0
  97. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2533.pdf +0 -0
  98. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2548.pdf +0 -0
  99. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2553-2.pdf +0 -0
  100. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2553.pdf +0 -0
  101. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2596.pdf +0 -0
  102. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2608_expected +0 -0
  103. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2634.pdf +0 -0
  104. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2635.pdf +0 -0
  105. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2645_1.pdf +0 -0
  106. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2645_2.pdf +0 -0
  107. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2645_3.pdf +0 -0
  108. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2710.pdf +0 -0
  109. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2730.pdf +0 -0
  110. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2742.pdf +0 -0
  111. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2788.pdf +0 -0
  112. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2791_content.pdf +0 -0
  113. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2791_coverpage.pdf +0 -0
  114. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2861.pdf +0 -0
  115. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2871.pdf +0 -0
  116. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2885.pdf +0 -0
  117. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2904.pdf +0 -0
  118. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2907.pdf +0 -0
  119. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2954.pdf +0 -0
  120. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2957_1.pdf +0 -0
  121. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2957_2.pdf +0 -0
  122. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2969.pdf +0 -0
  123. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_2979.pdf +0 -0
  124. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_3058.pdf +0 -0
  125. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_3062.pdf +0 -0
  126. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_3070.pdf +0 -0
  127. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_3072.pdf +0 -0
  128. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_3087.pdf +0 -0
  129. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_annot_file_info.pdf +0 -0
  130. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/test_delete_image.pdf +0 -0
  131. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/type3font.pdf +0 -0
  132. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/v110-changes.pdf +0 -0
  133. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/resources/widgettest.pdf +0 -0
  134. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/run_compound.py +0 -0
  135. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_2548.py +0 -0
  136. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_2634.py +0 -0
  137. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_2791.py +0 -0
  138. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_2904.py +0 -0
  139. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_2907.py +0 -0
  140. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_annots.py +0 -0
  141. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_badfonts.py +0 -0
  142. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_crypting.py +0 -0
  143. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_docs_samples.py +0 -0
  144. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_drawings.py +0 -0
  145. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_embeddedfiles.py +0 -0
  146. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_extractimage.py +0 -0
  147. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_flake8.py +0 -0
  148. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_font.py +0 -0
  149. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_general.py +0 -0
  150. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_imagebbox.py +0 -0
  151. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_insertimage.py +0 -0
  152. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_insertpdf.py +0 -0
  153. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_linequad.py +0 -0
  154. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_metadata.py +0 -0
  155. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_named_links.py +0 -0
  156. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_nonpdf.py +0 -0
  157. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_object_manipulation.py +0 -0
  158. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_page_links.py +0 -0
  159. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_pagedelete.py +0 -0
  160. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_pagelabels.py +0 -0
  161. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_pixmap.py +0 -0
  162. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_showpdfpage.py +0 -0
  163. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_story.py +0 -0
  164. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_tesseract.py +0 -0
  165. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_textbox.py +0 -0
  166. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_textsearch.py +0 -0
  167. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_toc.py +0 -0
  168. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_widgets.py +0 -0
  169. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/tests/test_word_delimiters.py +0 -0
  170. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/valgrind.supp +0 -0
  171. {PyMuPDF-1.23.23 → PyMuPDF-1.23.25}/wdev.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyMuPDF
3
- Version: 1.23.23
3
+ Version: 1.23.25
4
4
  Summary: A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.
5
5
  Description-Content-Type: text/markdown
6
6
  Author: Artifex
@@ -2,6 +2,33 @@ Change Log
2
2
  ==========
3
3
 
4
4
 
5
+ **Changes in version 1.23.25 (2024-02-20)**
6
+
7
+ * Fixed issues:
8
+
9
+ * **Fixed** `3182 <https://github.com/pymupdf/PyMuPDF/issues/3182>`_: Pixmap.invert_irect argument type error
10
+ * **Fixed** `3186 <https://github.com/pymupdf/PyMuPDF/issues/3186>`_: extractText() extracts broken text from pdf
11
+ * **Fixed** `3191 <https://github.com/pymupdf/PyMuPDF/issues/3191>`_: Error on .find_tables()
12
+
13
+ * Other:
14
+
15
+ * When building, be able to specify python-config directly, with environment
16
+ variable `PIPCL_PYTHON_CONFIG`.
17
+
18
+
19
+ **Changes in version 1.23.24 (2024-02-19)**
20
+
21
+ * Fixed issues:
22
+
23
+ * **Fixed** `3148 <https://github.com/pymupdf/PyMuPDF/issues/3148>`_: Table extraction - vertical text not handled correctly
24
+ * **Fixed** `3179 <https://github.com/pymupdf/PyMuPDF/issues/3179>`_: Table Detection: Incorrect Separation of Vector Graphics Clusters
25
+ * **Fixed** `3180 <https://github.com/pymupdf/PyMuPDF/issues/3180>`_: Cannot show optional content group: AttributeError: module 'fitz.mupdf' has no attribute 'pdf_array_push_drop'
26
+
27
+ * Other:
28
+
29
+ * Be able to test system install using `sudo pip install` instead of a venv.
30
+
31
+
5
32
  **Changes in version 1.23.23 (2024-02-18)**
6
33
 
7
34
  * Fixed issues:
@@ -1769,6 +1769,9 @@ class PythonFlags:
1769
1769
  Compile/link flags for the current python, for example the include path
1770
1770
  needed to get `Python.h`.
1771
1771
 
1772
+ The 'PIPCL_PYTHON_CONFIG' environment variable allows to override
1773
+ the location of the python-config executable.
1774
+
1772
1775
  Members:
1773
1776
  .includes:
1774
1777
  String containing compiler flags for include paths.
@@ -1789,43 +1792,45 @@ class PythonFlags:
1789
1792
  self.ldflags = f'-L {_lib_dir}'
1790
1793
 
1791
1794
  else:
1792
- # We use python-config which appears to work better than pkg-config
1793
- # because it copes with multiple installed python's, e.g.
1794
- # manylinux_2014's /opt/python/cp*-cp*/bin/python*.
1795
- #
1796
- # But... on non-macos it seems that we should not attempt to specify
1797
- # libpython on the link command. The manylinux docker containers
1798
- # don't actually contain libpython.so, and it seems that this
1799
- # deliberate. And the link command runs ok.
1800
- #
1801
- python_exe = os.path.realpath( sys.executable)
1802
- if darwin():
1803
- # Basic install of dev tools with `xcode-select --install` doesn't
1804
- # seem to provide a `python3-config` or similar, but there is a
1805
- # `python-config.py` accessible via sysconfig.
1795
+ python_config = os.environ.get("PIPCL_PYTHON_CONFIG")
1796
+ if not python_config:
1797
+ # We use python-config which appears to work better than pkg-config
1798
+ # because it copes with multiple installed python's, e.g.
1799
+ # manylinux_2014's /opt/python/cp*-cp*/bin/python*.
1806
1800
  #
1807
- # We try different possibilities and use the last one that
1808
- # works.
1801
+ # But... on non-macos it seems that we should not attempt to specify
1802
+ # libpython on the link command. The manylinux docker containers
1803
+ # don't actually contain libpython.so, and it seems that this
1804
+ # deliberate. And the link command runs ok.
1809
1805
  #
1810
- python_config = None
1811
- for pc in (
1812
- f'python3-config',
1813
- f'{sys.executable} {sysconfig.get_config_var("srcdir")}/python-config.py',
1814
- f'{python_exe}-config',
1815
- ):
1816
- e = subprocess.run(
1817
- f'{pc} --includes',
1818
- shell=1,
1819
- stdout=subprocess.DEVNULL,
1820
- stderr=subprocess.DEVNULL,
1821
- check=0,
1822
- ).returncode
1823
- log1(f'{e=} from {pc!r}.')
1824
- if e == 0:
1825
- python_config = pc
1826
- assert python_config, f'Cannot find python-config'
1827
- else:
1828
- python_config = f'{python_exe}-config'
1806
+ python_exe = os.path.realpath( sys.executable)
1807
+ if darwin():
1808
+ # Basic install of dev tools with `xcode-select --install` doesn't
1809
+ # seem to provide a `python3-config` or similar, but there is a
1810
+ # `python-config.py` accessible via sysconfig.
1811
+ #
1812
+ # We try different possibilities and use the last one that
1813
+ # works.
1814
+ #
1815
+ python_config = None
1816
+ for pc in (
1817
+ f'python3-config',
1818
+ f'{sys.executable} {sysconfig.get_config_var("srcdir")}/python-config.py',
1819
+ f'{python_exe}-config',
1820
+ ):
1821
+ e = subprocess.run(
1822
+ f'{pc} --includes',
1823
+ shell=1,
1824
+ stdout=subprocess.DEVNULL,
1825
+ stderr=subprocess.DEVNULL,
1826
+ check=0,
1827
+ ).returncode
1828
+ log1(f'{e=} from {pc!r}.')
1829
+ if e == 0:
1830
+ python_config = pc
1831
+ assert python_config, f'Cannot find python-config'
1832
+ else:
1833
+ python_config = f'{python_exe}-config'
1829
1834
  log1(f'Using {python_config=}.')
1830
1835
  try:
1831
1836
  self.includes = run( f'{python_config} --includes', capture=1).strip()
@@ -24,28 +24,39 @@ Args:
24
24
  --mupdf-git <git_args>
25
25
  Get or update `mupdf_dir` using git. If `mupdf_dir` already
26
26
  exists we run `git pull` in it; otherwise we run `git
27
- clone` with `git_args`. For example:
27
+ clone` with `<git_args> <mupdf_dir>`. For example:
28
28
  --mupdf-git "--branch master https://github.com/ArtifexSoftware/mupdf.git"
29
- --pymupdf-dir <pymupdf_dir>
30
- Path of PyMuPDF checkout; default is 'PyMuPDF'.
29
+ --mupdf-so-mode <mode>
30
+ Used with `install -m <mode> ...` when installing MuPDF. For example
31
+ `--mupdf-so-mode 744`.
32
+ --packages 0|1
33
+ If 1 (the default) we install required system packages such as
34
+ `libfreetype-dev`.
35
+ --pip 0|venv|sudo
36
+ Whether/how to install Python packages.
37
+ If '0' we assume required packages are already available.
38
+ If 'sudo' we install required Python packages using `sudo pip install
39
+ ...`.
40
+ If 'venv' (the default) we install Python packages and run installer
41
+ and test commands inside venv's.
31
42
  --prefix:
32
43
  Directory within `root`; default is `/usr/local`. Must start with `/`.
44
+ --pymupdf-dir <pymupdf_dir>
45
+ Path of PyMuPDF checkout; default is 'PyMuPDF'.
33
46
  --root <root>
34
47
  Root of install directory; default is `/`.
35
48
  --tesseract5 0|1
36
49
  If 1 (the default), we force installation of libtesseract-dev version
37
50
  5 (which is not available as a default package in Ubuntu-22.04) from
38
51
  package repository ppa:alex-p/tesseract-ocr-devel.
39
- --test-venv <venv_path>
40
- Run tests in specified venv; the default is a hard-coded venv name. The
41
- venv will be created and required packages installed using `pip`. If
42
- `venv-path` is empty string, we do not create or use a venv, and will
43
- instead attempt to install required packages with `pip` in the current
44
- Python environment.
52
+ --test-venv <test_venv>
53
+ Set the name of the venv in which we run tests (only with `--pip
54
+ venv`); the default is a hard-coded venv name. The venv will be
55
+ created, and required packages installed using `pip`.
45
56
  --use-installer 0|1
46
57
  If 1 (the default), we use `python -m installer` to install PyMuPDF
47
- from a generated wheel. Otherwise we use `pip install`, which refuses
48
- to do a system install with `--root /`, referencing PEP-668.
58
+ from a generated wheel. [Otherwise we use `pip install`, which refuses
59
+ to do a system install with `--root /`, referencing PEP-668.]
49
60
  -m 0|1
50
61
  If 1 (the default) we build and install MuPDF, otherwise we just show
51
62
  what command we would have run.
@@ -61,12 +72,14 @@ To only show what commands would be run, but not actually run them, specify `-m
61
72
  '''
62
73
 
63
74
  import glob
75
+ import multiprocessing
64
76
  import os
65
77
  import platform
66
78
  import subprocess
67
79
  import sys
68
80
  import sysconfig
69
81
 
82
+ import test as test_py
70
83
 
71
84
  # Requirements for a system build and install:
72
85
  #
@@ -107,6 +120,8 @@ def main():
107
120
  mupdf = True
108
121
  mupdf_dir = 'mupdf'
109
122
  mupdf_git = None
123
+ mupdf_so_mode = None
124
+ packages = True
110
125
  prefix = '/usr/local'
111
126
  pymupdf = True
112
127
  pymupdf_dir = os.path.abspath( f'{__file__}/../..')
@@ -114,6 +129,7 @@ def main():
114
129
  tesseract5 = True
115
130
  test = True
116
131
  test_venv = 'venv-pymupdf-sysinstall-test'
132
+ pip = 'venv'
117
133
 
118
134
  # Parse command-line.
119
135
  #
@@ -128,12 +144,15 @@ def main():
128
144
  return
129
145
  elif arg == '--mupdf-dir': mupdf_dir = next(args)
130
146
  elif arg == '--mupdf-git': mupdf_git = next(args)
147
+ elif arg == '--mupdf-so-mode': mupdf_so_mode = next(args)
148
+ elif arg == '--packages': packages = int(next(args))
131
149
  elif arg == '--prefix': prefix = next(args)
132
150
  elif arg == '--pymupdf-dir': pymupdf_dir = next(args)
133
151
  elif arg == '--root': root = next(args)
134
152
  elif arg == '--tesseract5': tesseract5 = int(next(args))
135
153
  elif arg == '--test-venv': test_venv = next(args)
136
154
  elif arg == '--use-installer': use_installer = int(next(args))
155
+ elif arg == '--pip': pip = next(args)
137
156
  elif arg == '-m': mupdf = int(next(args))
138
157
  elif arg == '-p': pymupdf = int(next(args))
139
158
  elif arg == '-t': test = int(next(args))
@@ -141,6 +160,8 @@ def main():
141
160
  assert 0, f'Unrecognised arg: {arg!r}'
142
161
 
143
162
  assert prefix.startswith('/')
163
+ pip_values = ('0', 'sudo', 'venv')
164
+ assert pip in pip_values, f'Unrecognised --pip value {pip!r} should be one of: {pip_values!r}'
144
165
  root = os.path.abspath(root)
145
166
  root_prefix = f'{root}{prefix}'.replace('//', '/')
146
167
 
@@ -161,44 +182,54 @@ def main():
161
182
  print(f'## Clone MuPDF into {mupdf_dir}.')
162
183
  run(f'git clone --recursive --depth 1 --shallow-submodules {mupdf_git} {mupdf_dir}')
163
184
 
164
- # Install required system packages. We assume a Debian package system.
165
- #
166
- print('## Install system packages required by MuPDF.')
167
- run(f'sudo apt update')
168
- run(f'sudo apt install {" ".join(g_sys_packages)}')
169
- # Ubuntu-22.04 has freeglut3-dev, not libglut-dev.
170
- run(f'sudo apt install libglut-dev | sudo apt install freeglut3-dev')
171
- if tesseract5:
172
- print(f'## Force installation of libtesseract-dev version 5.')
173
- # https://stackoverflow.com/questions/76834972/how-can-i-run-pytesseract-python-library-in-ubuntu-22-04
185
+ if packages:
186
+ # Install required system packages. We assume a Debian package system.
174
187
  #
175
- run('sudo apt install -y software-properties-common')
176
- run('sudo add-apt-repository ppa:alex-p/tesseract-ocr-devel')
177
- run('sudo apt update')
178
- run('sudo apt install -y libtesseract-dev')
179
- else:
180
- run('sudo apt install libtesseract-dev')
188
+ print('## Install system packages required by MuPDF.')
189
+ run(f'sudo apt update')
190
+ run(f'sudo apt install {" ".join(g_sys_packages)}')
191
+ # Ubuntu-22.04 has freeglut3-dev, not libglut-dev.
192
+ run(f'sudo apt install libglut-dev | sudo apt install freeglut3-dev')
193
+ if tesseract5:
194
+ print(f'## Force installation of libtesseract-dev version 5.')
195
+ # https://stackoverflow.com/questions/76834972/how-can-i-run-pytesseract-python-library-in-ubuntu-22-04
196
+ #
197
+ run('sudo apt install -y software-properties-common')
198
+ run('sudo add-apt-repository ppa:alex-p/tesseract-ocr-devel')
199
+ run('sudo apt update')
200
+ run('sudo apt install -y libtesseract-dev')
201
+ else:
202
+ run('sudo apt install libtesseract-dev')
181
203
 
182
204
  # Build+install MuPDF. We use mupd:Makefile's install-shared-python target.
183
205
  #
206
+ if pip == 'sudo':
207
+ print('## Installing Python packages required for building MuPDF and PyMuPDF.')
208
+ run(f'sudo pip install --upgrade pip')
209
+ names = (''
210
+ + test_py.get_pyproject_required(os.path.abspath(f'{__file__}/../../pyproject.toml'))
211
+ + ' '
212
+ + test_py.get_pyproject_required(os.path.abspath(f'{mupdf_dir}/pyproject.toml'))
213
+ )
214
+ run(f'sudo pip install {names}')
215
+
184
216
  print('## Build and install MuPDF.')
185
- if 1:
186
- # Current MuPDF creates softlinks with `ln -s` which breaks if there
187
- # was a previous build; it should do `ln -sf`. We make things work by
188
- # deleting any existing softlinks here.
189
- run(f'rm {root_prefix}/lib/libmupdf.so || true')
190
- run(f'rm {root_prefix}/lib/libmupdfcpp.so || true')
191
217
  command = f'cd {mupdf_dir}'
192
218
  command += f' && {sudo}make'
219
+ command += f' -j {multiprocessing.cpu_count()}'
193
220
  #command += f' EXE_LDFLAGS=-Wl,--trace' # Makes linker generate diagnostics as it runs.
194
221
  command += f' DESTDIR={root}'
195
222
  command += f' HAVE_LEPTONICA=yes'
196
223
  command += f' HAVE_TESSERACT=yes'
197
224
  command += f' USE_SYSTEM_LIBS=yes'
225
+ command += f' VENV_FLAG={"--venv" if pip == "venv" else ""}'
226
+ if mupdf_so_mode:
227
+ command += f' SO_INSTALL_MODE={mupdf_so_mode}'
198
228
  command += f' build_prefix=system-libs-'
199
229
  command += f' prefix={prefix}'
200
230
  command += f' verbose=yes'
201
231
  command += f' install-shared-python'
232
+ command += f' INSTALL_MODE=755'
202
233
  run( command)
203
234
 
204
235
  # Build+install PyMuPDF.
@@ -217,23 +248,34 @@ def main():
217
248
  env += f'PYMUPDF_SETUP_IMPLEMENTATIONS=b' # Only build the rebased implementation.
218
249
  if use_installer:
219
250
  print(f'## Building wheel.')
251
+ if pip == 'venv':
252
+ venv_name = 'venv-pymupdf-sysinstall'
220
253
  run(f'pwd')
221
254
  run(f'rm dist/* || true')
222
- run(f'{env} pip wheel -vv -w dist {os.path.abspath(pymupdf_dir)}')
255
+ if pip == 'venv':
256
+ run(f'{sys.executable} -m venv {venv_name}')
257
+ run(f'. {venv_name}/bin/activate && pip install --upgrade pip')
258
+ run(f'. {venv_name}/bin/activate && pip install --upgrade installer')
259
+ run(f'{env} {venv_name}/bin/python -m pip wheel -vv -w dist {os.path.abspath(pymupdf_dir)}')
260
+ elif pip == 'sudo':
261
+ run(f'sudo pip install --upgrade pip')
262
+ run(f'sudo pip install installer')
263
+ run(f'{env} pip wheel -vv -w dist {os.path.abspath(pymupdf_dir)}')
264
+ else:
265
+ log(f'Not installing "installer" because {pip=}.')
223
266
  wheel = glob.glob(f'dist/*')
224
267
  assert len(wheel) == 1, f'{wheel=}'
225
268
  wheel = wheel[0]
226
269
  print(f'## Installing wheel using `installer`.')
227
- venv = 'venv-pymupdf-sysinstall'
228
- run(f'{sys.executable} -m venv {venv}')
229
- run(f'. {venv}/bin/activate && pip install --upgrade pip')
230
- run(f'. {venv}/bin/activate && pip install --upgrade installer')
231
270
  pv = '.'.join(platform.python_version_tuple()[:2])
232
271
  p = f'{root_prefix}/lib/python{pv}'
233
272
  # `python -m installer` fails to overwrite existing files.
234
273
  run(f'{sudo}rm -r {p}/site-packages/fitz || true')
235
274
  run(f'{sudo}rm -r {p}/site-packages/PyMuPDF-*.dist-info || true')
236
- run(f'{sudo}{venv}/bin/python -m installer --destdir {root} --prefix {prefix} {wheel}')
275
+ if pip == 'venv':
276
+ run(f'{sudo}{venv_name}/bin/python -m installer --destdir {root} --prefix {prefix} {wheel}')
277
+ else:
278
+ run(f'{sudo}{sys.executable} -m installer --destdir {root} --prefix {prefix} {wheel}')
237
279
  # It seems that MuPDF Python bindings are installed into
238
280
  # `.../dist-packages` (from mupdf:Mafile's call of `$(shell python3
239
281
  # -c "import sysconfig; print(sysconfig.get_path('platlib'))")` while
@@ -267,7 +309,7 @@ def main():
267
309
  del sys.path[0]
268
310
  pythonpath = pipcl.install_dir(root)
269
311
 
270
- # Show contents of installation director. This is very slow on github,
312
+ # Show contents of installation directory. This is very slow on github,
271
313
  # where /usr/local contains lots of things.
272
314
  #run(f'find {root_prefix}|sort')
273
315
 
@@ -277,20 +319,27 @@ def main():
277
319
  def run(command):
278
320
  return run_command(command, doit=test)
279
321
  import gh_release
280
- # Create venv.
281
- run(f'{sys.executable} -m venv {test_venv}')
282
- # Install required packages.
283
- command = f'. {test_venv}/bin/activate'
284
- command += f' && pip install --upgrade pip'
285
- command += f' && pip install --upgrade {gh_release.test_packages}'
286
- run(command)
322
+ if pip == 'venv':
323
+ # Create venv.
324
+ run(f'{sys.executable} -m venv {test_venv}')
325
+ # Install required packages.
326
+ command = f'. {test_venv}/bin/activate'
327
+ command += f' && pip install --upgrade pip'
328
+ command += f' && pip install --upgrade {gh_release.test_packages}'
329
+ run(command)
330
+ elif pip == 'sudo':
331
+ run(f'sudo pip install --upgrade {gh_release.test_packages}')
332
+ else:
333
+ log(f'Not installing packages for testing because {pip=}.')
287
334
  # Run pytest.
288
335
  #
289
336
  # We need to set PYTHONPATH and LD_LIBRARY_PATH. In particular we
290
337
  # use pipcl.install_dir() to find where pipcl will have installed
291
338
  # PyMuPDF.
292
- command = f'. {test_venv}/bin/activate'
293
- command += f' && LD_LIBRARY_PATH={root_prefix}/lib PYTHONPATH={pythonpath}'
339
+ command = ''
340
+ if pip == 'venv':
341
+ command += f'. {test_venv}/bin/activate &&'
342
+ command += f' LD_LIBRARY_PATH={root_prefix}/lib PYTHONPATH={pythonpath}'
294
343
  command += f' pytest -k "not test_color_count and not test_3050" {pymupdf_dir}'
295
344
  run(command)
296
345
 
@@ -410,12 +410,13 @@ def test(
410
410
  log('\n' + venv_info(pytest_args=f'{pytest_options} {pytest_arg}'))
411
411
 
412
412
 
413
- def get_pyproject_required():
413
+ def get_pyproject_required(ppt=None):
414
414
  '''
415
415
  Returns space-separated names of required packages in pyproject.toml. We
416
416
  do not do a proper parse and rely on the packages being in a single line.
417
417
  '''
418
- ppt = os.path.abspath(f'{__file__}/../../pyproject.toml')
418
+ if ppt is None:
419
+ ppt = os.path.abspath(f'{__file__}/../../pyproject.toml')
419
420
  with open(ppt) as f:
420
421
  for line in f:
421
422
  m = re.match('^requires = \\[(.*)\\]$', line)
@@ -1072,7 +1072,7 @@ with open( f'{g_root}/READMErb.md', encoding='utf-8') as f:
1072
1072
  # We generate different wheels depending on g_flavour.
1073
1073
  #
1074
1074
 
1075
- version = '1.23.23'
1075
+ version = '1.23.25'
1076
1076
  version_b = '1.23.22'
1077
1077
 
1078
1078
  tag_python = None
@@ -16259,7 +16259,7 @@ def JM_invert_pixmap_rect( dest, b):
16259
16259
 
16260
16260
  def JM_irect_from_py(r):
16261
16261
  '''
16262
- PySequence to fz_irect. Default: infinite irect
16262
+ PySequence to mupdf.FzIrect. Default: infinite irect
16263
16263
  '''
16264
16264
  if isinstance(r, mupdf.FzIrect):
16265
16265
  return r
@@ -16267,7 +16267,11 @@ def JM_irect_from_py(r):
16267
16267
  r = mupdf.FzIrect( r.x0, r.y0, r.x1, r.y1)
16268
16268
  return r
16269
16269
  if isinstance(r, Rect):
16270
- ret = mupdf.fz_make_irect(r.x0, r.y0, r.x1, r.y1)
16270
+ ret = mupdf.FzRect(r.x0, r.y0, r.x1, r.y1)
16271
+ ret = mupdf.FzIrect(ret) # Uses fz_irect_from_rect().
16272
+ return ret
16273
+ if isinstance(r, mupdf.FzRect):
16274
+ ret = mupdf.FzIrect(r) # Uses fz_irect_from_rect().
16271
16275
  return ret
16272
16276
  if not r or not PySequence_Check(r) or PySequence_Size(r) != 4:
16273
16277
  return mupdf.FzIrect(mupdf.fz_infinite_irect)
@@ -16275,7 +16279,7 @@ def JM_irect_from_py(r):
16275
16279
  for i in range(4):
16276
16280
  f[i] = r[i]
16277
16281
  if f[i] is None:
16278
- return mupdf.FzRect(mupdf.fz_infinite_irect)
16282
+ return mupdf.FzIrect(mupdf.fz_infinite_irect)
16279
16283
  if f[i] < FZ_MIN_INF_RECT:
16280
16284
  f[i] = FZ_MIN_INF_RECT
16281
16285
  if f[i] > FZ_MAX_INF_RECT:
@@ -17437,7 +17441,7 @@ def JM_set_ocg_arrays_imp(arr, list_):
17437
17441
  # Not found.
17438
17442
  continue
17439
17443
  obj = mupdf.pdf_new_indirect(pdf, xref, 0)
17440
- mupdf.pdf_array_push_drop(arr, obj)
17444
+ mupdf.pdf_array_push(arr, obj)
17441
17445
 
17442
17446
 
17443
17447
  def JM_set_resource_property(ref, name, xref):
@@ -17814,9 +17818,6 @@ def PyUnicode_DecodeRawUnicodeEscape(s, errors='strict'):
17814
17818
  elif isinstance(s, bytes):
17815
17819
  rc = s[:]
17816
17820
  ret = rc.decode('raw_unicode_escape', errors=errors)
17817
- z = ret.find(chr(0))
17818
- if z >= 0:
17819
- ret = ret[:z]
17820
17821
  return ret
17821
17822
 
17822
17823
 
@@ -21729,8 +21730,8 @@ def int_rc(text):
21729
21730
  return int(text)
21730
21731
 
21731
21732
  VersionFitz = "1.23.10" # MuPDF version.
21732
- VersionBind = "1.23.23" # PyMuPDF version.
21733
- VersionDate = "2024-02-18 00:00:01"
21733
+ VersionBind = "1.23.25" # PyMuPDF version.
21734
+ VersionDate = "2024-02-20 00:00:01"
21734
21735
  VersionDate2 = VersionDate.replace('-', '').replace(' ', '').replace(':', '')
21735
21736
  version = (VersionBind, VersionFitz, VersionDate2)
21736
21737
  pymupdf_version_tuple = tuple( [int_rc(i) for i in VersionBind.split('.')])