pygit2 1.19.0__tar.gz → 1.19.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 (199) hide show
  1. {pygit2-1.19.0 → pygit2-1.19.1}/CHANGELOG.md +14 -0
  2. pygit2-1.19.1/Makefile +7 -0
  3. {pygit2-1.19.0 → pygit2-1.19.1}/PKG-INFO +1 -1
  4. {pygit2-1.19.0 → pygit2-1.19.1}/build.sh +11 -6
  5. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/_build.py +1 -1
  6. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/_pygit2.pyi +2 -2
  7. {pygit2-1.19.0 → pygit2-1.19.1}/pyproject.toml +6 -5
  8. {pygit2-1.19.0 → pygit2-1.19.1}/requirements-test.txt +0 -2
  9. pygit2-1.19.1/requirements-typing.txt +2 -0
  10. pygit2-1.19.1/requirements-wheel.txt +1 -0
  11. {pygit2-1.19.0 → pygit2-1.19.1}/src/diff.c +5 -0
  12. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_diff.py +67 -22
  13. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_repository.py +3 -1
  14. {pygit2-1.19.0 → pygit2-1.19.1}/test/utils.py +13 -1
  15. pygit2-1.19.0/Makefile +0 -7
  16. {pygit2-1.19.0 → pygit2-1.19.1}/AUTHORS.md +1 -1
  17. {pygit2-1.19.0 → pygit2-1.19.1}/COPYING +0 -0
  18. {pygit2-1.19.0 → pygit2-1.19.1}/README.md +0 -0
  19. {pygit2-1.19.0 → pygit2-1.19.1}/SPONSORS.md +0 -0
  20. {pygit2-1.19.0 → pygit2-1.19.1}/build.ps1 +0 -0
  21. {pygit2-1.19.0 → pygit2-1.19.1}/build_tag.py +0 -0
  22. {pygit2-1.19.0 → pygit2-1.19.1}/mypy-stubtest.ini +0 -0
  23. {pygit2-1.19.0 → pygit2-1.19.1}/mypy.ini +0 -0
  24. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/__init__.py +0 -0
  25. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/_libgit2/ffi.pyi +0 -0
  26. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/_run.py +0 -0
  27. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/blame.py +0 -0
  28. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/blob.py +0 -0
  29. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/branches.py +0 -0
  30. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/callbacks.py +0 -0
  31. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/config.py +0 -0
  32. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/credentials.py +0 -0
  33. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/attr.h +0 -0
  34. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/blame.h +0 -0
  35. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/buffer.h +0 -0
  36. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/callbacks.h +0 -0
  37. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/checkout.h +0 -0
  38. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/clone.h +0 -0
  39. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/commit.h +0 -0
  40. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/common.h +0 -0
  41. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/config.h +0 -0
  42. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/describe.h +0 -0
  43. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/diff.h +0 -0
  44. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/errors.h +0 -0
  45. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/graph.h +0 -0
  46. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/index.h +0 -0
  47. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/indexer.h +0 -0
  48. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/merge.h +0 -0
  49. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/net.h +0 -0
  50. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/oid.h +0 -0
  51. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/options.h +0 -0
  52. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/pack.h +0 -0
  53. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/proxy.h +0 -0
  54. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/refspec.h +0 -0
  55. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/remote.h +0 -0
  56. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/repository.h +0 -0
  57. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/revert.h +0 -0
  58. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/stash.h +0 -0
  59. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/strarray.h +0 -0
  60. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/submodule.h +0 -0
  61. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/transaction.h +0 -0
  62. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/transport.h +0 -0
  63. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/decl/types.h +0 -0
  64. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/enums.py +0 -0
  65. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/errors.py +0 -0
  66. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/ffi.py +0 -0
  67. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/filter.py +0 -0
  68. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/index.py +0 -0
  69. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/legacyenums.py +0 -0
  70. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/options.py +0 -0
  71. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/packbuilder.py +0 -0
  72. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/py.typed +0 -0
  73. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/references.py +0 -0
  74. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/refspec.py +0 -0
  75. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/remotes.py +0 -0
  76. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/repository.py +0 -0
  77. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/settings.py +0 -0
  78. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/submodules.py +0 -0
  79. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/transaction.py +0 -0
  80. {pygit2-1.19.0 → pygit2-1.19.1}/pygit2/utils.py +0 -0
  81. {pygit2-1.19.0 → pygit2-1.19.1}/pytest.ini +0 -0
  82. {pygit2-1.19.0 → pygit2-1.19.1}/requirements.txt +0 -0
  83. {pygit2-1.19.0 → pygit2-1.19.1}/setup.cfg +0 -0
  84. {pygit2-1.19.0 → pygit2-1.19.1}/setup.py +0 -0
  85. {pygit2-1.19.0 → pygit2-1.19.1}/src/blob.c +0 -0
  86. {pygit2-1.19.0 → pygit2-1.19.1}/src/branch.c +0 -0
  87. {pygit2-1.19.0 → pygit2-1.19.1}/src/branch.h +0 -0
  88. {pygit2-1.19.0 → pygit2-1.19.1}/src/commit.c +0 -0
  89. {pygit2-1.19.0 → pygit2-1.19.1}/src/diff.h +0 -0
  90. {pygit2-1.19.0 → pygit2-1.19.1}/src/error.c +0 -0
  91. {pygit2-1.19.0 → pygit2-1.19.1}/src/error.h +0 -0
  92. {pygit2-1.19.0 → pygit2-1.19.1}/src/filter.c +0 -0
  93. {pygit2-1.19.0 → pygit2-1.19.1}/src/filter.h +0 -0
  94. {pygit2-1.19.0 → pygit2-1.19.1}/src/mailmap.c +0 -0
  95. {pygit2-1.19.0 → pygit2-1.19.1}/src/mailmap.h +0 -0
  96. {pygit2-1.19.0 → pygit2-1.19.1}/src/note.c +0 -0
  97. {pygit2-1.19.0 → pygit2-1.19.1}/src/note.h +0 -0
  98. {pygit2-1.19.0 → pygit2-1.19.1}/src/object.c +0 -0
  99. {pygit2-1.19.0 → pygit2-1.19.1}/src/object.h +0 -0
  100. {pygit2-1.19.0 → pygit2-1.19.1}/src/odb.c +0 -0
  101. {pygit2-1.19.0 → pygit2-1.19.1}/src/odb.h +0 -0
  102. {pygit2-1.19.0 → pygit2-1.19.1}/src/odb_backend.c +0 -0
  103. {pygit2-1.19.0 → pygit2-1.19.1}/src/odb_backend.h +0 -0
  104. {pygit2-1.19.0 → pygit2-1.19.1}/src/oid.c +0 -0
  105. {pygit2-1.19.0 → pygit2-1.19.1}/src/oid.h +0 -0
  106. {pygit2-1.19.0 → pygit2-1.19.1}/src/patch.c +0 -0
  107. {pygit2-1.19.0 → pygit2-1.19.1}/src/patch.h +0 -0
  108. {pygit2-1.19.0 → pygit2-1.19.1}/src/pygit2.c +0 -0
  109. {pygit2-1.19.0 → pygit2-1.19.1}/src/refdb.c +0 -0
  110. {pygit2-1.19.0 → pygit2-1.19.1}/src/refdb.h +0 -0
  111. {pygit2-1.19.0 → pygit2-1.19.1}/src/refdb_backend.c +0 -0
  112. {pygit2-1.19.0 → pygit2-1.19.1}/src/refdb_backend.h +0 -0
  113. {pygit2-1.19.0 → pygit2-1.19.1}/src/reference.c +0 -0
  114. {pygit2-1.19.0 → pygit2-1.19.1}/src/reference.h +0 -0
  115. {pygit2-1.19.0 → pygit2-1.19.1}/src/repository.c +0 -0
  116. {pygit2-1.19.0 → pygit2-1.19.1}/src/repository.h +0 -0
  117. {pygit2-1.19.0 → pygit2-1.19.1}/src/revspec.c +0 -0
  118. {pygit2-1.19.0 → pygit2-1.19.1}/src/revspec.h +0 -0
  119. {pygit2-1.19.0 → pygit2-1.19.1}/src/signature.c +0 -0
  120. {pygit2-1.19.0 → pygit2-1.19.1}/src/signature.h +0 -0
  121. {pygit2-1.19.0 → pygit2-1.19.1}/src/stash.c +0 -0
  122. {pygit2-1.19.0 → pygit2-1.19.1}/src/tag.c +0 -0
  123. {pygit2-1.19.0 → pygit2-1.19.1}/src/tree.c +0 -0
  124. {pygit2-1.19.0 → pygit2-1.19.1}/src/tree.h +0 -0
  125. {pygit2-1.19.0 → pygit2-1.19.1}/src/treebuilder.c +0 -0
  126. {pygit2-1.19.0 → pygit2-1.19.1}/src/treebuilder.h +0 -0
  127. {pygit2-1.19.0 → pygit2-1.19.1}/src/types.h +0 -0
  128. {pygit2-1.19.0 → pygit2-1.19.1}/src/utils.c +0 -0
  129. {pygit2-1.19.0 → pygit2-1.19.1}/src/utils.h +0 -0
  130. {pygit2-1.19.0 → pygit2-1.19.1}/src/walker.c +0 -0
  131. {pygit2-1.19.0 → pygit2-1.19.1}/src/walker.h +0 -0
  132. {pygit2-1.19.0 → pygit2-1.19.1}/src/wildmatch.c +0 -0
  133. {pygit2-1.19.0 → pygit2-1.19.1}/src/wildmatch.h +0 -0
  134. {pygit2-1.19.0 → pygit2-1.19.1}/src/worktree.c +0 -0
  135. {pygit2-1.19.0 → pygit2-1.19.1}/src/worktree.h +0 -0
  136. {pygit2-1.19.0 → pygit2-1.19.1}/test/__init__.py +0 -0
  137. {pygit2-1.19.0 → pygit2-1.19.1}/test/conftest.py +0 -0
  138. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/barerepo.zip +0 -0
  139. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/binaryfilerepo.zip +0 -0
  140. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/blameflagsrepo.zip +0 -0
  141. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/dirtyrepo.zip +0 -0
  142. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/emptyrepo.zip +0 -0
  143. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/encoding.zip +0 -0
  144. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/gpgsigned.zip +0 -0
  145. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/submodulerepo.zip +0 -0
  146. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/testrepo.zip +0 -0
  147. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/testrepoformerging.zip +0 -0
  148. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/testrepopacked.zip +0 -0
  149. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/trailerrepo.zip +0 -0
  150. {pygit2-1.19.0 → pygit2-1.19.1}/test/data/utf8branchrepo.zip +0 -0
  151. {pygit2-1.19.0 → pygit2-1.19.1}/test/keys/pygit2_empty +0 -0
  152. {pygit2-1.19.0 → pygit2-1.19.1}/test/keys/pygit2_empty.pub +0 -0
  153. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_apply_diff.py +0 -0
  154. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_archive.py +0 -0
  155. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_attributes.py +0 -0
  156. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_blame.py +0 -0
  157. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_blob.py +0 -0
  158. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_branch.py +0 -0
  159. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_branch_empty.py +0 -0
  160. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_cherrypick.py +0 -0
  161. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_commit.py +0 -0
  162. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_commit_gpg.py +0 -0
  163. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_commit_trailer.py +0 -0
  164. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_config.py +0 -0
  165. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_credentials.py +0 -0
  166. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_describe.py +0 -0
  167. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_diff_binary.py +0 -0
  168. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_filter.py +0 -0
  169. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_index.py +0 -0
  170. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_mailmap.py +0 -0
  171. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_merge.py +0 -0
  172. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_nonunicode.py +0 -0
  173. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_note.py +0 -0
  174. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_object.py +0 -0
  175. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_odb.py +0 -0
  176. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_odb_backend.py +0 -0
  177. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_oid.py +0 -0
  178. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_options.py +0 -0
  179. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_packbuilder.py +0 -0
  180. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_patch.py +0 -0
  181. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_patch_encoding.py +0 -0
  182. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_refdb_backend.py +0 -0
  183. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_refs.py +0 -0
  184. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_remote.py +0 -0
  185. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_remote_prune.py +0 -0
  186. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_remote_utf8.py +0 -0
  187. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_repository_bare.py +0 -0
  188. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_repository_custom.py +0 -0
  189. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_repository_empty.py +0 -0
  190. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_revparse.py +0 -0
  191. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_revwalk.py +0 -0
  192. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_settings.py +0 -0
  193. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_signature.py +0 -0
  194. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_status.py +0 -0
  195. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_submodule.py +0 -0
  196. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_tag.py +0 -0
  197. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_transaction.py +0 -0
  198. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_tree.py +0 -0
  199. {pygit2-1.19.0 → pygit2-1.19.1}/test/test_treebuilder.py +0 -0
@@ -1,3 +1,17 @@
1
+ # 1.19.1 (2025-12-29)
2
+
3
+ - Update wheels to libgit2 1.9.2 and OpenSSL 3.5
4
+
5
+ - Fix: now diff's getitem/iter returns `None` for unchanged or binary files
6
+ [#1412](https://github.com/libgit2/pygit2/pull/1412)
7
+
8
+ - CI (macOS): arm, intel and pypy wheels (instead of universal)
9
+ [#1441](https://github.com/libgit2/pygit2/pull/1441)
10
+
11
+ - CI (pypy): fix tests
12
+ [#1437](https://github.com/libgit2/pygit2/pull/1437)
13
+
14
+
1
15
  # 1.19.0 (2025-10-23)
2
16
 
3
17
  - Add support for Python 3.14 and drop 3.10
pygit2-1.19.1/Makefile ADDED
@@ -0,0 +1,7 @@
1
+ .PHONY: build html
2
+
3
+ build:
4
+ OPENSSL_VERSION=3.5.4 LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.2 sh build.sh
5
+
6
+ html: build
7
+ make -C docs html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygit2
3
- Version: 1.19.0
3
+ Version: 1.19.1
4
4
  Summary: Python bindings for libgit2.
5
5
  Home-page: https://github.com/libgit2/pygit2
6
6
  Maintainer: J. David Ibáñez
@@ -22,14 +22,14 @@
22
22
  #
23
23
  # sh build.sh
24
24
  #
25
- # Build libgit2 1.9.0 (will use libssh2 if available), then build pygit2
25
+ # Build libgit2 1.9.2 (will use libssh2 if available), then build pygit2
26
26
  # inplace:
27
27
  #
28
- # LIBGIT2_VERSION=1.9.0 sh build.sh
28
+ # LIBGIT2_VERSION=1.9.2 sh build.sh
29
29
  #
30
- # Build libssh2 1.11.1 and libgit2 1.9.0, then build pygit2 inplace:
30
+ # Build libssh2 1.11.1 and libgit2 1.9.2, then build pygit2 inplace:
31
31
  #
32
- # LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.0 sh build.sh
32
+ # LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.2 sh build.sh
33
33
  #
34
34
  # Build inplace and run the tests:
35
35
  #
@@ -62,6 +62,8 @@ if [ "$CIBUILDWHEEL" = "1" ]; then
62
62
  apt-get install wget -y
63
63
  if [ -z "$OPENSSL_VERSION" ]; then
64
64
  apt-get install libssl-dev -y
65
+ else
66
+ apt-get install libtime-piece-perl -y
65
67
  fi
66
68
  elif [ -f /usr/bin/yum ]; then
67
69
  yum install wget zlib-devel -y
@@ -70,11 +72,14 @@ if [ "$CIBUILDWHEEL" = "1" ]; then
70
72
  else
71
73
  yum install perl-IPC-Cmd -y
72
74
  yum install perl-Pod-Html -y
75
+ yum install perl-Time-Piece -y
73
76
  fi
74
77
  elif [ -f /sbin/apk ]; then
75
78
  apk add wget
76
79
  if [ -z "$OPENSSL_VERSION" ]; then
77
- apk add openssl-dev
80
+ apk add --no-cache openssl-dev
81
+ else
82
+ apk add --no-cache perl
78
83
  fi
79
84
  fi
80
85
  rm -rf ci
@@ -268,7 +273,7 @@ if [ "$1" = "mypy" ]; then
268
273
  if [ -n "$WHEELDIR" ]; then
269
274
  $PREFIX/bin/pip install $WHEELDIR/pygit2*-$PYTHON_TAG-*.whl
270
275
  fi
271
- $PREFIX/bin/pip install -r requirements-test.txt
276
+ $PREFIX/bin/pip install -r requirements-test.txt -r requirements-typing.txt
272
277
  $PREFIX/bin/mypy pygit2 test
273
278
  fi
274
279
 
@@ -34,7 +34,7 @@ from pathlib import Path
34
34
  #
35
35
  # The version number of pygit2
36
36
  #
37
- __version__ = '1.19.0'
37
+ __version__ = '1.19.1'
38
38
 
39
39
 
40
40
  #
@@ -432,8 +432,8 @@ class Diff:
432
432
  def from_c(diff, repo) -> Diff: ...
433
433
  @staticmethod
434
434
  def parse_diff(git_diff: str | bytes) -> Diff: ...
435
- def __getitem__(self, index: int) -> Patch: ... # Diff_getitem
436
- def __iter__(self) -> Iterator[Patch]: ... # -> DiffIter
435
+ def __getitem__(self, index: int) -> Patch | None: ... # Diff_getitem
436
+ def __iter__(self) -> Iterator[Patch | None]: ... # -> DiffIter
437
437
  def __len__(self) -> int: ...
438
438
 
439
439
  class DiffDelta:
@@ -8,14 +8,16 @@ skip = "*musllinux_ppc64le"
8
8
  archs = ["native"]
9
9
  build-frontend = "default"
10
10
  dependency-versions = "pinned"
11
- environment = {LIBGIT2_VERSION="1.9.1", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.3.3", LIBGIT2="/project/ci"}
11
+ environment = {LIBGIT2_VERSION="1.9.2", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.5.4", LIBGIT2="/project/ci"}
12
12
 
13
13
  before-all = "sh build.sh"
14
14
  test-command = "pytest"
15
15
  test-sources = ["test", "pytest.ini"]
16
16
  before-test = "pip install -r {project}/requirements-test.txt"
17
17
  # Will avoid testing on emulated architectures (specifically ppc64le)
18
- test-skip = "*-*linux_ppc64le"
18
+ # Also, skip testing pypy on macOS arm64 due issue with bootstrapping git config paths
19
+ # see https://github.com/libgit2/pygit2/issues/1442
20
+ test-skip = "*-*linux_ppc64le pp*-macosx_arm64"
19
21
 
20
22
  [tool.cibuildwheel.linux]
21
23
  repair-wheel-command = "LD_LIBRARY_PATH=/project/ci/lib64 auditwheel repair -w {dest_dir} {wheel}"
@@ -25,13 +27,12 @@ select = "*-musllinux*"
25
27
  repair-wheel-command = "LD_LIBRARY_PATH=/project/ci/lib auditwheel repair -w {dest_dir} {wheel}"
26
28
 
27
29
  [tool.cibuildwheel.macos]
28
- archs = ["universal2"]
29
- environment = {LIBGIT2_VERSION="1.9.1", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.3.3", LIBGIT2="/Users/runner/work/pygit2/pygit2/ci"}
30
+ environment = {LIBGIT2_VERSION="1.9.2", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.5.4", LIBGIT2="/Users/runner/work/pygit2/pygit2/ci"}
30
31
  repair-wheel-command = "DYLD_LIBRARY_PATH=/Users/runner/work/pygit2/pygit2/ci/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}"
31
32
 
32
33
  [tool.cibuildwheel.windows]
33
34
  environment.LIBGIT2_SRC = "build/libgit2_src"
34
- environment.LIBGIT2_VERSION = "1.9.1"
35
+ environment.LIBGIT2_VERSION = "1.9.2"
35
36
  before-all = "powershell -File build.ps1"
36
37
 
37
38
  [[tool.cibuildwheel.overrides]]
@@ -1,4 +1,2 @@
1
1
  pytest
2
2
  pytest-cov
3
- mypy
4
- types-cffi
@@ -0,0 +1,2 @@
1
+ mypy
2
+ types-cffi
@@ -0,0 +1 @@
1
+ cibuildwheel ~= 3.3
@@ -533,6 +533,11 @@ diff_get_patch_byindex(git_diff *diff, size_t idx)
533
533
  if (err < 0)
534
534
  return Error_set(err);
535
535
 
536
+ /* libgit2 may decide not to create a patch if the file is
537
+ "unchanged or binary", but this isn't an error case */
538
+ if (patch == NULL)
539
+ Py_RETURN_NONE;
540
+
536
541
  return (PyObject*) wrap_patch(patch, NULL, NULL);
537
542
  }
538
543
 
@@ -28,6 +28,7 @@
28
28
  import textwrap
29
29
  from collections.abc import Iterator
30
30
  from itertools import chain
31
+ from pathlib import Path
31
32
 
32
33
  import pytest
33
34
 
@@ -35,6 +36,8 @@ import pygit2
35
36
  from pygit2 import Diff, Repository
36
37
  from pygit2.enums import DeltaStatus, DiffFlag, DiffOption, DiffStatsFormat, FileMode
37
38
 
39
+ from .utils import diff_safeiter
40
+
38
41
  COMMIT_SHA1_1 = '5fe808e8953c12735680c257f56600cb0de44b10'
39
42
  COMMIT_SHA1_2 = 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c'
40
43
  COMMIT_SHA1_3 = '2cdae28389c059815e951d0bb9eed6533f61a46b'
@@ -176,11 +179,11 @@ def test_diff_empty_index(dirtyrepo: Repository) -> None:
176
179
  head = repo[repo.lookup_reference('HEAD').resolve().target]
177
180
 
178
181
  diff = head.tree.diff_to_index(repo.index)
179
- files = [patch.delta.new_file.path for patch in diff]
182
+ files = [patch.delta.new_file.path for patch in diff_safeiter(diff)]
180
183
  assert DIFF_HEAD_TO_INDEX_EXPECTED == files
181
184
 
182
185
  diff = repo.diff('HEAD', cached=True)
183
- files = [patch.delta.new_file.path for patch in diff]
186
+ files = [patch.delta.new_file.path for patch in diff_safeiter(diff)]
184
187
  assert DIFF_HEAD_TO_INDEX_EXPECTED == files
185
188
 
186
189
 
@@ -189,17 +192,17 @@ def test_workdir_to_tree(dirtyrepo: Repository) -> None:
189
192
  head = repo[repo.lookup_reference('HEAD').resolve().target]
190
193
 
191
194
  diff = head.tree.diff_to_workdir()
192
- files = [patch.delta.new_file.path for patch in diff]
195
+ files = [patch.delta.new_file.path for patch in diff_safeiter(diff)]
193
196
  assert DIFF_HEAD_TO_WORKDIR_EXPECTED == files
194
197
 
195
198
  diff = repo.diff('HEAD')
196
- files = [patch.delta.new_file.path for patch in diff]
199
+ files = [patch.delta.new_file.path for patch in diff_safeiter(diff)]
197
200
  assert DIFF_HEAD_TO_WORKDIR_EXPECTED == files
198
201
 
199
202
 
200
203
  def test_index_to_workdir(dirtyrepo: Repository) -> None:
201
204
  diff = dirtyrepo.diff()
202
- files = [patch.delta.new_file.path for patch in diff]
205
+ files = [patch.delta.new_file.path for patch in diff_safeiter(diff)]
203
206
  assert DIFF_INDEX_TO_WORK_EXPECTED == files
204
207
 
205
208
 
@@ -217,15 +220,15 @@ def test_diff_empty_index_bare(barerepo: Repository) -> None:
217
220
  head = repo[repo.lookup_reference('HEAD').resolve().target]
218
221
 
219
222
  diff = barerepo.index.diff_to_tree(head.tree)
220
- files = [patch.delta.new_file.path.split('/')[0] for patch in diff]
223
+ files = [patch.delta.new_file.path.split('/')[0] for patch in diff_safeiter(diff)]
221
224
  assert [x.name for x in head.tree] == files
222
225
 
223
226
  diff = head.tree.diff_to_index(repo.index)
224
- files = [patch.delta.new_file.path.split('/')[0] for patch in diff]
227
+ files = [patch.delta.new_file.path.split('/')[0] for patch in diff_safeiter(diff)]
225
228
  assert [x.name for x in head.tree] == files
226
229
 
227
230
  diff = repo.diff('HEAD', cached=True)
228
- files = [patch.delta.new_file.path.split('/')[0] for patch in diff]
231
+ files = [patch.delta.new_file.path.split('/')[0] for patch in diff_safeiter(diff)]
229
232
  assert [x.name for x in head.tree] == files
230
233
 
231
234
 
@@ -235,9 +238,10 @@ def test_diff_tree(barerepo: Repository) -> None:
235
238
 
236
239
  def _test(diff: Diff) -> None:
237
240
  assert diff is not None
238
- assert 2 == sum(map(lambda x: len(x.hunks), diff))
241
+ assert 2 == sum(map(lambda x: len(x.hunks), diff_safeiter(diff)))
239
242
 
240
243
  patch = diff[0]
244
+ assert patch is not None
241
245
  hunk = patch.hunks[0]
242
246
  assert hunk.old_start == 1
243
247
  assert hunk.old_lines == 1
@@ -267,16 +271,16 @@ def test_diff_empty_tree(barerepo: Repository) -> None:
267
271
  diff = commit_a.tree.diff_to_tree()
268
272
 
269
273
  def get_context_for_lines(diff: Diff) -> Iterator[str]:
270
- hunks = chain.from_iterable(map(lambda x: x.hunks, diff))
274
+ hunks = chain.from_iterable(map(lambda x: x.hunks, diff_safeiter(diff)))
271
275
  lines = chain.from_iterable(map(lambda x: x.lines, hunks))
272
276
  return map(lambda x: x.origin, lines)
273
277
 
274
- entries = [p.delta.new_file.path for p in diff]
278
+ entries = [p.delta.new_file.path for p in diff_safeiter(diff)]
275
279
  assert all(commit_a.tree[x] for x in entries)
276
280
  assert all('-' == x for x in get_context_for_lines(diff))
277
281
 
278
282
  diff_swaped = commit_a.tree.diff_to_tree(swap=True)
279
- entries = [p.delta.new_file.path for p in diff_swaped]
283
+ entries = [p.delta.new_file.path for p in diff_safeiter(diff_swaped)]
280
284
  assert all(commit_a.tree[x] for x in entries)
281
285
  assert all('+' == x for x in get_context_for_lines(diff_swaped))
282
286
 
@@ -293,11 +297,15 @@ def test_diff_tree_opts(barerepo: Repository) -> None:
293
297
  for flag in [DiffOption.IGNORE_WHITESPACE, DiffOption.IGNORE_WHITESPACE_EOL]:
294
298
  diff = commit_c.tree.diff_to_tree(commit_d.tree, flag)
295
299
  assert diff is not None
296
- assert 0 == len(diff[0].hunks)
300
+ patch = diff[0]
301
+ assert patch is not None
302
+ assert 0 == len(patch.hunks)
297
303
 
298
304
  diff = commit_c.tree.diff_to_tree(commit_d.tree)
299
305
  assert diff is not None
300
- assert 1 == len(diff[0].hunks)
306
+ patch = diff[0]
307
+ assert patch is not None
308
+ assert 1 == len(patch.hunks)
301
309
 
302
310
 
303
311
  def test_diff_merge(barerepo: Repository) -> None:
@@ -310,13 +318,14 @@ def test_diff_merge(barerepo: Repository) -> None:
310
318
 
311
319
  diff_c = commit_b.tree.diff_to_tree(commit_c.tree)
312
320
  assert diff_c is not None
313
- assert 'b' not in [patch.delta.new_file.path for patch in diff_b]
314
- assert 'b' in [patch.delta.new_file.path for patch in diff_c]
321
+ assert 'b' not in [patch.delta.new_file.path for patch in diff_safeiter(diff_b)]
322
+ assert 'b' in [patch.delta.new_file.path for patch in diff_safeiter(diff_c)]
315
323
 
316
324
  diff_b.merge(diff_c)
317
- assert 'b' in [patch.delta.new_file.path for patch in diff_b]
325
+ assert 'b' in [patch.delta.new_file.path for patch in diff_safeiter(diff_b)]
318
326
 
319
327
  patch = diff_b[0]
328
+ assert patch is not None
320
329
  hunk = patch.hunks[0]
321
330
  assert hunk.old_start == 1
322
331
  assert hunk.old_lines == 1
@@ -340,6 +349,7 @@ def test_diff_ids(barerepo: Repository) -> None:
340
349
  commit_a = barerepo[COMMIT_SHA1_1]
341
350
  commit_b = barerepo[COMMIT_SHA1_2]
342
351
  patch = commit_a.tree.diff_to_tree(commit_b.tree)[0]
352
+ assert patch is not None
343
353
  delta = patch.delta
344
354
  assert delta.old_file.id == '7f129fd57e31e935c6d60a0c794efe4e6927664b'
345
355
  assert delta.new_file.id == 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
@@ -357,6 +367,7 @@ def test_hunk_content(barerepo: Repository) -> None:
357
367
  commit_a = barerepo[COMMIT_SHA1_1]
358
368
  commit_b = barerepo[COMMIT_SHA1_2]
359
369
  patch = commit_a.tree.diff_to_tree(commit_b.tree)[0]
370
+ assert patch is not None
360
371
  hunk = patch.hunks[0]
361
372
  lines = (f'{x.origin} {x.content}' for x in hunk.lines)
362
373
  assert HUNK_EXPECTED == ''.join(lines)
@@ -371,11 +382,15 @@ def test_find_similar(barerepo: Repository) -> None:
371
382
  # ~ Must pass INCLUDE_UNMODIFIED if you expect to emulate
372
383
  # ~ --find-copies-harder during rename transformion...
373
384
  diff = commit_a.tree.diff_to_tree(commit_b.tree, DiffOption.INCLUDE_UNMODIFIED)
374
- assert all(x.delta.status != DeltaStatus.RENAMED for x in diff)
375
- assert all(x.delta.status_char() != 'R' for x in diff)
385
+ assert all(
386
+ patch.delta.status != DeltaStatus.RENAMED for patch in diff_safeiter(diff)
387
+ )
388
+ assert all(patch.delta.status_char() != 'R' for patch in diff_safeiter(diff))
376
389
  diff.find_similar()
377
- assert any(x.delta.status == DeltaStatus.RENAMED for x in diff)
378
- assert any(x.delta.status_char() == 'R' for x in diff)
390
+ assert any(
391
+ patch.delta.status == DeltaStatus.RENAMED for patch in diff_safeiter(diff)
392
+ )
393
+ assert any(patch.delta.status_char() == 'R' for patch in diff_safeiter(diff))
379
394
 
380
395
 
381
396
  def test_diff_stats(barerepo: Repository) -> None:
@@ -398,7 +413,7 @@ def test_deltas(barerepo: Repository) -> None:
398
413
  commit_b = barerepo[COMMIT_SHA1_2]
399
414
  diff = commit_a.tree.diff_to_tree(commit_b.tree)
400
415
  deltas = list(diff.deltas)
401
- patches = list(diff)
416
+ patches = list(diff_safeiter(diff))
402
417
  assert len(deltas) == len(patches)
403
418
  for i, delta in enumerate(deltas):
404
419
  patch_delta = patches[i].delta
@@ -459,3 +474,33 @@ def test_diff_blobs(emptyrepo: Repository) -> None:
459
474
  assert diff_one_context_line.text == PATCH_BLOBS_ONE_CONTEXT_LINE
460
475
  diff_all_together = repo.diff(blob1, blob2, context_lines=1, interhunk_lines=1)
461
476
  assert diff_all_together.text == PATCH_BLOBS_DEFAULT
477
+
478
+
479
+ def test_diff_unchanged_file_no_patch(testrepo: Repository) -> None:
480
+ repo = testrepo
481
+
482
+ # Convert hello.txt line endings to CRLF
483
+ path = Path(repo.workdir) / 'hello.txt'
484
+ data = path.read_bytes()
485
+ data = data.replace(b'\n', b'\r\n')
486
+ path.write_bytes(data)
487
+
488
+ # Enable CRLF filter
489
+ repo.config['core.autocrlf'] = 'input'
490
+
491
+ diff = repo.diff()
492
+ assert len(diff) == 1
493
+
494
+ # Get patch #0 in the same diff several times.
495
+ # git_patch_from_diff eventually decides that the file is "unchanged";
496
+ # it returns a NULL patch in this case.
497
+ # https://libgit2.org/docs/reference/main/patch/git_patch_from_diff
498
+ for i in range(10): # loop typically exits in the third iteration
499
+ patch = diff[0]
500
+ if patch is None: # libgit2 decides the file is unchanged
501
+ break
502
+ assert patch.delta.new_file.path == path.name
503
+ assert patch.text == '' # no content change (just line endings)
504
+ else:
505
+ # Didn't find the edge case that this test is supposed to exercise.
506
+ assert False, 'libgit2 rebuilt a new patch every time'
@@ -456,7 +456,9 @@ def test_stash_partial(testrepo: Repository) -> None:
456
456
  )
457
457
  stash_commit = testrepo[stash_id].peel(pygit2.Commit)
458
458
  stash_diff = testrepo.diff(stash_commit.parents[0], stash_commit)
459
- stash_files = set(patch.delta.new_file.path for patch in stash_diff)
459
+ stash_files = set(
460
+ patch.delta.new_file.path for patch in utils.diff_safeiter(stash_diff)
461
+ )
460
462
  return stash_files == set(paths)
461
463
 
462
464
  # Stash a modified file
@@ -30,7 +30,7 @@ import socket
30
30
  import stat
31
31
  import sys
32
32
  import zipfile
33
- from collections.abc import Callable
33
+ from collections.abc import Callable, Iterator
34
34
  from pathlib import Path
35
35
  from types import TracebackType
36
36
  from typing import Any, Optional, ParamSpec, TypeVar
@@ -103,6 +103,18 @@ def rmtree(path: str | Path) -> None:
103
103
  shutil.rmtree(path, onerror=force_rm_handle)
104
104
 
105
105
 
106
+ def diff_safeiter(diff: pygit2.Diff) -> Iterator[pygit2.Patch]:
107
+ """
108
+ In rare cases, Diff.__iter__ may yield None (see diff_get_patch_byindex).
109
+ To make mypy happy, use this iterator instead of Diff.__iter__ to ensure
110
+ that all patches in a Diff are valid Patch objects, not None.
111
+ """
112
+ for patch in diff:
113
+ if patch is None:
114
+ raise TypeError('patch is None')
115
+ yield patch
116
+
117
+
106
118
  class TemporaryRepository:
107
119
  def __init__(self, name: str, tmp_path: Path) -> None:
108
120
  self.name = name
pygit2-1.19.0/Makefile DELETED
@@ -1,7 +0,0 @@
1
- .PHONY: build html
2
-
3
- build:
4
- OPENSSL_VERSION=3.3.3 LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.1 sh build.sh
5
-
6
- html: build
7
- make -C docs html
@@ -13,9 +13,9 @@ Authors:
13
13
  Dave Borowitz
14
14
  Brandon Milton
15
15
  Daniel Rodríguez Troitiño
16
+ Brendan Doherty
16
17
  Peter Rowlands
17
18
  Richo Healey
18
- Brendan Doherty
19
19
  Christian Boos
20
20
  Julien Miotte
21
21
  Nick Hynes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes