rustfits 0.1.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 (269) hide show
  1. rustfits-0.1.2/.github/workflows/ci.yml +244 -0
  2. rustfits-0.1.2/.gitignore +62 -0
  3. rustfits-0.1.2/.readthedocs.yaml +24 -0
  4. rustfits-0.1.2/.ruff.toml +14 -0
  5. rustfits-0.1.2/CLAUDE.md +3983 -0
  6. rustfits-0.1.2/Cargo.lock +854 -0
  7. rustfits-0.1.2/Cargo.toml +35 -0
  8. rustfits-0.1.2/LICENSE-APACHE +201 -0
  9. rustfits-0.1.2/LICENSE-MIT +21 -0
  10. rustfits-0.1.2/PKG-INFO +201 -0
  11. rustfits-0.1.2/README.md +186 -0
  12. rustfits-0.1.2/STRATEGY.md +126 -0
  13. rustfits-0.1.2/codecov.yml +30 -0
  14. rustfits-0.1.2/conda-requirements.txt +17 -0
  15. rustfits-0.1.2/conda-test-requirements.txt +24 -0
  16. rustfits-0.1.2/docs/DoA-plan.md +264 -0
  17. rustfits-0.1.2/docs/README.txt +3 -0
  18. rustfits-0.1.2/docs/_static/perf.css +13 -0
  19. rustfits-0.1.2/docs/api/compression.rst +30 -0
  20. rustfits-0.1.2/docs/api/convenience.rst +19 -0
  21. rustfits-0.1.2/docs/api/fits.rst +6 -0
  22. rustfits-0.1.2/docs/api/hdus/ascii_table.rst +18 -0
  23. rustfits-0.1.2/docs/api/hdus/base.rst +10 -0
  24. rustfits-0.1.2/docs/api/hdus/compressed_image.rst +9 -0
  25. rustfits-0.1.2/docs/api/hdus/compressed_table.rst +9 -0
  26. rustfits-0.1.2/docs/api/hdus/image.rst +8 -0
  27. rustfits-0.1.2/docs/api/hdus/subsets.rst +30 -0
  28. rustfits-0.1.2/docs/api/hdus/table.rst +8 -0
  29. rustfits-0.1.2/docs/api/hdus.rst +23 -0
  30. rustfits-0.1.2/docs/api/header.rst +14 -0
  31. rustfits-0.1.2/docs/conf.py +57 -0
  32. rustfits-0.1.2/docs/index.rst +53 -0
  33. rustfits-0.1.2/docs/internal/perf-history.md +394 -0
  34. rustfits-0.1.2/docs/internal/upstream-bugs.md +364 -0
  35. rustfits-0.1.2/docs/internal/zimage.md +1277 -0
  36. rustfits-0.1.2/docs/internal/ztable.md +1026 -0
  37. rustfits-0.1.2/docs/requirements.txt +4 -0
  38. rustfits-0.1.2/docs/tutorial/_perf_tables_self.rst +118 -0
  39. rustfits-0.1.2/docs/tutorial/_perf_tables_xtool.rst +387 -0
  40. rustfits-0.1.2/docs/tutorial/compression.rst +210 -0
  41. rustfits-0.1.2/docs/tutorial/drivers.rst +249 -0
  42. rustfits-0.1.2/docs/tutorial/errors.rst +139 -0
  43. rustfits-0.1.2/docs/tutorial/headers.rst +202 -0
  44. rustfits-0.1.2/docs/tutorial/images.rst +252 -0
  45. rustfits-0.1.2/docs/tutorial/index.rst +29 -0
  46. rustfits-0.1.2/docs/tutorial/limitations.rst +82 -0
  47. rustfits-0.1.2/docs/tutorial/migration.rst +397 -0
  48. rustfits-0.1.2/docs/tutorial/performance.rst +1082 -0
  49. rustfits-0.1.2/docs/tutorial/quickstart.rst +355 -0
  50. rustfits-0.1.2/docs/tutorial/tables.rst +452 -0
  51. rustfits-0.1.2/docs/vla-shapes.md +112 -0
  52. rustfits-0.1.2/perf/_compread.py +143 -0
  53. rustfits-0.1.2/perf/_data.py +215 -0
  54. rustfits-0.1.2/perf/_harness.py +391 -0
  55. rustfits-0.1.2/perf/_read2d.py +71 -0
  56. rustfits-0.1.2/perf/perf-all.py +889 -0
  57. rustfits-0.1.2/perf/perf-compressed-2d-isolation.py +156 -0
  58. rustfits-0.1.2/perf/perf-compressed-image-extend-2d.py +328 -0
  59. rustfits-0.1.2/perf/perf-compressed-image-extend-healsparse.py +262 -0
  60. rustfits-0.1.2/perf/perf-compressed-image-read-1d-scattered.py +282 -0
  61. rustfits-0.1.2/perf/perf-compressed-image-read-des.py +165 -0
  62. rustfits-0.1.2/perf/perf-compressed-image-read-healsparse.py +102 -0
  63. rustfits-0.1.2/perf/perf-compressed-image-read-random.py +81 -0
  64. rustfits-0.1.2/perf/perf-compressed-image-repack.py +222 -0
  65. rustfits-0.1.2/perf/perf-compressed-image-setitem.py +320 -0
  66. rustfits-0.1.2/perf/perf-compressed-image-write-des.py +124 -0
  67. rustfits-0.1.2/perf/perf-compressed-image-write-healsparse.py +117 -0
  68. rustfits-0.1.2/perf/perf-fits-contains-many-hdus.py +183 -0
  69. rustfits-0.1.2/perf/perf-fits-open-many-hdus.py +215 -0
  70. rustfits-0.1.2/perf/perf-fits-open-one.py +115 -0
  71. rustfits-0.1.2/perf/perf-image-extend-1d.py +199 -0
  72. rustfits-0.1.2/perf/perf-image-extend-2d.py +281 -0
  73. rustfits-0.1.2/perf/perf-image-read-1d.py +116 -0
  74. rustfits-0.1.2/perf/perf-image-read-2d.py +104 -0
  75. rustfits-0.1.2/perf/perf-image-write-1d.py +83 -0
  76. rustfits-0.1.2/perf/perf-image-write-2d.py +82 -0
  77. rustfits-0.1.2/perf/perf-table-append.py +323 -0
  78. rustfits-0.1.2/perf/perf-table-compressed-append-chunks.py +294 -0
  79. rustfits-0.1.2/perf/perf-table-compressed-read.py +169 -0
  80. rustfits-0.1.2/perf/perf-table-compressed-repack.py +210 -0
  81. rustfits-0.1.2/perf/perf-table-compressed-write.py +118 -0
  82. rustfits-0.1.2/perf/perf-table-read.py +156 -0
  83. rustfits-0.1.2/perf/perf-table-repack.py +230 -0
  84. rustfits-0.1.2/perf/perf-table-write.py +95 -0
  85. rustfits-0.1.2/pyproject.toml +20 -0
  86. rustfits-0.1.2/rustfits/__init__.py +30 -0
  87. rustfits-0.1.2/rustfits/convenience.py +171 -0
  88. rustfits-0.1.2/rustfits/fitsio.py +124 -0
  89. rustfits-0.1.2/src/cache.rs +121 -0
  90. rustfits-0.1.2/src/checksum.rs +477 -0
  91. rustfits-0.1.2/src/common.rs +936 -0
  92. rustfits-0.1.2/src/fits.rs +2765 -0
  93. rustfits-0.1.2/src/hdu.rs +276 -0
  94. rustfits-0.1.2/src/hdu_ascii_table/columns.rs +303 -0
  95. rustfits-0.1.2/src/hdu_ascii_table/edit.rs +787 -0
  96. rustfits-0.1.2/src/hdu_ascii_table/format.rs +322 -0
  97. rustfits-0.1.2/src/hdu_ascii_table/hdu.rs +1042 -0
  98. rustfits-0.1.2/src/hdu_ascii_table/meta.rs +29 -0
  99. rustfits-0.1.2/src/hdu_ascii_table/mod.rs +21 -0
  100. rustfits-0.1.2/src/hdu_ascii_table/read.rs +713 -0
  101. rustfits-0.1.2/src/hdu_ascii_table/setitem.rs +632 -0
  102. rustfits-0.1.2/src/hdu_ascii_table/write_fixed.rs +634 -0
  103. rustfits-0.1.2/src/hdu_ascii_table/write_setup.rs +379 -0
  104. rustfits-0.1.2/src/hdu_image.rs +2232 -0
  105. rustfits-0.1.2/src/hdu_image_compressed/checksum.rs +408 -0
  106. rustfits-0.1.2/src/hdu_image_compressed/extending.rs +472 -0
  107. rustfits-0.1.2/src/hdu_image_compressed/hdu.rs +852 -0
  108. rustfits-0.1.2/src/hdu_image_compressed/meta.rs +637 -0
  109. rustfits-0.1.2/src/hdu_image_compressed/mod.rs +28 -0
  110. rustfits-0.1.2/src/hdu_image_compressed/read.rs +1038 -0
  111. rustfits-0.1.2/src/hdu_image_compressed/repack.rs +350 -0
  112. rustfits-0.1.2/src/hdu_image_compressed/write.rs +2538 -0
  113. rustfits-0.1.2/src/hdu_table/columns.rs +499 -0
  114. rustfits-0.1.2/src/hdu_table/edit.rs +1262 -0
  115. rustfits-0.1.2/src/hdu_table/hdu.rs +1550 -0
  116. rustfits-0.1.2/src/hdu_table/iter.rs +179 -0
  117. rustfits-0.1.2/src/hdu_table/mod.rs +45 -0
  118. rustfits-0.1.2/src/hdu_table/read.rs +1479 -0
  119. rustfits-0.1.2/src/hdu_table/setitem.rs +1383 -0
  120. rustfits-0.1.2/src/hdu_table/write_fixed.rs +1008 -0
  121. rustfits-0.1.2/src/hdu_table/write_setup.rs +697 -0
  122. rustfits-0.1.2/src/hdu_table/write_vla.rs +1411 -0
  123. rustfits-0.1.2/src/hdu_table_compressed/append.rs +831 -0
  124. rustfits-0.1.2/src/hdu_table_compressed/checksum.rs +429 -0
  125. rustfits-0.1.2/src/hdu_table_compressed/extending.rs +510 -0
  126. rustfits-0.1.2/src/hdu_table_compressed/hdu.rs +1262 -0
  127. rustfits-0.1.2/src/hdu_table_compressed/meta.rs +73 -0
  128. rustfits-0.1.2/src/hdu_table_compressed/mod.rs +33 -0
  129. rustfits-0.1.2/src/hdu_table_compressed/read.rs +703 -0
  130. rustfits-0.1.2/src/hdu_table_compressed/repack.rs +743 -0
  131. rustfits-0.1.2/src/hdu_table_compressed/setitem.rs +755 -0
  132. rustfits-0.1.2/src/hdu_table_compressed/subset.rs +434 -0
  133. rustfits-0.1.2/src/hdu_table_compressed/write.rs +462 -0
  134. rustfits-0.1.2/src/hdu_table_compressed/write_setup.rs +598 -0
  135. rustfits-0.1.2/src/header.rs +2217 -0
  136. rustfits-0.1.2/src/lib.rs +78 -0
  137. rustfits-0.1.2/src/zimage/compression_config.rs +1011 -0
  138. rustfits-0.1.2/src/zimage/gzip.rs +222 -0
  139. rustfits-0.1.2/src/zimage/hcompress.rs +2448 -0
  140. rustfits-0.1.2/src/zimage/mod.rs +198 -0
  141. rustfits-0.1.2/src/zimage/plio.rs +599 -0
  142. rustfits-0.1.2/src/zimage/quantize.rs +1618 -0
  143. rustfits-0.1.2/src/zimage/rice.rs +797 -0
  144. rustfits-0.1.2/src/zimage/tile_io.rs +15 -0
  145. rustfits-0.1.2/tests/test_ascii_table_append.py +170 -0
  146. rustfits-0.1.2/tests/test_ascii_table_checksum.py +182 -0
  147. rustfits-0.1.2/tests/test_ascii_table_create.py +246 -0
  148. rustfits-0.1.2/tests/test_ascii_table_edit_columns.py +641 -0
  149. rustfits-0.1.2/tests/test_ascii_table_iter.py +194 -0
  150. rustfits-0.1.2/tests/test_ascii_table_read.py +657 -0
  151. rustfits-0.1.2/tests/test_ascii_table_read_slice.py +503 -0
  152. rustfits-0.1.2/tests/test_ascii_table_setitem.py +535 -0
  153. rustfits-0.1.2/tests/test_ascii_table_setitem_subset.py +398 -0
  154. rustfits-0.1.2/tests/test_ascii_table_write.py +323 -0
  155. rustfits-0.1.2/tests/test_convenience_read.py +373 -0
  156. rustfits-0.1.2/tests/test_convenience_write.py +643 -0
  157. rustfits-0.1.2/tests/test_fits_contains.py +150 -0
  158. rustfits-0.1.2/tests/test_fits_ftp.py +205 -0
  159. rustfits-0.1.2/tests/test_fits_getitem.py +289 -0
  160. rustfits-0.1.2/tests/test_fits_gz.py +238 -0
  161. rustfits-0.1.2/tests/test_fits_mem.py +252 -0
  162. rustfits-0.1.2/tests/test_fits_open.py +64 -0
  163. rustfits-0.1.2/tests/test_fits_open_multi.py +84 -0
  164. rustfits-0.1.2/tests/test_fits_remote.py +181 -0
  165. rustfits-0.1.2/tests/test_fitsio_shim.py +250 -0
  166. rustfits-0.1.2/tests/test_hdu_accessors.py +423 -0
  167. rustfits-0.1.2/tests/test_hdu_checksum.py +362 -0
  168. rustfits-0.1.2/tests/test_hdu_data_size.py +179 -0
  169. rustfits-0.1.2/tests/test_hdu_extending_noop.py +326 -0
  170. rustfits-0.1.2/tests/test_hdu_units.py +293 -0
  171. rustfits-0.1.2/tests/test_header_class.py +326 -0
  172. rustfits-0.1.2/tests/test_header_commentary_write.py +558 -0
  173. rustfits-0.1.2/tests/test_header_complex_write.py +261 -0
  174. rustfits-0.1.2/tests/test_header_continue.py +110 -0
  175. rustfits-0.1.2/tests/test_header_continue_write.py +357 -0
  176. rustfits-0.1.2/tests/test_header_edit.py +240 -0
  177. rustfits-0.1.2/tests/test_header_features.py +122 -0
  178. rustfits-0.1.2/tests/test_header_grow.py +377 -0
  179. rustfits-0.1.2/tests/test_header_hierarch_case.py +262 -0
  180. rustfits-0.1.2/tests/test_header_hierarch_write.py +608 -0
  181. rustfits-0.1.2/tests/test_header_lenient.py +219 -0
  182. rustfits-0.1.2/tests/test_header_mutation.py +413 -0
  183. rustfits-0.1.2/tests/test_header_protected.py +372 -0
  184. rustfits-0.1.2/tests/test_header_robustness.py +326 -0
  185. rustfits-0.1.2/tests/test_header_taint.py +200 -0
  186. rustfits-0.1.2/tests/test_healsparse_bitpack_roundtrip.py +441 -0
  187. rustfits-0.1.2/tests/test_image_blank.py +227 -0
  188. rustfits-0.1.2/tests/test_image_blank_mask.py +433 -0
  189. rustfits-0.1.2/tests/test_image_compressed_accessors.py +380 -0
  190. rustfits-0.1.2/tests/test_image_compressed_extend.py +474 -0
  191. rustfits-0.1.2/tests/test_image_compressed_extending.py +455 -0
  192. rustfits-0.1.2/tests/test_image_compressed_float_edges.py +393 -0
  193. rustfits-0.1.2/tests/test_image_compressed_gzip_level.py +232 -0
  194. rustfits-0.1.2/tests/test_image_compressed_quant_mutation.py +347 -0
  195. rustfits-0.1.2/tests/test_image_compressed_read_gzip.py +567 -0
  196. rustfits-0.1.2/tests/test_image_compressed_read_hcompress.py +259 -0
  197. rustfits-0.1.2/tests/test_image_compressed_read_plio.py +118 -0
  198. rustfits-0.1.2/tests/test_image_compressed_read_quantize.py +467 -0
  199. rustfits-0.1.2/tests/test_image_compressed_read_rice.py +346 -0
  200. rustfits-0.1.2/tests/test_image_compressed_read_slice.py +450 -0
  201. rustfits-0.1.2/tests/test_image_compressed_repack.py +392 -0
  202. rustfits-0.1.2/tests/test_image_compressed_setitem.py +502 -0
  203. rustfits-0.1.2/tests/test_image_compressed_unsigned_trick.py +318 -0
  204. rustfits-0.1.2/tests/test_image_compressed_write_gzip.py +297 -0
  205. rustfits-0.1.2/tests/test_image_compressed_write_gzip2.py +342 -0
  206. rustfits-0.1.2/tests/test_image_compressed_write_hcompress.py +659 -0
  207. rustfits-0.1.2/tests/test_image_compressed_write_plio.py +549 -0
  208. rustfits-0.1.2/tests/test_image_compressed_write_quantize.py +419 -0
  209. rustfits-0.1.2/tests/test_image_compressed_write_rice.py +489 -0
  210. rustfits-0.1.2/tests/test_image_compressed_write_unquantized.py +418 -0
  211. rustfits-0.1.2/tests/test_image_create.py +261 -0
  212. rustfits-0.1.2/tests/test_image_extend.py +253 -0
  213. rustfits-0.1.2/tests/test_image_extend_grow.py +244 -0
  214. rustfits-0.1.2/tests/test_image_general_scaling_write.py +502 -0
  215. rustfits-0.1.2/tests/test_image_read.py +222 -0
  216. rustfits-0.1.2/tests/test_image_read_slices.py +347 -0
  217. rustfits-0.1.2/tests/test_image_scalar_index.py +198 -0
  218. rustfits-0.1.2/tests/test_image_scale.py +268 -0
  219. rustfits-0.1.2/tests/test_image_scale_write.py +254 -0
  220. rustfits-0.1.2/tests/test_image_setitem.py +297 -0
  221. rustfits-0.1.2/tests/test_image_setitem_scaled_scalar.py +315 -0
  222. rustfits-0.1.2/tests/test_image_unaligned.py +80 -0
  223. rustfits-0.1.2/tests/test_image_write.py +653 -0
  224. rustfits-0.1.2/tests/test_repr.py +1209 -0
  225. rustfits-0.1.2/tests/test_table_append.py +377 -0
  226. rustfits-0.1.2/tests/test_table_bit_columns.py +612 -0
  227. rustfits-0.1.2/tests/test_table_compressed_accessors.py +361 -0
  228. rustfits-0.1.2/tests/test_table_compressed_append.py +407 -0
  229. rustfits-0.1.2/tests/test_table_compressed_appending.py +384 -0
  230. rustfits-0.1.2/tests/test_table_compressed_checksum.py +583 -0
  231. rustfits-0.1.2/tests/test_table_compressed_read.py +397 -0
  232. rustfits-0.1.2/tests/test_table_compressed_read_slice.py +412 -0
  233. rustfits-0.1.2/tests/test_table_compressed_read_vla.py +334 -0
  234. rustfits-0.1.2/tests/test_table_compressed_repack.py +283 -0
  235. rustfits-0.1.2/tests/test_table_compressed_setitem_cols.py +645 -0
  236. rustfits-0.1.2/tests/test_table_compressed_setitem_rows.py +609 -0
  237. rustfits-0.1.2/tests/test_table_compressed_setitem_stepped_subsets.py +492 -0
  238. rustfits-0.1.2/tests/test_table_compressed_setitem_vla.py +598 -0
  239. rustfits-0.1.2/tests/test_table_compressed_vla_append.py +492 -0
  240. rustfits-0.1.2/tests/test_table_compressed_vla_repack.py +613 -0
  241. rustfits-0.1.2/tests/test_table_compressed_write.py +570 -0
  242. rustfits-0.1.2/tests/test_table_compressed_write_vla.py +441 -0
  243. rustfits-0.1.2/tests/test_table_create.py +417 -0
  244. rustfits-0.1.2/tests/test_table_create_dtypes.py +265 -0
  245. rustfits-0.1.2/tests/test_table_create_input_forms.py +395 -0
  246. rustfits-0.1.2/tests/test_table_create_strings.py +316 -0
  247. rustfits-0.1.2/tests/test_table_create_subarray.py +283 -0
  248. rustfits-0.1.2/tests/test_table_edit_columns.py +1013 -0
  249. rustfits-0.1.2/tests/test_table_iter.py +403 -0
  250. rustfits-0.1.2/tests/test_table_read.py +2116 -0
  251. rustfits-0.1.2/tests/test_table_setitem.py +463 -0
  252. rustfits-0.1.2/tests/test_table_setitem_multi.py +435 -0
  253. rustfits-0.1.2/tests/test_table_setitem_subset.py +350 -0
  254. rustfits-0.1.2/tests/test_table_single_row.py +281 -0
  255. rustfits-0.1.2/tests/test_table_subset_read_write.py +464 -0
  256. rustfits-0.1.2/tests/test_table_subset_scalar_index.py +314 -0
  257. rustfits-0.1.2/tests/test_table_tnull.py +524 -0
  258. rustfits-0.1.2/tests/test_table_vla_repack.py +335 -0
  259. rustfits-0.1.2/tests/test_table_vla_setitem.py +581 -0
  260. rustfits-0.1.2/tests/test_table_vla_string_write.py +373 -0
  261. rustfits-0.1.2/tests/test_table_vla_write.py +463 -0
  262. rustfits-0.1.2/tests/test_table_vla_x_bit.py +515 -0
  263. rustfits-0.1.2/tools/cargo-test.sh +29 -0
  264. rustfits-0.1.2/tools/cfitsio-repro/README.md +505 -0
  265. rustfits-0.1.2/tools/cfitsio-repro/gzip2_complex_funpack.c +61 -0
  266. rustfits-0.1.2/tools/cfitsio-repro/pa_vla_funpack_crash.c +64 -0
  267. rustfits-0.1.2/tools/cfitsio-repro/plio_small_image_overflow.c +111 -0
  268. rustfits-0.1.2/tools/cfitsio-repro/run.sh +112 -0
  269. rustfits-0.1.2/tools/cfitsio-repro/setitem_sweep_corruption.c +77 -0
@@ -0,0 +1,244 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ # Cancel superseded in-progress runs for the same branch / PR — keeps
9
+ # the queue from piling up when you push twice in quick succession.
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ # ----- Lint -------------------------------------------------------
16
+ # Runs ruff format-check and ruff check on the Python sources. No
17
+ # Rust toolchain or build needed — fast feedback on style.
18
+ lint:
19
+ name: Lint (ruff)
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: mamba-org/setup-micromamba@v2
24
+ with:
25
+ environment-name: rustfits-lint
26
+ create-args: >-
27
+ python=3.12
28
+ ruff
29
+ cache-environment: true
30
+ init-shell: bash
31
+ - name: ruff format --check
32
+ shell: bash -el {0}
33
+ run: ruff format --check
34
+ - name: ruff check
35
+ shell: bash -el {0}
36
+ run: ruff check
37
+
38
+ # ----- Rust unit tests --------------------------------------------
39
+ # cargo test runs `#[cfg(test)] mod tests` blocks throughout the
40
+ # crate — pure-Rust logic (PRNG, byte conversions, parsers). The
41
+ # test binary links libpython via PyO3 even though the test
42
+ # functions themselves don't call Python, so we need Python on
43
+ # PATH so tools/cargo-test.sh can find libpython's directory via
44
+ # sysconfig.LIBDIR and prepend it to LD_LIBRARY_PATH.
45
+ rust-test:
46
+ name: cargo test
47
+ runs-on: ubuntu-latest
48
+ steps:
49
+ - uses: actions/checkout@v4
50
+ - name: Set up Python (so libpython is resolvable)
51
+ uses: actions/setup-python@v5
52
+ with:
53
+ python-version: '3.12'
54
+ - name: Set up Rust toolchain
55
+ uses: dtolnay/rust-toolchain@stable
56
+ - name: Cache cargo build
57
+ uses: Swatinem/rust-cache@v2
58
+ - name: cargo test (via libpython-aware wrapper)
59
+ run: tools/cargo-test.sh
60
+
61
+ # ----- Test matrix ------------------------------------------------
62
+ # ubuntu-latest + macos-latest x {python 3.12, 3.14}. On macOS we
63
+ # source-build fitsio via pip after the conda install — conda-forge's
64
+ # macOS fitsio/cfitsio binary has a libmalloc bad-free in cfitsio's
65
+ # ffbinit that crashes every test writing a compressed-image fixture.
66
+ # fitsio's own CI (https://github.com/esheldon/fitsio) source-builds
67
+ # the package on every leg for the same reason; we follow that
68
+ # pattern only on macOS to keep the linux install fast.
69
+ test:
70
+ name: Test (${{ matrix.os }}, py${{ matrix.python }})
71
+ runs-on: ${{ matrix.os }}
72
+ strategy:
73
+ fail-fast: false
74
+ matrix:
75
+ os: [ubuntu-latest, macos-latest]
76
+ python: ['3.12', '3.14']
77
+ steps:
78
+ - uses: actions/checkout@v4
79
+
80
+ - name: Set up Rust toolchain
81
+ uses: dtolnay/rust-toolchain@stable
82
+
83
+ # Caches target/ and ~/.cargo across runs — first build is full,
84
+ # subsequent builds are incremental.
85
+ - name: Cache cargo build
86
+ uses: Swatinem/rust-cache@v2
87
+
88
+ # `python-gil` pins the stock GIL Python build (vs the optional
89
+ # `python-freethreading` no-GIL build conda-forge ships from 3.13
90
+ # onward). rustfits has not been audited for free-threading
91
+ # safety; without the pin micromamba could pick the no-GIL
92
+ # variant on py3.14 and surface latent races as heap corruption
93
+ # (which is exactly what macOS py3.14 hit on the first run).
94
+ - name: Set up conda env (python ${{ matrix.python }})
95
+ uses: mamba-org/setup-micromamba@v2
96
+ with:
97
+ environment-name: rustfits-test
98
+ create-args: >-
99
+ python=${{ matrix.python }}
100
+ python-gil
101
+ cache-environment: true
102
+ init-shell: bash
103
+
104
+ - name: Install conda deps
105
+ shell: bash -el {0}
106
+ run: |
107
+ micromamba install -y -c conda-forge \
108
+ --file conda-requirements.txt \
109
+ --file conda-test-requirements.txt
110
+
111
+ # Replace the broken conda-forge fitsio macOS build with a fresh
112
+ # source build (cfitsio bundled in the fitsio sdist). --no-deps
113
+ # so we don't churn numpy/setuptools that conda already provided;
114
+ # --no-binary=fitsio forces pip to build from sdist instead of
115
+ # using a PyPI wheel (which may have been built by the same
116
+ # toolchain that produces the buggy conda-forge binary).
117
+ - name: Replace conda-forge fitsio with source build (macOS)
118
+ if: matrix.os == 'macos-latest'
119
+ shell: bash -el {0}
120
+ run: |
121
+ pip install --force-reinstall --no-deps --no-binary=fitsio fitsio
122
+
123
+ - name: maturin develop
124
+ shell: bash -el {0}
125
+ run: maturin develop
126
+
127
+ - name: pytest
128
+ shell: bash -el {0}
129
+ run: pytest
130
+
131
+ # ----- Sphinx docs build -----------------------------------------
132
+ # Mirrors what readthedocs.io does on every push: install rustfits
133
+ # (autodoc imports the module), install docs/requirements.txt, run
134
+ # sphinx-build with -W so any new warning is a hard failure. Catches
135
+ # broken cross-refs, missing autodoc targets, rst syntax errors, and
136
+ # bad intersphinx links before they reach RTD.
137
+ docs:
138
+ name: Sphinx build (-W)
139
+ runs-on: ubuntu-latest
140
+ steps:
141
+ - uses: actions/checkout@v4
142
+
143
+ - name: Set up Rust toolchain
144
+ uses: dtolnay/rust-toolchain@stable
145
+
146
+ - name: Cache cargo build
147
+ uses: Swatinem/rust-cache@v2
148
+
149
+ - name: Set up conda env (python 3.12)
150
+ uses: mamba-org/setup-micromamba@v2
151
+ with:
152
+ environment-name: rustfits-docs
153
+ create-args: >-
154
+ python=3.12
155
+ # cache-environment intentionally off: this env is small
156
+ # (sphinx + furo + maturin) and we hit recurring stale-cache
157
+ # corruption ("Cannot find a valid extracted directory cache
158
+ # for ...") on cached runs. Fresh resolve each time costs a
159
+ # few seconds and avoids the failure mode entirely.
160
+ cache-environment: false
161
+ init-shell: bash
162
+
163
+ - name: Install conda deps + sphinx
164
+ shell: bash -el {0}
165
+ run: |
166
+ micromamba install -y -c conda-forge \
167
+ --file conda-requirements.txt
168
+ pip install -r docs/requirements.txt
169
+
170
+ - name: maturin develop (so autodoc can import rustfits)
171
+ shell: bash -el {0}
172
+ run: maturin develop
173
+
174
+ - name: sphinx-build -W
175
+ shell: bash -el {0}
176
+ run: sphinx-build -W -b html docs docs/_build/html
177
+
178
+ # ----- Coverage (single config) ----------------------------------
179
+ # Python coverage via pytest-cov + Rust coverage via cargo-llvm-cov.
180
+ # Only runs on one OS / Python combo — coverage instrumentation
181
+ # roughly doubles compile time and the report doesn't change across
182
+ # platforms. Both reports get uploaded to codecov in one action.
183
+ coverage:
184
+ name: Coverage (linux, py3.12 → codecov)
185
+ runs-on: ubuntu-latest
186
+ steps:
187
+ - uses: actions/checkout@v4
188
+
189
+ - name: Set up Rust toolchain (with llvm-tools)
190
+ uses: dtolnay/rust-toolchain@stable
191
+ with:
192
+ components: llvm-tools-preview
193
+
194
+ - name: Cache cargo build
195
+ uses: Swatinem/rust-cache@v2
196
+
197
+ - name: Install cargo-llvm-cov
198
+ uses: taiki-e/install-action@v2
199
+ with:
200
+ tool: cargo-llvm-cov
201
+
202
+ - name: Set up conda env (python 3.12)
203
+ uses: mamba-org/setup-micromamba@v2
204
+ with:
205
+ environment-name: rustfits-cov
206
+ create-args: >-
207
+ python=3.12
208
+ cache-environment: true
209
+ init-shell: bash
210
+
211
+ - name: Install conda deps + pytest-cov
212
+ shell: bash -el {0}
213
+ run: |
214
+ micromamba install -y -c conda-forge \
215
+ --file conda-requirements.txt \
216
+ --file conda-test-requirements.txt \
217
+ pytest-cov
218
+
219
+ # cargo-llvm-cov show-env emits the RUSTFLAGS / LLVM_PROFILE_FILE
220
+ # / CARGO_LLVM_COV_TARGET_DIR that the instrumented build needs.
221
+ # Source it once so the cdylib built by maturin AND the .profraw
222
+ # files written by pytest land where `cargo llvm-cov report`
223
+ # expects them. The whole pipeline runs in one shell because
224
+ # `source <(...)` only affects the current shell — splitting it
225
+ # across CI steps would lose the env.
226
+ - name: Build + test with coverage, emit lcov
227
+ shell: bash -el {0}
228
+ run: |
229
+ source <(cargo llvm-cov show-env --export-prefix)
230
+ maturin develop
231
+ pytest --cov=rustfits --cov-report=xml
232
+ cargo llvm-cov report --lcov --output-path rust-coverage.lcov
233
+
234
+ - name: Upload coverage to codecov
235
+ uses: codecov/codecov-action@v5
236
+ with:
237
+ files: rust-coverage.lcov,coverage.xml
238
+ flags: rust,python
239
+ fail_ci_if_error: false
240
+ # CODECOV_TOKEN is optional for public repos but recommended
241
+ # by codecov to avoid rate-limiting. Add it under
242
+ # Settings → Secrets → Actions once you've connected the
243
+ # repo at codecov.io.
244
+ token: ${{ secrets.CODECOV_TOKEN }}
@@ -0,0 +1,62 @@
1
+ # Rust build output
2
+ /target/
3
+
4
+ # Override the global `*.lock` rule for this project: maturin/PyO3 packages
5
+ # pin transitive dependency versions for reproducible CI and source builds.
6
+ !Cargo.lock
7
+
8
+ # Compiled extension modules (maturin develop writes them next to the package)
9
+ *.so
10
+ *.dylib
11
+ *.pyd
12
+
13
+ # Python bytecode / caches
14
+ __pycache__/
15
+ *.py[cod]
16
+ *$py.class
17
+
18
+ # Test / type-check caches
19
+ .pytest_cache/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+ .coverage
23
+ htmlcov/
24
+
25
+ # Packaging artifacts
26
+ *.egg-info/
27
+ build/
28
+ dist/
29
+ wheels/
30
+
31
+ # Virtual environments
32
+ .venv/
33
+ venv/
34
+ env/
35
+
36
+ # Editor / IDE artifacts
37
+ *~
38
+ *.swp
39
+ *.swo
40
+ .*.swp
41
+ .*.swo
42
+ .idea/
43
+ .vscode/
44
+
45
+ # OS
46
+ .DS_Store
47
+ Thumbs.db
48
+
49
+ # Sphinx build output
50
+ docs/_build/
51
+
52
+ # cfitsio reproducer binaries + their generated FITS artifacts
53
+ /tools/cfitsio-repro/pa_vla_funpack_crash
54
+ /tools/cfitsio-repro/gzip2_complex_funpack
55
+ /tools/cfitsio-repro/setitem_sweep_corruption
56
+ /tools/cfitsio-repro/*.fits
57
+ /tools/cfitsio-repro/*.fits.fz
58
+ /tools/cfitsio-repro/core
59
+ /tools/cfitsio-repro/core.*
60
+
61
+ # Local stray files
62
+ /log
@@ -0,0 +1,24 @@
1
+ # Read the Docs build configuration.
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html
3
+ version: 2
4
+
5
+ build:
6
+ os: ubuntu-24.04
7
+ tools:
8
+ python: "3.12"
9
+ rust: "latest"
10
+ jobs:
11
+ # Build + install the maturin-backed extension into the build
12
+ # venv before Sphinx starts, so autodoc can `import rustfits`.
13
+ # `pip install .` honors pyproject.toml's [build-system] block
14
+ # (maturin), so this builds and installs the wheel in one step.
15
+ post_install:
16
+ - pip install .
17
+
18
+ sphinx:
19
+ configuration: docs/conf.py
20
+ fail_on_warning: true
21
+
22
+ python:
23
+ install:
24
+ - requirements: docs/requirements.txt
@@ -0,0 +1,14 @@
1
+ exclude = [
2
+ ".git",
3
+ "build",
4
+ "dist",
5
+ ".github",
6
+ ]
7
+ line-length = 79
8
+
9
+ [lint]
10
+ select = ["E", "F", "W"]
11
+ preview = true
12
+
13
+ [format]
14
+ quote-style = "preserve"