pygit2 1.19.0__tar.gz → 1.19.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. {pygit2-1.19.0 → pygit2-1.19.2}/AUTHORS.md +4 -1
  2. {pygit2-1.19.0 → pygit2-1.19.2}/CHANGELOG.md +33 -0
  3. pygit2-1.19.2/Makefile +7 -0
  4. {pygit2-1.19.0 → pygit2-1.19.2}/PKG-INFO +1 -1
  5. {pygit2-1.19.0 → pygit2-1.19.2}/build.sh +11 -6
  6. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/__init__.py +21 -2
  7. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/_build.py +1 -1
  8. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/_libgit2/ffi.pyi +12 -0
  9. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/_pygit2.pyi +4 -4
  10. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/_run.py +2 -0
  11. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/config.py +6 -6
  12. pygit2-1.19.2/pygit2/decl/filter.h +49 -0
  13. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/types.h +2 -0
  14. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/filter.py +99 -1
  15. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/repository.py +27 -0
  16. {pygit2-1.19.0 → pygit2-1.19.2}/pyproject.toml +8 -6
  17. {pygit2-1.19.0 → pygit2-1.19.2}/requirements-test.txt +0 -2
  18. pygit2-1.19.2/requirements-typing.txt +2 -0
  19. pygit2-1.19.2/requirements-wheel.txt +1 -0
  20. {pygit2-1.19.0 → pygit2-1.19.2}/src/branch.c +1 -1
  21. {pygit2-1.19.0 → pygit2-1.19.2}/src/diff.c +7 -2
  22. {pygit2-1.19.0 → pygit2-1.19.2}/src/filter.c +2 -0
  23. {pygit2-1.19.0 → pygit2-1.19.2}/src/mailmap.c +1 -1
  24. {pygit2-1.19.0 → pygit2-1.19.2}/src/note.c +1 -1
  25. {pygit2-1.19.0 → pygit2-1.19.2}/src/object.c +1 -1
  26. {pygit2-1.19.0 → pygit2-1.19.2}/src/odb.c +51 -4
  27. {pygit2-1.19.0 → pygit2-1.19.2}/src/odb_backend.c +1 -1
  28. {pygit2-1.19.0 → pygit2-1.19.2}/src/patch.c +1 -1
  29. {pygit2-1.19.0 → pygit2-1.19.2}/src/pygit2.c +28 -45
  30. {pygit2-1.19.0 → pygit2-1.19.2}/src/refdb.c +3 -5
  31. {pygit2-1.19.0 → pygit2-1.19.2}/src/refdb_backend.c +1 -1
  32. {pygit2-1.19.0 → pygit2-1.19.2}/src/reference.c +1 -1
  33. {pygit2-1.19.0 → pygit2-1.19.2}/src/repository.c +1 -1
  34. {pygit2-1.19.0 → pygit2-1.19.2}/src/tag.c +1 -1
  35. {pygit2-1.19.0 → pygit2-1.19.2}/src/tree.c +1 -1
  36. {pygit2-1.19.0 → pygit2-1.19.2}/src/treebuilder.c +1 -1
  37. {pygit2-1.19.0 → pygit2-1.19.2}/src/utils.c +29 -0
  38. {pygit2-1.19.0 → pygit2-1.19.2}/src/utils.h +1 -0
  39. {pygit2-1.19.0 → pygit2-1.19.2}/src/walker.c +1 -1
  40. {pygit2-1.19.0 → pygit2-1.19.2}/src/worktree.c +1 -1
  41. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_config.py +29 -0
  42. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_diff.py +67 -22
  43. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_filter.py +107 -13
  44. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_odb.py +18 -2
  45. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_repository.py +3 -1
  46. {pygit2-1.19.0 → pygit2-1.19.2}/test/utils.py +13 -1
  47. pygit2-1.19.0/Makefile +0 -7
  48. {pygit2-1.19.0 → pygit2-1.19.2}/COPYING +0 -0
  49. {pygit2-1.19.0 → pygit2-1.19.2}/README.md +0 -0
  50. {pygit2-1.19.0 → pygit2-1.19.2}/SPONSORS.md +0 -0
  51. {pygit2-1.19.0 → pygit2-1.19.2}/build.ps1 +0 -0
  52. {pygit2-1.19.0 → pygit2-1.19.2}/build_tag.py +0 -0
  53. {pygit2-1.19.0 → pygit2-1.19.2}/mypy-stubtest.ini +0 -0
  54. {pygit2-1.19.0 → pygit2-1.19.2}/mypy.ini +0 -0
  55. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/blame.py +0 -0
  56. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/blob.py +0 -0
  57. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/branches.py +0 -0
  58. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/callbacks.py +0 -0
  59. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/credentials.py +0 -0
  60. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/attr.h +0 -0
  61. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/blame.h +0 -0
  62. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/buffer.h +0 -0
  63. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/callbacks.h +0 -0
  64. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/checkout.h +0 -0
  65. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/clone.h +0 -0
  66. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/commit.h +0 -0
  67. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/common.h +0 -0
  68. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/config.h +0 -0
  69. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/describe.h +0 -0
  70. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/diff.h +0 -0
  71. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/errors.h +0 -0
  72. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/graph.h +0 -0
  73. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/index.h +0 -0
  74. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/indexer.h +0 -0
  75. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/merge.h +0 -0
  76. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/net.h +0 -0
  77. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/oid.h +0 -0
  78. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/options.h +0 -0
  79. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/pack.h +0 -0
  80. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/proxy.h +0 -0
  81. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/refspec.h +0 -0
  82. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/remote.h +0 -0
  83. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/repository.h +0 -0
  84. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/revert.h +0 -0
  85. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/stash.h +0 -0
  86. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/strarray.h +0 -0
  87. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/submodule.h +0 -0
  88. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/transaction.h +0 -0
  89. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/decl/transport.h +0 -0
  90. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/enums.py +0 -0
  91. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/errors.py +0 -0
  92. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/ffi.py +0 -0
  93. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/index.py +0 -0
  94. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/legacyenums.py +0 -0
  95. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/options.py +0 -0
  96. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/packbuilder.py +0 -0
  97. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/py.typed +0 -0
  98. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/references.py +0 -0
  99. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/refspec.py +0 -0
  100. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/remotes.py +0 -0
  101. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/settings.py +0 -0
  102. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/submodules.py +0 -0
  103. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/transaction.py +0 -0
  104. {pygit2-1.19.0 → pygit2-1.19.2}/pygit2/utils.py +0 -0
  105. {pygit2-1.19.0 → pygit2-1.19.2}/pytest.ini +0 -0
  106. {pygit2-1.19.0 → pygit2-1.19.2}/requirements.txt +0 -0
  107. {pygit2-1.19.0 → pygit2-1.19.2}/setup.cfg +0 -0
  108. {pygit2-1.19.0 → pygit2-1.19.2}/setup.py +0 -0
  109. {pygit2-1.19.0 → pygit2-1.19.2}/src/blob.c +0 -0
  110. {pygit2-1.19.0 → pygit2-1.19.2}/src/branch.h +0 -0
  111. {pygit2-1.19.0 → pygit2-1.19.2}/src/commit.c +0 -0
  112. {pygit2-1.19.0 → pygit2-1.19.2}/src/diff.h +0 -0
  113. {pygit2-1.19.0 → pygit2-1.19.2}/src/error.c +0 -0
  114. {pygit2-1.19.0 → pygit2-1.19.2}/src/error.h +0 -0
  115. {pygit2-1.19.0 → pygit2-1.19.2}/src/filter.h +0 -0
  116. {pygit2-1.19.0 → pygit2-1.19.2}/src/mailmap.h +0 -0
  117. {pygit2-1.19.0 → pygit2-1.19.2}/src/note.h +0 -0
  118. {pygit2-1.19.0 → pygit2-1.19.2}/src/object.h +0 -0
  119. {pygit2-1.19.0 → pygit2-1.19.2}/src/odb.h +0 -0
  120. {pygit2-1.19.0 → pygit2-1.19.2}/src/odb_backend.h +0 -0
  121. {pygit2-1.19.0 → pygit2-1.19.2}/src/oid.c +0 -0
  122. {pygit2-1.19.0 → pygit2-1.19.2}/src/oid.h +0 -0
  123. {pygit2-1.19.0 → pygit2-1.19.2}/src/patch.h +0 -0
  124. {pygit2-1.19.0 → pygit2-1.19.2}/src/refdb.h +0 -0
  125. {pygit2-1.19.0 → pygit2-1.19.2}/src/refdb_backend.h +0 -0
  126. {pygit2-1.19.0 → pygit2-1.19.2}/src/reference.h +0 -0
  127. {pygit2-1.19.0 → pygit2-1.19.2}/src/repository.h +0 -0
  128. {pygit2-1.19.0 → pygit2-1.19.2}/src/revspec.c +0 -0
  129. {pygit2-1.19.0 → pygit2-1.19.2}/src/revspec.h +0 -0
  130. {pygit2-1.19.0 → pygit2-1.19.2}/src/signature.c +0 -0
  131. {pygit2-1.19.0 → pygit2-1.19.2}/src/signature.h +0 -0
  132. {pygit2-1.19.0 → pygit2-1.19.2}/src/stash.c +0 -0
  133. {pygit2-1.19.0 → pygit2-1.19.2}/src/tree.h +0 -0
  134. {pygit2-1.19.0 → pygit2-1.19.2}/src/treebuilder.h +0 -0
  135. {pygit2-1.19.0 → pygit2-1.19.2}/src/types.h +0 -0
  136. {pygit2-1.19.0 → pygit2-1.19.2}/src/walker.h +0 -0
  137. {pygit2-1.19.0 → pygit2-1.19.2}/src/wildmatch.c +0 -0
  138. {pygit2-1.19.0 → pygit2-1.19.2}/src/wildmatch.h +0 -0
  139. {pygit2-1.19.0 → pygit2-1.19.2}/src/worktree.h +0 -0
  140. {pygit2-1.19.0 → pygit2-1.19.2}/test/__init__.py +0 -0
  141. {pygit2-1.19.0 → pygit2-1.19.2}/test/conftest.py +0 -0
  142. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/barerepo.zip +0 -0
  143. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/binaryfilerepo.zip +0 -0
  144. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/blameflagsrepo.zip +0 -0
  145. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/dirtyrepo.zip +0 -0
  146. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/emptyrepo.zip +0 -0
  147. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/encoding.zip +0 -0
  148. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/gpgsigned.zip +0 -0
  149. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/submodulerepo.zip +0 -0
  150. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/testrepo.zip +0 -0
  151. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/testrepoformerging.zip +0 -0
  152. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/testrepopacked.zip +0 -0
  153. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/trailerrepo.zip +0 -0
  154. {pygit2-1.19.0 → pygit2-1.19.2}/test/data/utf8branchrepo.zip +0 -0
  155. {pygit2-1.19.0 → pygit2-1.19.2}/test/keys/pygit2_empty +0 -0
  156. {pygit2-1.19.0 → pygit2-1.19.2}/test/keys/pygit2_empty.pub +0 -0
  157. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_apply_diff.py +0 -0
  158. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_archive.py +0 -0
  159. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_attributes.py +0 -0
  160. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_blame.py +0 -0
  161. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_blob.py +0 -0
  162. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_branch.py +0 -0
  163. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_branch_empty.py +0 -0
  164. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_cherrypick.py +0 -0
  165. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_commit.py +0 -0
  166. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_commit_gpg.py +0 -0
  167. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_commit_trailer.py +0 -0
  168. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_credentials.py +0 -0
  169. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_describe.py +0 -0
  170. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_diff_binary.py +0 -0
  171. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_index.py +0 -0
  172. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_mailmap.py +0 -0
  173. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_merge.py +0 -0
  174. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_nonunicode.py +0 -0
  175. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_note.py +0 -0
  176. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_object.py +0 -0
  177. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_odb_backend.py +0 -0
  178. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_oid.py +0 -0
  179. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_options.py +0 -0
  180. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_packbuilder.py +0 -0
  181. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_patch.py +0 -0
  182. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_patch_encoding.py +0 -0
  183. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_refdb_backend.py +0 -0
  184. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_refs.py +0 -0
  185. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_remote.py +0 -0
  186. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_remote_prune.py +0 -0
  187. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_remote_utf8.py +0 -0
  188. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_repository_bare.py +0 -0
  189. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_repository_custom.py +0 -0
  190. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_repository_empty.py +0 -0
  191. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_revparse.py +0 -0
  192. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_revwalk.py +0 -0
  193. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_settings.py +0 -0
  194. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_signature.py +0 -0
  195. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_status.py +0 -0
  196. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_submodule.py +0 -0
  197. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_tag.py +0 -0
  198. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_transaction.py +0 -0
  199. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_tree.py +0 -0
  200. {pygit2-1.19.0 → pygit2-1.19.2}/test/test_treebuilder.py +0 -0
@@ -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
@@ -138,6 +138,7 @@ Authors:
138
138
  Adam Spiers
139
139
  Adrien Nader
140
140
  Albin Söderström
141
+ Alexander Shadchin
141
142
  Alexandru Fikl
142
143
  Andrew Chin
143
144
  Andrew McNulty
@@ -182,6 +183,7 @@ Authors:
182
183
  Hugh Cole-Baker
183
184
  Isabella Stephens
184
185
  Jacob Swanson
186
+ Jah-yee
185
187
  Jasper Lievisse Adriaanse
186
188
  Jimisola Laursen
187
189
  Jiri Benc
@@ -237,6 +239,7 @@ Authors:
237
239
  Timo Röhling
238
240
  Victor Florea
239
241
  Vladimir Rutsky
242
+ Vruyr Gyolchanyan
240
243
  William Schueller
241
244
  Wim Jeantine-Glenn
242
245
  Yu Jianjian
@@ -1,3 +1,36 @@
1
+ # 1.19.2 (2026-03-29)
2
+
3
+ - Fix refcount and error handling issues in `filter_register(...)`
4
+
5
+ - Fix config with valueless keys
6
+ [#1457](https://github.com/libgit2/pygit2/pull/1457)
7
+
8
+ - New `Repository.load_filter_list(...)` and `FilterList`
9
+ [#1444](https://github.com/libgit2/pygit2/pull/1444)
10
+
11
+ - New `Odb.read_header(...)` and now `Odb.read(...)` returns `enums.ObjectType` instead of int
12
+ [#1450](https://github.com/libgit2/pygit2/pull/1450)
13
+
14
+ - Build and CI fixes
15
+ [#1446](https://github.com/libgit2/pygit2/pull/1446)
16
+ [#1448](https://github.com/libgit2/pygit2/pull/1448)
17
+ [#1455](https://github.com/libgit2/pygit2/pull/1455)
18
+
19
+
20
+ # 1.19.1 (2025-12-29)
21
+
22
+ - Update wheels to libgit2 1.9.2 and OpenSSL 3.5
23
+
24
+ - Fix: now diff's getitem/iter returns `None` for unchanged or binary files
25
+ [#1412](https://github.com/libgit2/pygit2/pull/1412)
26
+
27
+ - CI (macOS): arm, intel and pypy wheels (instead of universal)
28
+ [#1441](https://github.com/libgit2/pygit2/pull/1441)
29
+
30
+ - CI (pypy): fix tests
31
+ [#1437](https://github.com/libgit2/pygit2/pull/1437)
32
+
33
+
1
34
  # 1.19.0 (2025-10-23)
2
35
 
3
36
  - Add support for Python 3.14 and drop 3.10
pygit2-1.19.2/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.2
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
 
@@ -286,7 +286,6 @@ from ._pygit2 import (
286
286
  _cache_enums,
287
287
  discover_repository,
288
288
  filter_register,
289
- filter_unregister,
290
289
  hash,
291
290
  hashfile,
292
291
  init_file_backend,
@@ -545,6 +544,27 @@ def clone_repository(
545
544
  return Repository._from_c(crepo[0], owned=True)
546
545
 
547
546
 
547
+ def filter_unregister(name: str) -> None:
548
+ """
549
+ Unregister the given filter.
550
+
551
+ Note that the filter registry is not thread safe. Any registering or
552
+ deregistering of filters should be done outside of any possible usage
553
+ of the filters.
554
+
555
+ In particular, any FilterLists that use the filter must have been garbage
556
+ collected before you can unregister the filter.
557
+ """
558
+ from .filter import FilterList
559
+
560
+ if FilterList._is_filter_in_use(name):
561
+ raise RuntimeError(f"filter still in use: '{name}'")
562
+
563
+ c_name = to_bytes(name)
564
+ err = C.git_filter_unregister(c_name)
565
+ check_error(err)
566
+
567
+
548
568
  tree_entry_key = functools.cmp_to_key(tree_entry_cmp)
549
569
 
550
570
  settings = Settings()
@@ -610,7 +630,6 @@ __all__ = (
610
630
  # Low Level API (not present in .pyi)
611
631
  'FilterSource',
612
632
  'filter_register',
613
- 'filter_unregister',
614
633
  'GIT_APPLY_LOCATION_BOTH',
615
634
  'GIT_APPLY_LOCATION_INDEX',
616
635
  'GIT_APPLY_LOCATION_WORKDIR',
@@ -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.2'
38
38
 
39
39
 
40
40
  #
@@ -123,6 +123,10 @@ class GitBlameC:
123
123
  # incomplete
124
124
  pass
125
125
 
126
+ class GitBlobC:
127
+ # incomplete
128
+ pass
129
+
126
130
  class GitMergeOptionsC:
127
131
  file_favor: int
128
132
  flags: int
@@ -177,6 +181,10 @@ class GitDescribeOptionsC:
177
181
  class GitDescribeResultC:
178
182
  pass
179
183
 
184
+ class GitFilterListC:
185
+ # opaque struct
186
+ pass
187
+
180
188
  class GitIndexC:
181
189
  pass
182
190
 
@@ -264,6 +272,8 @@ def new(a: Literal['git_oid *']) -> GitOidC: ...
264
272
  @overload
265
273
  def new(a: Literal['git_blame **']) -> _Pointer[GitBlameC]: ...
266
274
  @overload
275
+ def new(a: Literal['git_blob **']) -> _Pointer[GitBlobC]: ...
276
+ @overload
267
277
  def new(a: Literal['git_clone_options *']) -> GitCloneOptionsC: ...
268
278
  @overload
269
279
  def new(a: Literal['git_merge_options *']) -> GitMergeOptionsC: ...
@@ -318,6 +328,8 @@ def new(a: Literal['git_signature *']) -> GitSignatureC: ...
318
328
  @overload
319
329
  def new(a: Literal['git_signature **']) -> _Pointer[GitSignatureC]: ...
320
330
  @overload
331
+ def new(a: Literal['git_filter_list **']) -> _Pointer[GitFilterListC]: ...
332
+ @overload
321
333
  def new(a: Literal['int *']) -> int_c: ...
322
334
  @overload
323
335
  def new(a: Literal['int64_t *']) -> int64_t: ...
@@ -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:
@@ -518,7 +518,8 @@ class Odb:
518
518
  def add_backend(self, backend: OdbBackend, priority: int) -> None: ...
519
519
  def add_disk_alternate(self, path: str | Path) -> None: ...
520
520
  def exists(self, oid: _OidArg) -> bool: ...
521
- def read(self, oid: _OidArg) -> tuple[int, bytes]: ...
521
+ def read(self, oid: _OidArg) -> tuple[ObjectType, bytes]: ...
522
+ def read_header(self, oid: _OidArg) -> tuple[ObjectType, int]: ...
522
523
  def write(self, type: int, data: bytes | str) -> Oid: ...
523
524
  def __contains__(self, other: _OidArg) -> bool: ...
524
525
  def __iter__(self) -> Iterator[Oid]: ... # Odb_as_iter
@@ -857,6 +858,5 @@ def reference_is_valid_name(refname: str) -> bool: ...
857
858
  def tree_entry_cmp(a: Object, b: Object) -> int: ...
858
859
  def _cache_enums() -> None: ...
859
860
  def filter_register(name: str, filter: type[Filter]) -> None: ...
860
- def filter_unregister(name: str) -> None: ...
861
861
 
862
862
  _OidArg = str | Oid
@@ -77,6 +77,7 @@ h_files = [
77
77
  'net.h',
78
78
  'refspec.h',
79
79
  'repository.h',
80
+ 'filter.h',
80
81
  'commit.h',
81
82
  'revert.h',
82
83
  'stash.h',
@@ -96,6 +97,7 @@ C_HEADER_SRC = '\n'.join(h_source)
96
97
  C_PREAMBLE = """\
97
98
  #include <git2.h>
98
99
  #include <git2/sys/repository.h>
100
+ #include <git2/sys/filter.h>
99
101
  """
100
102
 
101
103
  # ffi
@@ -73,7 +73,7 @@ class ConfigIterator:
73
73
 
74
74
 
75
75
  class ConfigMultivarIterator(ConfigIterator):
76
- def __next__(self) -> str: # type: ignore[override]
76
+ def __next__(self) -> str | None: # type: ignore[override]
77
77
  entry = self._next_entry()
78
78
  return entry.value
79
79
 
@@ -137,7 +137,7 @@ class Config:
137
137
 
138
138
  return True
139
139
 
140
- def __getitem__(self, key: str | bytes) -> str:
140
+ def __getitem__(self, key: str | bytes) -> str | None:
141
141
  """
142
142
  When using the mapping interface, the value is returned as a string. In
143
143
  order to apply the git-config parsing rules, you can use
@@ -365,8 +365,8 @@ class ConfigEntry:
365
365
  return ffi.string(self._entry.name)
366
366
 
367
367
  @cached_property
368
- def raw_value(self) -> bytes:
369
- return ffi.string(self.c_value)
368
+ def raw_value(self) -> bytes | None:
369
+ return ffi.string(self.c_value) if self.c_value != ffi.NULL else None
370
370
 
371
371
  @cached_property
372
372
  def level(self) -> int:
@@ -379,6 +379,6 @@ class ConfigEntry:
379
379
  return self.raw_name.decode('utf-8')
380
380
 
381
381
  @property
382
- def value(self) -> str:
382
+ def value(self) -> str | None:
383
383
  """The entry's value as a string."""
384
- return self.raw_value.decode('utf-8')
384
+ return self.raw_value.decode('utf-8') if self.raw_value is not None else None
@@ -0,0 +1,49 @@
1
+ typedef enum {
2
+ GIT_FILTER_TO_WORKTREE = ...,
3
+ GIT_FILTER_TO_ODB = ...,
4
+ } git_filter_mode_t;
5
+
6
+ typedef enum {
7
+ GIT_FILTER_DEFAULT = ...,
8
+ GIT_FILTER_ALLOW_UNSAFE = ...,
9
+ GIT_FILTER_NO_SYSTEM_ATTRIBUTES = ...,
10
+ GIT_FILTER_ATTRIBUTES_FROM_HEAD = ...,
11
+ GIT_FILTER_ATTRIBUTES_FROM_COMMIT = ...,
12
+ } git_filter_flag_t;
13
+
14
+ int git_filter_unregister(
15
+ const char *name);
16
+
17
+ int git_filter_list_load(
18
+ git_filter_list **filters,
19
+ git_repository *repo,
20
+ git_blob *blob,
21
+ const char *path,
22
+ git_filter_mode_t mode,
23
+ uint32_t flags);
24
+
25
+ int git_filter_list_contains(
26
+ git_filter_list *filters,
27
+ const char *name);
28
+
29
+ int git_filter_list_apply_to_buffer(
30
+ git_buf *out,
31
+ git_filter_list *filters,
32
+ const char* in,
33
+ size_t in_len);
34
+
35
+ int git_filter_list_apply_to_file(
36
+ git_buf *out,
37
+ git_filter_list *filters,
38
+ git_repository *repo,
39
+ const char *path);
40
+
41
+ int git_filter_list_apply_to_blob(
42
+ git_buf *out,
43
+ git_filter_list *filters,
44
+ git_blob *blob);
45
+
46
+ size_t git_filter_list_length(
47
+ const git_filter_list *fl);
48
+
49
+ void git_filter_list_free(git_filter_list *filters);
@@ -1,6 +1,8 @@
1
+ typedef struct git_blob git_blob;
1
2
  typedef struct git_commit git_commit;
2
3
  typedef struct git_annotated_commit git_annotated_commit;
3
4
  typedef struct git_config git_config;
5
+ typedef struct git_filter_list git_filter_list;
4
6
  typedef struct git_index git_index;
5
7
  typedef struct git_index_conflict_iterator git_index_conflict_iterator;
6
8
  typedef struct git_object git_object;
@@ -23,9 +23,20 @@
23
23
  # the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24
24
  # Boston, MA 02110-1301, USA.
25
25
 
26
+ from __future__ import annotations
27
+
28
+ import weakref
26
29
  from collections.abc import Callable
30
+ from typing import TYPE_CHECKING
31
+
32
+ from ._pygit2 import Blob, FilterSource
33
+ from .errors import check_error
34
+ from .ffi import C, ffi
35
+ from .utils import to_bytes
27
36
 
28
- from ._pygit2 import FilterSource
37
+ if TYPE_CHECKING:
38
+ from ._libgit2.ffi import GitFilterListC
39
+ from .repository import BaseRepository
29
40
 
30
41
 
31
42
  class Filter:
@@ -107,3 +118,90 @@ class Filter:
107
118
  Any remaining filtered output data must be written to
108
119
  `write_next` before returning.
109
120
  """
121
+
122
+
123
+ class FilterList:
124
+ _all_filter_lists: set[weakref.ReferenceType[FilterList]] = set()
125
+
126
+ _pointer: GitFilterListC
127
+
128
+ @classmethod
129
+ def _from_c(cls, ptr: GitFilterListC):
130
+ if ptr == ffi.NULL:
131
+ return None
132
+
133
+ fl = cls.__new__(cls)
134
+ fl._pointer = ptr
135
+
136
+ # Keep track of this FilterList until it's garbage collected. This lets
137
+ # `filter_unregister` ensure the user isn't trying to delete a filter
138
+ # that's still in use.
139
+ ref = weakref.ref(fl, FilterList._all_filter_lists.remove)
140
+ FilterList._all_filter_lists.add(ref)
141
+
142
+ return fl
143
+
144
+ @classmethod
145
+ def _is_filter_in_use(cls, name: str) -> bool:
146
+ for ref in cls._all_filter_lists:
147
+ fl = ref()
148
+ if fl is not None and name in fl:
149
+ return True
150
+ return False
151
+
152
+ def __contains__(self, name: str) -> bool:
153
+ if not isinstance(name, str):
154
+ raise TypeError('argument must be str')
155
+ c_name = to_bytes(name)
156
+ result = C.git_filter_list_contains(self._pointer, c_name)
157
+ return bool(result)
158
+
159
+ def __len__(self) -> int:
160
+ return C.git_filter_list_length(self._pointer)
161
+
162
+ def apply_to_buffer(self, data: bytes) -> bytes:
163
+ """
164
+ Apply a filter list to a data buffer.
165
+ Return the filtered contents.
166
+ """
167
+ buf = ffi.new('git_buf *')
168
+ err = C.git_filter_list_apply_to_buffer(buf, self._pointer, data, len(data))
169
+ check_error(err)
170
+ try:
171
+ return ffi.string(buf.ptr)
172
+ finally:
173
+ C.git_buf_dispose(buf)
174
+
175
+ def apply_to_file(self, repo: BaseRepository, path: str) -> bytes:
176
+ """
177
+ Apply a filter list to the contents of a file on disk.
178
+ Return the filtered contents.
179
+ """
180
+ buf = ffi.new('git_buf *')
181
+ c_path = to_bytes(path)
182
+ err = C.git_filter_list_apply_to_file(buf, self._pointer, repo._repo, c_path)
183
+ check_error(err)
184
+ try:
185
+ return ffi.string(buf.ptr)
186
+ finally:
187
+ C.git_buf_dispose(buf)
188
+
189
+ def apply_to_blob(self, blob: Blob) -> bytes:
190
+ """
191
+ Apply a filter list to a data buffer.
192
+ Return the filtered contents.
193
+ """
194
+ buf = ffi.new('git_buf *')
195
+
196
+ c_blob = ffi.new('git_blob **')
197
+ ffi.buffer(c_blob)[:] = blob._pointer[:]
198
+
199
+ err = C.git_filter_list_apply_to_blob(buf, self._pointer, c_blob[0])
200
+ check_error(err)
201
+ try:
202
+ return ffi.string(buf.ptr)
203
+ finally:
204
+ C.git_buf_dispose(buf)
205
+
206
+ def __del__(self):
207
+ C.git_filter_list_free(self._pointer)
@@ -64,6 +64,7 @@ from .enums import (
64
64
  DescribeStrategy,
65
65
  DiffOption,
66
66
  FileMode,
67
+ FilterMode,
67
68
  MergeFavor,
68
69
  MergeFileFlag,
69
70
  MergeFlag,
@@ -73,6 +74,7 @@ from .enums import (
73
74
  )
74
75
  from .errors import check_error
75
76
  from .ffi import C, ffi
77
+ from .filter import FilterList
76
78
  from .index import Index, IndexEntry, MergeFileResult
77
79
  from .packbuilder import PackBuilder
78
80
  from .references import References
@@ -235,6 +237,31 @@ class BaseRepository(_Repository):
235
237
  oid = Oid(raw=bytes(ffi.buffer(c_oid.id)[:]))
236
238
  return oid
237
239
 
240
+ def load_filter_list(
241
+ self, path: str, mode: FilterMode = FilterMode.TO_ODB
242
+ ) -> FilterList | None:
243
+ """
244
+ Load the filter list for a given path.
245
+ May return None if there are no filters to apply to this path.
246
+
247
+ Parameters:
248
+
249
+ path
250
+ Relative path of the file to be filtered
251
+
252
+ mode
253
+ Filtering direction: ODB to worktree (SMUDGE), or worktree to ODB
254
+ (CLEAN).
255
+ """
256
+ c_filters = ffi.new('git_filter_list **')
257
+ c_path = to_bytes(path)
258
+ c_mode = int(mode)
259
+
260
+ err = C.git_filter_list_load(c_filters, self._repo, ffi.NULL, c_path, c_mode, 0)
261
+ check_error(err)
262
+ fl = FilterList._from_c(c_filters[0])
263
+ return fl
264
+
238
265
  def __iter__(self) -> Iterator[Oid]:
239
266
  return iter(self.odb)
240
267
 
@@ -1,5 +1,6 @@
1
1
  [build-system]
2
- requires = ["setuptools", "wheel"]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
3
4
 
4
5
  [tool.cibuildwheel]
5
6
  enable = ["pypy"]
@@ -8,14 +9,16 @@ skip = "*musllinux_ppc64le"
8
9
  archs = ["native"]
9
10
  build-frontend = "default"
10
11
  dependency-versions = "pinned"
11
- environment = {LIBGIT2_VERSION="1.9.1", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.3.3", LIBGIT2="/project/ci"}
12
+ environment = {LIBGIT2_VERSION="1.9.2", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.5.4", LIBGIT2="/project/ci"}
12
13
 
13
14
  before-all = "sh build.sh"
14
15
  test-command = "pytest"
15
16
  test-sources = ["test", "pytest.ini"]
16
17
  before-test = "pip install -r {project}/requirements-test.txt"
17
18
  # Will avoid testing on emulated architectures (specifically ppc64le)
18
- test-skip = "*-*linux_ppc64le"
19
+ # Also, skip testing pypy on macOS arm64 due issue with bootstrapping git config paths
20
+ # see https://github.com/libgit2/pygit2/issues/1442
21
+ test-skip = "*-*linux_ppc64le pp*-macosx_arm64"
19
22
 
20
23
  [tool.cibuildwheel.linux]
21
24
  repair-wheel-command = "LD_LIBRARY_PATH=/project/ci/lib64 auditwheel repair -w {dest_dir} {wheel}"
@@ -25,13 +28,12 @@ select = "*-musllinux*"
25
28
  repair-wheel-command = "LD_LIBRARY_PATH=/project/ci/lib auditwheel repair -w {dest_dir} {wheel}"
26
29
 
27
30
  [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"}
31
+ environment = {LIBGIT2_VERSION="1.9.2", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.5.4", LIBGIT2="/Users/runner/work/pygit2/pygit2/ci"}
30
32
  repair-wheel-command = "DYLD_LIBRARY_PATH=/Users/runner/work/pygit2/pygit2/ci/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}"
31
33
 
32
34
  [tool.cibuildwheel.windows]
33
35
  environment.LIBGIT2_SRC = "build/libgit2_src"
34
- environment.LIBGIT2_VERSION = "1.9.1"
36
+ environment.LIBGIT2_VERSION = "1.9.2"
35
37
  before-all = "powershell -File build.ps1"
36
38
 
37
39
  [[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
@@ -275,7 +275,7 @@ Branch_upstream_name__get__(Branch *self)
275
275
  }
276
276
 
277
277
 
278
- PyMethodDef Branch_methods[] = {
278
+ static PyMethodDef Branch_methods[] = {
279
279
  METHOD(Branch, delete, METH_NOARGS),
280
280
  METHOD(Branch, is_head, METH_NOARGS),
281
281
  METHOD(Branch, is_checked_out, METH_NOARGS),
@@ -236,7 +236,7 @@ PyMemberDef DiffFile_members[] = {
236
236
  {NULL}
237
237
  };
238
238
 
239
- PyMethodDef DiffFile_methods[] = {
239
+ static PyMethodDef DiffFile_methods[] = {
240
240
  METHOD(DiffFile, from_c, METH_STATIC | METH_O),
241
241
  {NULL},
242
242
  };
@@ -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
 
@@ -909,7 +914,7 @@ DiffStats_dealloc(DiffStats *self)
909
914
  PyObject_Del(self);
910
915
  }
911
916
 
912
- PyMethodDef DiffStats_methods[] = {
917
+ static PyMethodDef DiffStats_methods[] = {
913
918
  METHOD(DiffStats, format, METH_VARARGS | METH_KEYWORDS),
914
919
  {NULL}
915
920
  };
@@ -551,7 +551,9 @@ void pygit2_filter_cleanup(git_filter *self, void *payload)
551
551
  void pygit2_filter_shutdown(git_filter *self)
552
552
  {
553
553
  pygit2_filter *filter = (pygit2_filter *)self;
554
+
554
555
  PyGILState_STATE gil = PyGILState_Ensure();
556
+ free((void*)filter->filter.attributes);
555
557
  Py_DECREF(filter->py_filter_cls);
556
558
  free(filter);
557
559
  PyGILState_Release(gil);
@@ -188,7 +188,7 @@ Mailmap_dealloc(Mailmap *self)
188
188
  }
189
189
 
190
190
 
191
- PyMethodDef Mailmap_methods[] = {
191
+ static PyMethodDef Mailmap_methods[] = {
192
192
  METHOD(Mailmap, add_entry, METH_VARARGS | METH_KEYWORDS),
193
193
  METHOD(Mailmap, resolve, METH_VARARGS),
194
194
  METHOD(Mailmap, resolve_signature, METH_VARARGS),
@@ -99,7 +99,7 @@ Note_dealloc(Note *self)
99
99
  }
100
100
 
101
101
 
102
- PyMethodDef Note_methods[] = {
102
+ static PyMethodDef Note_methods[] = {
103
103
  METHOD(Note, remove, METH_VARARGS),
104
104
  {NULL}
105
105
  };
@@ -302,7 +302,7 @@ PyGetSetDef Object_getseters[] = {
302
302
  {NULL}
303
303
  };
304
304
 
305
- PyMethodDef Object_methods[] = {
305
+ static PyMethodDef Object_methods[] = {
306
306
  METHOD(Object, read_raw, METH_NOARGS),
307
307
  METHOD(Object, peel, METH_O),
308
308
  {NULL}