specmod 0.2.1__tar.gz → 0.2.3__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 (218) hide show
  1. {specmod-0.2.1 → specmod-0.2.3}/.github/workflows/docs.yml +6 -1
  2. {specmod-0.2.1 → specmod-0.2.3}/.gitignore +11 -3
  3. {specmod-0.2.1 → specmod-0.2.3}/.readthedocs.yaml +7 -1
  4. specmod-0.2.3/.release-please-manifest.json +3 -0
  5. {specmod-0.2.1 → specmod-0.2.3}/CHANGELOG.md +29 -0
  6. {specmod-0.2.1 → specmod-0.2.3}/CITATION.cff +1 -1
  7. {specmod-0.2.1 → specmod-0.2.3}/PKG-INFO +4 -3
  8. {specmod-0.2.1 → specmod-0.2.3}/README.md +2 -2
  9. {specmod-0.2.1 → specmod-0.2.3}/docs/choosing-a-transform.md +2 -5
  10. specmod-0.2.3/docs/conf.py +190 -0
  11. specmod-0.2.3/docs/contributing.md +31 -0
  12. {specmod-0.2.1 → specmod-0.2.3}/docs/development.md +9 -6
  13. {specmod-0.2.1 → specmod-0.2.3}/docs/documentation.md +59 -9
  14. specmod-0.2.3/docs/getting-started.md +41 -0
  15. specmod-0.2.3/docs/guides.md +55 -0
  16. {specmod-0.2.1 → specmod-0.2.3}/docs/index.md +23 -44
  17. {specmod-0.2.1 → specmod-0.2.3}/docs/processing.md +155 -28
  18. {specmod-0.2.1 → specmod-0.2.3}/docs/releasing-data.md +10 -9
  19. {specmod-0.2.1 → specmod-0.2.3}/docs/releasing.md +32 -16
  20. {specmod-0.2.1 → specmod-0.2.3}/docs/roadmap.md +38 -13
  21. specmod-0.2.3/docs/upgrading.md +151 -0
  22. {specmod-0.2.1 → specmod-0.2.3}/pyproject.toml +4 -0
  23. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/collection.py +10 -6
  24. specmod-0.2.3/tutorial/SpecModTutorial.ipynb +1032 -0
  25. specmod-0.2.1/.release-please-manifest.json +0 -3
  26. specmod-0.2.1/docs/conf.py +0 -110
  27. specmod-0.2.1/tutorial/SpecModTutorial.ipynb +0 -2000
  28. specmod-0.2.1/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/2019-08-26T07:30:47.000000Z.h5 +0 -0
  29. specmod-0.2.1/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/flatfiles/2019-08-26T07:30:47.000000Z.csv +0 -29
  30. specmod-0.2.1/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/flatfiles/2019-08-26T07:30:47.000000Z.parquet +0 -0
  31. {specmod-0.2.1 → specmod-0.2.3}/.git-blame-ignore-revs +0 -0
  32. {specmod-0.2.1 → specmod-0.2.3}/.github/workflows/build.yml +0 -0
  33. {specmod-0.2.1 → specmod-0.2.3}/.github/workflows/release.yml +0 -0
  34. {specmod-0.2.1 → specmod-0.2.3}/.github/workflows/test.yml +0 -0
  35. {specmod-0.2.1 → specmod-0.2.3}/.pre-commit-config.yaml +0 -0
  36. {specmod-0.2.1 → specmod-0.2.3}/AGENTS.md +0 -0
  37. {specmod-0.2.1 → specmod-0.2.3}/CLAUDE.md +0 -0
  38. {specmod-0.2.1 → specmod-0.2.3}/CONTRIBUTING.md +0 -0
  39. {specmod-0.2.1 → specmod-0.2.3}/LICENSE +0 -0
  40. {specmod-0.2.1 → specmod-0.2.3}/datasets/magna_2020.toml +0 -0
  41. {specmod-0.2.1 → specmod-0.2.3}/datasets/pnr_2019.toml +0 -0
  42. {specmod-0.2.1 → specmod-0.2.3}/docs/REFACTOR_PLAN.md +0 -0
  43. {specmod-0.2.1 → specmod-0.2.3}/docs/api.md +0 -0
  44. {specmod-0.2.1 → specmod-0.2.3}/docs/notebooks/_build_notebook.py +0 -0
  45. {specmod-0.2.1 → specmod-0.2.3}/docs/notebooks/choosing-a-transform.ipynb +0 -0
  46. {specmod-0.2.1 → specmod-0.2.3}/docs/notes/api-audit.md +0 -0
  47. {specmod-0.2.1 → specmod-0.2.3}/docs/notes/window-position.md +0 -0
  48. {specmod-0.2.1 → specmod-0.2.3}/docs/pick-formats.md +0 -0
  49. {specmod-0.2.1 → specmod-0.2.3}/release-please-config.json +0 -0
  50. {specmod-0.2.1 → specmod-0.2.3}/requirements.txt +0 -0
  51. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/__init__.py +0 -0
  52. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/_vendor/__init__.py +0 -0
  53. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/_vendor/qiinv.py +0 -0
  54. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/acquire.py +0 -0
  55. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/api.py +0 -0
  56. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/cli.py +0 -0
  57. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/config/__init__.py +0 -0
  58. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/config/layers.py +0 -0
  59. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/config/provenance.py +0 -0
  60. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/config/sections.py +0 -0
  61. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/config/serialize.py +0 -0
  62. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/__init__.py +0 -0
  63. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/bandwidth.py +0 -0
  64. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/noise.py +0 -0
  65. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/scalogram.py +0 -0
  66. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/spectrum.py +0 -0
  67. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/core/units.py +0 -0
  68. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/datasets.py +0 -0
  69. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/distance.py +0 -0
  70. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/exceptions.py +0 -0
  71. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/fitting/__init__.py +0 -0
  72. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/fitting/base.py +0 -0
  73. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/fitting/event.py +0 -0
  74. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/fitting/guess.py +0 -0
  75. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/fitting/spectrum.py +0 -0
  76. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/io.py +0 -0
  77. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/magnitude.py +0 -0
  78. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/picks/__init__.py +0 -0
  79. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/picks/base.py +0 -0
  80. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/picks/delimited.py +0 -0
  81. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/picks/events.py +0 -0
  82. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/picks/resolution.py +0 -0
  83. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/picks/snuffler.py +0 -0
  84. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/pipeline.py +0 -0
  85. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/plotting.py +0 -0
  86. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/preprocess.py +0 -0
  87. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/smoothing/__init__.py +0 -0
  88. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/smoothing/base.py +0 -0
  89. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/smoothing/konno_ohmachi.py +0 -0
  90. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/smoothing/log_bins.py +0 -0
  91. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/sources/__init__.py +0 -0
  92. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/sources/attenuation.py +0 -0
  93. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/sources/composite.py +0 -0
  94. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/sources/motion.py +0 -0
  95. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/sources/source.py +0 -0
  96. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/spreading.py +0 -0
  97. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/staged.py +0 -0
  98. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/tables.py +0 -0
  99. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/__init__.py +0 -0
  100. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/base.py +0 -0
  101. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/cwt.py +0 -0
  102. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/fft.py +0 -0
  103. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/multitaper.py +0 -0
  104. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/prieto.py +0 -0
  105. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/transforms/quadratic.py +0 -0
  106. {specmod-0.2.1 → specmod-0.2.3}/src/specmod/utils.py +0 -0
  107. {specmod-0.2.1 → specmod-0.2.3}/stubs/README.md +0 -0
  108. {specmod-0.2.1 → specmod-0.2.3}/stubs/lmfit/__init__.pyi +0 -0
  109. {specmod-0.2.1 → specmod-0.2.3}/stubs/lmfit/model.pyi +0 -0
  110. {specmod-0.2.1 → specmod-0.2.3}/stubs/lmfit/parameter.pyi +0 -0
  111. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/__init__.pyi +0 -0
  112. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/clients/__init__.pyi +0 -0
  113. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/clients/fdsn/__init__.pyi +0 -0
  114. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/__init__.pyi +0 -0
  115. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/event.pyi +0 -0
  116. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/inventory.pyi +0 -0
  117. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/stream.pyi +0 -0
  118. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/trace.pyi +0 -0
  119. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/utcdatetime.pyi +0 -0
  120. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/util/__init__.pyi +0 -0
  121. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/core/util/base.pyi +0 -0
  122. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/geodetics/__init__.pyi +0 -0
  123. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/signal/__init__.pyi +0 -0
  124. {specmod-0.2.1 → specmod-0.2.3}/stubs/obspy/signal/konnoohmachismoothing.pyi +0 -0
  125. {specmod-0.2.1 → specmod-0.2.3}/studies/magna_2020_paper.toml +0 -0
  126. {specmod-0.2.1 → specmod-0.2.3}/tests/__init__.py +0 -0
  127. {specmod-0.2.1 → specmod-0.2.3}/tests/conftest.py +0 -0
  128. {specmod-0.2.1 → specmod-0.2.3}/tests/golden/motion_reference.json +0 -0
  129. {specmod-0.2.1 → specmod-0.2.3}/tests/golden/pipeline_reference.json +0 -0
  130. {specmod-0.2.1 → specmod-0.2.3}/tests/golden/window_reference.json +0 -0
  131. {specmod-0.2.1 → specmod-0.2.3}/tests/test_acquire.py +0 -0
  132. {specmod-0.2.1 → specmod-0.2.3}/tests/test_ambient_state.py +0 -0
  133. {specmod-0.2.1 → specmod-0.2.3}/tests/test_api_surface.py +0 -0
  134. {specmod-0.2.1 → specmod-0.2.3}/tests/test_collection.py +0 -0
  135. {specmod-0.2.1 → specmod-0.2.3}/tests/test_config.py +0 -0
  136. {specmod-0.2.1 → specmod-0.2.3}/tests/test_cwt.py +0 -0
  137. {specmod-0.2.1 → specmod-0.2.3}/tests/test_datasets.py +0 -0
  138. {specmod-0.2.1 → specmod-0.2.3}/tests/test_docs_are_current.py +0 -0
  139. {specmod-0.2.1 → specmod-0.2.3}/tests/test_end_to_end.py +0 -0
  140. {specmod-0.2.1 → specmod-0.2.3}/tests/test_fitting_defaults.py +0 -0
  141. {specmod-0.2.1 → specmod-0.2.3}/tests/test_golden_reference.py +0 -0
  142. {specmod-0.2.1 → specmod-0.2.3}/tests/test_import.py +0 -0
  143. {specmod-0.2.1 → specmod-0.2.3}/tests/test_io_and_plotting.py +0 -0
  144. {specmod-0.2.1 → specmod-0.2.3}/tests/test_legacy_fixes.py +0 -0
  145. {specmod-0.2.1 → specmod-0.2.3}/tests/test_magnitude.py +0 -0
  146. {specmod-0.2.1 → specmod-0.2.3}/tests/test_make_golden.py +0 -0
  147. {specmod-0.2.1 → specmod-0.2.3}/tests/test_pick_plugins.py +0 -0
  148. {specmod-0.2.1 → specmod-0.2.3}/tests/test_pick_readers.py +0 -0
  149. {specmod-0.2.1 → specmod-0.2.3}/tests/test_picks.py +0 -0
  150. {specmod-0.2.1 → specmod-0.2.3}/tests/test_pipeline.py +0 -0
  151. {specmod-0.2.1 → specmod-0.2.3}/tests/test_pipeline_smoke.py +0 -0
  152. {specmod-0.2.1 → specmod-0.2.3}/tests/test_preprocess.py +0 -0
  153. {specmod-0.2.1 → specmod-0.2.3}/tests/test_prieto.py +0 -0
  154. {specmod-0.2.1 → specmod-0.2.3}/tests/test_quadratic.py +0 -0
  155. {specmod-0.2.1 → specmod-0.2.3}/tests/test_release_config.py +0 -0
  156. {specmod-0.2.1 → specmod-0.2.3}/tests/test_smoothing.py +0 -0
  157. {specmod-0.2.1 → specmod-0.2.3}/tests/test_sources.py +0 -0
  158. {specmod-0.2.1 → specmod-0.2.3}/tests/test_spectral_wiring.py +0 -0
  159. {specmod-0.2.1 → specmod-0.2.3}/tests/test_staged.py +0 -0
  160. {specmod-0.2.1 → specmod-0.2.3}/tests/test_stubs.py +0 -0
  161. {specmod-0.2.1 → specmod-0.2.3}/tests/test_transforms.py +0 -0
  162. {specmod-0.2.1 → specmod-0.2.3}/tests/test_tutorial.py +0 -0
  163. {specmod-0.2.1 → specmod-0.2.3}/tests/test_typing_backlog.py +0 -0
  164. {specmod-0.2.1 → specmod-0.2.3}/tests/test_utils.py +0 -0
  165. {specmod-0.2.1 → specmod-0.2.3}/tests/test_versioning.py +0 -0
  166. {specmod-0.2.1 → specmod-0.2.3}/tools/check_built_version.py +0 -0
  167. {specmod-0.2.1 → specmod-0.2.3}/tools/check_floors.py +0 -0
  168. {specmod-0.2.1 → specmod-0.2.3}/tools/make_golden.py +0 -0
  169. {specmod-0.2.1 → specmod-0.2.3}/tools/measure_docs.py +0 -0
  170. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.picks +0 -0
  171. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.xml +0 -0
  172. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/stations/inventory.xml +0 -0
  173. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHE_2019-08-26T07:30:47.000000Z +0 -0
  174. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHN_2019-08-26T07:30:47.000000Z +0 -0
  175. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  176. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHE_2019-08-26T07:30:47.000000Z +0 -0
  177. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHN_2019-08-26T07:30:47.000000Z +0 -0
  178. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  179. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHE_2019-08-26T07:30:47.000000Z +0 -0
  180. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHN_2019-08-26T07:30:47.000000Z +0 -0
  181. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  182. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHE_2019-08-26T07:30:47.000000Z +0 -0
  183. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHN_2019-08-26T07:30:47.000000Z +0 -0
  184. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  185. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHE_2019-08-26T07:30:47.000000Z +0 -0
  186. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHN_2019-08-26T07:30:47.000000Z +0 -0
  187. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  188. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHE_2019-08-26T07:30:47.000000Z +0 -0
  189. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHN_2019-08-26T07:30:47.000000Z +0 -0
  190. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  191. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH1_2019-08-26T07:30:47.000000Z +0 -0
  192. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH2_2019-08-26T07:30:47.000000Z +0 -0
  193. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH3_2019-08-26T07:30:47.000000Z +0 -0
  194. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  195. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  196. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  197. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ02.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  198. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  199. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  200. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  201. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  202. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  203. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  204. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  205. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  206. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  207. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  208. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  209. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  210. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  211. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  212. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  213. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  214. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  215. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  216. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  217. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  218. {specmod-0.2.1 → specmod-0.2.3}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
@@ -33,7 +33,12 @@ jobs:
33
33
 
34
34
  # The package itself, not just the docs extra: autodoc imports every
35
35
  # module it documents, so a docs build is also an import check.
36
- - run: uv pip install -e ".[docs,io]"
36
+ #
37
+ # `tutorial` supplies the Jupyter kernel. `docs/conf.py` executes the
38
+ # tutorial notebook on every build instead of trusting committed outputs,
39
+ # so without ipykernel the build fails on a missing kernel. Keep this list
40
+ # in step with `.readthedocs.yaml`, which installs the same three.
41
+ - run: uv pip install -e ".[docs,io,tutorial]"
37
42
 
38
43
  - name: Build
39
44
  # No -W. Intersphinx resolves seven inventories over the network and
@@ -26,6 +26,11 @@ htmlcov/
26
26
 
27
27
  # Docs
28
28
  docs/_build/
29
+ # `docs/conf.py` copies `tutorial/` here so Sphinx can build the notebook from
30
+ # inside its source directory, with the data it reads by relative path. The
31
+ # copy is also what the notebook's own output lands in, which is the point —
32
+ # executing it where it lives would write into the working tree.
33
+ docs/tutorial/
29
34
 
30
35
  # Editors / OS
31
36
  .ftpconfig
@@ -39,9 +44,12 @@ docs/_build/
39
44
 
40
45
  # Tutorial output. Regenerated by running the notebook; committing it means a
41
46
  # diff every time anyone executes it, and a stale copy the moment the pipeline
42
- # changes. The inputs (Tutorial/Data, Tutorial/MetaData) *are* committed.
43
- Tutorial/Spectra/*.h5
44
- Tutorial/Spectra/FlatFiles/
47
+ # changes. The inputs — waveforms, stations, picks — *are* committed.
48
+ #
49
+ # These patterns named `Tutorial/Spectra/` until now, the capitalised layout
50
+ # from before the `src/` move, so they had matched nothing for the whole
51
+ # refactor and the three files below were tracked in spite of the rule above.
52
+ tutorial/data/events/*/spectra/
45
53
 
46
54
  # Created by `uv run` without --no-sync; this project resolves fresh on
47
55
  # purpose so the floors job can test the declared minimums.
@@ -42,6 +42,12 @@ python:
42
42
  extra_requirements:
43
43
  # `io` alongside `docs` because autodoc imports every module it
44
44
  # documents, and `specmod.io` imports h5py and pyarrow. Without it the
45
- # API reference loses those pages to import errors.
45
+ # API reference loses those pages to import errors — and the tutorial
46
+ # saves an HDF5 file, so it needs them at execution time too.
46
47
  - docs
47
48
  - io
49
+ # `tutorial` supplies the Jupyter kernel. `docs/conf.py` executes the
50
+ # notebook on every build rather than trusting committed outputs, which
51
+ # needs ipykernel, nbclient and nbformat present. Without it the build
52
+ # fails on a missing kernel rather than quietly publishing stale cells.
53
+ - tutorial
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.3"
3
+ }
@@ -9,6 +9,35 @@ 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.2.3](https://github.com/sgjholt/SpecMod/compare/v0.2.2...v0.2.3) (2026-09-05)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * correct four documented equations and behaviours that the code contradicts ([821792b](https://github.com/sgjholt/SpecMod/commit/821792b66d418b9c0048d717975b5a3716c52c20))
18
+ * point the DOI badge at the concept DOI, not v0.2.0's ([11e7f7a](https://github.com/sgjholt/SpecMod/commit/11e7f7a056fc17c91b22c1dc9d834f19b8b6dbe3))
19
+
20
+
21
+ ### Documentation
22
+
23
+ * an upgrade guide, and a table of contents with a shape ([4f35388](https://github.com/sgjholt/SpecMod/commit/4f353885cfd0768edeac225d7db4672a20c9120e))
24
+ * derive the roadmap's version, and say when its entries move ([1917d43](https://github.com/sgjholt/SpecMod/commit/1917d432c6fdae1969dacb506bdac986152e40d8))
25
+ * document moment and magnitude, which the page said were absent ([026abec](https://github.com/sgjholt/SpecMod/commit/026abecb9c6ed33017b306e825a6f84db2b343e4))
26
+ * state what is true now, not what the page used to say ([b17339b](https://github.com/sgjholt/SpecMod/commit/b17339b6ad383afd936f7f2a972549b313e19906))
27
+ * the documentation 1.0 was waiting on is done ([9693334](https://github.com/sgjholt/SpecMod/commit/9693334434738ae000bf61f1908524ee983ced17))
28
+
29
+ ## [0.2.2](https://github.com/sgjholt/SpecMod/compare/v0.2.1...v0.2.2) (2026-09-05)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * ignore the tutorial output at the path it is actually written to ([ad34cc7](https://github.com/sgjholt/SpecMod/commit/ad34cc7d44208e5bd49a2d1f1277516670848dc7))
35
+
36
+
37
+ ### Documentation
38
+
39
+ * publish the tutorial, executed on every build ([ccd1842](https://github.com/sgjholt/SpecMod/commit/ccd18429b9da5db875885d88269fb70686e6eaa3))
40
+
12
41
  ## [0.2.1](https://github.com/sgjholt/SpecMod/compare/v0.2.0...v0.2.1) (2026-08-23)
13
42
 
14
43
 
@@ -12,7 +12,7 @@ identifiers:
12
12
  # mints a version DOI per release; cite that one instead when reproducibility
13
13
  # matters and you need the reader to land on the exact version you ran.
14
14
  - type: doi
15
- value: "10.5281/zenodo.22071455"
15
+ value: "10.5281/zenodo.22071454"
16
16
  description: "Concept DOI — resolves to the latest release."
17
17
  keywords:
18
18
  - seismology
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: specmod
3
- Version: 0.2.1
3
+ Version: 0.2.3
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
@@ -38,6 +38,7 @@ Provides-Extra: docs
38
38
  Requires-Dist: myst-nb>=1.1; extra == 'docs'
39
39
  Requires-Dist: myst-parser>=3.0; extra == 'docs'
40
40
  Requires-Dist: pydata-sphinx-theme>=0.15; extra == 'docs'
41
+ Requires-Dist: sphinx-togglebutton>=0.3; extra == 'docs'
41
42
  Requires-Dist: sphinx>=7.3; extra == 'docs'
42
43
  Provides-Extra: io
43
44
  Requires-Dist: h5py>=3.11; extra == 'io'
@@ -58,7 +59,7 @@ Description-Content-Type: text/markdown
58
59
 
59
60
  [![PyPI](https://img.shields.io/pypi/v/specmod.svg)](https://pypi.org/project/specmod/)
60
61
  [![Documentation](https://readthedocs.org/projects/specmod/badge/?version=stable)](https://specmod.readthedocs.io/en/stable/)
61
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22071455.svg)](https://doi.org/10.5281/zenodo.22071455)
62
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22071454.svg)](https://doi.org/10.5281/zenodo.22071454)
62
63
 
63
64
  A Python toolbox for processing and modelling seismic spectra, following the
64
65
  method of Edwards *et al.* (2010).
@@ -237,7 +238,7 @@ The full documentation — the pipeline with its equations, the estimator
237
238
  comparison, pick formats, and an API reference — builds with Sphinx:
238
239
 
239
240
  ```bash
240
- uv pip install -e '.[docs]'
241
+ uv pip install -e '.[docs,io,tutorial]'
241
242
  sphinx-build -b html docs docs/_build/html
242
243
  ```
243
244
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![PyPI](https://img.shields.io/pypi/v/specmod.svg)](https://pypi.org/project/specmod/)
4
4
  [![Documentation](https://readthedocs.org/projects/specmod/badge/?version=stable)](https://specmod.readthedocs.io/en/stable/)
5
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22071455.svg)](https://doi.org/10.5281/zenodo.22071455)
5
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22071454.svg)](https://doi.org/10.5281/zenodo.22071454)
6
6
 
7
7
  A Python toolbox for processing and modelling seismic spectra, following the
8
8
  method of Edwards *et al.* (2010).
@@ -181,7 +181,7 @@ The full documentation — the pipeline with its equations, the estimator
181
181
  comparison, pick formats, and an API reference — builds with Sphinx:
182
182
 
183
183
  ```bash
184
- uv pip install -e '.[docs]'
184
+ uv pip install -e '.[docs,io,tutorial]'
185
185
  sphinx-build -b html docs docs/_build/html
186
186
  ```
187
187
 
@@ -253,11 +253,8 @@ or **0.03 magnitude units**. Against the 0.13 m.u. scatter quoted for spectral
253
253
  `Mw` that is small, but it is systematic rather than random, so it does not
254
254
  average away across stations at similar distance.
255
255
 
256
- > Earlier revisions of this page reported 89% for flat weighting and 650% for
257
- > adaptive here. The 650% was the adaptive collapse described above and is
258
- > gone. The remaining figures come from a differently-constructed sweep than
259
- > the original and are not directly comparable to it; this table is the one
260
- > `tools/measure_docs.py` reproduces.
256
+ > Every figure in this table is regenerated by `tools/measure_docs.py`, and
257
+ > `tests/test_docs_are_current.py` fails if the page and the code disagree.
261
258
 
262
259
  ### It costs you a diagnostic
263
260
 
@@ -0,0 +1,190 @@
1
+ """Sphinx configuration for the SpecMod documentation.
2
+
3
+ Build with::
4
+
5
+ uv pip install -e '.[docs,io,tutorial]'
6
+ sphinx-build -b html docs docs/_build/html
7
+
8
+ ``-W`` is deliberately **not** used. Intersphinx resolves seven inventories
9
+ over the network, and a warning is emitted whenever one of them is briefly
10
+ unreachable — turning a third party's downtime into a red build. The docs job
11
+ fails on a non-zero exit instead, which is what a genuinely broken build
12
+ gives.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import shutil
18
+ from importlib.metadata import PackageNotFoundError, version
19
+ from pathlib import Path
20
+
21
+ project = "SpecMod"
22
+ author = "James Holt"
23
+ #: Sphinx substitutes `%Y` with the build year, so this does not need editing
24
+ #: — and it honours `SOURCE_DATE_EPOCH`, so a reproducible build stamps the
25
+ #: source date rather than the day it happened to run. 2020 is the year in
26
+ #: `LICENSE` and the year the history starts.
27
+ copyright = "2020-%Y, James Holt"
28
+
29
+ try:
30
+ release = version("specmod")
31
+ except PackageNotFoundError: # pragma: no cover - docs built without an install
32
+ release = "0.0.0"
33
+ #: The short X.Y form, which is what the sidebar shows.
34
+ version = ".".join(release.split(".")[:2])
35
+
36
+ extensions = [
37
+ #: `myst_nb` supersedes `myst_parser` — it is a superset, and loading both
38
+ #: makes Sphinx complain that the `.md` parser is registered twice.
39
+ "myst_nb",
40
+ "sphinx.ext.autodoc",
41
+ "sphinx.ext.napoleon",
42
+ "sphinx.ext.intersphinx",
43
+ "sphinx.ext.viewcode",
44
+ #: Makes `:class: dropdown` collapse an admonition. The alpha warning on the
45
+ #: landing page is the reason: it has to be read once and then stops earning
46
+ #: the screen it occupies, and a caveat nobody scrolls past is worse than
47
+ #: one folded behind its own headline.
48
+ "sphinx_togglebutton",
49
+ ]
50
+ #: `sphinx_autodoc_typehints` is deliberately not used. `autodoc_typehints`
51
+ #: below is built into `sphinx.ext.autodoc` and does the same job here, and the
52
+ #: extension calls an API Sphinx 10 removes — it emits a deprecation warning
53
+ #: per module on Sphinx 9. One less dependency for no loss.
54
+
55
+ #: `REFACTOR_PLAN.md` is a working document, not documentation — it is written
56
+ #: for whoever is doing the refactor and records decisions and their evidence.
57
+ #: `notebooks/` holds the source for the transform comparison, which
58
+ #: `tools/measure_docs.py` renders into `choosing-a-transform.md`; the page is
59
+ #: what is published, so building the notebook too would duplicate it.
60
+ #: `notes/` *is* included: `choosing-a-transform.md` links to it for a
61
+ #: per-trace table, so excluding it broke that link.
62
+ exclude_patterns = [
63
+ "_build",
64
+ "REFACTOR_PLAN.md",
65
+ "notebooks/*",
66
+ "Thumbs.db",
67
+ ".DS_Store",
68
+ ]
69
+
70
+ # ------------------------------------------------------- the tutorial notebook
71
+
72
+ #: The tutorial lives in `tutorial/`, outside this source directory, next to the
73
+ #: 1 MB of PNR waveforms it reads through paths relative to itself. Sphinx only
74
+ #: builds what is under `docs/`, so it is copied in here.
75
+ #:
76
+ #: A copy rather than a move, and rather than executing it where it sits,
77
+ #: because **the notebook writes**: cell 53 saves an HDF5 file under
78
+ #: `data/events/<event>/spectra/` and cell 54 writes flatfiles beside it. Run in
79
+ #: place, a docs build would leave those artefacts in the working tree — which
80
+ #: is why `tests/test_tutorial.py` executes it in a `tmp_path` copy too. This is
81
+ #: the same trick, and the copy is what the artefacts land in.
82
+ #:
83
+ #: Copying the data with it is what keeps the notebook's `Path("data/events")`
84
+ #: working, so the notebook is identical whether opened from `tutorial/`, run by
85
+ #: pytest, or built here. `tutorial/` stays canonical: eight other files name
86
+ #: `tutorial/data/events/`, and the CI job that executes it records that a
87
+ #: renamed data directory has already broken this once.
88
+ _HERE = Path(__file__).parent
89
+ _TUTORIAL_SRC = _HERE.parent / "tutorial"
90
+ _TUTORIAL_DST = _HERE / "tutorial"
91
+
92
+ if _TUTORIAL_SRC.is_dir():
93
+ shutil.rmtree(_TUTORIAL_DST, ignore_errors=True)
94
+ shutil.copytree(_TUTORIAL_SRC, _TUTORIAL_DST)
95
+
96
+ #: `force`, not `auto`. The `nbstripout` hook means the notebook arrives with no
97
+ #: outputs, so `auto` would execute it today and quietly stop the moment anyone
98
+ #: committed a notebook with outputs saved — publishing whatever was last run by
99
+ #: hand. Forcing it means the page can only ever show output the code produced
100
+ #: against the code being documented, whatever is in the file.
101
+ nb_execution_mode = "force"
102
+ #: Matches `tests/test_tutorial.py`. The whole notebook runs in ~40s; the
103
+ #: default 30s is per cell, and the two-stage fit is the one that would trip it.
104
+ nb_execution_timeout = 600
105
+ #: A notebook that raises fails the build. That is the point: an executed
106
+ #: tutorial is only a guarantee if a broken one is loud.
107
+ nb_execution_raise_on_error = True
108
+ #: `False` keeps the kernel's working directory at the notebook's own, which is
109
+ #: what `Path("data/events")` resolves against.
110
+ nb_execution_in_temp = False
111
+
112
+ #: Markdown for the prose pages — every one in `docs/` is written that way, and
113
+ #: allowing reStructuredText too would mean two syntaxes for the same job — plus
114
+ #: `.ipynb` for the tutorial.
115
+ #:
116
+ #: Both map to `myst-nb`, which is the only parser name `myst_nb` 1.4 registers:
117
+ #: it does not re-register `myst_parser`'s `markdown`, so leaving `.md` pointing
118
+ #: at that fails the build outright with "Source parser for markdown not
119
+ #: registered". The `myst-nb` parser is a superset and reads the prose pages
120
+ #: identically.
121
+ source_suffix = {".md": "myst-nb", ".ipynb": "myst-nb"}
122
+
123
+ #: `linkify` is deliberately absent: it needs `linkify-it-py` and every link in
124
+ #: these pages is already explicit.
125
+ myst_enable_extensions = [
126
+ "colon_fence", # ::: fences, so a directive can hold a code block
127
+ "deflist",
128
+ "dollarmath",
129
+ "substitution",
130
+ ]
131
+ #: Heading anchors down to h3, so `docs/*.md` can link to each other's sections.
132
+ myst_heading_anchors = 3
133
+
134
+ #: `{{ release }}` in a page resolves to the version this site was built from.
135
+ #: The roadmap used to state it in prose, which meant it was wrong from the
136
+ #: moment of the next release — it said v0.2.0 through two that followed. A
137
+ #: version is derivable, so deriving it removes the only part of that page that
138
+ #: went stale on a timetable rather than on a decision.
139
+ myst_substitutions = {"release": release}
140
+
141
+ # ------------------------------------------------------------------ autodoc
142
+
143
+ autodoc_typehints = "description"
144
+ autodoc_member_order = "bysource"
145
+ autodoc_default_options = {
146
+ "members": True,
147
+ "show-inheritance": True,
148
+ "member-order": "bysource",
149
+ }
150
+
151
+ napoleon_google_docstring = False
152
+ napoleon_numpy_docstring = True
153
+
154
+ intersphinx_mapping = {
155
+ "python": ("https://docs.python.org/3", None),
156
+ "numpy": ("https://numpy.org/doc/stable", None),
157
+ "scipy": ("https://docs.scipy.org/doc/scipy", None),
158
+ "pandas": ("https://pandas.pydata.org/docs", None),
159
+ "matplotlib": ("https://matplotlib.org/stable", None),
160
+ "obspy": ("https://docs.obspy.org", None),
161
+ "lmfit": ("https://lmfit.github.io/lmfit-py", None),
162
+ }
163
+ #: Resolving these needs the network. A build without it still produces a
164
+ #: site, with the cross-references left as plain text.
165
+ intersphinx_disabled_reftypes = ["*"]
166
+
167
+ # --------------------------------------------------------------------- html
168
+
169
+ html_theme = "pydata_sphinx_theme"
170
+ html_title = f"{project} {version}"
171
+ html_theme_options = {
172
+ "github_url": "https://github.com/sgjholt/SpecMod",
173
+ "show_prev_next": True,
174
+ "navigation_with_keys": False,
175
+ #: This theme puts *top-level* toctree entries in the header and gives the
176
+ #: sidebar the current section's children. A flat toctree therefore
177
+ #: produces a header of ten items and an empty sidebar, with `:caption:`
178
+ #: nowhere to render — which is what this site had. The four section pages
179
+ #: are what give the sidebar something to nest.
180
+ #:
181
+ #: `show_nav_level: 1` expands each section's own entries rather than
182
+ #: leaving them behind a disclosure triangle, so a reader can see a
183
+ #: section's contents without a click.
184
+ "show_nav_level": 1,
185
+ #: Deep enough for a section, its pages, and their headings — which is what
186
+ #: makes a long page like `processing` navigable from the sidebar rather
187
+ #: than by scrolling.
188
+ "navigation_depth": 3,
189
+ }
190
+ html_static_path: list[str] = []
@@ -0,0 +1,31 @@
1
+ # Working on SpecMod
2
+
3
+ Where the project is going, how to work on it, and how a merged commit becomes
4
+ a release.
5
+
6
+ [Roadmap](roadmap.md)
7
+ : What has shipped and in which version, what is being worked on, and what 1.0
8
+ will mean. Milestones, not dates.
9
+
10
+ [Developer guide](development.md)
11
+ : Quick start, the repository mapped, the daily loop, every tool and check, and
12
+ where development stops and releasing begins. Includes working with coding
13
+ agents.
14
+
15
+ [Documentation workflow](documentation.md)
16
+ : Building this site locally, previewing a pull request's build, how the
17
+ tutorial is executed into it, and how to add a page.
18
+
19
+ [Releasing the software](releasing.md)
20
+ : How a merged commit becomes a tag, a PyPI release and a DOI — and the
21
+ one-time repository settings none of it works without.
22
+
23
+ ```{toctree}
24
+ :maxdepth: 2
25
+ :hidden:
26
+
27
+ roadmap
28
+ development
29
+ documentation
30
+ releasing
31
+ ```
@@ -246,12 +246,12 @@ bounded rather than explained, and says so in as many words.
246
246
 
247
247
  ## What CI runs
248
248
 
249
- Five jobs in `test.yml`, plus two more workflows. All of them run on every pull
250
- request.
249
+ Six jobs in `test.yml`, plus three more workflows. All of them run on every
250
+ pull request except `release.yml`, which fires only on a push to `main`.
251
251
 
252
252
  | Job | Workflow | Does |
253
253
  |---|---|---|
254
- | `lint` | `test.yml` | `ruff check`, `ruff format --check`, and the `ci/` mirror check |
254
+ | `lint` | `test.yml` | `ruff check` and `ruff format --check` over `src/ tests/ tools/` |
255
255
  | `typecheck` | `test.yml` | `mypy`, strict, over the whole package |
256
256
  | `test` | `test.yml` | pytest on 3.11/3.12/3.13 × ubuntu/macOS, coverage to Codecov from one cell |
257
257
  | `floors` | `test.yml` | installs the *declared minimum* versions and runs the suite |
@@ -403,9 +403,12 @@ has happened here:
403
403
  not there. Three commits went out with session trailers before this was
404
404
  noticed; the config now installs both hook types from one command, and the
405
405
  first thing `AGENTS.md` says is to run it.
406
- - **An agent's token cannot push `.github/workflows/`.** This is what the
407
- `ci/` mirror exists for. An agent that does not know about it will either
408
- fail the push or, worse, quietly drop the change.
406
+ - **An agent's token may not be able to push `.github/workflows/`.** The
407
+ permission is granted here now, and the `ci/` mirror that used to work around
408
+ it is gone — keeping two copies of every workflow in step cost more than the
409
+ problem it solved. If the permission is ever withdrawn the push is rejected
410
+ loudly, naming `workflows`; the answer is to ask for it back, not to rebuild
411
+ the mirror.
409
412
  - **A development container often lacks the optional extras**, so an agent's
410
413
  green run can be greener than CI's. `--without-optional-extras` is the check.
411
414
  - **A harness may append its own commit trailers.** The repository's rules take
@@ -32,7 +32,7 @@ those are separate clocks.
32
32
  ## Building it locally
33
33
 
34
34
  ```sh
35
- uv pip install -e '.[docs]'
35
+ uv pip install -e '.[docs,io,tutorial]'
36
36
  sphinx-build -b html docs docs/_build/html
37
37
  python -m http.server -d docs/_build/html 8000 # then open localhost:8000
38
38
  ```
@@ -136,9 +136,11 @@ Two things in it are load-bearing and easy to lose:
136
136
  clones shallow to save time, and `hatch-vcs` derives the version from
137
137
  `git describe`. Without those two lines every build — including a tagged one
138
138
  — reports the fallback `0.0.0` in the sidebar.
139
- - **`extra_requirements: [docs, io]`.** The `io` extra is there because autodoc
140
- imports `specmod.io`, which imports h5py and pyarrow. The CI job installs the
141
- same pair for the same reason.
139
+ - **`extra_requirements: [docs, io, tutorial]`.** `io` because autodoc imports
140
+ `specmod.io`, which imports h5py and pyarrow — and because the tutorial saves
141
+ an HDF5 file while executing. `tutorial` for the Jupyter kernel that executes
142
+ it. The CI `docs` job installs the same three for the same reasons; keep them
143
+ in step or one of the two builds fails on a missing kernel.
142
144
 
143
145
  ## Versions, and what to link to
144
146
 
@@ -168,11 +170,19 @@ page depends on is documentation whatever its folder is called.
168
170
  ### Adding a page
169
171
 
170
172
  1. Write `docs/<name>.md` in MyST Markdown.
171
- 2. Add it to the `toctree` at the bottom of `docs/index.md`, and usually to the
172
- "Where to start" list above it.
173
+ 2. **Add it to the `toctree` of the section it belongs to** — not to
174
+ `index.md`. The site has four section pages, each owning its own toctree:
175
+ `getting-started.md`, `guides.md`, `api.md` and `contributing.md`. Add a
176
+ description to the list on that page too, since the sidebar shows titles
177
+ only.
173
178
  3. Build. A page in no toctree builds but warns, and is reachable only by a
174
179
  direct link.
175
180
 
181
+ `index.md`'s toctree holds only those four. That is what gives the sidebar its
182
+ nesting: this theme puts top-level toctree entries in the header and gives the
183
+ sidebar the current section's children, so a page added at the top level lands
184
+ in the header and flattens the navigation for everything else.
185
+
176
186
  If a page is a supporting note rather than a top-level one, put it in a hidden
177
187
  toctree on the page that cites it — that is how `notes/window-position.md` is
178
188
  attached to `choosing-a-transform.md`:
@@ -195,8 +205,11 @@ pages can link to each other's sections.
195
205
  those work; without it MyST does not read `$` at all.
196
206
  - `amsmath` is **not** enabled — nothing here uses a bare `\begin{align}`
197
207
  outside `$` delimiters. A `\begin{cases}` inside `$$` renders without it.
198
- - Markdown only. `source_suffix` maps `.md`; there is no reStructuredText in
199
- `docs/`, so there is one syntax rather than two.
208
+ - Markdown and notebooks. `source_suffix` maps `.md` and `.ipynb`, both to
209
+ `myst-nb` — there is no reStructuredText in `docs/`, so there is one prose
210
+ syntax rather than two. Both suffixes name `myst-nb` because that is the only
211
+ parser `myst_nb` registers; pointing `.md` at `myst_parser`'s `markdown`
212
+ fails the build with "Source parser for markdown not registered".
200
213
  - For a Sphinx directive that has no MyST spelling, drop into rST:
201
214
 
202
215
  ````markdown
@@ -223,7 +236,44 @@ the first build:
223
236
 
224
237
  Type hints come from the annotations via `autodoc_typehints = "description"`.
225
238
  `sphinx-autodoc-typehints` is deliberately **not** used: measured, it produced
226
- the same 367 documented objects while calling an API Sphinx 10 removes.
239
+ the same number of documented objects while calling an API Sphinx 10 removes.
240
+
241
+ ### The tutorial notebook
242
+
243
+ `tutorial/SpecModTutorial.ipynb` is published as part of the site and
244
+ **executed on every build** (`nb_execution_mode = "force"`). Every figure and
245
+ number on the page came from running that code against the code being
246
+ documented, and a notebook that raises fails the build
247
+ (`nb_execution_raise_on_error = True`). That is the whole point: a tutorial
248
+ nobody runs is the first thing to rot, and this one broke three times before
249
+ anything executed it.
250
+
251
+ Three things about the arrangement are worth knowing before changing it.
252
+
253
+ **It is copied into `docs/tutorial/` by `conf.py`, not moved.** Sphinx builds
254
+ only what is under `docs/`, and the notebook reads its 1 MB of waveforms
255
+ through paths relative to itself — so the data has to travel with it. The copy
256
+ is gitignored. `tutorial/` stays canonical because eight other files name
257
+ `tutorial/data/events/`, and a renamed data directory has broken this before.
258
+
259
+ **The copy is also what the notebook writes into.** It saves an HDF5 file and
260
+ two flatfiles as part of the lesson. Executed where it lives, a docs build
261
+ would leave those in your working tree; `tests/test_tutorial.py` copies to
262
+ `tmp_path` for exactly the same reason.
263
+
264
+ **Outputs are stripped in git**, by the `nbstripout` pre-commit hook, and
265
+ regenerated at build time. Do not commit them back: `force` ignores them, so a
266
+ committed output is never what a reader sees — only a stale diff.
267
+
268
+ The kernel comes from the `tutorial` extra. Both `.readthedocs.yaml` and
269
+ `.github/workflows/docs.yml` install `[docs,io,tutorial]`; keep them in step or
270
+ one of the two builds fails on a missing kernel. This does mean the notebook
271
+ executes twice per pull request — once here, and once in the `notebook` CI job,
272
+ which runs the single `-m notebook` test that executes it in a `tmp_path` copy.
273
+ Roughly 40 seconds, paid twice, to catch a broken notebook either as a failed
274
+ build or as a failed test. The cheaper checks around it — that every name the
275
+ notebook imports resolves, and that deleted modules stay unmentioned even in
276
+ prose — are unmarked, so they run in the `test` matrix job instead.
227
277
 
228
278
  ### Numbers in prose
229
279
 
@@ -0,0 +1,41 @@
1
+ # Getting started
2
+
3
+ Install it, run one event end to end, and find out what moved if you have code
4
+ written against `0.1`.
5
+
6
+ ```sh
7
+ pip install specmod
8
+ ```
9
+
10
+ Python 3.11 or newer. Saving and loading spectra needs the `io` extra —
11
+ `pip install "specmod[io]"` — without which SpecMod computes and plots normally
12
+ but cannot write a result. The other extras are listed in the
13
+ [README](https://github.com/sgjholt/SpecMod#installation).
14
+
15
+ While this is `0.x`, pin an exact version in anything you intend to publish.
16
+ The [roadmap](roadmap.md) says what has shipped and what 1.0 will mean.
17
+
18
+ [Tutorial](tutorial/SpecModTutorial.ipynb)
19
+ : One event from waveforms and picks to source parameters. Every figure and
20
+ number on the page is produced by executing the notebook when this site is
21
+ built, so it cannot describe an API that no longer exists. **Start here.**
22
+
23
+ [Upgrading from 0.1](upgrading.md)
24
+ : For code written against the pre-refactor `0.1.1` on `master`. Modules moved,
25
+ were renamed to snake_case, and several were deleted, so old code fails at
26
+ its imports rather than running and quietly giving different numbers.
27
+
28
+ ## Then
29
+
30
+ [How a spectrum is processed](processing.md) is the reference for what each
31
+ stage does and the conventions it uses — the amplitude convention, the Parseval
32
+ contract, and the moment and magnitude equations. It is the page to read once
33
+ the tutorial has run.
34
+
35
+ ```{toctree}
36
+ :maxdepth: 2
37
+ :hidden:
38
+
39
+ tutorial/SpecModTutorial
40
+ upgrading
41
+ ```
@@ -0,0 +1,55 @@
1
+ # Guides
2
+
3
+ What each stage does, why it is done that way, and what the choices cost.
4
+
5
+ ## The pipeline, and the conventions
6
+
7
+ [How a spectrum is processed](processing.md)
8
+ : Every step from a raw waveform to a moment magnitude, with the equation it
9
+ applies and a pointer to the code that applies it.
10
+
11
+ This is also where the conventions are stated, deliberately in the sections
12
+ that apply them rather than on a page of their own:
13
+
14
+ [Amplitude convention](processing.md#4-amplitude-convention)
15
+ : `FAS` is the folded $2\lvert X\rvert$; `MAGNITUDE` is the unfolded
16
+ $\lvert X\rvert$, **and that is the one $\Omega$ is defined in**. Reading a
17
+ folded plateau as $\Omega$ puts $M_0$ out by two — 0.2 magnitude units.
18
+
19
+ [The Parseval contract](processing.md#the-parseval-contract)
20
+ : The one energy check every estimator is held to, which is what lets
21
+ multitaper, Welch, FFT and the CWT be interchangeable rather than merely
22
+ similar.
23
+
24
+ [Moment and magnitude](processing.md#9-moment-and-magnitude)
25
+ : The $M_0$ and $M_w$ equations, the medium constants and where they come
26
+ from, and the two distances that are in different units on purpose.
27
+
28
+ ## Choices that change the answer
29
+
30
+ [Choosing a transform](choosing-a-transform.md)
31
+ : What each estimator does to your data, measured. On real windows the plateau
32
+ moves by 7–15% between estimators — about 0.03 magnitude units — and window
33
+ position alone reaches 0.08. Small against the 0.13 m.u. scatter quoted for
34
+ spectral $M_w$, but systematic rather than random, so it does not average
35
+ away across stations at similar distance.
36
+
37
+ [Reading picks](pick-formats.md)
38
+ : What arrival formats are read out of the box, how to add one, and how a pick
39
+ is matched to a trace.
40
+
41
+ ## Working with data
42
+
43
+ [Publishing a dataset](releasing-data.md)
44
+ : Taking an event from an FDSN archive to a hash-pinned entry in the registry,
45
+ so a result can be reproduced from the same bytes.
46
+
47
+ ```{toctree}
48
+ :maxdepth: 2
49
+ :hidden:
50
+
51
+ processing
52
+ choosing-a-transform
53
+ pick-formats
54
+ releasing-data
55
+ ```