specmod 0.2.3__tar.gz → 0.4.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 (272) hide show
  1. {specmod-0.2.3 → specmod-0.4.0}/.github/workflows/build.yml +7 -3
  2. {specmod-0.2.3 → specmod-0.4.0}/.github/workflows/docs.yml +7 -3
  3. {specmod-0.2.3 → specmod-0.4.0}/.github/workflows/release.yml +6 -2
  4. {specmod-0.2.3 → specmod-0.4.0}/.github/workflows/test.yml +31 -11
  5. {specmod-0.2.3 → specmod-0.4.0}/.pre-commit-config.yaml +9 -3
  6. specmod-0.4.0/.release-please-manifest.json +3 -0
  7. {specmod-0.2.3 → specmod-0.4.0}/CHANGELOG.md +59 -0
  8. {specmod-0.2.3 → specmod-0.4.0}/PKG-INFO +6 -5
  9. {specmod-0.2.3 → specmod-0.4.0}/README.md +3 -3
  10. {specmod-0.2.3 → specmod-0.4.0}/docs/REFACTOR_PLAN.md +100 -21
  11. specmod-0.4.0/docs/_builders/_notebook.py +162 -0
  12. specmod-0.2.3/docs/notebooks/_build_notebook.py → specmod-0.4.0/docs/_builders/choosing_a_transform.py +132 -103
  13. specmod-0.4.0/docs/_builders/specmod_tutorial.py +980 -0
  14. specmod-0.4.0/docs/_static/academic.css +70 -0
  15. specmod-0.4.0/docs/_static/fonts/OFL-fira-code.txt +93 -0
  16. specmod-0.4.0/docs/_static/fonts/OFL-merriweather.txt +93 -0
  17. specmod-0.4.0/docs/_static/fonts/OFL-open-sans.txt +88 -0
  18. specmod-0.4.0/docs/_static/fonts/README.md +7 -0
  19. specmod-0.4.0/docs/_static/fonts/fira-code-400-greek.woff2 +0 -0
  20. specmod-0.4.0/docs/_static/fonts/fira-code-400-latin-ext.woff2 +0 -0
  21. specmod-0.4.0/docs/_static/fonts/fira-code-400-latin.woff2 +0 -0
  22. specmod-0.4.0/docs/_static/fonts/merriweather-latin-ext.woff2 +0 -0
  23. specmod-0.4.0/docs/_static/fonts/merriweather-latin.woff2 +0 -0
  24. specmod-0.4.0/docs/_static/fonts/open-sans-greek.woff2 +0 -0
  25. specmod-0.4.0/docs/_static/fonts/open-sans-latin-ext.woff2 +0 -0
  26. specmod-0.4.0/docs/_static/fonts/open-sans-latin.woff2 +0 -0
  27. specmod-0.4.0/docs/_static/fonts.css +134 -0
  28. specmod-0.4.0/docs/_static/katex/LICENSE +21 -0
  29. specmod-0.4.0/docs/_static/katex/README.md +9 -0
  30. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  31. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  32. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  33. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  34. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  35. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  36. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  37. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  38. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  39. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  40. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  41. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  42. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  43. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  44. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  45. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  46. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  47. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  48. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  49. specmod-0.4.0/docs/_static/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  50. specmod-0.4.0/docs/_static/katex/katex.min.css +1 -0
  51. specmod-0.4.0/docs/_static/specmod-logo-academic-dark-mark.svg +340 -0
  52. specmod-0.4.0/docs/_static/specmod-logo-academic-dark.svg +333 -0
  53. specmod-0.4.0/docs/_static/specmod-logo-academic-mark.svg +340 -0
  54. specmod-0.4.0/docs/_static/specmod-logo-academic.svg +333 -0
  55. {specmod-0.2.3 → specmod-0.4.0}/docs/api.md +22 -9
  56. specmod-0.4.0/docs/branding.md +163 -0
  57. {specmod-0.2.3 → specmod-0.4.0}/docs/choosing-a-transform.md +84 -0
  58. {specmod-0.2.3 → specmod-0.4.0}/docs/conf.py +87 -25
  59. {specmod-0.2.3 → specmod-0.4.0}/docs/development.md +2 -1
  60. {specmod-0.2.3 → specmod-0.4.0}/docs/documentation.md +114 -1
  61. {specmod-0.2.3 → specmod-0.4.0}/docs/getting-started.md +3 -3
  62. {specmod-0.2.3 → specmod-0.4.0}/docs/index.md +2 -2
  63. {specmod-0.2.3 → specmod-0.4.0}/docs/notebooks/choosing-a-transform.ipynb +4 -4
  64. {specmod-0.2.3 → specmod-0.4.0}/docs/notes/api-audit.md +2 -2
  65. {specmod-0.2.3 → specmod-0.4.0}/docs/pick-formats.md +9 -8
  66. {specmod-0.2.3 → specmod-0.4.0}/docs/processing.md +44 -5
  67. {specmod-0.2.3 → specmod-0.4.0}/docs/roadmap.md +45 -16
  68. {specmod-0.2.3 → specmod-0.4.0}/docs/upgrading.md +106 -27
  69. {specmod-0.2.3 → specmod-0.4.0}/pyproject.toml +5 -1
  70. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/api.py +6 -2
  71. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/config/sections.py +55 -5
  72. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/bandwidth.py +122 -4
  73. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/collection.py +230 -29
  74. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/noise.py +1 -0
  75. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/datasets.py +1 -1
  76. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/distance.py +2 -2
  77. specmod-0.4.0/src/specmod/io/__init__.py +54 -0
  78. specmod-0.4.0/src/specmod/io/backend.py +28 -0
  79. specmod-0.4.0/src/specmod/io/hdf5.py +119 -0
  80. specmod-0.4.0/src/specmod/io/layout.py +85 -0
  81. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/pipeline.py +67 -1
  82. specmod-0.4.0/src/specmod/plotting/__init__.py +31 -0
  83. specmod-0.4.0/src/specmod/plotting/grid.py +60 -0
  84. specmod-0.2.3/src/specmod/plotting.py → specmod-0.4.0/src/specmod/plotting/pair.py +6 -78
  85. specmod-0.4.0/src/specmod/plotting/style.py +24 -0
  86. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/preprocess.py +160 -117
  87. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/smoothing/__init__.py +19 -2
  88. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/smoothing/base.py +16 -1
  89. specmod-0.4.0/src/specmod/smoothing/log_window.py +215 -0
  90. specmod-0.4.0/src/specmod/smoothing/savitzky_golay.py +127 -0
  91. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/__init__.py +16 -1
  92. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/utils.py +2 -1
  93. {specmod-0.2.3 → specmod-0.4.0}/tests/conftest.py +5 -10
  94. {specmod-0.2.3 → specmod-0.4.0}/tests/golden/motion_reference.json +140 -0
  95. {specmod-0.2.3 → specmod-0.4.0}/tests/golden/pipeline_reference.json +140 -0
  96. {specmod-0.2.3 → specmod-0.4.0}/tests/golden/window_reference.json +140 -0
  97. {specmod-0.2.3 → specmod-0.4.0}/tests/test_api_surface.py +1 -3
  98. {specmod-0.2.3 → specmod-0.4.0}/tests/test_collection.py +228 -4
  99. {specmod-0.2.3 → specmod-0.4.0}/tests/test_config.py +141 -1
  100. specmod-0.4.0/tests/test_docs_are_current.py +152 -0
  101. {specmod-0.2.3 → specmod-0.4.0}/tests/test_end_to_end.py +3 -8
  102. {specmod-0.2.3 → specmod-0.4.0}/tests/test_golden_reference.py +74 -9
  103. {specmod-0.2.3 → specmod-0.4.0}/tests/test_io_and_plotting.py +8 -3
  104. {specmod-0.2.3 → specmod-0.4.0}/tests/test_legacy_fixes.py +10 -10
  105. {specmod-0.2.3 → specmod-0.4.0}/tests/test_pick_plugins.py +1 -1
  106. {specmod-0.2.3 → specmod-0.4.0}/tests/test_picks.py +4 -4
  107. {specmod-0.2.3 → specmod-0.4.0}/tests/test_pipeline.py +123 -1
  108. {specmod-0.2.3 → specmod-0.4.0}/tests/test_preprocess.py +169 -74
  109. {specmod-0.2.3 → specmod-0.4.0}/tests/test_release_config.py +88 -0
  110. specmod-0.4.0/tests/test_smoothing.py +431 -0
  111. {specmod-0.2.3 → specmod-0.4.0}/tests/test_staged.py +1 -1
  112. {specmod-0.2.3 → specmod-0.4.0}/tests/test_stubs.py +2 -2
  113. specmod-0.4.0/tests/test_tools_track_the_api.py +125 -0
  114. {specmod-0.2.3 → specmod-0.4.0}/tests/test_tutorial.py +3 -1
  115. {specmod-0.2.3 → specmod-0.4.0}/tools/make_golden.py +34 -4
  116. specmod-0.4.0/tools/make_logo.py +158 -0
  117. {specmod-0.2.3 → specmod-0.4.0}/tools/measure_docs.py +107 -7
  118. specmod-0.4.0/tools/vendor_fonts.py +175 -0
  119. specmod-0.4.0/tools/vendor_katex.py +122 -0
  120. specmod-0.2.3/tutorial/SpecModTutorial.ipynb → specmod-0.4.0/tutorial/specmod-tutorial.ipynb +241 -54
  121. specmod-0.2.3/.release-please-manifest.json +0 -3
  122. specmod-0.2.3/src/specmod/io.py +0 -241
  123. specmod-0.2.3/tests/test_docs_are_current.py +0 -80
  124. specmod-0.2.3/tests/test_smoothing.py +0 -226
  125. {specmod-0.2.3 → specmod-0.4.0}/.git-blame-ignore-revs +0 -0
  126. {specmod-0.2.3 → specmod-0.4.0}/.gitignore +0 -0
  127. {specmod-0.2.3 → specmod-0.4.0}/.readthedocs.yaml +0 -0
  128. {specmod-0.2.3 → specmod-0.4.0}/AGENTS.md +0 -0
  129. {specmod-0.2.3 → specmod-0.4.0}/CITATION.cff +0 -0
  130. {specmod-0.2.3 → specmod-0.4.0}/CLAUDE.md +0 -0
  131. {specmod-0.2.3 → specmod-0.4.0}/CONTRIBUTING.md +0 -0
  132. {specmod-0.2.3 → specmod-0.4.0}/LICENSE +0 -0
  133. {specmod-0.2.3 → specmod-0.4.0}/datasets/magna_2020.toml +0 -0
  134. {specmod-0.2.3 → specmod-0.4.0}/datasets/pnr_2019.toml +0 -0
  135. {specmod-0.2.3 → specmod-0.4.0}/docs/contributing.md +0 -0
  136. {specmod-0.2.3 → specmod-0.4.0}/docs/guides.md +0 -0
  137. {specmod-0.2.3 → specmod-0.4.0}/docs/notes/window-position.md +0 -0
  138. {specmod-0.2.3 → specmod-0.4.0}/docs/releasing-data.md +0 -0
  139. {specmod-0.2.3 → specmod-0.4.0}/docs/releasing.md +0 -0
  140. {specmod-0.2.3 → specmod-0.4.0}/release-please-config.json +0 -0
  141. {specmod-0.2.3 → specmod-0.4.0}/requirements.txt +0 -0
  142. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/__init__.py +0 -0
  143. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/_vendor/__init__.py +0 -0
  144. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/_vendor/qiinv.py +0 -0
  145. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/acquire.py +0 -0
  146. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/cli.py +0 -0
  147. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/config/__init__.py +0 -0
  148. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/config/layers.py +0 -0
  149. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/config/provenance.py +0 -0
  150. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/config/serialize.py +0 -0
  151. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/__init__.py +0 -0
  152. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/scalogram.py +0 -0
  153. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/spectrum.py +0 -0
  154. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/core/units.py +0 -0
  155. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/exceptions.py +0 -0
  156. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/fitting/__init__.py +0 -0
  157. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/fitting/base.py +0 -0
  158. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/fitting/event.py +0 -0
  159. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/fitting/guess.py +0 -0
  160. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/fitting/spectrum.py +0 -0
  161. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/magnitude.py +0 -0
  162. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/picks/__init__.py +0 -0
  163. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/picks/base.py +0 -0
  164. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/picks/delimited.py +0 -0
  165. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/picks/events.py +0 -0
  166. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/picks/resolution.py +0 -0
  167. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/picks/snuffler.py +0 -0
  168. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/smoothing/konno_ohmachi.py +0 -0
  169. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/smoothing/log_bins.py +0 -0
  170. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/sources/__init__.py +0 -0
  171. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/sources/attenuation.py +0 -0
  172. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/sources/composite.py +0 -0
  173. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/sources/motion.py +0 -0
  174. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/sources/source.py +0 -0
  175. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/spreading.py +0 -0
  176. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/staged.py +0 -0
  177. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/tables.py +0 -0
  178. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/base.py +0 -0
  179. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/cwt.py +0 -0
  180. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/fft.py +0 -0
  181. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/multitaper.py +0 -0
  182. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/prieto.py +0 -0
  183. {specmod-0.2.3 → specmod-0.4.0}/src/specmod/transforms/quadratic.py +0 -0
  184. {specmod-0.2.3 → specmod-0.4.0}/stubs/README.md +0 -0
  185. {specmod-0.2.3 → specmod-0.4.0}/stubs/lmfit/__init__.pyi +0 -0
  186. {specmod-0.2.3 → specmod-0.4.0}/stubs/lmfit/model.pyi +0 -0
  187. {specmod-0.2.3 → specmod-0.4.0}/stubs/lmfit/parameter.pyi +0 -0
  188. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/__init__.pyi +0 -0
  189. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/clients/__init__.pyi +0 -0
  190. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/clients/fdsn/__init__.pyi +0 -0
  191. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/__init__.pyi +0 -0
  192. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/event.pyi +0 -0
  193. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/inventory.pyi +0 -0
  194. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/stream.pyi +0 -0
  195. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/trace.pyi +0 -0
  196. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/utcdatetime.pyi +0 -0
  197. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/util/__init__.pyi +0 -0
  198. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/core/util/base.pyi +0 -0
  199. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/geodetics/__init__.pyi +0 -0
  200. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/signal/__init__.pyi +0 -0
  201. {specmod-0.2.3 → specmod-0.4.0}/stubs/obspy/signal/konnoohmachismoothing.pyi +0 -0
  202. {specmod-0.2.3 → specmod-0.4.0}/studies/magna_2020_paper.toml +0 -0
  203. {specmod-0.2.3 → specmod-0.4.0}/tests/__init__.py +0 -0
  204. {specmod-0.2.3 → specmod-0.4.0}/tests/test_acquire.py +0 -0
  205. {specmod-0.2.3 → specmod-0.4.0}/tests/test_ambient_state.py +0 -0
  206. {specmod-0.2.3 → specmod-0.4.0}/tests/test_cwt.py +0 -0
  207. {specmod-0.2.3 → specmod-0.4.0}/tests/test_datasets.py +0 -0
  208. {specmod-0.2.3 → specmod-0.4.0}/tests/test_fitting_defaults.py +0 -0
  209. {specmod-0.2.3 → specmod-0.4.0}/tests/test_import.py +0 -0
  210. {specmod-0.2.3 → specmod-0.4.0}/tests/test_magnitude.py +0 -0
  211. {specmod-0.2.3 → specmod-0.4.0}/tests/test_make_golden.py +0 -0
  212. {specmod-0.2.3 → specmod-0.4.0}/tests/test_pick_readers.py +0 -0
  213. {specmod-0.2.3 → specmod-0.4.0}/tests/test_pipeline_smoke.py +0 -0
  214. {specmod-0.2.3 → specmod-0.4.0}/tests/test_prieto.py +0 -0
  215. {specmod-0.2.3 → specmod-0.4.0}/tests/test_quadratic.py +0 -0
  216. {specmod-0.2.3 → specmod-0.4.0}/tests/test_sources.py +0 -0
  217. {specmod-0.2.3 → specmod-0.4.0}/tests/test_spectral_wiring.py +0 -0
  218. {specmod-0.2.3 → specmod-0.4.0}/tests/test_transforms.py +0 -0
  219. {specmod-0.2.3 → specmod-0.4.0}/tests/test_typing_backlog.py +0 -0
  220. {specmod-0.2.3 → specmod-0.4.0}/tests/test_utils.py +0 -0
  221. {specmod-0.2.3 → specmod-0.4.0}/tests/test_versioning.py +0 -0
  222. {specmod-0.2.3 → specmod-0.4.0}/tools/check_built_version.py +0 -0
  223. {specmod-0.2.3 → specmod-0.4.0}/tools/check_floors.py +0 -0
  224. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.picks +0 -0
  225. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.xml +0 -0
  226. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/stations/inventory.xml +0 -0
  227. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHE_2019-08-26T07:30:47.000000Z +0 -0
  228. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHN_2019-08-26T07:30:47.000000Z +0 -0
  229. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  230. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHE_2019-08-26T07:30:47.000000Z +0 -0
  231. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHN_2019-08-26T07:30:47.000000Z +0 -0
  232. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  233. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHE_2019-08-26T07:30:47.000000Z +0 -0
  234. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHN_2019-08-26T07:30:47.000000Z +0 -0
  235. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  236. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHE_2019-08-26T07:30:47.000000Z +0 -0
  237. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHN_2019-08-26T07:30:47.000000Z +0 -0
  238. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  239. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHE_2019-08-26T07:30:47.000000Z +0 -0
  240. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHN_2019-08-26T07:30:47.000000Z +0 -0
  241. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  242. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHE_2019-08-26T07:30:47.000000Z +0 -0
  243. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHN_2019-08-26T07:30:47.000000Z +0 -0
  244. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  245. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH1_2019-08-26T07:30:47.000000Z +0 -0
  246. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH2_2019-08-26T07:30:47.000000Z +0 -0
  247. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH3_2019-08-26T07:30:47.000000Z +0 -0
  248. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  249. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  250. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  251. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ02.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  252. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  253. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  254. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  255. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  256. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  257. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  258. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  259. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  260. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  261. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  262. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  263. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  264. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  265. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  266. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  267. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  268. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  269. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  270. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  271. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  272. {specmod-0.2.3 → specmod-0.4.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
@@ -10,10 +10,14 @@ jobs:
10
10
  build:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v4
13
+ - uses: actions/checkout@v7
14
14
  with:
15
15
  fetch-depth: 0 # hatch-vcs derives the version from tags
16
- - uses: astral-sh/setup-uv@v5
16
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
17
+ # publishes no bare major tag — `@v10` does not resolve, and using it
18
+ # fails every job at "Getting action download info", before a step runs.
19
+ # Bump this deliberately; do not "tidy" it to `@v10`.
20
+ - uses: astral-sh/setup-uv@v10.0.1
17
21
  - run: uv python install 3.11
18
22
 
19
23
  - name: Build sdist and wheel
@@ -34,7 +38,7 @@ jobs:
34
38
  print('specmod', specmod.__version__, '- wheel imports cleanly')
35
39
  "
36
40
 
37
- - uses: actions/upload-artifact@v4
41
+ - uses: actions/upload-artifact@v7
38
42
  with:
39
43
  name: dist
40
44
  path: dist/
@@ -24,10 +24,14 @@ jobs:
24
24
  docs:
25
25
  runs-on: ubuntu-latest
26
26
  steps:
27
- - uses: actions/checkout@v4
27
+ - uses: actions/checkout@v7
28
28
  with:
29
29
  fetch-depth: 0 # hatch-vcs derives the version from tags
30
- - uses: astral-sh/setup-uv@v5
30
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
31
+ # publishes no bare major tag — `@v10` does not resolve, and using it
32
+ # fails every job at "Getting action download info", before a step runs.
33
+ # Bump this deliberately; do not "tidy" it to `@v10`.
34
+ - uses: astral-sh/setup-uv@v10.0.1
31
35
  - run: uv python install 3.11
32
36
  - run: uv venv # create a venv to install into
33
37
 
@@ -50,7 +54,7 @@ jobs:
50
54
 
51
55
  # Not a Pages artefact: this is a plain zip anyone can download from the
52
56
  # run and open locally, and it stays useful if Read the Docs is down.
53
- - uses: actions/upload-artifact@v4
57
+ - uses: actions/upload-artifact@v7
54
58
  with:
55
59
  name: docs-html
56
60
  path: docs/_build/html
@@ -77,7 +77,7 @@ jobs:
77
77
  id-token: write # mandatory for Trusted Publishing
78
78
  contents: read
79
79
  steps:
80
- - uses: actions/checkout@v4
80
+ - uses: actions/checkout@v7
81
81
  with:
82
82
  # The tag, not the branch. main has already moved on by one commit
83
83
  # (the release PR merge), and hatch-vcs would derive a .postN.devN
@@ -85,7 +85,11 @@ jobs:
85
85
  ref: ${{ needs.release-please.outputs.tag_name }}
86
86
  fetch-depth: 0 # hatch-vcs derives the version by describing tags
87
87
 
88
- - uses: astral-sh/setup-uv@v5
88
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
89
+ # publishes no bare major tag — `@v10` does not resolve, and using it
90
+ # fails every job at "Getting action download info", before a step runs.
91
+ # Bump this deliberately; do not "tidy" it to `@v10`.
92
+ - uses: astral-sh/setup-uv@v10.0.1
89
93
  - run: uv python install 3.11
90
94
  - run: uv build
91
95
 
@@ -14,8 +14,12 @@ jobs:
14
14
  lint:
15
15
  runs-on: ubuntu-latest
16
16
  steps:
17
- - uses: actions/checkout@v4
18
- - uses: astral-sh/setup-uv@v5
17
+ - uses: actions/checkout@v7
18
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
19
+ # publishes no bare major tag — `@v10` does not resolve, and using it
20
+ # fails every job at "Getting action download info", before a step runs.
21
+ # Bump this deliberately; do not "tidy" it to `@v10`.
22
+ - uses: astral-sh/setup-uv@v10.0.1
19
23
  with:
20
24
  enable-cache: true
21
25
  - run: uv python install 3.11
@@ -28,10 +32,14 @@ jobs:
28
32
  typecheck:
29
33
  runs-on: ubuntu-latest
30
34
  steps:
31
- - uses: actions/checkout@v4
35
+ - uses: actions/checkout@v7
32
36
  with:
33
37
  fetch-depth: 0 # hatch-vcs needs history to derive the version
34
- - uses: astral-sh/setup-uv@v5
38
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
39
+ # publishes no bare major tag — `@v10` does not resolve, and using it
40
+ # fails every job at "Getting action download info", before a step runs.
41
+ # Bump this deliberately; do not "tidy" it to `@v10`.
42
+ - uses: astral-sh/setup-uv@v10.0.1
35
43
  with:
36
44
  enable-cache: true
37
45
  - run: uv python install 3.11
@@ -48,10 +56,14 @@ jobs:
48
56
  os: [ubuntu-latest, macos-latest]
49
57
  python-version: ["3.11", "3.12", "3.13"]
50
58
  steps:
51
- - uses: actions/checkout@v4
59
+ - uses: actions/checkout@v7
52
60
  with:
53
61
  fetch-depth: 0
54
- - uses: astral-sh/setup-uv@v5
62
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
63
+ # publishes no bare major tag — `@v10` does not resolve, and using it
64
+ # fails every job at "Getting action download info", before a step runs.
65
+ # Bump this deliberately; do not "tidy" it to `@v10`.
66
+ - uses: astral-sh/setup-uv@v10.0.1
55
67
  with:
56
68
  enable-cache: true
57
69
  - run: uv python install ${{ matrix.python-version }}
@@ -64,7 +76,7 @@ jobs:
64
76
  # execution is excluded because it costs ~40s and a Jupyter kernel, and
65
77
  # is worth paying once rather than six times — see the notebook job.
66
78
  run: uv run pytest -m "not dataset and not notebook" --cov=specmod --cov-report=xml --cov-report=term
67
- - uses: codecov/codecov-action@v4
79
+ - uses: codecov/codecov-action@v7
68
80
  if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
69
81
  with:
70
82
  files: coverage.xml
@@ -73,10 +85,14 @@ jobs:
73
85
  floors:
74
86
  runs-on: ubuntu-latest
75
87
  steps:
76
- - uses: actions/checkout@v4
88
+ - uses: actions/checkout@v7
77
89
  with:
78
90
  fetch-depth: 0
79
- - uses: astral-sh/setup-uv@v5
91
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
92
+ # publishes no bare major tag — `@v10` does not resolve, and using it
93
+ # fails every job at "Getting action download info", before a step runs.
94
+ # Bump this deliberately; do not "tidy" it to `@v10`.
95
+ - uses: astral-sh/setup-uv@v10.0.1
80
96
  - run: uv python install 3.11
81
97
  - run: uv venv
82
98
  # Exercise the declared minimums. CI otherwise installs the newest of
@@ -92,10 +108,14 @@ jobs:
92
108
  # third kind, so it runs per-PR rather than at release.
93
109
  runs-on: ubuntu-latest
94
110
  steps:
95
- - uses: actions/checkout@v4
111
+ - uses: actions/checkout@v7
96
112
  with:
97
113
  fetch-depth: 0
98
- - uses: astral-sh/setup-uv@v5
114
+ # Pinned to a full version, unlike the other three. `astral-sh/setup-uv`
115
+ # publishes no bare major tag — `@v10` does not resolve, and using it
116
+ # fails every job at "Getting action download info", before a step runs.
117
+ # Bump this deliberately; do not "tidy" it to `@v10`.
118
+ - uses: astral-sh/setup-uv@v10.0.1
99
119
  with:
100
120
  enable-cache: true
101
121
  - run: uv python install 3.11
@@ -36,12 +36,18 @@ repos:
36
36
  # running the hooks over one silently stripped six bytes from the middle
37
37
  # of it — a corrupted pickle that still looks like a plausible diff.
38
38
  # Anything binary has to be excluded by hand; the hooks do not detect it.
39
+ #
40
+ # The two vendored directories under `docs/_static/` are excluded for
41
+ # both reasons at once. Their `.woff2` files are binary, and the licences
42
+ # beside them have to stay byte identical to what upstream publishes —
43
+ # `trailing-whitespace` edited Merriweather's OFL the first time it was
44
+ # staged, which is a licence rewritten to satisfy a linter.
39
45
  - id: end-of-file-fixer
40
- exclude: '\.spec$'
46
+ exclude: &verbatim '(\.spec$|^docs/_static/(fonts|katex)/)'
41
47
  - id: trailing-whitespace
42
- exclude: '\.spec$'
48
+ exclude: *verbatim
43
49
  - id: mixed-line-ending
44
- exclude: '\.spec$'
50
+ exclude: *verbatim
45
51
 
46
52
  - repo: https://github.com/kynan/nbstripout
47
53
  rev: 0.8.1
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.4.0"
3
+ }
@@ -9,6 +9,65 @@ release could have this problem — every later one has a real predecessor tag
9
9
  so leave subsequent headings as generated. release-please only prepends to this
10
10
  file, so this edit survives. -->
11
11
 
12
+ ## [0.4.0](https://github.com/sgjholt/SpecMod/compare/v0.3.0...v0.4.0) (2026-09-16)
13
+
14
+
15
+ ### Features
16
+
17
+ * **smoothing:** wire [smoothing] method up, and add three more methods ([fff3ab1](https://github.com/sgjholt/SpecMod/commit/fff3ab1ef01a7f4d942fd776821d0418a0642a55))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **config:** refuse a [smoothing] method the pipeline does not apply ([1f18c68](https://github.com/sgjholt/SpecMod/commit/1f18c68a71794c2b1612a7cf0feedcfef39b625b))
23
+ * **test:** compare the roadmap against the published minor, not the proposed one ([1e34b4e](https://github.com/sgjholt/SpecMod/commit/1e34b4e5ab2bdef5d65f6fc0d620a42b9c3891eb))
24
+ * **tools:** call the preprocess API that 0.3.0 left behind ([8501c8e](https://github.com/sgjholt/SpecMod/commit/8501c8ed618e5d652b9eeffc36893115a58fd7d5))
25
+
26
+
27
+ ### Documentation
28
+
29
+ * keep the reasoning out of the docstrings, in comments where it belongs ([2684ec9](https://github.com/sgjholt/SpecMod/commit/2684ec923c8dcf59e882b2d11e9dc11ccbcf3766))
30
+ * say what tagging the frozen commit does and does not trigger ([2273219](https://github.com/sgjholt/SpecMod/commit/2273219e2a78ac1c1562118c2a1b3bce4df597dd))
31
+ * state what the smoothers are, not how they were arrived at ([4c97491](https://github.com/sgjholt/SpecMod/commit/4c97491d50aba5a1468304072ab3c6ed2904f2e0))
32
+ * the 0.3.0 work shipped a week ago, so stop calling it unreleased ([e2aaced](https://github.com/sgjholt/SpecMod/commit/e2aaced546a247b2c5967f01586c19928bcfe297))
33
+ * v0.1.1 is master's tip, which is what freezing it was for ([db50972](https://github.com/sgjholt/SpecMod/commit/db509729f3b7877a20b5691dddec8a6e139fb466))
34
+
35
+ ## [0.3.0](https://github.com/sgjholt/SpecMod/compare/v0.2.3...v0.3.0) (2026-09-06)
36
+
37
+
38
+ ### ⚠ BREAKING CHANGES
39
+
40
+ * the tutorial page moves from `/tutorial/SpecModTutorial.html` to `/tutorial/specmod-tutorial.html`.
41
+ * the ten mutating functions in `specmod.preprocess` are renamed and now return a new stream or trace. `get_signal` is removed, and the two undated deprecation shims are gone.
42
+
43
+ ### Features
44
+
45
+ * let the fitted band be capped, fixed or corrected by hand ([ba241a9](https://github.com/sgjholt/SpecMod/commit/ba241a95d94a298418b3c6f414a0026b9f310926))
46
+ * preprocess returns new streams instead of mutating ([78aabeb](https://github.com/sgjholt/SpecMod/commit/78aabeb4856eda4208787fcd53b0df77bc50bd1c))
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * give the noise and bandwidth registries a documented home ([daeb2cc](https://github.com/sgjholt/SpecMod/commit/daeb2cc43eff2869e9617e4111f281f9bd4d33bb))
52
+ * **transforms:** re-export every public name from base ([67c24c3](https://github.com/sgjholt/SpecMod/commit/67c24c3dda80f7fbc1bd51861861bde48d943eac))
53
+
54
+
55
+ ### Code Refactoring
56
+
57
+ * **docs:** build the tutorial from a script too ([de846c6](https://github.com/sgjholt/SpecMod/commit/de846c6128fc7922df8e1e3c2c1c01f2b8bf95bb))
58
+ * **docs:** one notebook builder per notebook, named after it ([0175f89](https://github.com/sgjholt/SpecMod/commit/0175f890f5f92668341a17bece7149f7d8f8c6b7))
59
+ * split io and plotting into packages ([027b77f](https://github.com/sgjholt/SpecMod/commit/027b77f7d050716b7d98fc873a8a4e93098d1d68))
60
+
61
+
62
+ ### Documentation
63
+
64
+ * adopt the academic theme from the branding manual ([76f0aa0](https://github.com/sgjholt/SpecMod/commit/76f0aa0a40a134eeb91b8ada04c8f5fa66243c54))
65
+ * kebab-case the tutorial notebook, snake_case its builder ([5a65b73](https://github.com/sgjholt/SpecMod/commit/5a65b7336980bf5d7163c4cad28e7c273715c0a3))
66
+ * measure the MathJax figure instead of asserting it ([cba7e01](https://github.com/sgjholt/SpecMod/commit/cba7e0116a09ba8d4565308ee8c0227d138b20cd))
67
+ * render maths with KaTeX, served from this site ([902d3fe](https://github.com/sgjholt/SpecMod/commit/902d3fec4230e6af17ea1b7a9d32d9e9c153fd8e))
68
+ * self-host the branding fonts ([c1e6f9f](https://github.com/sgjholt/SpecMod/commit/c1e6f9fe16f4ec48c5e788e6b29181c5ffc01bbf))
69
+ * the decomposition is finished ([bbb2b71](https://github.com/sgjholt/SpecMod/commit/bbb2b7189b9f98c3baa48fe907bc2c414455f5d9))
70
+
12
71
  ## [0.2.3](https://github.com/sgjholt/SpecMod/compare/v0.2.2...v0.2.3) (2026-09-05)
13
72
 
14
73
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: specmod
3
- Version: 0.2.3
3
+ Version: 0.4.0
4
4
  Summary: A Python toolbox for processing and modelling seismic spectra
5
5
  Project-URL: Homepage, https://github.com/sgjholt/SpecMod
6
6
  Project-URL: Repository, https://github.com/sgjholt/SpecMod
@@ -35,11 +35,12 @@ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
35
35
  Requires-Dist: pytest>=8.0; extra == 'dev'
36
36
  Requires-Dist: ruff>=0.6; extra == 'dev'
37
37
  Provides-Extra: docs
38
+ Requires-Dist: furo>=2024.1; extra == 'docs'
38
39
  Requires-Dist: myst-nb>=1.1; extra == 'docs'
39
40
  Requires-Dist: myst-parser>=3.0; extra == 'docs'
40
- Requires-Dist: pydata-sphinx-theme>=0.15; extra == 'docs'
41
41
  Requires-Dist: sphinx-togglebutton>=0.3; extra == 'docs'
42
42
  Requires-Dist: sphinx>=7.3; extra == 'docs'
43
+ Requires-Dist: sphinxcontrib-katex>=0.9; extra == 'docs'
43
44
  Provides-Extra: io
44
45
  Requires-Dist: h5py>=3.11; extra == 'io'
45
46
  Requires-Dist: pyarrow>=16.0; extra == 'io'
@@ -179,13 +180,13 @@ changes nothing else.
179
180
 
180
181
  ## Reading picks
181
182
 
182
- Arrivals are attached to traces by `set_picks`, which detects the format from
183
- the file rather than from its name:
183
+ `with_picks` returns a stream with arrivals attached, detecting the format
184
+ from the file rather than from its name:
184
185
 
185
186
  ```python
186
187
  import specmod.preprocess as pre
187
188
 
188
- pre.set_picks(stream, "event.xml")
189
+ stream = pre.with_picks(stream, "event.xml")
189
190
  ```
190
191
 
191
192
  Everything `obspy.read_events` parses is read through one delegate — QuakeML,
@@ -122,13 +122,13 @@ changes nothing else.
122
122
 
123
123
  ## Reading picks
124
124
 
125
- Arrivals are attached to traces by `set_picks`, which detects the format from
126
- the file rather than from its name:
125
+ `with_picks` returns a stream with arrivals attached, detecting the format
126
+ from the file rather than from its name:
127
127
 
128
128
  ```python
129
129
  import specmod.preprocess as pre
130
130
 
131
- pre.set_picks(stream, "event.xml")
131
+ stream = pre.with_picks(stream, "event.xml")
132
132
  ```
133
133
 
134
134
  Everything `obspy.read_events` parses is read through one delegate — QuakeML,
@@ -1087,7 +1087,7 @@ and there are presumably more in your working directories.
1087
1087
  Two ways out, and the first is much better:
1088
1088
 
1089
1089
  1. **Convert in the old environment.** Phase 0 is already building a Docker image
1090
- where the 0.1.0 code runs (§6.7). Add a small
1090
+ where the 0.1.1 code runs (§6.7). Add a small
1091
1091
  `scripts/convert_legacy_spec.py` to it that loads `.spec` files with the old
1092
1092
  classes present and writes the new HDF5 format. This is a one-shot migration
1093
1093
  with no lasting cost to the codebase.
@@ -2742,13 +2742,30 @@ Two further problems with reproducing the published run from this repository:
2742
2742
  manuscript filename (`...SRL3`) suggests a third revision, which would also
2743
2743
  explain a 2021 code state behind a 2020 access date.
2744
2744
 
2745
- Practical consequence: **the candidate is `ba3f7ec` or later, not the
2745
+ The evidence narrows it: **the candidate is `ba3f7ec` or later, not the
2746
2746
  pre-November-2020 commits**, because the earlier code cannot perform the
2747
2747
  workflow the paper describes. Only `09f57b9` (removed cython) changes
2748
2748
  `specmod/` after that, so the realistic candidates are `ba3f7ec` and
2749
- `453c77c`. Pick one, record the reasoning, and move on — this is the
2750
- strongest possible argument for the `v0.1.0` tag (§6.7) and for `hatch-vcs`
2751
- (§6.4): it must never be this hard again.
2749
+ `453c77c`.
2750
+
2751
+ **Answered: `453c77c`** — the tip of `master`, 2021-08-12. On the author's
2752
+ word, and it is why `master` was frozen at that commit rather than at any
2753
+ other: the branch *is* the v0.1.1 record (§6.7). Which of the two the
2754
+ evidence above prefers was never the question it looked like.
2755
+
2756
+ What that settles and what it does not: the code is identified, so §5.2.6
2757
+ step 2 can be run against a known commit. The dating oddity is unchanged —
2758
+ the manuscript's access date still precedes the commit it cites, which the
2759
+ third revision (`...SRL3`) explains without needing the code to have moved.
2760
+ It is recorded rather than resolved, because nothing in the repository can
2761
+ resolve it.
2762
+
2763
+ This is still the strongest possible argument for tagging that commit (§6.7)
2764
+ and for `hatch-vcs` (§6.4): a version that takes a page of archaeology to
2765
+ identify must never happen again. **No `v0.1.1` tag exists yet.** Creating
2766
+ one is safe — `453c77c` is an ancestor of `main`, and every later release
2767
+ tag outranks it for `hatch-vcs`, so nothing derives a version from it — but
2768
+ it is repository state, not something a commit here can carry.
2752
2769
  2. **The full published pipeline is not in this repository.** The two-stage
2753
2770
  inversion (fit Ω/`f_c`/`t*` free, then fix event `f_c` to the
2754
2771
  inverse-hypocentral-distance-weighted mean of station `f_c` and refit) and the
@@ -3414,6 +3431,31 @@ been audited once is worth more than one that reads confidently throughout.
3414
3431
  | "`commitlint`-enforced" again, in §6.4 | The §7 instance was corrected and this one was left standing, in the same document. §6.4 corrected. |
3415
3432
  | `publish.yml` "GitHub Release published → PyPI" | It would never have run. release-please creates the release with the default `GITHUB_TOKEN`, and events triggered by that token do not start a workflow. The publish job moved into `release.yml`, gated on `release_created`. §6.5 corrected. |
3416
3433
 
3434
+ **A fourth of the same shape, found later** — the three above were corrected in
3435
+ the prose; this one was a live setting:
3436
+
3437
+ > `[smoothing] method` — "Name -> smoother, for resolving `SmoothingConfig.method`"
3438
+
3439
+ `SMOOTHERS` existed, `method` validated against its `Literal`, and **no code
3440
+ anywhere read it**. The comparison binned with `log_bin` unconditionally.
3441
+ Measured on the 28 PNR windows, `log_bins`, `konno_ohmachi` and `none` produced
3442
+ bit-identical output — `none` included, which reads as "leave my spectra
3443
+ unsmoothed" while every spectrum went on being binned exactly as before.
3444
+
3445
+ **Fixed rather than documented.** `SpectrumPair.compare` now takes a `smoother`,
3446
+ `[smoothing] method` resolves to one, and the registry gained `log_window`
3447
+ (constant-relative-bandwidth smoothing with a selectable window shape, and a
3448
+ median option) and `savitzky_golay` beside the two that were there.
3449
+ `tests/test_config.py::TestEverySmoothingMethodIsWiredUp` and
3450
+ `tests/test_pipeline.py::TestTheConfiguredSmootherReachesTheComparison` are the
3451
+ mechanism the comment claimed: each accepted value resolves, carries its
3452
+ section's parameters, and survives the whole path on real windows.
3453
+
3454
+ `log_bins` stays `core.collection.log_bin` rather than `smoothing.LogBinner` —
3455
+ the two differ in clamping and in what `n_bins` counts, and the difference is
3456
+ every committed golden number. The default path is unchanged, which the golden
3457
+ suite asserts and which is why this could land without moving a number.
3458
+
3417
3459
  **A claim whose mechanism is absent but whose property holds — for a different
3418
3460
  reason, which matters:**
3419
3461
 
@@ -3460,7 +3502,8 @@ of §5.2, and the two-stage fit API of §5.2.5.
3460
3502
  **`master` is frozen; `main` is the trunk.** `main` was branched from `master` at
3461
3503
  `453c77c` and is where all refactor work lands. `master` is never committed to
3462
3504
  again — it becomes the permanent, named record of the pre-refactor code, doing
3463
- the job a `v0.1.0` tag would have done.
3505
+ the job a `v0.1.1` tag would have done. Its tip, `453c77c`, **is** the v0.1.1
3506
+ the Magna paper cites (§5.2.5, §8).
3464
3507
 
3465
3508
  **Every pull request must target `sgjholt/SpecMod`, never `uofuseismo/SpecMod`.**
3466
3509
  This is not a matter of care — it is a GitHub default working against you.
@@ -3498,7 +3541,7 @@ Two consequences worth acting on:
3498
3541
  - [ ] Settings → Actions → confirm workflows are enabled
3499
3542
  - [ ] Settings → Branches → protect `master` (no pushes, no deletion) so the
3500
3543
  frozen record stays frozen
3501
- - [ ] `git tag -a v0.1.0 453c77c -m "pre-refactor snapshot" && git push origin v0.1.0`
3544
+ - [ ] `git tag -a v0.1.1 453c77c -m "the version the Magna paper cites" && git push origin v0.1.1`
3502
3545
 
3503
3546
  **No Claude session URLs in commit messages, PR bodies, or any other published
3504
3547
  artifact.** The repository is public and those links are private session state. A
@@ -3516,12 +3559,20 @@ needed and neither can be made from a git client:
3516
3559
  convention rather than a guarantee — one absent-minded `git push origin
3517
3560
  master` and the record is gone.
3518
3561
 
3519
- Optionally also tag `453c77c` as `v0.1.0` for good measure; belt and braces, and
3520
- it gives release-please an explicit floor to generate the first changelog from.
3521
- The two are complementary — the tag is immutable, the branch is discoverable.
3562
+ Also tag `453c77c` as `v0.1.1` — no longer optional now that §8 records it as
3563
+ the commit the paper cites. A branch is discoverable and a tag is immutable,
3564
+ and a citation should resolve to the immutable one.
3565
+
3566
+ Tagging it publishes nothing. No workflow triggers on tags; the PyPI upload is
3567
+ gated on release-please's `release_created`, which only a merged release PR on
3568
+ `main` can set; and `git describe` takes the nearest tag, which is a release
3569
+ far ahead of this one. **Do not create a GitHub Release from the tag**, which
3570
+ is the one action that would publish: Zenodo listens to the release webhook and
3571
+ would mint a DOI for the pre-refactor code. The commit has no `pyproject.toml`
3572
+ and is not packageable.
3522
3573
 
3523
3574
  > Note on tooling limits: tag pushes are blocked in the automation environment
3524
- > this plan was written in (HTTP 403 on `push origin v0.1.0`, while branch
3575
+ > this plan was written in (HTTP 403 on `push origin v0.1.1`, while branch
3525
3576
  > pushes to the same remote succeed), which is why `main` exists as a branch
3526
3577
  > rather than the state being pinned by a tag. **This does not affect the release
3527
3578
  > automation in §6.4** — release-please creates tags from inside GitHub Actions
@@ -3531,10 +3582,10 @@ The two are complementary — the tag is immutable, the branch is discoverable.
3531
3582
 
3532
3583
  Worth being precise about what any of this does and does not preserve: it
3533
3584
  preserves the **code**, but the code is not **runnable** — `mtspec` no longer
3534
- builds on any current toolchain (§2.1). Reproducing a 0.1.0 result needs three
3585
+ builds on any current toolchain (§2.1). Reproducing a 0.1.1 result needs three
3535
3586
  things, which is what Phase 0 delivers:
3536
3587
 
3537
- 1. `master` (and optionally `v0.1.0`) — the source.
3588
+ 1. `master` (and the `v0.1.1` tag on its tip) — the source.
3538
3589
  2. A `Dockerfile` pinning `gfortran`, `python 3.9`, `numpy<2` — the environment
3539
3590
  that can still build `mtspec`. Also the only place existing `.spec` pickles
3540
3591
  can be read (§4.6).
@@ -3565,13 +3616,13 @@ Each phase ends green on CI and is independently mergeable.
3565
3616
 
3566
3617
  | Phase | Work | Depends on | Rough size |
3567
3618
  |---|---|---|---|
3568
- | **0. Safety net** | Freeze `master`, default branch → `main`, optional `v0.1.0` tag (§6.7); reproducible legacy env (`Dockerfile`: gfortran + ObsPy 1.2.0 / SciPy 1.4.1 / NumPy 1.18 / pandas 1.0.0 (§5.2.6)); write `datasets/magna_2020.toml` and a first cut of `specmod.acquire`, publish the artifact as a `data-v1` release asset (§5.2); capture golden outputs for PNR **and** Magna; reproduce Table S2 / Figure 2 with 0.1.1 (§5.2.6 step 2); convert any `.spec` files (§4.6) | — | 1.5–2 days |
3619
+ | **0. Safety net** | Freeze `master`, default branch → `main`, optional `v0.1.1` tag (§6.7); reproducible legacy env (`Dockerfile`: gfortran + ObsPy 1.2.0 / SciPy 1.4.1 / NumPy 1.18 / pandas 1.0.0 (§5.2.6)); write `datasets/magna_2020.toml` and a first cut of `specmod.acquire`, publish the artifact as a `data-v1` release asset (§5.2); capture golden outputs for PNR **and** Magna; reproduce Table S2 / Figure 2 with 0.1.1 (§5.2.6 step 2); convert any `.spec` files (§4.6) | — | 1.5–2 days |
3569
3620
  | **1. Make it installable** | `pyproject.toml` + hatch-vcs, `src/` layout, `__init__.py`; ruff config, one-shot `ruff format` + `.git-blame-ignore-revs`, module renames to snake_case; mypy skeleton; pre-commit; `test`/`build` CI; `.gitignore`, `CITATION.cff`; fix the three hard breakages (§1) and the four `F821` bugs ruff finds (§2.5); delete `Tests/Tutorial/`, strip notebook outputs, subset the inventory (§5.1) | 0 | 3–4 days |
3570
3621
  | **2. De-globalise** | `config/` package per §4.8 — semantic groups, layer resolution, `config show`/`freeze`, provenance stamping; remove all module-level config reads (tracked by `PLW0603`); `Motion`/`AmplitudeKind` enums; `Spectrum` as a frozen dataclass with `duration`; mutable class attrs (`RUF012`); `isinstance` checks; `logging`. **Tag `v0.2.0`** | 1 | 3–4 days |
3571
3622
  | **2b. Release plumbing** ✅ | ~~Sphinx skeleton + `pydata-sphinx-theme` + autodoc/napoleon/intersphinx~~ ✅; ~~`docs.yml` → a published site~~ ✅ — Read the Docs rather than GH Pages, for versions (§6.3); ~~release-please + PyPI Trusted Publishing~~ ✅ — one `release.yml`, not two workflows (§6.5); ~~Zenodo webhook~~ ✅ documented. Five repository settings have to be turned on by hand: `docs/releasing.md` lists them. The `ci/` mirror that staged workflow files for hand-copying is gone — it existed because an agent token could not push `.github/workflows/`, and that permission is now granted. Parallel with 2 | 1 | 1–2 days |
3572
3623
  | **3. Transform layer** | `SpectralEstimator` protocol; `FFTEstimator`, `WelchEstimator`, `MultitaperEstimator`; `smoothing/` incl. Konno–Ohmachi and `LogBinner`; mtspec demoted to optional legacy backend; Tier 1 + Tier 2 tests; theory docs page | 2 | 5–7 days |
3573
3624
  | **4. CWT** | `CWTEstimator` + `Scalogram`; COI handling; the Parseval/units calibration and its test; `time_average()`; `ScalogramQC` + the four QC checks; COI floor into `BandwidthSelector`; scalogram plotting; HDF5 scalogram storage | 3 | 6–8 days |
3574
- | **5. Decompose** | Split `Spectral.py` (655 lines) into `core/` + `snr/` ✅; ~~`Fitting.py` → `fitting/`~~ ✅ — `base`/`guess`/`spectrum`/`event`, 745 lines to four modules of 30–300, public names unchanged; models as objects ✅; `io/`; `viz/`; non-mutating operations; mypy override list → empty ✅; `picks/` per §4.9 ✅ | 3 | 4–6 days |
3625
+ | **5. Decompose** ✅ | Split `Spectral.py` (655 lines) into `core/` + `snr/` ✅; ~~`Fitting.py` → `fitting/`~~ ✅ — `base`/`guess`/`spectrum`/`event`, 745 lines to four modules of 30–300, public names unchanged; models as objects ✅; ~~`io/`~~ ✅ — `layout`/`hdf5`/`backend`; ~~`viz/`~~ ✅ — shipped as `plotting/`, `pair`/`grid`/`style`; ~~non-mutating operations~~ ✅ — `preprocess` was the last holdout, and the ten functions were renamed rather than only re-signatured so the break is loud; mypy override list → empty ✅; `picks/` per §4.9 ✅ | 3 | 4–6 days |
3575
3626
  | **6. Ship** | Full docs content, tutorial rewritten as an executed `myst-nb` page with no `os.chdir`, 0.1→1.0 "what changed" page, **1.0 release** | 4, 5 | 2–3 days |
3576
3627
 
3577
3628
  **Executing the tutorial was pulled forward out of Phase 6.** The `myst-nb`
@@ -3658,20 +3709,48 @@ changes anything shipped.
3658
3709
  ### Still open
3659
3710
 
3660
3711
  1. **Default estimator.** Multitaper (matching current behaviour) or FFT +
3661
- Konno–Ohmachi (faster, more conventional in engineering seismology)?
3712
+ Konno–Ohmachi (more conventional in engineering seismology)? **No longer
3713
+ blocked** — §6.6's dead `[smoothing] method` is wired up, so the second
3714
+ option is selectable — and now measured, on the 28 PNR windows with each
3715
+ station fitted freely:
3716
+
3717
+ | Against the shipped multitaper + `log_bins` | Median ΔMw | Per-station range | `fc` ratio |
3718
+ |---|---|---|---|
3719
+ | `fft` + `log_bins` | −0.039 | −0.85 to +1.90 | 0.003 to 5.0 |
3720
+ | `fft` + `konno_ohmachi` | +0.027 | −0.52 to +0.51 | 0.038 to 3.2 |
3721
+
3722
+ **The smoothing is what makes the switch defensible, not the estimator.**
3723
+ FFT with the shipped binner moves a station by up to 1.9 magnitude units,
3724
+ because `log_bins` reduces the axis without reducing the variance — 151 log
3725
+ bins over a few hundred Fourier samples is roughly one sample per bin.
3726
+ Pairing it with a real smoother halves the worst excursion and pulls the
3727
+ `fc` range in by a third. The median station barely moves either way.
3728
+
3729
+ What this event cannot settle: the *event* corner is unconstrained under all
3730
+ three (stage-one spread 895% to 1042% of the event value), so the ensemble
3731
+ number is not evidence. Deciding on the ensemble needs an event where it is
3732
+ constrained.
3733
+
3734
+ Speed, measured rather than assumed and far too small to decide on: the
3735
+ transform is 0.209 s against 0.323 s for the 28 windows, and the smoothing
3736
+ adds 0.14 s (`log_bins`) to 0.83 s (`konno_ohmachi`) on top.
3737
+
3662
3738
  2. **Python floor.** 3.11 is proposed. Any users stuck on 3.9/3.10?
3663
3739
  3. **History rewrite.** Deleting the 9.9 MB catalog and stripping the notebook
3664
3740
  (§5.1) shrinks the *working tree* but leaves both in history, so a fresh clone
3665
3741
  still pulls ~15 MiB. Rewriting history with `git-filter-repo` would recover it
3666
3742
  — but it rewrites every SHA, which moves what `master` and `main` currently
3667
- point at and invalidates any `v0.1.0` tag. Given the end state is a ~1 MB repo
3743
+ point at and invalidates any `v0.1.1` tag. Given the end state is a ~1 MB repo
3668
3744
  either way, **the recommendation is to leave history alone**: a one-time 15 MiB
3669
3745
  clone is a much smaller cost than an unrecoverable pre-refactor record. Only
3670
3746
  worth revisiting if the history genuinely becomes a burden.
3671
- 4. **Which commit is "v0.1.1"?** The paper cites SpecMod v0.1.1; no such tag
3672
- exists and the source carries no version string (§5.2.5). Reproducing the
3673
- published run needs that commit identified — by submission date against the
3674
- history, if nothing better is available. Only you can make that call.
3747
+ 4. ~~**Which commit is "v0.1.1"?**~~ **Resolved: `453c77c`**, the tip of
3748
+ `master`, 2021-08-12 — which is what freezing `master` at that commit was
3749
+ for (§6.7). The archaeology in §5.2.5 narrowed it to two candidates and
3750
+ could not choose between them; the answer did not come from the repository
3751
+ and was never going to. §5.2.6 step 2 now has a known commit to run. No
3752
+ `v0.1.1` tag exists yet, and creating one is repository state rather than
3753
+ something a commit can carry.
3675
3754
  5. ~~**Was noise rotation on for the published run?**~~ **Assumed on.** Not
3676
3755
  recalled, so `studies/magna_2020_paper.toml` starts from the shipped values —
3677
3756
  `ROTATE_NOISE = true`, `ROT_METHOD = 2`, `ROT_PARS = {inc = 0.05, space =