specmod 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. {specmod-0.2.1 → specmod-0.2.2}/.github/workflows/docs.yml +6 -1
  2. {specmod-0.2.1 → specmod-0.2.2}/.gitignore +11 -3
  3. {specmod-0.2.1 → specmod-0.2.2}/.readthedocs.yaml +7 -1
  4. specmod-0.2.2/.release-please-manifest.json +3 -0
  5. {specmod-0.2.1 → specmod-0.2.2}/CHANGELOG.md +12 -0
  6. {specmod-0.2.1 → specmod-0.2.2}/PKG-INFO +1 -1
  7. {specmod-0.2.1 → specmod-0.2.2}/docs/conf.py +61 -7
  8. {specmod-0.2.1 → specmod-0.2.2}/docs/documentation.md +39 -2
  9. {specmod-0.2.1 → specmod-0.2.2}/docs/index.md +6 -0
  10. {specmod-0.2.1 → specmod-0.2.2}/docs/roadmap.md +14 -5
  11. specmod-0.2.2/tutorial/SpecModTutorial.ipynb +1032 -0
  12. specmod-0.2.1/.release-please-manifest.json +0 -3
  13. specmod-0.2.1/tutorial/SpecModTutorial.ipynb +0 -2000
  14. specmod-0.2.1/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/2019-08-26T07:30:47.000000Z.h5 +0 -0
  15. specmod-0.2.1/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/flatfiles/2019-08-26T07:30:47.000000Z.csv +0 -29
  16. specmod-0.2.1/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/flatfiles/2019-08-26T07:30:47.000000Z.parquet +0 -0
  17. {specmod-0.2.1 → specmod-0.2.2}/.git-blame-ignore-revs +0 -0
  18. {specmod-0.2.1 → specmod-0.2.2}/.github/workflows/build.yml +0 -0
  19. {specmod-0.2.1 → specmod-0.2.2}/.github/workflows/release.yml +0 -0
  20. {specmod-0.2.1 → specmod-0.2.2}/.github/workflows/test.yml +0 -0
  21. {specmod-0.2.1 → specmod-0.2.2}/.pre-commit-config.yaml +0 -0
  22. {specmod-0.2.1 → specmod-0.2.2}/AGENTS.md +0 -0
  23. {specmod-0.2.1 → specmod-0.2.2}/CITATION.cff +0 -0
  24. {specmod-0.2.1 → specmod-0.2.2}/CLAUDE.md +0 -0
  25. {specmod-0.2.1 → specmod-0.2.2}/CONTRIBUTING.md +0 -0
  26. {specmod-0.2.1 → specmod-0.2.2}/LICENSE +0 -0
  27. {specmod-0.2.1 → specmod-0.2.2}/README.md +0 -0
  28. {specmod-0.2.1 → specmod-0.2.2}/datasets/magna_2020.toml +0 -0
  29. {specmod-0.2.1 → specmod-0.2.2}/datasets/pnr_2019.toml +0 -0
  30. {specmod-0.2.1 → specmod-0.2.2}/docs/REFACTOR_PLAN.md +0 -0
  31. {specmod-0.2.1 → specmod-0.2.2}/docs/api.md +0 -0
  32. {specmod-0.2.1 → specmod-0.2.2}/docs/choosing-a-transform.md +0 -0
  33. {specmod-0.2.1 → specmod-0.2.2}/docs/development.md +0 -0
  34. {specmod-0.2.1 → specmod-0.2.2}/docs/notebooks/_build_notebook.py +0 -0
  35. {specmod-0.2.1 → specmod-0.2.2}/docs/notebooks/choosing-a-transform.ipynb +0 -0
  36. {specmod-0.2.1 → specmod-0.2.2}/docs/notes/api-audit.md +0 -0
  37. {specmod-0.2.1 → specmod-0.2.2}/docs/notes/window-position.md +0 -0
  38. {specmod-0.2.1 → specmod-0.2.2}/docs/pick-formats.md +0 -0
  39. {specmod-0.2.1 → specmod-0.2.2}/docs/processing.md +0 -0
  40. {specmod-0.2.1 → specmod-0.2.2}/docs/releasing-data.md +0 -0
  41. {specmod-0.2.1 → specmod-0.2.2}/docs/releasing.md +0 -0
  42. {specmod-0.2.1 → specmod-0.2.2}/pyproject.toml +0 -0
  43. {specmod-0.2.1 → specmod-0.2.2}/release-please-config.json +0 -0
  44. {specmod-0.2.1 → specmod-0.2.2}/requirements.txt +0 -0
  45. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/__init__.py +0 -0
  46. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/_vendor/__init__.py +0 -0
  47. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/_vendor/qiinv.py +0 -0
  48. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/acquire.py +0 -0
  49. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/api.py +0 -0
  50. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/cli.py +0 -0
  51. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/config/__init__.py +0 -0
  52. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/config/layers.py +0 -0
  53. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/config/provenance.py +0 -0
  54. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/config/sections.py +0 -0
  55. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/config/serialize.py +0 -0
  56. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/__init__.py +0 -0
  57. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/bandwidth.py +0 -0
  58. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/collection.py +0 -0
  59. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/noise.py +0 -0
  60. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/scalogram.py +0 -0
  61. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/spectrum.py +0 -0
  62. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/core/units.py +0 -0
  63. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/datasets.py +0 -0
  64. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/distance.py +0 -0
  65. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/exceptions.py +0 -0
  66. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/fitting/__init__.py +0 -0
  67. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/fitting/base.py +0 -0
  68. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/fitting/event.py +0 -0
  69. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/fitting/guess.py +0 -0
  70. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/fitting/spectrum.py +0 -0
  71. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/io.py +0 -0
  72. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/magnitude.py +0 -0
  73. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/picks/__init__.py +0 -0
  74. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/picks/base.py +0 -0
  75. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/picks/delimited.py +0 -0
  76. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/picks/events.py +0 -0
  77. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/picks/resolution.py +0 -0
  78. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/picks/snuffler.py +0 -0
  79. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/pipeline.py +0 -0
  80. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/plotting.py +0 -0
  81. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/preprocess.py +0 -0
  82. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/smoothing/__init__.py +0 -0
  83. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/smoothing/base.py +0 -0
  84. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/smoothing/konno_ohmachi.py +0 -0
  85. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/smoothing/log_bins.py +0 -0
  86. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/sources/__init__.py +0 -0
  87. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/sources/attenuation.py +0 -0
  88. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/sources/composite.py +0 -0
  89. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/sources/motion.py +0 -0
  90. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/sources/source.py +0 -0
  91. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/spreading.py +0 -0
  92. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/staged.py +0 -0
  93. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/tables.py +0 -0
  94. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/__init__.py +0 -0
  95. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/base.py +0 -0
  96. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/cwt.py +0 -0
  97. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/fft.py +0 -0
  98. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/multitaper.py +0 -0
  99. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/prieto.py +0 -0
  100. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/transforms/quadratic.py +0 -0
  101. {specmod-0.2.1 → specmod-0.2.2}/src/specmod/utils.py +0 -0
  102. {specmod-0.2.1 → specmod-0.2.2}/stubs/README.md +0 -0
  103. {specmod-0.2.1 → specmod-0.2.2}/stubs/lmfit/__init__.pyi +0 -0
  104. {specmod-0.2.1 → specmod-0.2.2}/stubs/lmfit/model.pyi +0 -0
  105. {specmod-0.2.1 → specmod-0.2.2}/stubs/lmfit/parameter.pyi +0 -0
  106. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/__init__.pyi +0 -0
  107. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/clients/__init__.pyi +0 -0
  108. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/clients/fdsn/__init__.pyi +0 -0
  109. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/__init__.pyi +0 -0
  110. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/event.pyi +0 -0
  111. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/inventory.pyi +0 -0
  112. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/stream.pyi +0 -0
  113. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/trace.pyi +0 -0
  114. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/utcdatetime.pyi +0 -0
  115. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/util/__init__.pyi +0 -0
  116. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/core/util/base.pyi +0 -0
  117. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/geodetics/__init__.pyi +0 -0
  118. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/signal/__init__.pyi +0 -0
  119. {specmod-0.2.1 → specmod-0.2.2}/stubs/obspy/signal/konnoohmachismoothing.pyi +0 -0
  120. {specmod-0.2.1 → specmod-0.2.2}/studies/magna_2020_paper.toml +0 -0
  121. {specmod-0.2.1 → specmod-0.2.2}/tests/__init__.py +0 -0
  122. {specmod-0.2.1 → specmod-0.2.2}/tests/conftest.py +0 -0
  123. {specmod-0.2.1 → specmod-0.2.2}/tests/golden/motion_reference.json +0 -0
  124. {specmod-0.2.1 → specmod-0.2.2}/tests/golden/pipeline_reference.json +0 -0
  125. {specmod-0.2.1 → specmod-0.2.2}/tests/golden/window_reference.json +0 -0
  126. {specmod-0.2.1 → specmod-0.2.2}/tests/test_acquire.py +0 -0
  127. {specmod-0.2.1 → specmod-0.2.2}/tests/test_ambient_state.py +0 -0
  128. {specmod-0.2.1 → specmod-0.2.2}/tests/test_api_surface.py +0 -0
  129. {specmod-0.2.1 → specmod-0.2.2}/tests/test_collection.py +0 -0
  130. {specmod-0.2.1 → specmod-0.2.2}/tests/test_config.py +0 -0
  131. {specmod-0.2.1 → specmod-0.2.2}/tests/test_cwt.py +0 -0
  132. {specmod-0.2.1 → specmod-0.2.2}/tests/test_datasets.py +0 -0
  133. {specmod-0.2.1 → specmod-0.2.2}/tests/test_docs_are_current.py +0 -0
  134. {specmod-0.2.1 → specmod-0.2.2}/tests/test_end_to_end.py +0 -0
  135. {specmod-0.2.1 → specmod-0.2.2}/tests/test_fitting_defaults.py +0 -0
  136. {specmod-0.2.1 → specmod-0.2.2}/tests/test_golden_reference.py +0 -0
  137. {specmod-0.2.1 → specmod-0.2.2}/tests/test_import.py +0 -0
  138. {specmod-0.2.1 → specmod-0.2.2}/tests/test_io_and_plotting.py +0 -0
  139. {specmod-0.2.1 → specmod-0.2.2}/tests/test_legacy_fixes.py +0 -0
  140. {specmod-0.2.1 → specmod-0.2.2}/tests/test_magnitude.py +0 -0
  141. {specmod-0.2.1 → specmod-0.2.2}/tests/test_make_golden.py +0 -0
  142. {specmod-0.2.1 → specmod-0.2.2}/tests/test_pick_plugins.py +0 -0
  143. {specmod-0.2.1 → specmod-0.2.2}/tests/test_pick_readers.py +0 -0
  144. {specmod-0.2.1 → specmod-0.2.2}/tests/test_picks.py +0 -0
  145. {specmod-0.2.1 → specmod-0.2.2}/tests/test_pipeline.py +0 -0
  146. {specmod-0.2.1 → specmod-0.2.2}/tests/test_pipeline_smoke.py +0 -0
  147. {specmod-0.2.1 → specmod-0.2.2}/tests/test_preprocess.py +0 -0
  148. {specmod-0.2.1 → specmod-0.2.2}/tests/test_prieto.py +0 -0
  149. {specmod-0.2.1 → specmod-0.2.2}/tests/test_quadratic.py +0 -0
  150. {specmod-0.2.1 → specmod-0.2.2}/tests/test_release_config.py +0 -0
  151. {specmod-0.2.1 → specmod-0.2.2}/tests/test_smoothing.py +0 -0
  152. {specmod-0.2.1 → specmod-0.2.2}/tests/test_sources.py +0 -0
  153. {specmod-0.2.1 → specmod-0.2.2}/tests/test_spectral_wiring.py +0 -0
  154. {specmod-0.2.1 → specmod-0.2.2}/tests/test_staged.py +0 -0
  155. {specmod-0.2.1 → specmod-0.2.2}/tests/test_stubs.py +0 -0
  156. {specmod-0.2.1 → specmod-0.2.2}/tests/test_transforms.py +0 -0
  157. {specmod-0.2.1 → specmod-0.2.2}/tests/test_tutorial.py +0 -0
  158. {specmod-0.2.1 → specmod-0.2.2}/tests/test_typing_backlog.py +0 -0
  159. {specmod-0.2.1 → specmod-0.2.2}/tests/test_utils.py +0 -0
  160. {specmod-0.2.1 → specmod-0.2.2}/tests/test_versioning.py +0 -0
  161. {specmod-0.2.1 → specmod-0.2.2}/tools/check_built_version.py +0 -0
  162. {specmod-0.2.1 → specmod-0.2.2}/tools/check_floors.py +0 -0
  163. {specmod-0.2.1 → specmod-0.2.2}/tools/make_golden.py +0 -0
  164. {specmod-0.2.1 → specmod-0.2.2}/tools/measure_docs.py +0 -0
  165. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.picks +0 -0
  166. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.xml +0 -0
  167. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/stations/inventory.xml +0 -0
  168. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHE_2019-08-26T07:30:47.000000Z +0 -0
  169. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHN_2019-08-26T07:30:47.000000Z +0 -0
  170. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  171. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHE_2019-08-26T07:30:47.000000Z +0 -0
  172. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHN_2019-08-26T07:30:47.000000Z +0 -0
  173. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  174. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHE_2019-08-26T07:30:47.000000Z +0 -0
  175. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHN_2019-08-26T07:30:47.000000Z +0 -0
  176. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  177. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHE_2019-08-26T07:30:47.000000Z +0 -0
  178. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHN_2019-08-26T07:30:47.000000Z +0 -0
  179. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  180. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHE_2019-08-26T07:30:47.000000Z +0 -0
  181. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHN_2019-08-26T07:30:47.000000Z +0 -0
  182. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  183. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHE_2019-08-26T07:30:47.000000Z +0 -0
  184. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHN_2019-08-26T07:30:47.000000Z +0 -0
  185. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  186. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH1_2019-08-26T07:30:47.000000Z +0 -0
  187. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH2_2019-08-26T07:30:47.000000Z +0 -0
  188. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH3_2019-08-26T07:30:47.000000Z +0 -0
  189. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  190. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  191. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  192. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ02.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  193. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  194. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  195. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  196. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  197. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  198. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  199. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  200. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  201. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  202. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  203. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  204. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  205. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  206. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  207. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  208. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  209. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  210. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  211. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  212. {specmod-0.2.1 → specmod-0.2.2}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  213. {specmod-0.2.1 → specmod-0.2.2}/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.2"
3
+ }
@@ -9,6 +9,18 @@ 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.2](https://github.com/sgjholt/SpecMod/compare/v0.2.1...v0.2.2) (2026-09-05)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * ignore the tutorial output at the path it is actually written to ([ad34cc7](https://github.com/sgjholt/SpecMod/commit/ad34cc7d44208e5bd49a2d1f1277516670848dc7))
18
+
19
+
20
+ ### Documentation
21
+
22
+ * publish the tutorial, executed on every build ([ccd1842](https://github.com/sgjholt/SpecMod/commit/ccd18429b9da5db875885d88269fb70686e6eaa3))
23
+
12
24
  ## [0.2.1](https://github.com/sgjholt/SpecMod/compare/v0.2.0...v0.2.1) (2026-08-23)
13
25
 
14
26
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: specmod
3
- Version: 0.2.1
3
+ Version: 0.2.2
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
@@ -14,7 +14,9 @@ gives.
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import shutil
17
18
  from importlib.metadata import PackageNotFoundError, version
19
+ from pathlib import Path
18
20
 
19
21
  project = "SpecMod"
20
22
  author = "James Holt"
@@ -32,7 +34,9 @@ except PackageNotFoundError: # pragma: no cover - docs built without an install
32
34
  version = ".".join(release.split(".")[:2])
33
35
 
34
36
  extensions = [
35
- "myst_parser",
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",
36
40
  "sphinx.ext.autodoc",
37
41
  "sphinx.ext.napoleon",
38
42
  "sphinx.ext.intersphinx",
@@ -45,9 +49,10 @@ extensions = [
45
49
 
46
50
  #: `REFACTOR_PLAN.md` is a working document, not documentation — it is written
47
51
  #: for whoever is doing the refactor and records decisions and their evidence.
48
- #: `notebooks/` is built by Phase 6 with myst-nb; until then the `.ipynb` files
49
- #: would be copied in without being executed, which is worse than leaving them
50
- #: out. `notes/` *is* included: `choosing-a-transform.md` links to it for a
52
+ #: `notebooks/` holds the source for the transform comparison, which
53
+ #: `tools/measure_docs.py` renders into `choosing-a-transform.md`; the page is
54
+ #: what is published, so building the notebook too would duplicate it.
55
+ #: `notes/` *is* included: `choosing-a-transform.md` links to it for a
51
56
  #: per-trace table, so excluding it broke that link.
52
57
  exclude_patterns = [
53
58
  "_build",
@@ -57,9 +62,58 @@ exclude_patterns = [
57
62
  ".DS_Store",
58
63
  ]
59
64
 
60
- #: Markdown only. Every page in `docs/` is already written that way, and
61
- #: allowing both means two syntaxes for the same job.
62
- source_suffix = {".md": "markdown"}
65
+ # ------------------------------------------------------- the tutorial notebook
66
+
67
+ #: The tutorial lives in `tutorial/`, outside this source directory, next to the
68
+ #: 1 MB of PNR waveforms it reads through paths relative to itself. Sphinx only
69
+ #: builds what is under `docs/`, so it is copied in here.
70
+ #:
71
+ #: A copy rather than a move, and rather than executing it where it sits,
72
+ #: because **the notebook writes**: cell 53 saves an HDF5 file under
73
+ #: `data/events/<event>/spectra/` and cell 54 writes flatfiles beside it. Run in
74
+ #: place, a docs build would leave those artefacts in the working tree — which
75
+ #: is why `tests/test_tutorial.py` executes it in a `tmp_path` copy too. This is
76
+ #: the same trick, and the copy is what the artefacts land in.
77
+ #:
78
+ #: Copying the data with it is what keeps the notebook's `Path("data/events")`
79
+ #: working, so the notebook is identical whether opened from `tutorial/`, run by
80
+ #: pytest, or built here. `tutorial/` stays canonical: eight other files name
81
+ #: `tutorial/data/events/`, and the CI job that executes it records that a
82
+ #: renamed data directory has already broken this once.
83
+ _HERE = Path(__file__).parent
84
+ _TUTORIAL_SRC = _HERE.parent / "tutorial"
85
+ _TUTORIAL_DST = _HERE / "tutorial"
86
+
87
+ if _TUTORIAL_SRC.is_dir():
88
+ shutil.rmtree(_TUTORIAL_DST, ignore_errors=True)
89
+ shutil.copytree(_TUTORIAL_SRC, _TUTORIAL_DST)
90
+
91
+ #: `force`, not `auto`. `auto` executes only notebooks that arrive without
92
+ #: outputs, and the tutorial is committed *with* 28 cells of them — so `auto`
93
+ #: would publish whatever was last saved by hand, which is the silent rot this
94
+ #: is meant to end. Forcing it means the page can only show output the code
95
+ #: actually produced against the code being documented.
96
+ nb_execution_mode = "force"
97
+ #: Matches `tests/test_tutorial.py`. The whole notebook runs in ~40s; the
98
+ #: default 30s is per cell, and the two-stage fit is the one that would trip it.
99
+ nb_execution_timeout = 600
100
+ #: A notebook that raises fails the build. That is the point: an executed
101
+ #: tutorial is only a guarantee if a broken one is loud.
102
+ nb_execution_raise_on_error = True
103
+ #: `False` keeps the kernel's working directory at the notebook's own, which is
104
+ #: what `Path("data/events")` resolves against.
105
+ nb_execution_in_temp = False
106
+
107
+ #: Markdown for the prose pages — every one in `docs/` is written that way, and
108
+ #: allowing reStructuredText too would mean two syntaxes for the same job — plus
109
+ #: `.ipynb` for the tutorial.
110
+ #:
111
+ #: Both map to `myst-nb`, which is the only parser name `myst_nb` 1.4 registers:
112
+ #: it does not re-register `myst_parser`'s `markdown`, so leaving `.md` pointing
113
+ #: at that fails the build outright with "Source parser for markdown not
114
+ #: registered". The `myst-nb` parser is a superset and reads the prose pages
115
+ #: identically.
116
+ source_suffix = {".md": "myst-nb", ".ipynb": "myst-nb"}
63
117
 
64
118
  #: `linkify` is deliberately absent: it needs `linkify-it-py` and every link in
65
119
  #: these pages is already explicit.
@@ -195,8 +195,11 @@ pages can link to each other's sections.
195
195
  those work; without it MyST does not read `$` at all.
196
196
  - `amsmath` is **not** enabled — nothing here uses a bare `\begin{align}`
197
197
  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.
198
+ - Markdown and notebooks. `source_suffix` maps `.md` and `.ipynb`, both to
199
+ `myst-nb` — there is no reStructuredText in `docs/`, so there is one prose
200
+ syntax rather than two. Both suffixes name `myst-nb` because that is the only
201
+ parser `myst_nb` registers; pointing `.md` at `myst_parser`'s `markdown`
202
+ fails the build with "Source parser for markdown not registered".
200
203
  - For a Sphinx directive that has no MyST spelling, drop into rST:
201
204
 
202
205
  ````markdown
@@ -225,6 +228,40 @@ Type hints come from the annotations via `autodoc_typehints = "description"`.
225
228
  `sphinx-autodoc-typehints` is deliberately **not** used: measured, it produced
226
229
  the same 367 documented objects while calling an API Sphinx 10 removes.
227
230
 
231
+ ### The tutorial notebook
232
+
233
+ `tutorial/SpecModTutorial.ipynb` is published as part of the site and
234
+ **executed on every build** (`nb_execution_mode = "force"`). Every figure and
235
+ number on the page came from running that code against the code being
236
+ documented, and a notebook that raises fails the build
237
+ (`nb_execution_raise_on_error = True`). That is the whole point: a tutorial
238
+ nobody runs is the first thing to rot, and this one broke three times before
239
+ anything executed it.
240
+
241
+ Three things about the arrangement are worth knowing before changing it.
242
+
243
+ **It is copied into `docs/tutorial/` by `conf.py`, not moved.** Sphinx builds
244
+ only what is under `docs/`, and the notebook reads its 1 MB of waveforms
245
+ through paths relative to itself — so the data has to travel with it. The copy
246
+ is gitignored. `tutorial/` stays canonical because eight other files name
247
+ `tutorial/data/events/`, and a renamed data directory has broken this before.
248
+
249
+ **The copy is also what the notebook writes into.** It saves an HDF5 file and
250
+ two flatfiles as part of the lesson. Executed where it lives, a docs build
251
+ would leave those in your working tree; `tests/test_tutorial.py` copies to
252
+ `tmp_path` for exactly the same reason.
253
+
254
+ **Outputs are stripped in git**, by the `nbstripout` pre-commit hook, and
255
+ regenerated at build time. Do not commit them back: `force` ignores them, so a
256
+ committed output is never what a reader sees — only a stale diff.
257
+
258
+ The kernel comes from the `tutorial` extra. Both `.readthedocs.yaml` and
259
+ `.github/workflows/docs.yml` install `[docs,io,tutorial]`; keep them in step or
260
+ one of the two builds fails on a missing kernel. This does mean the notebook
261
+ executes twice per pull request — once here and once in the `notebook` CI job,
262
+ which also checks imports and that deleted modules stay unmentioned. Roughly
263
+ 40 seconds, paid twice, for two genuinely different failures.
264
+
228
265
  ### Numbers in prose
229
266
 
230
267
  Any table that came from a measurement is generated, not typed. Edit
@@ -45,6 +45,11 @@ print(fits.table[["id", "llpsp", "fc", "ts"]])
45
45
 
46
46
  ## Where to start
47
47
 
48
+ [Tutorial](tutorial/SpecModTutorial.ipynb)
49
+ : One event end to end — waveforms and picks in, source parameters out. Every
50
+ figure and number on the page is produced by running the notebook at build
51
+ time, so it cannot describe an API that no longer exists.
52
+
48
53
  [Processing](processing.md)
49
54
  : Every step of the pipeline with the equation it implements — what a window
50
55
  is, how the noise is compared against it, and what the bandwidth selector
@@ -97,6 +102,7 @@ one either way.
97
102
  :maxdepth: 2
98
103
  :hidden:
99
104
 
105
+ tutorial/SpecModTutorial
100
106
  processing
101
107
  choosing-a-transform
102
108
  pick-formats
@@ -102,15 +102,24 @@ What is left: `io.py` and `plotting.py` are still single modules, and the
102
102
  operations that mutate in place need to return new objects instead. Neither is
103
103
  large — the split is about responsibilities, not line count.
104
104
 
105
+ ### The tutorial, executed
106
+
107
+ The tutorial is published as part of this site and **re-executed on every
108
+ build**, so every figure and number on the page came from running the code
109
+ being documented. A notebook that stops working fails the build rather than
110
+ going quietly stale, which is what it was listed as a 1.0 requirement for.
111
+
105
112
  ## Planned
106
113
 
107
114
  ### 1.0 — the API stops moving
108
115
 
109
- The theory page that states the normalisation and units conventions
110
- explicitly, the tutorial rebuilt as an executed notebook so it cannot rot
111
- silently, and a "what changed since 0.1" guide for anyone upgrading. Then the
112
- 1.0 release, which is the promise that names and signatures stop moving
113
- without a deprecation cycle.
116
+ Two things left: the theory page that states the normalisation and units
117
+ conventions explicitly, and a "what changed since 0.1" guide for anyone
118
+ upgrading. Then the 1.0 release, which is the promise that names and
119
+ signatures stop moving without a deprecation cycle.
120
+
121
+ The third — the tutorial rebuilt as an executed notebook, so it cannot rot
122
+ silently — is merged and sits under *In progress* above until it ships.
114
123
 
115
124
  That promise is the whole content of the number, which is why it has to be a
116
125
  decision rather than something a breaking commit does on its way past. Until