PyMuPDF 1.26.0__tar.gz → 1.26.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 (303) hide show
  1. {pymupdf-1.26.0 → pymupdf-1.26.1}/PKG-INFO +1 -1
  2. {pymupdf-1.26.0 → pymupdf-1.26.1}/changes.txt +24 -1
  3. {pymupdf-1.26.0 → pymupdf-1.26.1}/pipcl.py +195 -48
  4. {pymupdf-1.26.0 → pymupdf-1.26.1}/scripts/test.py +616 -314
  5. {pymupdf-1.26.0 → pymupdf-1.26.1}/setup.py +37 -20
  6. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/__init__.py +118 -626
  7. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/utils.py +2 -3
  8. pymupdf-1.26.1/tests/resources/test-rewrite-images.pdf +0 -0
  9. pymupdf-1.26.1/tests/resources/test_2608_expected +14 -0
  10. pymupdf-1.26.1/tests/resources/test_3624_expected.png +0 -0
  11. pymupdf-1.26.1/tests/resources/test_4412.pdf +0 -0
  12. pymupdf-1.26.1/tests/resources/test_4503.pdf +0 -0
  13. pymupdf-1.26.1/tests/resources/test_4546.pdf +0 -0
  14. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/run_compound.py +14 -0
  15. pymupdf-1.26.1/tests/test_4520.py +11 -0
  16. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_font.py +6 -1
  17. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_general.py +23 -3
  18. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_insertpdf.py +16 -0
  19. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_memory.py +3 -3
  20. pymupdf-1.26.1/tests/test_rewrite_images.py +15 -0
  21. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_textextract.py +93 -0
  22. {pymupdf-1.26.0 → pymupdf-1.26.1}/wdev.py +65 -13
  23. pymupdf-1.26.0/tests/resources/test_3624_expected.png +0 -0
  24. {pymupdf-1.26.0 → pymupdf-1.26.1}/COPYING +0 -0
  25. {pymupdf-1.26.0 → pymupdf-1.26.1}/README.md +0 -0
  26. {pymupdf-1.26.0 → pymupdf-1.26.1}/READMEb.md +0 -0
  27. {pymupdf-1.26.0 → pymupdf-1.26.1}/READMEd.md +0 -0
  28. {pymupdf-1.26.0 → pymupdf-1.26.1}/pyproject.toml +0 -0
  29. {pymupdf-1.26.0 → pymupdf-1.26.1}/pytest.ini +0 -0
  30. {pymupdf-1.26.0 → pymupdf-1.26.1}/scripts/gh_release.py +0 -0
  31. {pymupdf-1.26.0 → pymupdf-1.26.1}/scripts/sysinstall.py +0 -0
  32. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/__main__.py +0 -0
  33. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/_apply_pages.py +0 -0
  34. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/_wxcolors.py +0 -0
  35. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/extra.i +0 -0
  36. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/fitz___init__.py +0 -0
  37. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/fitz_table.py +0 -0
  38. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/fitz_utils.py +0 -0
  39. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/pymupdf.py +0 -0
  40. {pymupdf-1.26.0 → pymupdf-1.26.1}/src/table.py +0 -0
  41. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/__init__.py +0 -0
  42. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/__main__.py +0 -0
  43. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/_config.h +0 -0
  44. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/fitz_old.i +0 -0
  45. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-annot.i +0 -0
  46. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-convert.i +0 -0
  47. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-defines.i +0 -0
  48. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-devices.i +0 -0
  49. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-fields.i +0 -0
  50. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-fileobj.i +0 -0
  51. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-geo-c.i +0 -0
  52. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-geo-py.i +0 -0
  53. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-globals.i +0 -0
  54. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-other.i +0 -0
  55. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-pdfinfo.i +0 -0
  56. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-pixmap.i +0 -0
  57. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-portfolio.i +0 -0
  58. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-python.i +0 -0
  59. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-select.i +0 -0
  60. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-stext.i +0 -0
  61. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/helper-xobject.i +0 -0
  62. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/utils.py +0 -0
  63. {pymupdf-1.26.0 → pymupdf-1.26.1}/src_classic/version.i +0 -0
  64. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/README.md +0 -0
  65. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/conftest.py +0 -0
  66. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/gentle_compare.py +0 -0
  67. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/001003ED.pdf +0 -0
  68. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/1.pdf +0 -0
  69. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/2.pdf +0 -0
  70. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/2201.00069.pdf +0 -0
  71. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/3.pdf +0 -0
  72. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/4.pdf +0 -0
  73. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/Bezier.epub +0 -0
  74. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/PragmaticaC.otf +0 -0
  75. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/battery-file-22.pdf +0 -0
  76. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/bug1945.pdf +0 -0
  77. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/bug1971.pdf +0 -0
  78. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/chinese-tables.pdf +0 -0
  79. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/chinese-tables.pickle +0 -0
  80. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/circular-toc.pdf +0 -0
  81. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/cms-etc-filled.pdf +0 -0
  82. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/cython.pdf +0 -0
  83. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/cython.pickle +0 -0
  84. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/dotted-gridlines.pdf +0 -0
  85. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/full_toc.txt +0 -0
  86. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/github_sample.pdf +0 -0
  87. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/has-bad-fonts.pdf +0 -0
  88. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/image-file1.pdf +0 -0
  89. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/img-regular.pdf +0 -0
  90. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/img-transparent.pdf +0 -0
  91. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/img-transparent.png +0 -0
  92. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/interfield-calculation.pdf +0 -0
  93. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/joined.pdf +0 -0
  94. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/merge-form1.pdf +0 -0
  95. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/merge-form2.pdf +0 -0
  96. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/metadata.txt +0 -0
  97. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/mupdf_explored.pdf +0 -0
  98. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/nur-ruhig.jpg +0 -0
  99. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/quad-calc-0.pdf +0 -0
  100. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/simple_toc.txt +0 -0
  101. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/small-table.pdf +0 -0
  102. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/strict-yes-no.pdf +0 -0
  103. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/symbol-list.pdf +0 -0
  104. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/symbols.txt +0 -0
  105. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-2333.pdf +0 -0
  106. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-2462.pdf +0 -0
  107. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-2812.pdf +0 -0
  108. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-3143.pdf +0 -0
  109. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-3150.pdf +0 -0
  110. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-3207.pdf +0 -0
  111. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-3591.pdf +0 -0
  112. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-3820.pdf +0 -0
  113. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-4055.pdf +0 -0
  114. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-707448.pdf +0 -0
  115. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-707673.pdf +0 -0
  116. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-E+A.pdf +0 -0
  117. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test-linebreaks.pdf +0 -0
  118. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test2093.pdf +0 -0
  119. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test2182.pdf +0 -0
  120. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test2238.pdf +0 -0
  121. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_1645_expected.pdf +0 -0
  122. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_1824.pdf +0 -0
  123. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2108.pdf +0 -0
  124. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2270.pdf +0 -0
  125. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2533.pdf +0 -0
  126. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2548.pdf +0 -0
  127. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2553-2.pdf +0 -0
  128. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2553.pdf +0 -0
  129. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2596.pdf +0 -0
  130. /pymupdf-1.26.0/tests/resources/test_2608_expected → /pymupdf-1.26.1/tests/resources/test_2608_expected_1.26 +0 -0
  131. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2634.pdf +0 -0
  132. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2635.pdf +0 -0
  133. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2645_1.pdf +0 -0
  134. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2645_2.pdf +0 -0
  135. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2645_3.pdf +0 -0
  136. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2710.pdf +0 -0
  137. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2730.pdf +0 -0
  138. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2742.pdf +0 -0
  139. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2788.pdf +0 -0
  140. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2791_content.pdf +0 -0
  141. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2791_coverpage.pdf +0 -0
  142. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2861.pdf +0 -0
  143. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2871.pdf +0 -0
  144. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2885.pdf +0 -0
  145. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2904.pdf +0 -0
  146. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2907.pdf +0 -0
  147. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2954.pdf +0 -0
  148. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2957_1.pdf +0 -0
  149. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2957_2.pdf +0 -0
  150. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2969.pdf +0 -0
  151. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_2979.pdf +0 -0
  152. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3050_expected.png +0 -0
  153. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3058.pdf +0 -0
  154. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3062.pdf +0 -0
  155. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3070.pdf +0 -0
  156. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3072.pdf +0 -0
  157. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3087.pdf +0 -0
  158. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3179.pdf +0 -0
  159. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3186.pdf +0 -0
  160. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3197.pdf +0 -0
  161. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3357.pdf +0 -0
  162. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3362.pdf +0 -0
  163. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3376.pdf +0 -0
  164. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3448.pdf +0 -0
  165. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3448.pdf-expected.png +0 -0
  166. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3450.pdf +0 -0
  167. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3493.epub +0 -0
  168. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3569.pdf +0 -0
  169. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3594.pdf +0 -0
  170. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3615.epub +0 -0
  171. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3624.pdf +0 -0
  172. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3650.pdf +0 -0
  173. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3654.docx +0 -0
  174. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3677.pdf +0 -0
  175. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3687-3.epub +0 -0
  176. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3687.epub +0 -0
  177. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3705.pdf +0 -0
  178. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3725.pdf +0 -0
  179. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3727.pdf +0 -0
  180. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3780.pdf +0 -0
  181. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3789.pdf +0 -0
  182. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3842.pdf +0 -0
  183. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3848.pdf +0 -0
  184. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3854.pdf +0 -0
  185. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3854_expected.png +0 -0
  186. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf +0 -0
  187. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.0.png +0 -0
  188. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.1.png +0 -0
  189. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.2.png +0 -0
  190. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.3.png +0 -0
  191. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.4.png +0 -0
  192. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.5.png +0 -0
  193. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.6.png +0 -0
  194. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3863.pdf.pdf.7.png +0 -0
  195. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3886.pdf +0 -0
  196. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3887.pdf +0 -0
  197. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3933.pdf +0 -0
  198. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3950.pdf +0 -0
  199. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_3994.pdf +0 -0
  200. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4004.pdf +0 -0
  201. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4017.pdf +0 -0
  202. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4026.pdf +0 -0
  203. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4034.pdf +0 -0
  204. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4043.pdf +0 -0
  205. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4047.pdf +0 -0
  206. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4079.pdf +0 -0
  207. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4079_after.pdf +0 -0
  208. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4079_after_1.25.pdf +0 -0
  209. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4090.pdf +0 -0
  210. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4125.pdf +0 -0
  211. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4139.pdf +0 -0
  212. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4141.pdf +0 -0
  213. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4147.pdf +0 -0
  214. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4179.pdf +0 -0
  215. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4179_expected.png +0 -0
  216. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4180.pdf +0 -0
  217. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4180_expected.png +0 -0
  218. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4182.pdf +0 -0
  219. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4182_expected.png +0 -0
  220. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4224.pdf +0 -0
  221. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4245.pdf +0 -0
  222. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4245_expected.png +0 -0
  223. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4263.pdf +0 -0
  224. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4363.pdf +0 -0
  225. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4415.pdf +0 -0
  226. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4415_out_expected.png +0 -0
  227. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4423.pdf +0 -0
  228. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4435.pdf +0 -0
  229. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4479.pdf +0 -0
  230. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_4505.pdf +0 -0
  231. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_annot_file_info.pdf +0 -0
  232. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_delete_image.pdf +0 -0
  233. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.cbz +0 -0
  234. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.doc +0 -0
  235. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.docx +0 -0
  236. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.epub +0 -0
  237. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.fb2 +0 -0
  238. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.html +0 -0
  239. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.jpg +0 -0
  240. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.mobi +0 -0
  241. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.pdf +0 -0
  242. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.svg +0 -0
  243. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.xhtml +0 -0
  244. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.xml +0 -0
  245. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2.xps +0 -0
  246. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_open2_expected.json +0 -0
  247. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/test_toc_count.pdf +0 -0
  248. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/text-find-ligatures.pdf +0 -0
  249. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/type3font.pdf +0 -0
  250. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/v110-changes.pdf +0 -0
  251. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/resources/widgettest.pdf +0 -0
  252. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_2548.py +0 -0
  253. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_2634.py +0 -0
  254. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_2904.py +0 -0
  255. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_2907.py +0 -0
  256. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_4141.py +0 -0
  257. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_4466.pdf +0 -0
  258. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_4505.py +0 -0
  259. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_annots.py +0 -0
  260. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_badfonts.py +0 -0
  261. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_balance_count.py +0 -0
  262. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_barcode.py +0 -0
  263. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_cluster_drawings.py +0 -0
  264. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_codespell.py +0 -0
  265. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_crypting.py +0 -0
  266. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_docs_samples.py +0 -0
  267. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_drawings.py +0 -0
  268. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_embeddedfiles.py +0 -0
  269. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_extractimage.py +0 -0
  270. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_flake8.py +0 -0
  271. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_geometry.py +0 -0
  272. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_imagebbox.py +0 -0
  273. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_imagemasks.py +0 -0
  274. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_import.py +0 -0
  275. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_insertimage.py +0 -0
  276. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_linebreaks.py +0 -0
  277. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_linequad.py +0 -0
  278. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_metadata.py +0 -0
  279. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_mupdf_regressions.py +0 -0
  280. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_named_links.py +0 -0
  281. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_nonpdf.py +0 -0
  282. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_object_manipulation.py +0 -0
  283. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_objectstreams.py +0 -0
  284. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_optional_content.py +0 -0
  285. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_page_links.py +0 -0
  286. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_pagedelete.py +0 -0
  287. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_pagelabels.py +0 -0
  288. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_pixmap.py +0 -0
  289. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_pylint.py +0 -0
  290. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_remove-rotation.py +0 -0
  291. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_rtl.py +0 -0
  292. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_showpdfpage.py +0 -0
  293. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_spikes.py +0 -0
  294. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_story.py +0 -0
  295. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_tables.py +0 -0
  296. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_tesseract.py +0 -0
  297. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_textbox.py +0 -0
  298. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_textsearch.py +0 -0
  299. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_toc.py +0 -0
  300. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_widgets.py +0 -0
  301. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/test_word_delimiters.py +0 -0
  302. {pymupdf-1.26.0 → pymupdf-1.26.1}/tests/util.py +0 -0
  303. {pymupdf-1.26.0 → pymupdf-1.26.1}/valgrind.supp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyMuPDF
3
- Version: 1.26.0
3
+ Version: 1.26.1
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,27 @@ Change Log
2
2
  ==========
3
3
 
4
4
 
5
+ **Changes in version 1.26.1**
6
+
7
+ * Use MuPDF-1.26.2.
8
+
9
+ * Fixed issues:
10
+
11
+ * **Fixed** `4520 <https://github.com/pymupdf/PyMuPDF/issues/4520>`_: show_pdf_page does not like empty pages created by new_page
12
+ * **Fixed** `4524 <https://github.com/pymupdf/PyMuPDF/issues/4524>`_: fitz.get_text ignores 'pages' kwarg
13
+ * **Fixed** `4412 <https://github.com/pymupdf/PyMuPDF/issues/4412>`_: Regression? Spurious error? in insert_pdf in v1.25.4
14
+
15
+ * Other:
16
+
17
+ * Partial fix for `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_: Undetected character styles
18
+ * New method `Document.rewrite_images()`, useful for reducing file size, changing image formats, or converting color spaces.
19
+ * `Page.get_text()`: restrict positional args to match docs.
20
+ * Removed bogus definition of class `Shape`.
21
+ * Removed release date from module, docs and changelog.
22
+ * `pymupdf.pymupdf_date` and `pymupdf.VersionDate` are now both None.
23
+ * They will be removed in a future release.
24
+
25
+
5
26
  **Changes in version 1.26.0 (2025-05-22)**
6
27
 
7
28
  * Use MuPDF-1.26.1.
@@ -32,7 +53,9 @@ Change Log
32
53
  * Added runtime assert that that PyMuPDF and MuPDF were built with compatible
33
54
  NDEBUG settings (related to `4390 <https://github.com/pymupdf/PyMuPDF/issues/4390>`_).
34
55
  * Simplified handling of filename/filetype when opening documents.
35
-
56
+ * Removed PDF linearization support.
57
+ * Calls to `Document.save()` with `linear` set to true will now raise an exception.
58
+ * See https://artifex.com/blog/mupdf-removes-linearisation for more information.
36
59
 
37
60
  **Changes in version 1.25.5 (2025-03-31)**
38
61
 
@@ -21,6 +21,7 @@ import io
21
21
  import os
22
22
  import platform
23
23
  import re
24
+ import shlex
24
25
  import shutil
25
26
  import site
26
27
  import subprocess
@@ -654,12 +655,12 @@ class Package:
654
655
  z.writestr(f'{dist_info_dir}/RECORD', record.get(f'{dist_info_dir}/RECORD'))
655
656
 
656
657
  st = os.stat(path)
657
- log1( f'Have created wheel size={st.st_size}: {path}')
658
+ log1( f'Have created wheel size={st.st_size:,}: {path}')
658
659
  if g_verbose >= 2:
659
660
  with zipfile.ZipFile(path, compression=self.wheel_compression) as z:
660
661
  log2(f'Contents are:')
661
662
  for zi in sorted(z.infolist(), key=lambda z: z.filename):
662
- log2(f' {zi.file_size: 10d} {zi.filename}')
663
+ log2(f' {zi.file_size: 10,d} {zi.filename}')
663
664
 
664
665
  return os.path.basename(path)
665
666
 
@@ -1901,6 +1902,105 @@ def git_items( directory, submodules=False):
1901
1902
  return ret
1902
1903
 
1903
1904
 
1905
+ def git_get(
1906
+ remote,
1907
+ local,
1908
+ *,
1909
+ branch=None,
1910
+ depth=1,
1911
+ env_extra=None,
1912
+ tag=None,
1913
+ update=True,
1914
+ submodules=True,
1915
+ ):
1916
+ '''
1917
+ Ensures that <local> is a git checkout (at either <tag>, or <branch> HEAD)
1918
+ of a remote repository.
1919
+
1920
+ Exactly one of <branch> and <tag> must be specified.
1921
+
1922
+ Args:
1923
+ remote:
1924
+ Remote git repostitory, for example
1925
+ 'https://github.com/ArtifexSoftware/mupdf.git'.
1926
+ local:
1927
+ Local directory. If <local>/.git exists, we attempt to run `git
1928
+ update` in it.
1929
+ branch:
1930
+ Branch to use.
1931
+ depth:
1932
+ Depth of local checkout when cloning and fetching, or None.
1933
+ env_extra:
1934
+ Dict of extra name=value environment variables to use whenever we
1935
+ run git.
1936
+ tag:
1937
+ Tag to use.
1938
+ update:
1939
+ If false we do not update existing repository. Might be useful if
1940
+ testing without network access.
1941
+ submodules:
1942
+ If true, we clone with `--recursive --shallow-submodules` and run
1943
+ `git submodule update --init --recursive` before returning.
1944
+ '''
1945
+ log0(f'{remote=} {local=} {branch=} {tag=}')
1946
+ assert (branch and not tag) or (not branch and tag), f'Must specify exactly one of <branch> and <tag>.'
1947
+
1948
+ depth_arg = f' --depth {depth}' if depth else ''
1949
+
1950
+ def do_update():
1951
+ # This seems to pull in the entire repository.
1952
+ log0(f'do_update(): attempting to update {local=}.')
1953
+ # Remove any local changes.
1954
+ run(f'cd {local} && git checkout .', env_extra=env_extra)
1955
+ if tag:
1956
+ # `-u` avoids `fatal: Refusing to fetch into current branch`.
1957
+ # Using '+' and `revs/tags/` prefix seems to avoid errors like:
1958
+ # error: cannot update ref 'refs/heads/v3.16.44':
1959
+ # trying to write non-commit object
1960
+ # 06c4ae5fe39a03b37a25a8b95214d9f8f8a867b8 to branch
1961
+ # 'refs/heads/v3.16.44'
1962
+ #
1963
+ run(f'cd {local} && git fetch -fuv{depth_arg} {remote} +refs/tags/{tag}:refs/tags/{tag}', env_extra=env_extra)
1964
+ run(f'cd {local} && git checkout {tag}', env_extra=env_extra)
1965
+ if branch:
1966
+ # `-u` avoids `fatal: Refusing to fetch into current branch`.
1967
+ run(f'cd {local} && git fetch -fuv{depth_arg} {remote} {branch}:{branch}', env_extra=env_extra)
1968
+ run(f'cd {local} && git checkout {branch}', env_extra=env_extra)
1969
+
1970
+ do_clone = True
1971
+ if os.path.isdir(f'{local}/.git'):
1972
+ if update:
1973
+ # Try to update existing checkout.
1974
+ try:
1975
+ do_update()
1976
+ do_clone = False
1977
+ except Exception as e:
1978
+ log0(f'Failed to update existing checkout {local}: {e}')
1979
+ else:
1980
+ do_clone = False
1981
+
1982
+ if do_clone:
1983
+ # No existing git checkout, so do a fresh clone.
1984
+ #_fs_remove(local)
1985
+ log0(f'Cloning to: {local}')
1986
+ command = f'git clone --config core.longpaths=true{depth_arg}'
1987
+ if submodules:
1988
+ command += f' --recursive --shallow-submodules'
1989
+ if branch:
1990
+ command += f' -b {branch}'
1991
+ if tag:
1992
+ command += f' -b {tag}'
1993
+ command += f' {remote} {local}'
1994
+ run(command, env_extra=env_extra)
1995
+ do_update()
1996
+
1997
+ if submodules:
1998
+ run(f'cd {local} && git submodule update --init --recursive', env_extra=env_extra)
1999
+
2000
+ # Show sha of checkout.
2001
+ run( f'cd {local} && git show --pretty=oneline|head -n 1', check=False)
2002
+
2003
+
1904
2004
  def run(
1905
2005
  command,
1906
2006
  *,
@@ -1951,9 +2051,14 @@ def run(
1951
2051
  env = os.environ.copy()
1952
2052
  env.update(env_extra)
1953
2053
  lines = _command_lines( command)
1954
- nl = '\n'
1955
2054
  if verbose:
1956
- log1( f'Running: {nl.join(lines)}', caller=caller+1)
2055
+ text = f'Running:'
2056
+ if env_extra:
2057
+ for k in sorted(env_extra.keys()):
2058
+ text += f' {k}={shlex.quote(env_extra[k])}'
2059
+ nl = '\n'
2060
+ text += f' {nl.join(lines)}'
2061
+ log1(text, caller=caller+1)
1957
2062
  sep = ' ' if windows() else ' \\\n'
1958
2063
  command2 = sep.join( lines)
1959
2064
  cp = subprocess.run(
@@ -1990,6 +2095,39 @@ def linux():
1990
2095
  def openbsd():
1991
2096
  return platform.system() == 'OpenBSD'
1992
2097
 
2098
+
2099
+ def show_system():
2100
+ '''
2101
+ Show useful information about the system plus argv and environ.
2102
+ '''
2103
+ def log(text):
2104
+ log0(text, caller=3)
2105
+
2106
+ #log(f'{__file__=}')
2107
+ #log(f'{__name__=}')
2108
+ log(f'{os.getcwd()=}')
2109
+ log(f'{platform.machine()=}')
2110
+ log(f'{platform.platform()=}')
2111
+ log(f'{platform.python_version()=}')
2112
+ log(f'{platform.system()=}')
2113
+ log(f'{platform.uname()=}')
2114
+ log(f'{sys.executable=}')
2115
+ log(f'{sys.version=}')
2116
+ log(f'{sys.version_info=}')
2117
+ log(f'{list(sys.version_info)=}')
2118
+
2119
+ log(f'CPU bits: {cpu_bits()}')
2120
+
2121
+ log(f'sys.argv ({len(sys.argv)}):')
2122
+ for i, arg in enumerate(sys.argv):
2123
+ log(f' {i}: {arg!r}')
2124
+
2125
+ log(f'os.environ ({len(os.environ)}):')
2126
+ for k in sorted( os.environ.keys()):
2127
+ v = os.environ[ k]
2128
+ log( f' {k}: {v!r}')
2129
+
2130
+
1993
2131
  class PythonFlags:
1994
2132
  '''
1995
2133
  Compile/link flags for the current python, for example the include path
@@ -2164,6 +2302,10 @@ def _command_lines( command):
2164
2302
  return lines
2165
2303
 
2166
2304
 
2305
+ def cpu_bits():
2306
+ return int.bit_length(sys.maxsize+1)
2307
+
2308
+
2167
2309
  def _cpu_name():
2168
2310
  '''
2169
2311
  Returns `x32` or `x64` depending on Python build.
@@ -2418,7 +2560,7 @@ def log2(text='', caller=1):
2418
2560
 
2419
2561
  def _log(text, level, caller):
2420
2562
  '''
2421
- Logs lines with prefix.
2563
+ Logs lines with prefix, if <level> is lower than <g_verbose>.
2422
2564
  '''
2423
2565
  if level <= g_verbose:
2424
2566
  fr = inspect.stack(context=0)[caller]
@@ -2445,49 +2587,6 @@ def relpath(path, start=None):
2445
2587
  return os.path.relpath(path, start)
2446
2588
 
2447
2589
 
2448
- def number_sep( s):
2449
- '''
2450
- Simple number formatter, adds commas in-between thousands. `s` can be a
2451
- number or a string. Returns a string.
2452
-
2453
- >>> number_sep(1)
2454
- '1'
2455
- >>> number_sep(12)
2456
- '12'
2457
- >>> number_sep(123)
2458
- '123'
2459
- >>> number_sep(1234)
2460
- '1,234'
2461
- >>> number_sep(12345)
2462
- '12,345'
2463
- >>> number_sep(123456)
2464
- '123,456'
2465
- >>> number_sep(1234567)
2466
- '1,234,567'
2467
- >>> number_sep(-131072)
2468
- '-131,072'
2469
- '''
2470
- if not isinstance( s, str):
2471
- s = str( s)
2472
- ret = ''
2473
- if s.startswith('-'):
2474
- ret += '-'
2475
- s = s[1:]
2476
- c = s.find( '.')
2477
- if c==-1: c = len(s)
2478
- end = s.find('e')
2479
- if end == -1: end = s.find('E')
2480
- if end == -1: end = len(s)
2481
- for i in range( end):
2482
- ret += s[i]
2483
- if i<c-1 and (c-i-1)%3==0:
2484
- ret += ','
2485
- elif i>c and i<end-1 and (i-c)%3==0:
2486
- ret += ','
2487
- ret += s[end:]
2488
- return ret
2489
-
2490
-
2491
2590
  def _so_suffix(use_so_versioning=True):
2492
2591
  '''
2493
2592
  Filename suffix for shared libraries is defined in pep-3149. The
@@ -2619,3 +2718,51 @@ class _Record:
2619
2718
  if record_path:
2620
2719
  ret += f'{record_path},,\n'
2621
2720
  return ret
2721
+
2722
+
2723
+ class NewFiles:
2724
+ '''
2725
+ Detects new/modified/updated files matching a glob pattern. Useful for
2726
+ detecting wheels created by pip or cubuildwheel etc.
2727
+ '''
2728
+ def __init__(self, glob_pattern):
2729
+ # Find current matches of <glob_pattern>.
2730
+ self.glob_pattern = glob_pattern
2731
+ self.items0 = self._items()
2732
+ def get(self):
2733
+ '''
2734
+ Returns list of new matches of <glob_pattern> - paths of files that
2735
+ were not present previously, or have different mtimes or have different
2736
+ contents.
2737
+ '''
2738
+ ret = list()
2739
+ items = self._items()
2740
+ for path, id_ in items.items():
2741
+ id0 = self.items0.get(path)
2742
+ if id0 != id_:
2743
+ #mtime0, hash0 = id0
2744
+ #mtime1, hash1 = id_
2745
+ #log0(f'New/modified file {path=}.')
2746
+ #log0(f' {mtime0=} {"==" if mtime0==mtime1 else "!="} {mtime1=}.')
2747
+ #log0(f' {hash0=} {"==" if hash0==hash1 else "!="} {hash1=}.')
2748
+ ret.append(path)
2749
+ return ret
2750
+ def get_one(self):
2751
+ '''
2752
+ Returns new match of <glob_pattern>, asserting that there is exactly
2753
+ one.
2754
+ '''
2755
+ ret = self.get()
2756
+ assert len(ret) == 1, f'{len(ret)=}'
2757
+ return ret[0]
2758
+ def _file_id(self, path):
2759
+ mtime = os.stat(path).st_mtime
2760
+ with open(path, 'rb') as f:
2761
+ hash_ = hashlib.file_digest(f, hashlib.md5).digest()
2762
+ return mtime, hash_
2763
+ def _items(self):
2764
+ ret = dict()
2765
+ for path in glob.glob(self.glob_pattern):
2766
+ if os.path.isfile(path):
2767
+ ret[path] = self._file_id(path)
2768
+ return ret