nullpol 0.2.16__tar.gz → 0.3.0__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 (229) hide show
  1. {nullpol-0.2.16 → nullpol-0.3.0}/.github/ISSUE_TEMPLATE/feature-request.md +0 -1
  2. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/ci.yml +20 -3
  3. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/codeql.yml +3 -3
  4. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/scheduled-release.yml +33 -2
  5. nullpol-0.3.0/.github/workflows/support_floor_update.yml +64 -0
  6. {nullpol-0.2.16 → nullpol-0.3.0}/.gitignore +3 -0
  7. {nullpol-0.2.16 → nullpol-0.3.0}/.pre-commit-config.yaml +5 -5
  8. {nullpol-0.2.16 → nullpol-0.3.0}/PKG-INFO +20 -21
  9. {nullpol-0.2.16 → nullpol-0.3.0}/README.md +4 -4
  10. {nullpol-0.2.16 → nullpol-0.3.0}/cliff.toml +1 -1
  11. {nullpol-0.2.16 → nullpol-0.3.0}/docs/installation.md +1 -1
  12. {nullpol-0.2.16 → nullpol-0.3.0}/pyproject.toml +34 -25
  13. {nullpol-0.2.16 → nullpol-0.3.0}/renovate.json +17 -0
  14. nullpol-0.3.0/scripts/release_version.py +150 -0
  15. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/likelihood/chi2_tf_likelihood.py +10 -3
  16. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/likelihood/time_frequency_likelihood.py +5 -2
  17. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/inverse_wavelet_freq.py +6 -6
  18. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/inverse_wavelet_time.py +6 -6
  19. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/wavelet_freq.py +5 -5
  20. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/wavelet_time.py +2 -2
  21. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/data_generation.py +15 -2
  22. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/input.py +1 -0
  23. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/main.py +1 -0
  24. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/parser.py +1 -1
  25. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/__init__.py +3 -2
  26. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/pesummary.py +1 -1
  27. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/tgrflow.py +1 -1
  28. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/htcondor/nullpol_pipe_dag_creator.py +3 -3
  29. nullpol-0.3.0/src/nullpol/integrations/scheduler.py +21 -0
  30. nullpol-0.3.0/src/nullpol/integrations/slurm/__init__.py +7 -0
  31. nullpol-0.3.0/src/nullpol/integrations/slurm/dag.py +73 -0
  32. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/likelihood/test_chi2_tf_likelihood.py +51 -10
  33. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/likelihood/test_time_frequency_likelihood.py +1 -1
  34. nullpol-0.3.0/tests/cli/test_data_generation.py +103 -0
  35. {nullpol-0.2.16 → nullpol-0.3.0}/tests/cli/test_input.py +24 -0
  36. nullpol-0.3.0/tests/integrations/slurm/test_dag.py +210 -0
  37. nullpol-0.3.0/tests/test_release_version.py +148 -0
  38. {nullpol-0.2.16 → nullpol-0.3.0}/uv.lock +309 -566
  39. {nullpol-0.2.16 → nullpol-0.3.0}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  40. {nullpol-0.2.16 → nullpol-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  41. {nullpol-0.2.16 → nullpol-0.3.0}/.github/pull_request_template.md +0 -0
  42. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/documentation.yml +0 -0
  43. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/draft-release.yml +0 -0
  44. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/publish.yml +0 -0
  45. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/publish_testpypi.yml +0 -0
  46. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/release.yml +0 -0
  47. {nullpol-0.2.16 → nullpol-0.3.0}/.github/workflows/semantic-pr-check.yml +0 -0
  48. {nullpol-0.2.16 → nullpol-0.3.0}/.markdownlint.yaml +0 -0
  49. {nullpol-0.2.16 → nullpol-0.3.0}/.prettierignore +0 -0
  50. {nullpol-0.2.16 → nullpol-0.3.0}/.prettierrc.yaml +0 -0
  51. {nullpol-0.2.16 → nullpol-0.3.0}/.typos.toml +0 -0
  52. {nullpol-0.2.16 → nullpol-0.3.0}/CITATION.cff +0 -0
  53. {nullpol-0.2.16 → nullpol-0.3.0}/CODE_OF_CONDUCT.md +0 -0
  54. {nullpol-0.2.16 → nullpol-0.3.0}/CONTRIBUTING.md +0 -0
  55. {nullpol-0.2.16 → nullpol-0.3.0}/LICENSE +0 -0
  56. {nullpol-0.2.16 → nullpol-0.3.0}/SECURITY.md +0 -0
  57. {nullpol-0.2.16 → nullpol-0.3.0}/docs/.gitignore +0 -0
  58. {nullpol-0.2.16 → nullpol-0.3.0}/docs/asimov.md +0 -0
  59. {nullpol-0.2.16 → nullpol-0.3.0}/docs/citing.md +0 -0
  60. {nullpol-0.2.16 → nullpol-0.3.0}/docs/contributing.md +0 -0
  61. {nullpol-0.2.16 → nullpol-0.3.0}/docs/examples/scalar-tensor.md +0 -0
  62. {nullpol-0.2.16 → nullpol-0.3.0}/docs/index.md +0 -0
  63. {nullpol-0.2.16 → nullpol-0.3.0}/docs/injections.md +0 -0
  64. {nullpol-0.2.16 → nullpol-0.3.0}/docs/javascripts/mathjax.js +0 -0
  65. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/index.md +0 -0
  66. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/antenna_patterns/index.md +0 -0
  67. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/clustering/index.md +0 -0
  68. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/index.md +0 -0
  69. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/likelihood/index.md +0 -0
  70. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/null_stream/index.md +0 -0
  71. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/prior/index.md +0 -0
  72. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/analysis/tf_transforms/index.md +0 -0
  73. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/cli/index.md +0 -0
  74. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/index.md +0 -0
  75. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/integrations/asimov/index.md +0 -0
  76. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/integrations/htcondor/index.md +0 -0
  77. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/integrations/index.md +0 -0
  78. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/simulation/index.md +0 -0
  79. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/utils/index.md +0 -0
  80. {nullpol-0.2.16 → nullpol-0.3.0}/docs/reference/nullpol/version.md +0 -0
  81. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/generate_injection_file.sh +0 -0
  82. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/injections.json +0 -0
  83. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/data/scalar_tensor_injection_data0_0_generation_data_dump.pickle +0 -0
  84. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1.err +0 -0
  85. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1.out +0 -0
  86. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1_final_result.err +0 -0
  87. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1_final_result.out +0 -0
  88. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_generation/scalar_tensor_injection_data0_0_generation.err +0 -0
  89. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_generation/scalar_tensor_injection_data0_0_generation.out +0 -0
  90. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/result/scalar_tensor_injection_data0_0_analysis_H1L1V1_dynesty.pickle +0 -0
  91. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/result/scalar_tensor_injection_data0_0_analysis_H1L1V1_resume.pickle +0 -0
  92. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/results_page/overview.html +0 -0
  93. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/scalar_tensor_injection_config_complete.ini +0 -0
  94. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/bash_scalar_tensor_injection.sh +0 -0
  95. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit +0 -0
  96. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.condor.sub +0 -0
  97. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.dagman.out +0 -0
  98. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.lib.err +0 -0
  99. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.lib.out +0 -0
  100. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.metrics +0 -0
  101. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/scalar_tensor_injection_data0_0_analysis_H1L1V1.submit +0 -0
  102. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/scalar_tensor_injection_data0_0_analysis_H1L1V1_final_result.submit +0 -0
  103. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/scalar_tensor_injection_data0_0_generation.submit +0 -0
  104. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/prior.prior +0 -0
  105. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/scalar_tensor_injection.ini +0 -0
  106. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor/scalar_tensor_injection.prior +0 -0
  107. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_fractional_projection/generate_injection_file.sh +0 -0
  108. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_fractional_projection/scalar_tensor_injection.ini +0 -0
  109. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_fractional_projection/scalar_tensor_injection.prior +0 -0
  110. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_gaussian/generate_injection_file.sh +0 -0
  111. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_gaussian/scalar_tensor_injection.ini +0 -0
  112. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_gaussian/scalar_tensor_injection.prior +0 -0
  113. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_h_marginalized/generate_injection_file.sh +0 -0
  114. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_h_marginalized/scalar_tensor_injection.ini +0 -0
  115. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_h_marginalized/scalar_tensor_injection.prior +0 -0
  116. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_weighted_gaussian/generate_injection_file.sh +0 -0
  117. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_weighted_gaussian/scalar_tensor_injection.ini +0 -0
  118. {nullpol-0.2.16 → nullpol-0.3.0}/examples/injection/scalar_tensor_weighted_gaussian/scalar_tensor_injection.prior +0 -0
  119. {nullpol-0.2.16 → nullpol-0.3.0}/scripts/README.md +0 -0
  120. {nullpol-0.2.16 → nullpol-0.3.0}/scripts/auto_generate_init.py +0 -0
  121. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/.gitignore +0 -0
  122. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/__init__.py +0 -0
  123. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/__init__.py +0 -0
  124. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/antenna_patterns/__init__.py +0 -0
  125. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/antenna_patterns/base.py +0 -0
  126. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/antenna_patterns/conditioning.py +0 -0
  127. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/antenna_patterns/encoding.py +0 -0
  128. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/antenna_patterns/processor.py +0 -0
  129. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/clustering/__init__.py +0 -0
  130. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/clustering/algorithm.py +0 -0
  131. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/clustering/application.py +0 -0
  132. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/clustering/coherent_sky_scan.py +0 -0
  133. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/clustering/plotting.py +0 -0
  134. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/clustering/threshold_filter.py +0 -0
  135. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/data_context.py +0 -0
  136. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/likelihood/__init__.py +0 -0
  137. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/null_stream/__init__.py +0 -0
  138. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/null_stream/calculator.py +0 -0
  139. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/null_stream/projections.py +0 -0
  140. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/prior/__init__.py +0 -0
  141. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/prior/default.py +0 -0
  142. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/prior/prior_files/polarization.prior +0 -0
  143. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/result.py +0 -0
  144. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/__init__.py +0 -0
  145. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/stft.py +0 -0
  146. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/utils.py +0 -0
  147. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/analysis/tf_transforms/wavelet_transforms.py +0 -0
  148. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/__init__.py +0 -0
  149. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/create_injection.py +0 -0
  150. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/create_time_frequency_filter_from_sample.py +0 -0
  151. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/data_analysis.py +0 -0
  152. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/get_asimov_yaml.py +0 -0
  153. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/templates/__init__.py +0 -0
  154. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/templates/config.ini +0 -0
  155. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/templates/default_config_create_injection.ini +0 -0
  156. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/templates/default_config_create_time_frequency_filter_from_sample.ini +0 -0
  157. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/cli/templates/example_signal_parameters_create_injection.json +0 -0
  158. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/__init__.py +0 -0
  159. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/asimov.py +0 -0
  160. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/templates/__init__.py +0 -0
  161. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/templates/analysis_defaults.yaml +0 -0
  162. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/templates/nullpol.ini +0 -0
  163. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/templates/nullpol_analysis.yaml +0 -0
  164. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/asimov/utility.py +0 -0
  165. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/htcondor/__init__.py +0 -0
  166. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/htcondor/analysis_node.py +0 -0
  167. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/integrations/htcondor/generation_node.py +0 -0
  168. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/simulation/__init__.py +0 -0
  169. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/simulation/injection.py +0 -0
  170. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/simulation/source.py +0 -0
  171. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/utils/__init__.py +0 -0
  172. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/utils/error.py +0 -0
  173. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/utils/filesystem.py +0 -0
  174. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/utils/imports.py +0 -0
  175. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/utils/json_utils.py +0 -0
  176. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/utils/log.py +0 -0
  177. {nullpol-0.2.16 → nullpol-0.3.0}/src/nullpol/version.py +0 -0
  178. {nullpol-0.2.16 → nullpol-0.3.0}/tests/.gitignore +0 -0
  179. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/__init__.py +0 -0
  180. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/antenna_patterns/__init__.py +0 -0
  181. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/antenna_patterns/test_base.py +0 -0
  182. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/antenna_patterns/test_conditioning.py +0 -0
  183. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/antenna_patterns/test_encoding.py +0 -0
  184. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/antenna_patterns/test_processor.py +0 -0
  185. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/clustering/__init__.py +0 -0
  186. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/clustering/test_algorithm.py +0 -0
  187. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/clustering/test_application.py +0 -0
  188. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/clustering/test_plotting.py +0 -0
  189. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/clustering/test_threshold_filter.py +0 -0
  190. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/fixtures/injections.json +0 -0
  191. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/null_stream/__init__.py +0 -0
  192. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/null_stream/test_calculator.py +0 -0
  193. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/null_stream/test_projections.py +0 -0
  194. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/prior/__init__.py +0 -0
  195. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/prior/test_default.py +0 -0
  196. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/test_data_context.py +0 -0
  197. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/test_result.py +0 -0
  198. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/__init__.py +0 -0
  199. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_inverse_wavelet_freq.py +0 -0
  200. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_inverse_wavelet_time.py +0 -0
  201. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_stft.py +0 -0
  202. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_utils.py +0 -0
  203. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_wavelet_freq.py +0 -0
  204. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_wavelet_time.py +0 -0
  205. {nullpol-0.2.16 → nullpol-0.3.0}/tests/analysis/tf_transforms/test_wavelet_transforms.py +0 -0
  206. {nullpol-0.2.16 → nullpol-0.3.0}/tests/cli/__init__.py +0 -0
  207. {nullpol-0.2.16 → nullpol-0.3.0}/tests/cli/fixtures/mock_psd.txt +0 -0
  208. {nullpol-0.2.16 → nullpol-0.3.0}/tests/cli/test_create_injection.py +0 -0
  209. {nullpol-0.2.16 → nullpol-0.3.0}/tests/cli/test_create_time_frequency_filter.py +0 -0
  210. {nullpol-0.2.16 → nullpol-0.3.0}/tests/cli/test_data_analysis_validation.py +0 -0
  211. {nullpol-0.2.16 → nullpol-0.3.0}/tests/integrations/__init__.py +0 -0
  212. {nullpol-0.2.16 → nullpol-0.3.0}/tests/integrations/asimov/__init__.py +0 -0
  213. {nullpol-0.2.16 → nullpol-0.3.0}/tests/integrations/asimov/conftest.py +0 -0
  214. {nullpol-0.2.16 → nullpol-0.3.0}/tests/integrations/asimov/test_tgrflow.py +0 -0
  215. {nullpol-0.2.16 → nullpol-0.3.0}/tests/integrations/asimov/test_tgrflow_integration.py +0 -0
  216. {nullpol-0.2.16 → nullpol-0.3.0}/tests/integrations/asimov/test_utility.py +0 -0
  217. {nullpol-0.2.16 → nullpol-0.3.0}/tests/simulation/__init__.py +0 -0
  218. {nullpol-0.2.16 → nullpol-0.3.0}/tests/simulation/test_injection.py +0 -0
  219. {nullpol-0.2.16 → nullpol-0.3.0}/tests/simulation/test_source.py +0 -0
  220. {nullpol-0.2.16 → nullpol-0.3.0}/tests/smoke_test.py +0 -0
  221. {nullpol-0.2.16 → nullpol-0.3.0}/tests/test_import.py +0 -0
  222. {nullpol-0.2.16 → nullpol-0.3.0}/tests/test_version.py +0 -0
  223. {nullpol-0.2.16 → nullpol-0.3.0}/tests/utils/__init__.py +0 -0
  224. {nullpol-0.2.16 → nullpol-0.3.0}/tests/utils/test_error.py +0 -0
  225. {nullpol-0.2.16 → nullpol-0.3.0}/tests/utils/test_filesystem.py +0 -0
  226. {nullpol-0.2.16 → nullpol-0.3.0}/tests/utils/test_imports.py +0 -0
  227. {nullpol-0.2.16 → nullpol-0.3.0}/tests/utils/test_json_utils.py +0 -0
  228. {nullpol-0.2.16 → nullpol-0.3.0}/tests/utils/test_log.py +0 -0
  229. {nullpol-0.2.16 → nullpol-0.3.0}/zensical.toml +0 -0
@@ -28,7 +28,6 @@ import nullpol
28
28
 
29
29
  # How you'd like to use the new feature
30
30
  result = nullpol.new_function(param="example")
31
-
32
31
  ```
33
32
 
34
33
  ## 🌈 Use Case & Benefits
@@ -11,8 +11,17 @@ jobs:
11
11
  test:
12
12
  strategy:
13
13
  matrix:
14
- python-version: ['3.12', '3.13', '3.14']
14
+ # Locked resolutions run everywhere; the SPEC 0 minimum
15
+ # (lowest-direct) runs on ubuntu with the oldest supported
16
+ # Python, since floor versions predate newer interpreters'
17
+ # wheels.
18
+ python-version: ['3.13', '3.14']
15
19
  os: [ubuntu-latest, macos-latest]
20
+ resolution: [locked]
21
+ include:
22
+ - os: ubuntu-latest
23
+ python-version: '3.13'
24
+ resolution: lowest-direct
16
25
  runs-on: ${{ matrix.os }}
17
26
  steps:
18
27
  - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
@@ -26,10 +35,18 @@ jobs:
26
35
  enable-cache: 'true'
27
36
 
28
37
  - name: Install dependencies
29
- run: uv sync --group dev --frozen
38
+ shell: bash
39
+ env:
40
+ RESOLUTION: ${{ matrix.resolution }}
41
+ run: |
42
+ if [ "$RESOLUTION" = "lowest-direct" ]; then
43
+ uv sync --group dev --upgrade --resolution lowest-direct
44
+ else
45
+ uv sync --group dev --frozen
46
+ fi
30
47
 
31
48
  - name: Run tests with pytest
32
- run: uv run --frozen pytest
49
+ run: uv run --no-sync pytest
33
50
 
34
51
  - name: Upload coverage to Codecov
35
52
  if: ${{ !cancelled() }}
@@ -18,12 +18,12 @@ jobs:
18
18
  - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
19
19
 
20
20
  - name: Initialize CodeQL
21
- uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4
21
+ uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
22
22
  with:
23
23
  languages: python
24
24
 
25
25
  - name: Autobuild
26
- uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4
26
+ uses: github/codeql-action/autobuild@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
27
27
 
28
28
  - name: Perform CodeQL Analysis
29
- uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4
29
+ uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
@@ -4,6 +4,17 @@ on:
4
4
  schedule:
5
5
  - cron: '0 0 * * 2'
6
6
  workflow_dispatch:
7
+ inputs:
8
+ allow_major_bump:
9
+ description:
10
+ 'Let a breaking change bump 0.x.y into 1.0.0. Off by
11
+ default: while the package is pre-1.0 a breaking change
12
+ bumps the minor instead, because 1.x declares a stable API.
13
+ Has no effect once the current major is >= 1, where a major
14
+ bump is enforced anyway.'
15
+ required: false
16
+ default: false
17
+ type: boolean
7
18
 
8
19
  permissions:
9
20
  contents: write
@@ -20,7 +31,7 @@ jobs:
20
31
 
21
32
  - name: Check for new commits
22
33
  id: check_commits
23
- uses: isaac-cf-wong/detect-git-changes-action@051225b2ef2faf2a02d61f16d1a027cdf941498d # v0.0.21
34
+ uses: isaac-cf-wong/detect-git-changes-action@9863c3c0ba155ed10b54072f711ae8807aedbc87 # v0.0.22
24
35
  with:
25
36
  use-latest-tag: true
26
37
 
@@ -57,12 +68,32 @@ jobs:
57
68
 
58
69
  - name: Bump version and push tag
59
70
  id: tag_version
71
+ env:
72
+ # The flag itself, or empty, so the shell never has to interpret a truth value.
73
+ # The `inputs` context keeps a typed boolean as a boolean; `github.event.inputs`
74
+ # would hand over the *string* `false`, which is truthy in a shell test. On a
75
+ # `schedule` event `inputs` is absent, which is falsy -- the default.
76
+ ALLOW_MAJOR_BUMP:
77
+ ${{ inputs.allow_major_bump && '--allow-major-bump' || ''
78
+ }}
60
79
  run: |
80
+ set -euo pipefail
61
81
  PREVIOUS_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
62
82
  if [ "$PREVIOUS_TAG" = "none" ]; then
63
83
  NEW_TAG="v0.1.0"
64
84
  else
65
- NEW_TAG=$(uv run --frozen git-cliff --bumped-version --config cliff.toml 2>/dev/null)
85
+ # git-cliff proposes; `release_version.py` decides. git-cliff sends a breaking
86
+ # change straight to the next major, so at v0.x.y it answers v1.0.0 and would
87
+ # publish a stable-API claim as a side effect. While the major is 0 that is
88
+ # demoted to a minor bump unless this run was dispatched with allow_major_bump.
89
+ # At 1.x and above the proposal is taken unchanged. git-cliff's stderr is no
90
+ # longer discarded: an empty proposal must fail the run, not become a tag.
91
+ PROPOSED_TAG=$(uv run --frozen git-cliff --bumped-version --config cliff.toml)
92
+ NEW_TAG=$(uv run --frozen python scripts/release_version.py \
93
+ --current "$PREVIOUS_TAG" \
94
+ --proposed "$PROPOSED_TAG" \
95
+ ${ALLOW_MAJOR_BUMP})
96
+ echo "git-cliff proposed $PROPOSED_TAG; releasing $NEW_TAG"
66
97
  fi
67
98
  if ! git rev-parse "$NEW_TAG" >/dev/null 2>&1; then
68
99
  echo "Creating annotated tag $NEW_TAG"
@@ -0,0 +1,64 @@
1
+ name: Support floor update
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 6 1 * *' # monthly, 1st at 06:00 UTC
6
+ workflow_dispatch:
7
+
8
+ concurrency:
9
+ group: support-floor-update
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ update-floors:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
20
+ with:
21
+ persist-credentials: false
22
+
23
+ - name: Apply support policy (spec0, from pyproject tool table)
24
+ id: policy
25
+ uses: isaac-cf-wong/dependency-support-policy-action@74dfcfcc079cd22b26713242940f65ba2b3c70c7 # v0.2.9
26
+ with:
27
+ mode: update
28
+
29
+ # PRs created with the default GITHUB_TOKEN do not trigger CI, so
30
+ # the PR is created with a GitHub App installation token instead.
31
+ - name: Mint app token
32
+ if: steps.policy.outputs.changed == 'true'
33
+ id: app-token
34
+ uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2
35
+ with:
36
+ app-id: ${{ vars.APP_ID }}
37
+ private-key: ${{ secrets.APP_PRIVATE_KEY }}
38
+ permission-contents: write
39
+ permission-pull-requests: write
40
+
41
+ - name: Create or update pull request
42
+ if: steps.policy.outputs.changed == 'true'
43
+ id: pr
44
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
45
+ with:
46
+ token: ${{ steps.app-token.outputs.token }}
47
+ branch: dependency-support-policy/update
48
+ title: 'chore(deps): raise minimum supported versions'
49
+ commit-message:
50
+ 'chore(deps): raise minimum supported versions'
51
+ body: |
52
+ Automated rolling support-floor update (SPEC 0).
53
+
54
+ ```json
55
+ ${{ steps.policy.outputs.dependency-floors-changed }}
56
+ ```
57
+ labels: dependencies
58
+
59
+ - name: Enable auto-merge
60
+ if: steps.pr.outputs.pull-request-number
61
+ env:
62
+ GH_TOKEN: ${{ steps.app-token.outputs.token }}
63
+ PR_NUMBER: ${{ steps.pr.outputs.pull-request-number }}
64
+ run: gh pr merge --squash --auto "$PR_NUMBER"
@@ -192,3 +192,6 @@ local_config.*
192
192
 
193
193
  # Spellcheck files
194
194
  !.ignore_words.txt
195
+
196
+ # CodeGraph index
197
+ .codegraph/
@@ -17,9 +17,9 @@ repos:
17
17
  - id: check-json
18
18
 
19
19
  - repo: https://github.com/astral-sh/ruff-pre-commit
20
- rev: v0.15.22
20
+ rev: v0.17.0
21
21
  hooks:
22
- - id: ruff
22
+ - id: ruff-check
23
23
  args: [--fix, --config=pyproject.toml]
24
24
  - id: ruff-format
25
25
 
@@ -29,13 +29,13 @@ repos:
29
29
  - id: taplo-format
30
30
 
31
31
  - repo: https://github.com/crate-ci/typos
32
- rev: v1.50.3
32
+ rev: v1.51.1
33
33
  hooks:
34
34
  - id: typos
35
35
  args: []
36
36
 
37
37
  - repo: https://github.com/rbubley/mirrors-prettier
38
- rev: v3.9.9
38
+ rev: v3.9.10
39
39
  hooks:
40
40
  - id: prettier
41
41
 
@@ -48,7 +48,7 @@ repos:
48
48
  - .markdownlint.yaml
49
49
 
50
50
  - repo: https://github.com/astral-sh/uv-pre-commit
51
- rev: 0.12.23
51
+ rev: 0.13.0
52
52
  hooks:
53
53
  # Update the uv lockfile
54
54
  - id: uv-lock
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nullpol
3
- Version: 0.2.16
3
+ Version: 0.3.0
4
4
  Summary: A package to perform model-independent polarization test of gravitational-wave signals.
5
5
  Project-URL: Documentation, https://isaac-cf-wong.github.io/nullpol/
6
6
  Project-URL: Source, https://github.com/isaac-cf-wong/nullpol
@@ -15,26 +15,25 @@ Classifier: Development Status :: 3 - Alpha
15
15
  Classifier: Intended Audience :: Developers
16
16
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
17
17
  Classifier: Programming Language :: Python :: 3 :: Only
18
- Classifier: Programming Language :: Python :: 3.12
19
18
  Classifier: Programming Language :: Python :: 3.13
20
19
  Classifier: Programming Language :: Python :: 3.14
21
- Requires-Python: >=3.12
20
+ Requires-Python: >=3.13
22
21
  Requires-Dist: bilby-pipe>=1.9.0
23
- Requires-Dist: bilby>=2.8.0
24
- Requires-Dist: configargparse>=1.7.5
25
- Requires-Dist: gwpy>=4.0.1
26
- Requires-Dist: h5py>=3.16.0
27
- Requires-Dist: healpy>=1.19.0
28
- Requires-Dist: matplotlib>=3.10.9
29
- Requires-Dist: numba>=0.65.0
30
- Requires-Dist: numpy<2.4,>=2.3.5
31
- Requires-Dist: pandas>=3.0.3
32
- Requires-Dist: pycbc>=2.11.0
33
- Requires-Dist: rocket-fft>=0.3.1
34
- Requires-Dist: scipy<1.17.0,>=1.16.3
22
+ Requires-Dist: bilby>=2.7.0
23
+ Requires-Dist: configargparse>=1.7.1
24
+ Requires-Dist: gwpy>=4.0.0
25
+ Requires-Dist: h5py>=3.13.0
26
+ Requires-Dist: healpy>=1.18.0
27
+ Requires-Dist: matplotlib>=3.10.0
28
+ Requires-Dist: numba>=0.61.2
29
+ Requires-Dist: numpy<2.6,>=2.2.0
30
+ Requires-Dist: pandas>=2.3.0
31
+ Requires-Dist: pycbc>=2.10.0
32
+ Requires-Dist: rocket-fft>=0.3.0
33
+ Requires-Dist: scipy<1.19.0,>=1.15.0
35
34
  Provides-Extra: asimov
36
- Requires-Dist: asimov>=0.7.1; extra == 'asimov'
37
- Requires-Dist: cbcflow>=0.6.3; extra == 'asimov'
35
+ Requires-Dist: asimov>=0.6.0; extra == 'asimov'
36
+ Requires-Dist: cbcflow>=0.6.0; extra == 'asimov'
38
37
  Description-Content-Type: text/markdown
39
38
 
40
39
  # nullpol
@@ -79,15 +78,15 @@ pages for more details:
79
78
  [uv on GitHub](https://github.com/astral-sh/uv)
80
79
  - Full documentation and usage guide: [uv docs](https://docs.astral.sh/uv/)
81
80
 
82
- **Note:** The package is built and tested against Python 3.12–3.14. When
81
+ **Note:** The package is built and tested against Python 3.13–3.14. When
83
82
  creating a virtual environment with `uv`, specify the Python version to ensure
84
- compatibility: `uv venv --python 3.12`.
83
+ compatibility: `uv venv --python 3.13`.
85
84
 
86
85
  ### From PyPI
87
86
 
88
87
  ```bash
89
88
  # Create a virtual environment (recommended with uv)
90
- uv venv --python 3.12
89
+ uv venv --python 3.13
91
90
  source .venv/bin/activate # On Windows: .venv\Scripts\activate
92
91
  uv pip install nullpol
93
92
  ```
@@ -104,7 +103,7 @@ uv pip install nullpol[asimov]
104
103
  git clone https://github.com/isaac-cf-wong/nullpol.git
105
104
  cd nullpol
106
105
  # Create a virtual environment (recommended with uv)
107
- uv venv --python 3.12
106
+ uv venv --python 3.13
108
107
  source .venv/bin/activate # On Windows: .venv\Scripts\activate
109
108
  uv sync
110
109
  ```
@@ -40,15 +40,15 @@ pages for more details:
40
40
  [uv on GitHub](https://github.com/astral-sh/uv)
41
41
  - Full documentation and usage guide: [uv docs](https://docs.astral.sh/uv/)
42
42
 
43
- **Note:** The package is built and tested against Python 3.12–3.14. When
43
+ **Note:** The package is built and tested against Python 3.13–3.14. When
44
44
  creating a virtual environment with `uv`, specify the Python version to ensure
45
- compatibility: `uv venv --python 3.12`.
45
+ compatibility: `uv venv --python 3.13`.
46
46
 
47
47
  ### From PyPI
48
48
 
49
49
  ```bash
50
50
  # Create a virtual environment (recommended with uv)
51
- uv venv --python 3.12
51
+ uv venv --python 3.13
52
52
  source .venv/bin/activate # On Windows: .venv\Scripts\activate
53
53
  uv pip install nullpol
54
54
  ```
@@ -65,7 +65,7 @@ uv pip install nullpol[asimov]
65
65
  git clone https://github.com/isaac-cf-wong/nullpol.git
66
66
  cd nullpol
67
67
  # Create a virtual environment (recommended with uv)
68
- uv venv --python 3.12
68
+ uv venv --python 3.13
69
69
  source .venv/bin/activate # On Windows: .venv\Scripts\activate
70
70
  uv sync
71
71
  ```
@@ -111,7 +111,7 @@ filter_commits = false
111
111
  # An array of link parsers for extracting external references, and turning them into URLs, using regex.
112
112
  link_parsers = []
113
113
  # Include only the tags that belong to the current branch.
114
- use_branch_tags = false
114
+ use_branch_tags = true
115
115
  # Order releases topologically instead of chronologically.
116
116
  topo_order = false
117
117
  # Order releases topologically instead of chronologically.
@@ -44,6 +44,6 @@ and documentation dependencies.
44
44
 
45
45
  ## Requirements
46
46
 
47
- - Python 3.12 or higher
47
+ - Python 3.13 or higher
48
48
  - Key dependencies: bilby, bilby_pipe, gwpy, numpy, scipy, matplotlib
49
49
  - Full list available in `pyproject.toml`
@@ -17,43 +17,42 @@ classifiers = [
17
17
  "Intended Audience :: Developers",
18
18
  "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
19
19
  "Programming Language :: Python :: 3 :: Only",
20
- "Programming Language :: Python :: 3.12",
21
20
  "Programming Language :: Python :: 3.13",
22
21
  "Programming Language :: Python :: 3.14",
23
22
  ]
24
- requires-python = ">=3.12"
23
+ requires-python = ">=3.13"
25
24
  dynamic = ["version"]
26
25
  dependencies = [
27
- "matplotlib>=3.10.9",
28
- "numpy>=2.3.5,<2.4",
29
- "bilby>=2.8.0",
26
+ "matplotlib>=3.10.0",
27
+ "numpy>=2.2.0,<2.6",
28
+ "bilby>=2.7.0",
30
29
  "bilby_pipe>=1.9.0",
31
- "gwpy>=4.0.1",
32
- "numba>=0.65.0",
33
- "rocket-fft>=0.3.1",
34
- "scipy>=1.16.3,<1.17.0",
35
- "ConfigArgParse>=1.7.5",
36
- "pycbc>=2.11.0",
37
- "healpy>=1.19.0",
38
- "h5py>=3.16.0",
39
- "pandas>=3.0.3",
30
+ "gwpy>=4.0.0",
31
+ "numba>=0.61.2",
32
+ "rocket-fft>=0.3.0",
33
+ "scipy>=1.15.0,<1.19.0",
34
+ "ConfigArgParse>=1.7.1",
35
+ "pycbc>=2.10.0",
36
+ "healpy>=1.18.0",
37
+ "h5py>=3.13.0",
38
+ "pandas>=2.3.0",
40
39
  ]
41
40
 
42
41
  [project.optional-dependencies]
43
- asimov = ["asimov>=0.7.1", "cbcflow>=0.6.3"]
42
+ asimov = ["asimov>=0.6.0", "cbcflow>=0.6.0"]
44
43
 
45
44
  [dependency-groups]
46
45
  dev = [
47
- "ruff>=0.15.16",
48
- "prek>=0.4.4",
49
- "pytest-github-actions-annotate-failures>=0.4.0",
46
+ "ruff>=0.17.0",
47
+ "prek>=0.5.5",
48
+ "pytest-github-actions-annotate-failures>=0.4.2",
50
49
  "pytest-cov>=7.1.0",
51
- "pytest-mock>=3.15.1",
52
- "pytest>=9.0.3",
50
+ "pytest-mock>=3.16.0",
51
+ "pytest>=9.1.1",
53
52
  ]
54
- docs = ["zensical>=0.0.44", "mkdocstrings-python>=2.0.4"]
55
- build = ["hatch>=1.17.0"]
56
- release = ["git-cliff>=2.13.1"]
53
+ docs = ["zensical>=0.0.69", "mkdocstrings-python>=2.0.9"]
54
+ build = ["hatch>=1.18.1"]
55
+ release = ["git-cliff>=2.14.2"]
57
56
 
58
57
  [project.urls]
59
58
  Documentation = "https://isaac-cf-wong.github.io/nullpol/"
@@ -80,6 +79,13 @@ tgrflow = 'nullpol.integrations.asimov.tgrflow:Collector'
80
79
  [project.entry-points.'asimov.hooks.applicator']
81
80
  tgrflow = 'nullpol.integrations.asimov.tgrflow:Applicator'
82
81
 
82
+ [tool.dependency-support-policy]
83
+ # Rolling support floors (SPEC 0): runtime lower bounds are raised on a schedule
84
+ # by the support_floor_update.yml workflow, not by Renovate. See renovate.json.
85
+ policy = "spec0"
86
+ groups = ["project", "optional"]
87
+ lock = "minimal"
88
+
83
89
  [tool.uv-dynamic-versioning]
84
90
  vcs = "git" # default
85
91
  style = "semver" # or pep440, semver, etc.
@@ -98,7 +104,7 @@ fail_under = 0
98
104
 
99
105
  [tool.pytest.ini_options]
100
106
  addopts = "--cov-report xml:coverage.xml --cov src --cov-append -m 'not integration' --cov-report=term-missing"
101
- pythonpath = ["src"]
107
+ pythonpath = ["src", "scripts"]
102
108
  testpaths = "tests"
103
109
  junit_family = "xunit2"
104
110
  markers = [
@@ -112,7 +118,7 @@ markers = [
112
118
 
113
119
  [tool.ruff]
114
120
  line-length = 120 # Matches Black's default
115
- target-version = "py312" # Align with CI (3.12–3.14) and requires-python (>=3.12)
121
+ target-version = "py313" # Align with CI (3.13–3.14) and requires-python (>=3.13)
116
122
  lint.extend-select = [
117
123
  "E",
118
124
  "F",
@@ -141,6 +147,7 @@ lint.ignore = [
141
147
  "N806", # Scientific variable names (e.g. F_matrix, wavelet_Nt)
142
148
  "PLR0912", # Too many branches in scientific algorithms
143
149
  "PLR0913", # Too many arguments in scientific APIs
150
+ "PLR0917", # Too many positional arguments in scientific APIs
144
151
  "PLR0915", # Too many statements in complex analysis code
145
152
  ]
146
153
  fix = true # Enable autofix
@@ -166,11 +173,13 @@ convention = "google"
166
173
  "PT018",
167
174
  "RUF043",
168
175
  "S110",
176
+ "BLE001",
169
177
  ]
170
178
  # S101: allow assert statements
171
179
  # ARG001: allow unused function arguments (common in fixtures)
172
180
  # PLC0415: allow import statements not at the top level
173
181
  # PLR2004: allow magic values in the unit tests
182
+ # BLE001: allow broad exception handlers in tolerance tests
174
183
  "src/nullpol/analysis/result.py" = ["PLC0415", "S301"]
175
184
  "scripts/*" = ["SIM102", "PLC0415", "PLR2004"]
176
185
 
@@ -15,6 +15,23 @@
15
15
  "schedule": ["before 4am on monday"]
16
16
  },
17
17
  "packageRules": [
18
+ {
19
+ "matchManagers": ["pep621"],
20
+ "matchDepTypes": [
21
+ "project.dependencies",
22
+ "project.optional-dependencies"
23
+ ],
24
+ "matchPackageNames": ["!numpy", "!scipy"],
25
+ "description": "Runtime lower bounds are owned by the dependency-support-policy (SPEC 0) workflow.",
26
+ "enabled": false
27
+ },
28
+ {
29
+ "matchManagers": ["pep621"],
30
+ "matchDepTypes": ["project.dependencies"],
31
+ "matchPackageNames": ["numpy", "scipy"],
32
+ "description": "Raise only the upper caps; widen keeps the SPEC 0 lower bounds untouched.",
33
+ "rangeStrategy": "widen"
34
+ },
18
35
  {
19
36
  "matchManagers": ["pep621"],
20
37
  "matchUpdateTypes": ["patch", "minor"],
@@ -0,0 +1,150 @@
1
+ """Decide the version the next release ships under, given git-cliff's proposal.
2
+
3
+ The scheduled release asks `git-cliff --bumped-version` for a tag. git-cliff's default sends a breaking
4
+ change to the next major, which is right for a package that has promised an API and wrong for one that
5
+ has not: at `v0.10.2` a breaking change answers `v1.0.0`. That would publish a stable-API claim as a
6
+ side effect of a fix that only renames things.
7
+
8
+ The rule this applies:
9
+
10
+ while the current version is `0.x.y`, a proposed major bump is demoted to a minor bump, unless the
11
+ release was run with `allow_major_bump`; once the current major is `>= 1`, git-cliff's answer stands
12
+ untouched.
13
+
14
+ `cliff.toml` cannot express that. `[bump] breaking_always_bump_major = false` would also disable the
15
+ enforced major bump at `>= 1`, which is the half worth keeping -- so the decision is post-processing on
16
+ git-cliff's answer rather than configuration of it.
17
+
18
+ Run as a script it takes the two versions and prints the answer, which is what the workflow uses:
19
+
20
+ python scripts/release_version.py --current v0.4.1 --proposed "$(git-cliff --bumped-version)"
21
+
22
+ It lives in `scripts/` rather than in `src/`: it is release tooling and has no business in the wheel.
23
+ `pyproject.toml` puts `scripts` on the test path so it is covered like anything else, because a wrong
24
+ answer here is both expensive and silent -- a version cannot be unpublished, and nothing downstream
25
+ would flag `1.0.0` as unintended.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import argparse
31
+ import re
32
+ import sys
33
+
34
+ #: A release tag: an optional `v`, then exactly three dot-separated numbers. Deliberately strict --
35
+ #: pre-release and build metadata are not used by this project's tags, and a tag shape nobody expected
36
+ #: is a reason to stop the release rather than to guess at it.
37
+ _VERSION = re.compile(r"^v?(\d+)\.(\d+)\.(\d+)$")
38
+
39
+
40
+ def _parse(version: str, *, described_as: str) -> tuple[int, int, int]:
41
+ """Return the numeric components of *version*.
42
+
43
+ Args:
44
+ version: The tag, with or without a leading `v`.
45
+ described_as: What to call it in the message, so a failure names which of the two was wrong.
46
+
47
+ Returns:
48
+ The major, minor and patch components.
49
+
50
+ Raises:
51
+ ValueError: If the version is not `<major>.<minor>.<patch>`, optionally `v`-prefixed.
52
+ """
53
+ matched = _VERSION.match(version.strip())
54
+ if matched is None:
55
+ raise ValueError(
56
+ f"could not read {described_as} {version!r} as a version: expected `<major>.<minor>.<patch>`, "
57
+ f"optionally prefixed with `v`. Refusing to guess, because the answer becomes a published tag."
58
+ )
59
+ major, minor, patch = matched.groups()
60
+ return int(major), int(minor), int(patch)
61
+
62
+
63
+ def choose_version(*, current: str, proposed: str, allow_major_bump: bool = False) -> str:
64
+ """Return the version to release, holding the major back while the package is pre-1.0.
65
+
66
+ Args:
67
+ current: The latest released tag, e.g. from `git describe --tags --abbrev=0`.
68
+ proposed: What `git-cliff --bumped-version` suggests.
69
+ allow_major_bump: Take the proposal even if it crosses into `1.x`. This is the explicit
70
+ negotiation the rule leaves open; it does nothing once the current major is `>= 1`, where a
71
+ major bump is enforced anyway.
72
+
73
+ Returns:
74
+ The tag to create, carrying the `v` prefix if *proposed* had one.
75
+
76
+ Raises:
77
+ ValueError: If either version is unreadable, or the proposal is not ahead of the current version.
78
+ """
79
+ current_parts = _parse(current, described_as="the current version")
80
+ proposed_parts = _parse(proposed, described_as="the proposed version")
81
+ current_major, current_minor, _ = current_parts
82
+ proposed_major = proposed_parts[0]
83
+
84
+ # Checked before the rule is applied, because both numbers are only visible here. A proposal that is
85
+ # not ahead means git-cliff ran against the wrong history, and the release would either collide with
86
+ # an existing tag or publish a version that reads as older than the one before it.
87
+ if proposed_parts <= current_parts:
88
+ raise ValueError(
89
+ f"the proposed version {proposed!r} is not ahead of the current version {current!r}. "
90
+ f"git-cliff was run against unexpected history; releasing this would either collide with an "
91
+ f"existing tag or publish a version that reads as older."
92
+ )
93
+
94
+ # Normalised once, and it is the normalised form that is returned. Validating a stripped copy while
95
+ # returning the original meant `" v2.0.0 "` passed the parser and came back with its spaces, and
96
+ # `git check-ref-format 'refs/tags/ v2.0.0 '` refuses that -- so the release would have failed at the
97
+ # tag, with a message about ref format rather than about where the whitespace came from. The demoted
98
+ # path was never exposed to it, since it builds its answer out of parsed numbers. The general shape
99
+ # of the bug: validating a copy is not validating the thing you return.
100
+ #
101
+ # Not cosmetic in practice: the proposal arrives from `$(git-cliff ...)`, and command substitution
102
+ # strips trailing newlines but nothing else.
103
+ proposed = proposed.strip()
104
+ prefix = "v" if proposed.startswith("v") else ""
105
+
106
+ # The rule applies to exactly one situation: a 0.x package being pushed to 1.0 by a breaking change.
107
+ # Everything else -- 0.x staying in 0.x, and any bump at 1.x or above -- is git-cliff's answer.
108
+ demote = current_major == 0 and proposed_major > current_major and not allow_major_bump
109
+ if not demote:
110
+ return proposed
111
+
112
+ # A minor bump, with the patch reset: this is a 0.x minor release, not a major one wearing a smaller
113
+ # number. `0.10.1` -> `0.11.0`.
114
+ return f"{prefix}{current_major}.{current_minor + 1}.0"
115
+
116
+
117
+ def main(argv: list[str] | None = None) -> int:
118
+ """Print the version to release.
119
+
120
+ Args:
121
+ argv: Command-line arguments, for testing; defaults to `sys.argv[1:]`.
122
+
123
+ Returns:
124
+ The process exit status: 0 on success, 2 if the versions could not be used.
125
+ """
126
+ parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
127
+ parser.add_argument("--current", required=True, help="the latest released tag")
128
+ parser.add_argument("--proposed", required=True, help="the tag git-cliff proposes")
129
+ parser.add_argument(
130
+ "--allow-major-bump",
131
+ action="store_true",
132
+ help="accept a bump into the next major while the current major is 0",
133
+ )
134
+ arguments = parser.parse_args(argv)
135
+ try:
136
+ print(
137
+ choose_version(
138
+ current=arguments.current,
139
+ proposed=arguments.proposed,
140
+ allow_major_bump=arguments.allow_major_bump,
141
+ )
142
+ )
143
+ except ValueError as error:
144
+ print(f"error: {error}", file=sys.stderr)
145
+ return 2
146
+ return 0
147
+
148
+
149
+ if __name__ == "__main__":
150
+ sys.exit(main())