metrust 0.4.2__tar.gz → 0.4.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 (229) hide show
  1. {metrust-0.4.2 → metrust-0.4.3}/.github/workflows/ci.yml +55 -11
  2. {metrust-0.4.2 → metrust-0.4.3}/.github/workflows/docs.yml +4 -4
  3. {metrust-0.4.2 → metrust-0.4.3}/.github/workflows/release.yml +12 -12
  4. {metrust-0.4.2 → metrust-0.4.3}/Cargo.lock +1 -1
  5. {metrust-0.4.2 → metrust-0.4.3}/Cargo.toml +1 -1
  6. {metrust-0.4.2 → metrust-0.4.3}/PKG-INFO +1 -1
  7. {metrust-0.4.2 → metrust-0.4.3}/benches/bench_python.py +18 -1
  8. {metrust-0.4.2 → metrust-0.4.3}/docs/compatibility.md +19 -9
  9. metrust-0.4.3/docs/delegation-ledger.md +29 -0
  10. {metrust-0.4.2 → metrust-0.4.3}/mkdocs.yml +1 -0
  11. {metrust-0.4.2 → metrust-0.4.3}/pyproject.toml +1 -1
  12. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/calc/__init__.py +63 -18
  13. metrust-0.4.3/tests/run_ci_mode.py +45 -0
  14. metrust-0.4.3/tests/test_cookbook_replays.py +282 -0
  15. metrust-0.4.3/tests/test_delegation_ledger.py +187 -0
  16. {metrust-0.4.2 → metrust-0.4.3}/.gitignore +0 -0
  17. {metrust-0.4.2 → metrust-0.4.3}/BENCHMARKS.md +0 -0
  18. {metrust-0.4.2 → metrust-0.4.3}/README.md +0 -0
  19. {metrust-0.4.2 → metrust-0.4.3}/VERIFICATION.md +0 -0
  20. {metrust-0.4.2 → metrust-0.4.3}/benches/bench_hrrr.py +0 -0
  21. {metrust-0.4.2 → metrust-0.4.3}/benches/bench_hrrr_vs_metpy.py +0 -0
  22. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/Cargo.toml +0 -0
  23. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/benches/calc_bench.rs +0 -0
  24. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/atmo.rs +0 -0
  25. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/kinematics.rs +0 -0
  26. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/mod.rs +0 -0
  27. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/severe.rs +0 -0
  28. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/smooth.rs +0 -0
  29. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/thermo.rs +0 -0
  30. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/utils.rs +0 -0
  31. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/calc/wind.rs +0 -0
  32. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/constants.rs +0 -0
  33. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/interpolate/mod.rs +0 -0
  34. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/gempak.rs +0 -0
  35. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/gempak_dm.rs +0 -0
  36. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/gempak_sounding.rs +0 -0
  37. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/gempak_surface.rs +0 -0
  38. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/gini.rs +0 -0
  39. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/level3.rs +0 -0
  40. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/metar.rs +0 -0
  41. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/mod.rs +0 -0
  42. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/station.rs +0 -0
  43. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/io/wpc.rs +0 -0
  44. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/lib.rs +0 -0
  45. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/plots/mod.rs +0 -0
  46. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/projections.rs +0 -0
  47. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/src/units.rs +0 -0
  48. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/tests/test_gempak.rs +0 -0
  49. {metrust-0.4.2 → metrust-0.4.3}/crates/metrust/tests/test_new_functions.rs +0 -0
  50. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/Cargo.toml +0 -0
  51. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/composite.rs +0 -0
  52. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/cache.rs +0 -0
  53. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/catalog.rs +0 -0
  54. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/client.rs +0 -0
  55. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/fallback.rs +0 -0
  56. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/idx.rs +0 -0
  57. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/mod.rs +0 -0
  58. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/sources.rs +0 -0
  59. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/download/streaming.rs +0 -0
  60. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/dynamics.rs +0 -0
  61. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/error.rs +0 -0
  62. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/grid.rs +0 -0
  63. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/mod.rs +0 -0
  64. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/ops.rs +0 -0
  65. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/parser.rs +0 -0
  66. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/search.rs +0 -0
  67. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/streaming.rs +0 -0
  68. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/tables.rs +0 -0
  69. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/tests.rs +0 -0
  70. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/unpack.rs +0 -0
  71. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/grib2/writer.rs +0 -0
  72. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/gridmath.rs +0 -0
  73. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/lib.rs +0 -0
  74. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/metfuncs.rs +0 -0
  75. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/cfs.rs +0 -0
  76. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/ecmwf.rs +0 -0
  77. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/era5.rs +0 -0
  78. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/gefs.rs +0 -0
  79. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/gfs.rs +0 -0
  80. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/href.rs +0 -0
  81. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/hrrr.rs +0 -0
  82. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/hrrr_ak.rs +0 -0
  83. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/latest.rs +0 -0
  84. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/mod.rs +0 -0
  85. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/mrms.rs +0 -0
  86. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/nam.rs +0 -0
  87. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/nbm.rs +0 -0
  88. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/rap.rs +0 -0
  89. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/rrfs.rs +0 -0
  90. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/rtma.rs +0 -0
  91. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/sref.rs +0 -0
  92. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/urma.rs +0 -0
  93. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/models/wpc.rs +0 -0
  94. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/products.rs +0 -0
  95. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/projection.rs +0 -0
  96. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/regrid.rs +0 -0
  97. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/ansi.rs +0 -0
  98. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/colormap.rs +0 -0
  99. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/contour.rs +0 -0
  100. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/cross_section.rs +0 -0
  101. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/encode.rs +0 -0
  102. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/filled_contour.rs +0 -0
  103. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/hodograph.rs +0 -0
  104. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/mod.rs +0 -0
  105. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/overlay.rs +0 -0
  106. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/raster.rs +0 -0
  107. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/skewt.rs +0 -0
  108. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-core/src/render/station.rs +0 -0
  109. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/Cargo.toml +0 -0
  110. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/error.rs +0 -0
  111. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/field.rs +0 -0
  112. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/lib.rs +0 -0
  113. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/meta.rs +0 -0
  114. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/projection.rs +0 -0
  115. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/radial.rs +0 -0
  116. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/site.rs +0 -0
  117. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/sounding.rs +0 -0
  118. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-field/src/time.rs +0 -0
  119. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/Cargo.toml +0 -0
  120. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/composite.rs +0 -0
  121. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/dynamics.rs +0 -0
  122. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/gridmath.rs +0 -0
  123. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/interpolate.rs +0 -0
  124. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/lib.rs +0 -0
  125. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/regrid.rs +0 -0
  126. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-math/src/thermo.rs +0 -0
  127. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/Cargo.toml +0 -0
  128. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/cells.rs +0 -0
  129. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/color_table.rs +0 -0
  130. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/derived.rs +0 -0
  131. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/detection.rs +0 -0
  132. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/level2.rs +0 -0
  133. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/lib.rs +0 -0
  134. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/products.rs +0 -0
  135. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/render.rs +0 -0
  136. {metrust-0.4.2 → metrust-0.4.3}/crates/wx-radar/src/sites.rs +0 -0
  137. {metrust-0.4.2 → metrust-0.4.3}/demos/hrrr_diffusion_training.md +0 -0
  138. {metrust-0.4.2 → metrust-0.4.3}/docs/api/atmospheric.md +0 -0
  139. {metrust-0.4.2 → metrust-0.4.3}/docs/api/grid-composites.md +0 -0
  140. {metrust-0.4.2 → metrust-0.4.3}/docs/api/io.md +0 -0
  141. {metrust-0.4.2 → metrust-0.4.3}/docs/api/kinematics.md +0 -0
  142. {metrust-0.4.2 → metrust-0.4.3}/docs/api/moisture.md +0 -0
  143. {metrust-0.4.2 → metrust-0.4.3}/docs/api/severe.md +0 -0
  144. {metrust-0.4.2 → metrust-0.4.3}/docs/api/smoothing.md +0 -0
  145. {metrust-0.4.2 → metrust-0.4.3}/docs/api/thermodynamics.md +0 -0
  146. {metrust-0.4.2 → metrust-0.4.3}/docs/api/units.md +0 -0
  147. {metrust-0.4.2 → metrust-0.4.3}/docs/api/wind.md +0 -0
  148. {metrust-0.4.2 → metrust-0.4.3}/docs/guides/arrays.md +0 -0
  149. {metrust-0.4.2 → metrust-0.4.3}/docs/guides/installation.md +0 -0
  150. {metrust-0.4.2 → metrust-0.4.3}/docs/guides/migration.md +0 -0
  151. {metrust-0.4.2 → metrust-0.4.3}/docs/index.md +0 -0
  152. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/architecture.md +0 -0
  153. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/grid-kinematics.md +0 -0
  154. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/index.md +0 -0
  155. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/interpolation.md +0 -0
  156. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/io-formats.md +0 -0
  157. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/metpy-compatibility.md +0 -0
  158. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/moisture.md +0 -0
  159. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/parallelism.md +0 -0
  160. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/severe-weather.md +0 -0
  161. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/smoothing.md +0 -0
  162. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/thermodynamics.md +0 -0
  163. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/units-and-pint.md +0 -0
  164. {metrust-0.4.2 → metrust-0.4.3}/docs/methodology/wind.md +0 -0
  165. {metrust-0.4.2 → metrust-0.4.3}/docs/performance.md +0 -0
  166. {metrust-0.4.2 → metrust-0.4.3}/docs/tutorials/first-grid.md +0 -0
  167. {metrust-0.4.2 → metrust-0.4.3}/docs/tutorials/first-sounding.md +0 -0
  168. {metrust-0.4.2 → metrust-0.4.3}/docs/tutorials/reading-the-numbers.md +0 -0
  169. {metrust-0.4.2 → metrust-0.4.3}/docs/tutorials/recipes.md +0 -0
  170. {metrust-0.4.2 → metrust-0.4.3}/docs/tutorials/weather-101.md +0 -0
  171. {metrust-0.4.2 → metrust-0.4.3}/examples/cookbook_500hpa_grid.py +0 -0
  172. {metrust-0.4.2 → metrust-0.4.3}/examples/cookbook_sounding.py +0 -0
  173. {metrust-0.4.2 → metrust-0.4.3}/examples/sounderpy_dropin.py +0 -0
  174. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/__init__.py +0 -0
  175. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/constants/__init__.py +0 -0
  176. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/interpolate/__init__.py +0 -0
  177. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/io/__init__.py +0 -0
  178. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/plots/__init__.py +0 -0
  179. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/units.py +0 -0
  180. {metrust-0.4.2 → metrust-0.4.3}/python/metrust/xarray.py +0 -0
  181. {metrust-0.4.2 → metrust-0.4.3}/src/lib.rs +0 -0
  182. {metrust-0.4.2 → metrust-0.4.3}/src/py_atmo.rs +0 -0
  183. {metrust-0.4.2 → metrust-0.4.3}/src/py_constants.rs +0 -0
  184. {metrust-0.4.2 → metrust-0.4.3}/src/py_interpolate.rs +0 -0
  185. {metrust-0.4.2 → metrust-0.4.3}/src/py_io.rs +0 -0
  186. {metrust-0.4.2 → metrust-0.4.3}/src/py_kinematics.rs +0 -0
  187. {metrust-0.4.2 → metrust-0.4.3}/src/py_severe.rs +0 -0
  188. {metrust-0.4.2 → metrust-0.4.3}/src/py_smooth.rs +0 -0
  189. {metrust-0.4.2 → metrust-0.4.3}/src/py_thermo.rs +0 -0
  190. {metrust-0.4.2 → metrust-0.4.3}/src/py_utils.rs +0 -0
  191. {metrust-0.4.2 → metrust-0.4.3}/src/py_wind.rs +0 -0
  192. {metrust-0.4.2 → metrust-0.4.3}/tests/api_audit_calc.md +0 -0
  193. {metrust-0.4.2 → metrust-0.4.3}/tests/api_audit_other.md +0 -0
  194. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmark.py +0 -0
  195. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmark_gpu.py +0 -0
  196. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_01_hrrr_severe.py +0 -0
  197. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_02_gfs_upper_air.py +0 -0
  198. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_03_rap_warm_front.py +0 -0
  199. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_04_nam_winter.py +0 -0
  200. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_05_hrrr_supercell.py +0 -0
  201. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_06_gfs_jet.py +0 -0
  202. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_07_hrrr_fire.py +0 -0
  203. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_08_era5_tropical.py +0 -0
  204. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_09_rap_aviation.py +0 -0
  205. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_10_hrrr_squall.py +0 -0
  206. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_11_gfs_cold_air.py +0 -0
  207. {metrust-0.4.2 → metrust-0.4.3}/tests/benchmarks/bench_12_hrrr_pbl.py +0 -0
  208. {metrust-0.4.2 → metrust-0.4.3}/tests/sounding_3way.py +0 -0
  209. {metrust-0.4.2 → metrust-0.4.3}/tests/sounding_comparison.png +0 -0
  210. {metrust-0.4.2 → metrust-0.4.3}/tests/test_gpu_backend.py +0 -0
  211. {metrust-0.4.2 → metrust-0.4.3}/tests/test_metpy_dropin_compat.py +0 -0
  212. {metrust-0.4.2 → metrust-0.4.3}/tests/test_python_compat.py +0 -0
  213. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity.py +0 -0
  214. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_interp_dataset.py +0 -0
  215. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_kinematics_extra.py +0 -0
  216. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_remaining.py +0 -0
  217. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_sounding_core.py +0 -0
  218. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_thermo_layers.py +0 -0
  219. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_utils_misc.py +0 -0
  220. {metrust-0.4.2 → metrust-0.4.3}/tests/test_runtime_parity_wind_profiles.py +0 -0
  221. {metrust-0.4.2 → metrust-0.4.3}/tests/test_signature_parity.py +0 -0
  222. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_constants.py +0 -0
  223. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_edge_cases.py +0 -0
  224. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_kinematics.py +0 -0
  225. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_severe_atmo.py +0 -0
  226. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_smooth_interp.py +0 -0
  227. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_thermo.py +0 -0
  228. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_units.py +0 -0
  229. {metrust-0.4.2 → metrust-0.4.3}/tests/verify_wind.py +0 -0
@@ -5,23 +5,31 @@ on:
5
5
  branches: [master, main]
6
6
  pull_request:
7
7
 
8
+ env:
9
+ METPY_VERSION: "1.7.1"
10
+
8
11
  jobs:
9
- test:
12
+ smoke:
13
+ name: Smoke (${{ matrix.os }}, py${{ matrix.python-version }})
10
14
  runs-on: ${{ matrix.os }}
11
15
  strategy:
16
+ fail-fast: false
12
17
  matrix:
13
- os: [ubuntu-latest, windows-latest, macos-latest]
14
- python-version: ["3.10", "3.12"]
18
+ os: [ubuntu-latest, windows-latest, macos-14]
19
+ python-version: ["3.12"]
15
20
  steps:
16
- - uses: actions/checkout@v4
21
+ - uses: actions/checkout@v5
17
22
 
18
- - uses: actions/setup-python@v5
23
+ - uses: actions/setup-python@v6
19
24
  with:
20
25
  python-version: ${{ matrix.python-version }}
21
26
 
22
27
  - name: Install Rust
23
28
  uses: dtolnay/rust-toolchain@stable
24
29
 
30
+ - name: Rust cache
31
+ uses: Swatinem/rust-cache@v2
32
+
25
33
  - name: Install package and test deps
26
34
  run: |
27
35
  python -m pip install --upgrade pip
@@ -33,11 +41,47 @@ jobs:
33
41
  - name: Run Python compatibility tests
34
42
  run: python -m pytest tests/test_python_compat.py -q
35
43
 
44
+ differential:
45
+ name: Differential (${{ matrix.mode }}, py${{ matrix.python-version }})
46
+ runs-on: ubuntu-latest
47
+ strategy:
48
+ fail-fast: false
49
+ matrix:
50
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
51
+ mode: ["metrust-only", "metpy", "metpy-xarray"]
52
+ steps:
53
+ - uses: actions/checkout@v5
54
+
55
+ - uses: actions/setup-python@v6
56
+ with:
57
+ python-version: ${{ matrix.python-version }}
58
+
59
+ - name: Install Rust
60
+ uses: dtolnay/rust-toolchain@stable
61
+
62
+ - name: Rust cache
63
+ uses: Swatinem/rust-cache@v2
64
+
65
+ - name: Install test dependencies
66
+ shell: bash
67
+ run: |
68
+ python -m pip install --upgrade pip
69
+ python -m pip install -e "." pytest numpy pint pandas
70
+ if [[ "${{ matrix.mode }}" != "metrust-only" ]]; then
71
+ python -m pip install "MetPy==${METPY_VERSION}"
72
+ fi
73
+ if [[ "${{ matrix.mode }}" == "metpy-xarray" ]]; then
74
+ python -m pip install xarray
75
+ fi
76
+
77
+ - name: Run differential test mode
78
+ run: python tests/run_ci_mode.py ${{ matrix.mode }}
79
+
36
80
  bench-rust:
37
81
  name: Rust Benchmarks
38
82
  runs-on: ubuntu-latest
39
83
  steps:
40
- - uses: actions/checkout@v4
84
+ - uses: actions/checkout@v5
41
85
 
42
86
  - name: Install Rust
43
87
  uses: dtolnay/rust-toolchain@stable
@@ -49,7 +93,7 @@ jobs:
49
93
  run: cargo bench --package metrust --bench calc_bench
50
94
 
51
95
  - name: Upload criterion artifacts
52
- uses: actions/upload-artifact@v4
96
+ uses: actions/upload-artifact@v7
53
97
  if: always()
54
98
  with:
55
99
  name: criterion-report
@@ -60,9 +104,9 @@ jobs:
60
104
  name: Python Benchmarks
61
105
  runs-on: ubuntu-latest
62
106
  steps:
63
- - uses: actions/checkout@v4
107
+ - uses: actions/checkout@v5
64
108
 
65
- - uses: actions/setup-python@v5
109
+ - uses: actions/setup-python@v6
66
110
  with:
67
111
  python-version: "3.12"
68
112
 
@@ -75,13 +119,13 @@ jobs:
75
119
  - name: Install metrust and MetPy
76
120
  run: |
77
121
  python -m pip install --upgrade pip
78
- python -m pip install -e "." numpy pint metpy
122
+ python -m pip install -e "." numpy pint "MetPy==${METPY_VERSION}"
79
123
 
80
124
  - name: Run three-tier benchmark
81
125
  run: python benches/bench_python.py --json
82
126
 
83
127
  - name: Upload benchmark results
84
- uses: actions/upload-artifact@v4
128
+ uses: actions/upload-artifact@v7
85
129
  if: always()
86
130
  with:
87
131
  name: python-bench-results
@@ -18,13 +18,13 @@ jobs:
18
18
  build:
19
19
  runs-on: ubuntu-latest
20
20
  steps:
21
- - uses: actions/checkout@v4
22
- - uses: actions/setup-python@v5
21
+ - uses: actions/checkout@v5
22
+ - uses: actions/setup-python@v6
23
23
  with:
24
24
  python-version: "3.12"
25
25
  - run: pip install mkdocs-material
26
26
  - run: mkdocs build
27
- - uses: actions/upload-pages-artifact@v3
27
+ - uses: actions/upload-pages-artifact@v4
28
28
  with:
29
29
  path: site
30
30
 
@@ -36,4 +36,4 @@ jobs:
36
36
  url: ${{ steps.deployment.outputs.page_url }}
37
37
  steps:
38
38
  - id: deployment
39
- uses: actions/deploy-pages@v4
39
+ uses: actions/deploy-pages@v5
@@ -22,8 +22,8 @@ jobs:
22
22
  - runner: ubuntu-22.04
23
23
  target: aarch64
24
24
  steps:
25
- - uses: actions/checkout@v4
26
- - uses: actions/setup-python@v5
25
+ - uses: actions/checkout@v5
26
+ - uses: actions/setup-python@v6
27
27
  with:
28
28
  python-version: '3.12'
29
29
  - name: Build wheels
@@ -33,7 +33,7 @@ jobs:
33
33
  args: --release --out dist -i python3.10 python3.11 python3.12 python3.13
34
34
  manylinux: auto
35
35
  - name: Upload wheels
36
- uses: actions/upload-artifact@v4
36
+ uses: actions/upload-artifact@v7
37
37
  with:
38
38
  name: wheels-linux-${{ matrix.platform.target }}
39
39
  path: dist
@@ -50,8 +50,8 @@ jobs:
50
50
  - runner: macos-14
51
51
  target: aarch64
52
52
  steps:
53
- - uses: actions/checkout@v4
54
- - uses: actions/setup-python@v5
53
+ - uses: actions/checkout@v5
54
+ - uses: actions/setup-python@v6
55
55
  with:
56
56
  python-version: '3.12'
57
57
  - name: Build wheels
@@ -60,7 +60,7 @@ jobs:
60
60
  target: ${{ matrix.platform.target }}
61
61
  args: --release --out dist
62
62
  - name: Upload wheels
63
- uses: actions/upload-artifact@v4
63
+ uses: actions/upload-artifact@v7
64
64
  with:
65
65
  name: wheels-macos-${{ matrix.platform.target }}
66
66
  path: dist
@@ -72,8 +72,8 @@ jobs:
72
72
  matrix:
73
73
  target: [x64]
74
74
  steps:
75
- - uses: actions/checkout@v4
76
- - uses: actions/setup-python@v5
75
+ - uses: actions/checkout@v5
76
+ - uses: actions/setup-python@v6
77
77
  with:
78
78
  python-version: '3.12'
79
79
  architecture: ${{ matrix.target }}
@@ -82,7 +82,7 @@ jobs:
82
82
  with:
83
83
  args: --release --out dist
84
84
  - name: Upload wheels
85
- uses: actions/upload-artifact@v4
85
+ uses: actions/upload-artifact@v7
86
86
  with:
87
87
  name: wheels-windows-${{ matrix.target }}
88
88
  path: dist
@@ -91,14 +91,14 @@ jobs:
91
91
  sdist:
92
92
  runs-on: ubuntu-latest
93
93
  steps:
94
- - uses: actions/checkout@v4
94
+ - uses: actions/checkout@v5
95
95
  - name: Build sdist
96
96
  uses: PyO3/maturin-action@v1
97
97
  with:
98
98
  command: sdist
99
99
  args: --out dist
100
100
  - name: Upload sdist
101
- uses: actions/upload-artifact@v4
101
+ uses: actions/upload-artifact@v7
102
102
  with:
103
103
  name: wheels-sdist
104
104
  path: dist
@@ -115,7 +115,7 @@ jobs:
115
115
  id-token: write # trusted publishing
116
116
  steps:
117
117
  - name: Download all wheels
118
- uses: actions/download-artifact@v4
118
+ uses: actions/download-artifact@v8
119
119
  with:
120
120
  pattern: wheels-*
121
121
  merge-multiple: true
@@ -802,7 +802,7 @@ dependencies = [
802
802
 
803
803
  [[package]]
804
804
  name = "metrust-py"
805
- version = "0.4.2"
805
+ version = "0.4.3"
806
806
  dependencies = [
807
807
  "metrust",
808
808
  "numpy",
@@ -8,7 +8,7 @@ license = "MIT"
8
8
 
9
9
  [package]
10
10
  name = "metrust-py"
11
- version = "0.4.2"
11
+ version = "0.4.3"
12
12
  edition.workspace = true
13
13
  description = "Python bindings for metrust, a Rust-powered MetPy-compatible calculation layer"
14
14
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metrust
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -127,6 +127,7 @@ _raw_calc = None # metrust._metrust.calc (T1)
127
127
  _mr_calc = None # metrust.calc (T2 -- Pint wrapper)
128
128
  _mp_calc = None # metpy.calc (T3)
129
129
  _mp_units = None # metpy.units.units
130
+ _mr_units = None # metrust.units.units
130
131
 
131
132
 
132
133
  def _import_raw():
@@ -145,6 +146,14 @@ def _import_metrust():
145
146
  return _mr_calc
146
147
 
147
148
 
149
+ def _import_metrust_units():
150
+ global _mr_units
151
+ if _mr_units is None:
152
+ from metrust.units import units as mu
153
+ _mr_units = mu
154
+ return _mr_units
155
+
156
+
148
157
  def _import_metpy():
149
158
  global _mp_calc, _mp_units
150
159
  if _mp_calc is None:
@@ -345,8 +354,16 @@ def _bench_wind(tiers):
345
354
  lambda: rc.storm_relative_helicity(u_p, v_p, z_p, 1000.0, 10.0, 5.0)))
346
355
  if 2 in tiers:
347
356
  mc = _import_metrust()
357
+ mu = _import_metrust_units()
348
358
  results.append(run_bench(name, 2, "T2 metrust+Pint",
349
- lambda: mc.storm_relative_helicity(u_p, v_p, z_p, 1000.0, 10.0, 5.0)))
359
+ lambda: mc.storm_relative_helicity(
360
+ z_p * mu.meter,
361
+ u_p * mu("m/s"),
362
+ v_p * mu("m/s"),
363
+ 1000 * mu.meter,
364
+ storm_u=10 * mu("m/s"),
365
+ storm_v=5 * mu("m/s"),
366
+ )))
350
367
  if 3 in tiers:
351
368
  try:
352
369
  mpc, mu = _import_metpy()
@@ -17,13 +17,23 @@ calculation surface.
17
17
  | Tier | Description |
18
18
  |------|-------------|
19
19
  | **Native Rust** | Function is implemented entirely in Rust. The Python wrapper strips Pint units, calls the Rust function, and re-attaches units. No MetPy dependency. |
20
+ | **Native + Optional MetPy Delegation** | Function uses the Rust path by default, but can delegate specific parity-sensitive call forms to MetPy when MetPy is installed. |
20
21
  | **Native + Rust Array Binding** | Same as Native Rust, but the function also exposes a vectorized `_array` variant in the Rust extension so that array inputs are processed in a single FFI call instead of element-wise Python loops. 28 functions have this optimization. |
21
22
  | **MetPy Shim** | Module forwards attribute lookups to the corresponding MetPy module via lazy import. MetPy must be installed separately. Used for `plots`, `xarray`, and `io.Level2File`. |
22
23
 
23
- When MetPy is not installed, all `metrust.calc` functions still work (they
24
- never import MetPy). Only the shimmed surfaces (`metrust.plots`,
24
+ When MetPy is not installed, all `metrust.calc` functions still work through
25
+ their local metrust implementations. Only the shimmed surfaces (`metrust.plots`,
25
26
  `metrust.xarray`, `metrust.io.Level2File`) require MetPy at runtime.
26
27
 
28
+ Current differential-CI target:
29
+
30
+ - `MetPy 1.7.1`
31
+ - Python `3.10` through `3.13`
32
+ - dependency modes: `metrust-only`, `metrust + MetPy`, and `metrust + MetPy + xarray`
33
+
34
+ For the exact list of parity-sensitive `metrust.calc` paths that may delegate
35
+ to MetPy when available, see the [delegation ledger](delegation-ledger.md).
36
+
27
37
  ---
28
38
 
29
39
  ## 2. metrust.calc Function Matrix
@@ -69,15 +79,15 @@ never import MetPy). Only the shimmed surfaces (`metrust.plots`,
69
79
  | `mixing_ratio_from_specific_humidity` | Native + Array | `metpy.calc.mixing_ratio_from_specific_humidity` | |
70
80
  | `specific_humidity_from_mixing_ratio` | Native + Array | `metpy.calc.specific_humidity_from_mixing_ratio` | |
71
81
  | `lcl` | Native | `metpy.calc.lcl` | Scalar only. Returns (p_lcl, t_lcl). Rust also exposes `lcl_pressure` and `lcl_pressure_array` internally. See section 5 for approximation differences. |
72
- | `lfc` | Native (profile) | `metpy.calc.lfc` | Operates on full sounding profiles. |
73
- | `el` | Native (profile) | `metpy.calc.el` | Operates on full sounding profiles. |
74
- | `cape_cin` | Native (profile) | `metpy.calc.cape_cin` | Extended signature: supports parcel_type, ml_depth, mu_depth, top_m, and returns (CAPE, CIN, LCL height, LFC height). |
82
+ | `lfc` | Native (profile) | `metpy.calc.lfc` | Native by default; optionally delegates to MetPy for quantity-profile parity-sensitive cases. |
83
+ | `el` | Native (profile) | `metpy.calc.el` | Native by default; optionally delegates to MetPy for quantity-profile parity-sensitive cases. |
84
+ | `cape_cin` | Native (profile) | `metpy.calc.cape_cin` | Native by default; MetPy parcel-profile form can optionally delegate for exact parity. Extended signature supports parcel_type, ml_depth, mu_depth, top_m, and returns (CAPE, CIN, LCL height, LFC height). |
75
85
  | `surface_based_cape_cin` | Native (profile) | `metpy.calc.surface_based_cape_cin` | |
76
86
  | `mixed_layer_cape_cin` | Native (profile) | `metpy.calc.mixed_layer_cape_cin` | |
77
87
  | `most_unstable_cape_cin` | Native (profile) | `metpy.calc.most_unstable_cape_cin` | |
78
- | `downdraft_cape` | Native (profile) | `metpy.calc.downdraft_cape` | |
88
+ | `downdraft_cape` | Native (profile) | `metpy.calc.downdraft_cape` | Native by default; optionally delegates on quantity-profile calls when MetPy is available. |
79
89
  | `parcel_profile` | Native (profile) | `metpy.calc.parcel_profile` | |
80
- | `parcel_profile_with_lcl` | Native (profile) | `metpy.calc.parcel_profile_with_lcl` | |
90
+ | `parcel_profile_with_lcl` | Native (profile) | `metpy.calc.parcel_profile_with_lcl` | Native by default; optionally delegates on quantity-profile calls when MetPy is available. |
81
91
  | `dry_lapse` | Native (profile) | `metpy.calc.dry_lapse` | |
82
92
  | `moist_lapse` | Native (profile) | `metpy.calc.moist_lapse` | |
83
93
  | `ccl` | Native (profile) | `metpy.calc.ccl` | Convective Condensation Level. |
@@ -178,7 +188,7 @@ major moisture conversions:
178
188
  | `frontogenesis` | Native (grid) | `metpy.calc.frontogenesis` | Petterssen frontogenesis. |
179
189
  | `geostrophic_wind` | Native (grid) | `metpy.calc.geostrophic_wind` | |
180
190
  | `ageostrophic_wind` | Native (grid) | `metpy.calc.ageostrophic_wind` | |
181
- | `potential_vorticity_baroclinic` | Native (grid) | `metpy.calc.potential_vorticity_baroclinic` | Ertel PV. |
191
+ | `potential_vorticity_baroclinic` | Native (grid) | `metpy.calc.potential_vorticity_baroclinic` | Ertel PV. Native by default with optional MetPy delegation on parity-sensitive quantity/DataArray calls. |
182
192
  | `potential_vorticity_barotropic` | Native (grid) | `metpy.calc.potential_vorticity_barotropic` | |
183
193
  | `normal_component` | Native (profile) | `metpy.calc.normal_component` | Cross-section decomposition. |
184
194
  | `tangential_component` | Native (profile) | `metpy.calc.tangential_component` | Cross-section decomposition. |
@@ -196,7 +206,7 @@ major moisture conversions:
196
206
  | `stretching_deformation` | Native (grid) | `metpy.calc.stretching_deformation` | |
197
207
  | `total_deformation` | Native (grid) | `metpy.calc.total_deformation` | |
198
208
  | `geospatial_gradient` | Native (grid) | (no direct MetPy equivalent) | Gradient on lat/lon grids with spherical corrections. |
199
- | `geospatial_laplacian` | Native (grid) | (no direct MetPy equivalent) | Laplacian on lat/lon grids with spherical corrections. |
209
+ | `geospatial_laplacian` | Native (grid) | (no direct MetPy equivalent) | Laplacian on lat/lon grids with spherical corrections. Native by default with optional MetPy delegation on parity-sensitive quantity/DataArray calls. |
200
210
  | `advection_3d` | Native (grid) | (no direct MetPy equivalent) | 3-D advection including vertical term. |
201
211
 
202
212
  ### 2.5 Severe Weather Parameters
@@ -0,0 +1,29 @@
1
+ # Optional MetPy Delegation Ledger
2
+
3
+ `metrust.calc` is Rust-first by default, but a small parity-sensitive subset can
4
+ delegate to `metpy.calc` when MetPy is installed. This page is the explicit
5
+ ledger for that behavior.
6
+
7
+ Current compatibility target:
8
+
9
+ - MetPy `1.7.1`
10
+ - Python `3.10` to `3.13`
11
+ - CI modes: `metrust-only`, `metrust + MetPy`, `metrust + MetPy + xarray`
12
+
13
+ ## Calc Delegations
14
+
15
+ | Function | Delegates When | Local Fallback |
16
+ |---|---|---|
17
+ | `lfc` | Quantity profile inputs, especially MetPy's more complex `which=` handling | metrust native profile intersection solver |
18
+ | `el` | Quantity profile inputs, especially MetPy's more complex `which=` handling | metrust native profile intersection solver |
19
+ | `cape_cin` | MetPy parcel-profile form where the 4th positional argument is temperature-like | metrust native CAPE/CIN integration |
20
+ | `downdraft_cape` | Quantity profile inputs when MetPy is available | metrust native DCAPE layer selection and integration |
21
+ | `parcel_profile_with_lcl` | Quantity profile inputs in the MetPy profile-returning form | metrust native interpolation and parcel-trace construction |
22
+ | `potential_vorticity_baroclinic` | Quantity/DataArray inputs in the MetPy-style baroclinic-PV form | metrust native PV computation with local dx/dy and latitude handling |
23
+ | `geospatial_laplacian` | Quantity/DataArray geospatial-laplacian inputs when MetPy is available | metrust native geospatial gradient and derivative path |
24
+
25
+ ## CI Guarantees
26
+
27
+ - `tests/test_delegation_ledger.py` verifies the ledger stays in sync with the code.
28
+ - The same test file verifies delegated functions still run with MetPy blocked.
29
+ - Differential CI runs the relevant suites against pinned MetPy `1.7.1`.
@@ -108,3 +108,4 @@ nav:
108
108
  - I/O Formats: methodology/io-formats.md
109
109
  - Performance: performance.md
110
110
  - Compatibility: compatibility.md
111
+ - Delegation Ledger: delegation-ledger.md
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "metrust"
7
- version = "0.4.2"
7
+ version = "0.4.3"
8
8
  description = "Rust-powered MetPy-compatible calculation layer with optional GPU acceleration"
9
9
  requires-python = ">=3.9"
10
10
  license = {text = "MIT"}
@@ -43,6 +43,49 @@ class InvalidSoundingError(Exception):
43
43
  _BACKEND = "cpu"
44
44
  _GPU_CALC = None
45
45
 
46
+ METPY_COMPATIBILITY_TARGET = {
47
+ "metpy": "1.7.1",
48
+ "python": ("3.10", "3.11", "3.12", "3.13"),
49
+ }
50
+
51
+ METPY_OPTIONAL_CALC_DELEGATIONS = (
52
+ {
53
+ "function": "lfc",
54
+ "trigger": "Quantity profile inputs, with MetPy-preferred handling for complex which selections.",
55
+ "fallback": "Native profile intersection solver in metrust.",
56
+ },
57
+ {
58
+ "function": "el",
59
+ "trigger": "Quantity profile inputs, with MetPy-preferred handling for complex which selections.",
60
+ "fallback": "Native profile intersection solver in metrust.",
61
+ },
62
+ {
63
+ "function": "cape_cin",
64
+ "trigger": "MetPy parcel-profile form where the 4th positional argument is temperature-like.",
65
+ "fallback": "Native CAPE/CIN integration path in metrust.",
66
+ },
67
+ {
68
+ "function": "downdraft_cape",
69
+ "trigger": "Quantity profile inputs when MetPy is available.",
70
+ "fallback": "Native metrust DCAPE layer-selection and integration path.",
71
+ },
72
+ {
73
+ "function": "parcel_profile_with_lcl",
74
+ "trigger": "Quantity profile inputs in the profile-returning MetPy form.",
75
+ "fallback": "Native metrust profile interpolation and parcel trace path.",
76
+ },
77
+ {
78
+ "function": "potential_vorticity_baroclinic",
79
+ "trigger": "Quantity/DataArray inputs in the MetPy-style baroclinic PV calling form.",
80
+ "fallback": "Native metrust PV computation with local dx/dy and latitude handling.",
81
+ },
82
+ {
83
+ "function": "geospatial_laplacian",
84
+ "trigger": "Quantity/DataArray geospatial laplacian inputs when MetPy is available.",
85
+ "fallback": "Native metrust geospatial gradient and derivative path.",
86
+ },
87
+ )
88
+
46
89
 
47
90
  def _normalize_backend_name(backend):
48
91
  name = str(backend).strip().lower()
@@ -5386,6 +5429,12 @@ def geospatial_laplacian(f, *args, dx=None, dy=None, x_dim=-1, y_dim=-2,
5386
5429
  dx, dy = _resolve_dx_dy(f, dx=dx, dy=dy, latitude=latitude, longitude=longitude)
5387
5430
  if dx is None or dy is None:
5388
5431
  raise TypeError("geospatial_laplacian requires dx/dy or inferable latitude/longitude coordinates")
5432
+ if hasattr(f, "magnitude"):
5433
+ f_arr = np.asarray(f.magnitude, dtype=np.float64)
5434
+ elif _is_dataarray_like(f):
5435
+ f_arr = np.asarray(f.values, dtype=np.float64)
5436
+ else:
5437
+ f_arr = np.asarray(f, dtype=np.float64)
5389
5438
  if parallel_scale is None and meridional_scale is None:
5390
5439
  ps, ms = _get_scale_factors(f)
5391
5440
  parallel_scale = ps if ps is not None else parallel_scale
@@ -5403,13 +5452,13 @@ def geospatial_laplacian(f, *args, dx=None, dy=None, x_dim=-1, y_dim=-2,
5403
5452
  longitude=longitude,
5404
5453
  crs=crs,
5405
5454
  )
5406
- x_axis = x_dim % np.ndim(np.asarray(_strip(f) if hasattr(f, "to") else f))
5407
- y_axis = y_dim % np.ndim(np.asarray(_strip(f) if hasattr(f, "to") else f))
5455
+ x_axis = x_dim % f_arr.ndim
5456
+ y_axis = y_dim % f_arr.ndim
5408
5457
  term_x = first_derivative(grad_u, delta=dx, axis=x_axis)
5409
5458
  term_y = first_derivative(grad_v, delta=dy, axis=y_axis)
5410
5459
  return term_x + term_y
5411
- x_axis = x_dim % np.ndim(np.asarray(_strip(f) if hasattr(f, "to") else f))
5412
- y_axis = y_dim % np.ndim(np.asarray(_strip(f) if hasattr(f, "to") else f))
5460
+ x_axis = x_dim % f_arr.ndim
5461
+ y_axis = y_dim % f_arr.ndim
5413
5462
  return second_derivative(f, delta=dx, axis=x_axis) + second_derivative(f, delta=dy, axis=y_axis)
5414
5463
 
5415
5464
 
@@ -6164,12 +6213,15 @@ def smooth_window(scalar_grid, window, passes=1, normalize_weights=True):
6164
6213
  )
6165
6214
 
6166
6215
  data_units = getattr(scalar_grid, "units", None)
6216
+ unit_str = str(data_units) if data_units is not None else None
6217
+ if unit_str is None:
6218
+ unit_str = getattr(getattr(scalar_grid, "attrs", None), "get", lambda *_: None)("units")
6167
6219
  data = np.array(getattr(scalar_grid, "magnitude", scalar_grid))
6168
6220
  for _ in range(int(passes)):
6169
6221
  data[inner_full_index] = sum(
6170
6222
  weights[index] * data[offset_full_index(index)] for index in weight_indexes
6171
6223
  )
6172
- return data * data_units if data_units is not None else data
6224
+ return _wrap_result_like(scalar_grid, data, unit_str=unit_str)
6173
6225
 
6174
6226
 
6175
6227
  def _gradient_axes_and_positions(f, axes, coordinates, deltas):
@@ -8222,19 +8274,12 @@ class _MetPyCalcSignatureHook(importlib.abc.MetaPathFinder, importlib.abc.Loader
8222
8274
  if fullname != "metpy.calc":
8223
8275
  return None
8224
8276
 
8225
- for finder in sys.meta_path:
8226
- if finder is self:
8227
- continue
8228
- find_spec = getattr(finder, "find_spec", None)
8229
- if find_spec is None:
8230
- continue
8231
- spec = find_spec(fullname, path, target)
8232
- if spec is None:
8233
- continue
8234
- self._wrapped_loader = spec.loader
8235
- spec.loader = self
8236
- return spec
8237
- return None
8277
+ spec = importlib.machinery.PathFinder.find_spec(fullname, path)
8278
+ if spec is None:
8279
+ return None
8280
+ self._wrapped_loader = spec.loader
8281
+ spec.loader = self
8282
+ return spec
8238
8283
 
8239
8284
  def create_module(self, spec):
8240
8285
  if self._wrapped_loader is not None and hasattr(self._wrapped_loader, "create_module"):
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ import sys
5
+
6
+
7
+ MODE_TESTS = {
8
+ "metrust-only": [
9
+ "tests/test_python_compat.py",
10
+ "tests/test_delegation_ledger.py",
11
+ ],
12
+ "metpy": [
13
+ "tests/test_signature_parity.py",
14
+ "tests/test_runtime_parity.py",
15
+ "tests/test_runtime_parity_sounding_core.py",
16
+ "tests/test_runtime_parity_thermo_layers.py",
17
+ "tests/test_runtime_parity_wind_profiles.py",
18
+ "tests/test_runtime_parity_remaining.py",
19
+ "tests/test_delegation_ledger.py",
20
+ "tests/test_cookbook_replays.py::test_cookbook_sounding_workflow_replay",
21
+ ],
22
+ "metpy-xarray": [
23
+ "tests/test_metpy_dropin_compat.py",
24
+ "tests/test_runtime_parity_interp_dataset.py",
25
+ "tests/test_runtime_parity_kinematics_extra.py",
26
+ "tests/test_runtime_parity_utils_misc.py",
27
+ "tests/test_delegation_ledger.py",
28
+ "tests/test_cookbook_replays.py::test_cookbook_grid_workflow_replay",
29
+ "tests/test_cookbook_replays.py::test_cookbook_xarray_workflow_replay",
30
+ ],
31
+ }
32
+
33
+
34
+ def main() -> int:
35
+ if len(sys.argv) != 2 or sys.argv[1] not in MODE_TESTS:
36
+ valid = ", ".join(sorted(MODE_TESTS))
37
+ raise SystemExit(f"usage: {sys.argv[0]} <mode>; valid modes: {valid}")
38
+
39
+ mode = sys.argv[1]
40
+ cmd = [sys.executable, "-m", "pytest", "-q", *MODE_TESTS[mode]]
41
+ return subprocess.call(cmd)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ raise SystemExit(main())