PyGeoFetch 2.6.3.0__tar.gz → 2.6.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/CHANGELOG.md +7 -7
  2. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/LICENSE +0 -0
  3. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/MANIFEST.in +0 -0
  4. {pygeofetch-2.6.3.0/pygeofetch.egg-info → pygeofetch-2.6.4.0}/PKG-INFO +4 -2
  5. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/README.md +2 -2
  6. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/__init__.py +5 -2
  7. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/__init__.py +0 -0
  8. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/auth_commands.py +0 -0
  9. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/classify_commands.py +77 -15
  10. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/config_commands.py +0 -0
  11. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/download_commands.py +0 -0
  12. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/index_commands.py +186 -36
  13. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/main.py +21 -7
  14. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/monitor_commands.py +0 -0
  15. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/multisensor_commands.py +0 -0
  16. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/optical_commands.py +92 -16
  17. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/pipeline_process_commands.py +0 -0
  18. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/postprocess_commands.py +31 -7
  19. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/preprocess_commands.py +0 -0
  20. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/sar_commands.py +0 -0
  21. pygeofetch-2.6.4.0/pygeofetch/cli/scale_commands.py +288 -0
  22. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/cli/search_commands.py +1 -1
  23. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/config/__init__.py +0 -0
  24. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/config/defaults.yaml +0 -0
  25. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/config/settings.py +0 -0
  26. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/__init__.py +0 -0
  27. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/authenticator.py +0 -0
  28. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/cache_manager.py +0 -0
  29. pygeofetch-2.6.4.0/pygeofetch/core/chunked_processor.py +324 -0
  30. pygeofetch-2.6.4.0/pygeofetch/core/data_formats/__init__.py +23 -0
  31. pygeofetch-2.6.4.0/pygeofetch/core/data_formats/geoparquet_io.py +216 -0
  32. pygeofetch-2.6.4.0/pygeofetch/core/data_formats/zarr_io.py +250 -0
  33. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/data_organizer.py +5 -1
  34. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/downloader.py +0 -0
  35. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/engine.py +52 -2
  36. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/logging.py +194 -1
  37. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/monitor.py +0 -0
  38. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/orbits.py +60 -11
  39. pygeofetch-2.6.4.0/pygeofetch/core/progress.py +175 -0
  40. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/scheduler.py +0 -0
  41. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/searcher.py +18 -12
  42. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/core/state.py +0 -0
  43. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/geotech/__init__.py +0 -0
  44. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/geotech/risk_mapper.py +0 -0
  45. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/__init__.py +0 -0
  46. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/advanced_safeguards.py +38 -21
  47. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/analysis.py +0 -0
  48. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/annotation.py +25 -4
  49. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/atmosphere.py +0 -0
  50. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/auto_fallback.py +4 -2
  51. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/coregister.py +0 -0
  52. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/deburst.py +0 -0
  53. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/esd.py +0 -0
  54. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/extraction.py +0 -0
  55. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/feasibility.py +66 -21
  56. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/flatearth.py +0 -0
  57. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/geolocation.py +0 -0
  58. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/gpu.py +0 -0
  59. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/interferogram.py +0 -0
  60. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/ionosphere.py +0 -0
  61. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/offset_geometry.py +0 -0
  62. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/offset_tracking.py +0 -0
  63. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/preflight.py +272 -59
  64. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/provenance.py +0 -0
  65. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/ps_selection.py +0 -0
  66. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/splitspectrum_diagnostic.py +0 -0
  67. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/stack_selection.py +0 -0
  68. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/synthetic.py +0 -0
  69. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/timeseries.py +0 -0
  70. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/unwrap.py +0 -0
  71. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/validate.py +0 -0
  72. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/visualize.py +0 -0
  73. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/insar/workflow.py +0 -0
  74. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/meta.yaml +1 -1
  75. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/models/__init__.py +0 -0
  76. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/models/download_task.py +3 -0
  77. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/models/satellite_data.py +0 -0
  78. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/models/search_query.py +0 -0
  79. pygeofetch-2.6.4.0/pygeofetch/models/stream_options.py +141 -0
  80. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/models/user_auth.py +0 -0
  81. pygeofetch-2.6.4.0/pygeofetch/multisensor/_init.py +55 -0
  82. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/multisensor/dem_differencing.py +55 -9
  83. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/multisensor/flood_mapping.py +59 -19
  84. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/multisensor/insar_optical_fusion.py +16 -7
  85. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/multisensor/terrain_corrected_change.py +58 -12
  86. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/multisensor/vegetation_disturbance.py +74 -26
  87. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/optical/__init__.py +1 -1
  88. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/optical/offset_tracking.py +1 -1
  89. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/__init__.py +0 -0
  90. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/base.py +18 -7
  91. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/batch.py +0 -0
  92. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/classification.py +72 -27
  93. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/indices.py +69 -29
  94. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/pipeline.py +0 -0
  95. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/postprocessor.py +72 -14
  96. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/preprocessor.py +9 -2
  97. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/sar.py +0 -0
  98. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processing/uq_exporter.py +0 -0
  99. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processor/__init__.py +0 -0
  100. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processor/indices.py +1 -1
  101. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processor/landsat.py +0 -0
  102. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processor/loader.py +0 -0
  103. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processor/stacker.py +0 -0
  104. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/processor/timeseries.py +0 -0
  105. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/__init__.py +1 -1
  106. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/airbus_oneatlas.py +0 -0
  107. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/alaska_satellite_facility.py +9 -7
  108. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/aws_earth.py +6 -3
  109. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/base.py +21 -0
  110. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/copernicus.py +0 -0
  111. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/copernicus_nodes.py +2 -2
  112. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/digitalglobe.py +1 -1
  113. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/earth_explorer_additional.py +1 -1
  114. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/element84.py +0 -0
  115. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/eodag_provider.py +0 -0
  116. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/esa_scihub.py +0 -0
  117. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/geoserver_generic.py +6 -6
  118. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/google_earth_engine.py +0 -0
  119. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/inpe_cbers.py +3 -3
  120. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/isro_bhuvan.py +5 -5
  121. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/jaxa_earth.py +1 -1
  122. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/maxar_gbdx.py +5 -5
  123. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/nasa_earthdata.py +1 -1
  124. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/nasa_earthdata_cloud.py +7 -3
  125. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/noaa_big_data.py +0 -0
  126. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/opentopography.py +1 -1
  127. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/planet.py +1 -1
  128. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/planetary_computer.py +17 -0
  129. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/sentinel_hub.py +1 -1
  130. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/terrabotics.py +0 -0
  131. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/providers/usgs.py +1 -1
  132. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/__init__.py +1 -1
  133. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/_native.py +0 -0
  134. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/_ost.py +0 -0
  135. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/_sarxarray.py +0 -0
  136. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/extraction.py +0 -0
  137. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/math.py +0 -0
  138. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/pipelines.py +0 -0
  139. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/sar/processor.py +1 -1
  140. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/stac_compute/__init__.py +0 -0
  141. pygeofetch-2.6.4.0/pygeofetch/stac_compute/burst_streaming.py +253 -0
  142. pygeofetch-2.6.4.0/pygeofetch/stac_compute/cog_streamer.py +186 -0
  143. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/stac_compute/lightweight_prefetch.py +0 -0
  144. pygeofetch-2.6.4.0/pygeofetch/stac_compute/window_calculator.py +134 -0
  145. pygeofetch-2.6.4.0/pygeofetch/streaming/__init__.py +37 -0
  146. pygeofetch-2.6.4.0/pygeofetch/streaming/scene.py +295 -0
  147. pygeofetch-2.6.4.0/pygeofetch/streaming/windowed.py +402 -0
  148. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/__init__.py +0 -0
  149. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/file_utils.py +0 -0
  150. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/gcp_recovery.py +0 -0
  151. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/geo_utils.py +0 -0
  152. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/geocoding.py +16 -10
  153. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/logging_setup.py +0 -0
  154. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/retry_handler.py +0 -0
  155. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/sar_math.py +0 -0
  156. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/utils/validators.py +0 -0
  157. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/validation/__init__.py +0 -0
  158. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/validation/optical_validator.py +0 -0
  159. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/viz/__init__.py +0 -0
  160. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/viz/map.py +0 -0
  161. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch/viz/plot.py +0 -0
  162. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0/pygeofetch.egg-info}/PKG-INFO +4 -2
  163. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch.egg-info/SOURCES.txt +16 -0
  164. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch.egg-info/requires.txt +2 -0
  165. pygeofetch-2.6.4.0/pygeofetch.egg-info/top_level.txt +1 -0
  166. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pyproject.toml +3 -1
  167. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/setup.cfg +0 -0
  168. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_advanced_safeguards.py +0 -0
  169. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_airbus_oneatlas.py +0 -0
  170. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_alaska_satellite_facility.py +0 -0
  171. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_atmospheric_circular_regression.py +0 -0
  172. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_auto_fallback.py +0 -0
  173. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_auto_fallback_fixed.py +22 -8
  174. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_build_sbas_network-new.py +0 -0
  175. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_build_sbas_network.py +0 -0
  176. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_burst_metadata.py +0 -0
  177. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_burst_processing_integration.py +0 -0
  178. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_burst_sync_large_gap.py +0 -0
  179. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_burst_sync_prescreening.py +0 -0
  180. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_burst_synchronization.py +0 -0
  181. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_circuit_breaker_wiring.py +0 -0
  182. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_cli_optical_validation.py +0 -0
  183. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_copernicus_nodes.py +0 -0
  184. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_coregister_integration.py +0 -0
  185. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_coregister_upgrades (1).py +0 -0
  186. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_coregister_upgrades.py +0 -0
  187. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_credential_encryption.py +0 -0
  188. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_data_organizer.py +0 -0
  189. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_dem_differencing_pipeline.py +0 -0
  190. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_digitalglobe.py +0 -0
  191. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_earth_explorer_additional.py +0 -0
  192. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_era5_atmospheric_correction.py +0 -0
  193. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_esa_scihub.py +0 -0
  194. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_extraction.py +0 -0
  195. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_flat_earth_phase.py +0 -0
  196. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_flood_mapping_pipeline.py +0 -0
  197. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_gcp_reprojection.py +0 -0
  198. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_geology_indices_and_rvi_fix.py +0 -0
  199. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_geoserver_generic.py +0 -0
  200. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_google_earth_engine.py +0 -0
  201. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_inpe_cbers.py +0 -0
  202. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_insar.py +0 -0
  203. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_insar_optical_fusion_pipeline.py +0 -0
  204. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_ionosphere.py +0 -0
  205. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_isro_bhuvan.py +0 -0
  206. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_jaxa_earth.py +0 -0
  207. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_lightweight_prefetch.py +0 -0
  208. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_map_preview_consolidation.py +0 -0
  209. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_models.py +0 -0
  210. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_monitor.py +0 -0
  211. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_nasa_earthdata_cloud_s3_fix.py +0 -0
  212. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_nasa_earthdata_public_search.py +0 -0
  213. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_noaa_big_data.py +0 -0
  214. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_offset_tracking.py +0 -0
  215. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_opentopography_pointcloud_usgs.py +0 -0
  216. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_optical_offset_tracking.py +93 -21
  217. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_optical_validation_wiring.py +0 -0
  218. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_optical_validator.py +0 -0
  219. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_optical_validator_stac.py +39 -13
  220. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_pgv_integration_contract.py +0 -0
  221. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_pipeline_process_export.py +0 -0
  222. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_planet_asset_type_fix.py +20 -16
  223. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_preflight_gate.py +0 -0
  224. pygeofetch-2.6.4.0/tests/test_preflight_quiet.py +340 -0
  225. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_preflight_spatial_baseline.py +30 -20
  226. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_provider_geometry_audit.py +1 -1
  227. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_provider_scene_disambiguation.py +0 -0
  228. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_providers.py +0 -0
  229. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_ps_selection.py +0 -0
  230. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_raster_collocation_integration.py +0 -0
  231. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_reference_pixel_and_despike.py +0 -0
  232. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_risk_mapper.py +0 -0
  233. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_risk_mapping.py +0 -0
  234. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_sar_pipelines.py +0 -0
  235. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_screen_stack_orchestration.py +0 -0
  236. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_search_download.py +0 -0
  237. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_sentinel_hub_catalog_fix.py +0 -0
  238. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_sign_convention.py +0 -0
  239. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_splitspectrum_diagnostic.py +0 -0
  240. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_stack_selection_consolidation.py +0 -0
  241. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_state.py +0 -0
  242. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_strain_and_fusion.py +0 -0
  243. pygeofetch-2.6.4.0/tests/test_streaming.py +566 -0
  244. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_terrain_corrected_change_pipeline.py +0 -0
  245. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_topo_r2_bug.py +0 -0
  246. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_uq_exporter.py +0 -0
  247. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_utils.py +0 -0
  248. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_vegetation_disturbance_pipeline.py +0 -0
  249. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_viz_plot.py +0 -0
  250. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/tests/test_wls_inversion.py +0 -0
  251. pygeofetch-2.6.3.0/pygeofetch.egg-info/top_level.txt +0 -2
  252. /pygeofetch-2.6.3.0/pygeofetch/multisensor/_init.py → /pygeofetch-2.6.4.0/pygeofetch/multisensor/__init__.py +0 -0
  253. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch.egg-info/dependency_links.txt +0 -0
  254. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch.egg-info/entry_points.txt +0 -0
  255. {pygeofetch-2.6.3.0 → pygeofetch-2.6.4.0}/pygeofetch.egg-info/not-zip-safe +0 -0
@@ -20,7 +20,7 @@ date, and marked accordingly rather than filled in with invented
20
20
  bullet points.
21
21
  ```
22
22
 
23
- ## [Unreleased] — v2.6.3.0.4
23
+ ## [Unreleased] — v2.6.4.0.4
24
24
 
25
25
  ```{note}
26
26
  Not yet published to PyPI. This entry documents work completed and
@@ -130,7 +130,7 @@ audit and remain open for a follow-up pass.
130
130
 
131
131
  ---
132
132
 
133
- ## [2.6.3.0.4] — 2026-08-25 (latest)
133
+ ## [2.6.4.0.4] — 2026-08-25 (latest)
134
134
 
135
135
  Confirmed via direct fetch of the current PyPI listing.
136
136
 
@@ -149,7 +149,7 @@ Confirmed via direct fetch of the current PyPI listing.
149
149
  - `SearchQuery.sort_ascending: bool` — earlier examples showed a `sort_order: "asc"/"desc"` string field that doesn't exist on the model (the CLI's `--sort-order` flag does convert to this internally, so CLI docs were unaffected)
150
150
  - `DownloadOptions.post_process` requires a list of `PostProcessAction` objects — passing plain strings raises a real `pydantic.ValidationError`
151
151
 
152
- ## [2.6.3.0] — 2026-08-24
152
+ ## [2.6.4.0] — 2026-08-24
153
153
  Real, verified release. Detailed notes not independently recovered from PyPI's release-history page (no distinct per-version notes exposed for this release specifically).
154
154
 
155
155
  ## [2.6.1] — 2026-08-22
@@ -261,9 +261,9 @@ recovered.
261
261
 
262
262
  ```{note}
263
263
  The previous version of this changelog had an entry labeled
264
- **"2.6.3.0.4 — 2026-07-12"** describing 22+ providers, Sentinel-1C/1D
264
+ **"2.6.4.0.4 — 2026-07-12"** describing 22+ providers, Sentinel-1C/1D
265
265
  support, SLC search with provider routing, precise orbit file
266
- management, 17 spectral indices, and various bug fixes. **2.6.3.0.4 was
266
+ management, 17 spectral indices, and various bug fixes. **2.6.4.0.4 was
267
267
  only ever released once, on 2026-08-25** — it was never released on
268
268
  2026-07-12. The date matches this real release, **1.0.8**, exactly.
269
269
  That content is reproduced below under the version it actually
@@ -406,8 +406,8 @@ The version of this file uploaded for this update had **5 entries
406
406
  covering 5 dates**. PyPI's real release history has **54 releases**.
407
407
  Specific issues found and fixed:
408
408
 
409
- 1. **Two different entries were both labeled `2.6.3.0.4`**, dated
410
- 2026-07-29 and 2026-07-12. **2.6.3.0.4 was only ever released once**,
409
+ 1. **Two different entries were both labeled `2.6.4.0.4`**, dated
410
+ 2026-07-29 and 2026-07-12. **2.6.4.0.4 was only ever released once**,
411
411
  on 2026-08-25 (confirmed directly from the live PyPI listing).
412
412
  2. **The 2026-07-12 entry's date exactly matches a real release**
413
413
  — version **1.0.8** — and its content (22+ providers, Sentinel-1C/D,
File without changes
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 2.6.3.0
3
+ Version: 2.6.4.0
4
4
  Summary: Universal satellite data pipeline + geospatial processing platform
5
5
  Author-email: Samuel Appiah Kubi <appiahkubis14@gmail.com>
6
6
  License: MIT License
@@ -43,6 +43,8 @@ Requires-Python: >=3.9
43
43
  Description-Content-Type: text/markdown
44
44
  License-File: LICENSE
45
45
  Requires-Dist: httpx>=0.27
46
+ Requires-Dist: pydantic
47
+ Requires-Dist: rich
46
48
  Requires-Dist: click>=8.1
47
49
  Requires-Dist: pydantic>=2.5
48
50
  Requires-Dist: pydantic-settings>=2.1
@@ -369,7 +371,7 @@ If you use PyGeoFetch in your research or operational work, please cite it using
369
371
  title = {PyGeoFetch: A Unified Python Framework for Multi-Provider Satellite Data Acquisition, Pre-download Quality Control, and Geospatial Processing},
370
372
  year = {2026},
371
373
  publisher = {Zenodo},
372
- version = {2.6.3.0.1},
374
+ version = {2.6.4.0.1},
373
375
  doi = {10.5281/zenodo.22087230},
374
376
  url = {https://doi.org/10.5281/zenodo.22087230}
375
377
  }
@@ -229,7 +229,7 @@ If you use PyGeoFetch in your research or operational work, please cite it using
229
229
  title = {PyGeoFetch: A Unified Python Framework for Multi-Provider Satellite Data Acquisition, Pre-download Quality Control, and Geospatial Processing},
230
230
  year = {2026},
231
231
  publisher = {Zenodo},
232
- version = {2.6.3.0.1},
232
+ version = {2.6.4.0.1},
233
233
  doi = {10.5281/zenodo.22087230},
234
234
  url = {https://doi.org/10.5281/zenodo.22087230}
235
235
  }
@@ -263,4 +263,4 @@ pip install -e ".[test]" && pytest tests/ -v
263
263
 
264
264
  ## License
265
265
 
266
- MIT — see [LICENSE](LICENSE). © 2026 Samuel Appiah Kubi.
266
+ MIT — see [LICENSE](LICENSE). © 2026 Samuel Appiah Kubi.
@@ -30,13 +30,16 @@ CLI::
30
30
  pygeofetch doctor
31
31
  """
32
32
 
33
- __version__ = "2.6.3.0.4"
33
+ __version__ = "2.6.4.0.4"
34
34
  __author__ = "PyGeoFetch Contributors"
35
35
  __license__ = "MIT"
36
36
 
37
37
  from pygeofetch.core.engine import PyGeoFetch # noqa: F401
38
+ from pygeofetch.core.logging import (
39
+ quiet_logs, # noqa: F401 (notebook-friendly logging)
40
+ )
38
41
 
39
- __all__ = ["PyGeoFetch", "__version__"]
42
+ __all__ = ["PyGeoFetch", "quiet_logs", "__version__"]
40
43
 
41
44
 
42
45
  # Optional modules — lazy imported to avoid hard dependency errors
@@ -45,7 +45,14 @@ def classify() -> None:
45
45
 
46
46
  @classify.command("kmeans")
47
47
  @click.argument("inputs", nargs=-1, type=click.Path(exists=True))
48
- @click.option("--clusters", "-k", default=5, show_default=True, type=int, help="Number of clusters.")
48
+ @click.option(
49
+ "--clusters",
50
+ "-k",
51
+ default=5,
52
+ show_default=True,
53
+ type=int,
54
+ help="Number of clusters.",
55
+ )
49
56
  @click.option("--output", "-o", default=None)
50
57
  @click.option("--random-state", default=42, show_default=True, type=int)
51
58
  # @clip_options
@@ -59,21 +66,62 @@ def kmeans_cmd(inputs, clusters, output, random_state, bbox, geometry, geometry_
59
66
  sys.exit(1)
60
67
  e = _engine()
61
68
  r = e.classify.kmeans(
62
- inputs=list(inputs), n_clusters=clusters, output=output, random_state=random_state,
63
- bbox=bbox, geometry=geometry, geometry_crs=geometry_crs,
69
+ inputs=list(inputs),
70
+ n_clusters=clusters,
71
+ output=output,
72
+ random_state=random_state,
73
+ bbox=bbox,
74
+ geometry=geometry,
75
+ geometry_crs=geometry_crs,
64
76
  )
65
77
  _pr(r, f"K-means ({clusters} clusters)")
66
78
 
67
79
 
68
80
  @classify.command("train")
69
81
  @click.argument("inputs", nargs=-1, type=click.Path(exists=True))
70
- @click.option("--training-data", required=True, type=click.Path(exists=True), help="Vector file (GeoJSON/Shapefile) with labeled training geometries.")
71
- @click.option("--class-field", required=True, help="Attribute column holding the real class label.")
72
- @click.option("--output-model", "-o", required=True, help="Where to save the trained model.")
73
- @click.option("--model-type", default="random_forest", type=click.Choice(["random_forest", "svm"]), show_default=True)
74
- @click.option("--n-estimators", default=100, show_default=True, type=int, help="Random Forest tree count.")
75
- @click.option("--test-size", default=0.2, show_default=True, type=float, help="Fraction of samples held out for real accuracy reporting.")
76
- def train_cmd(inputs, training_data, class_field, output_model, model_type, n_estimators, test_size):
82
+ @click.option(
83
+ "--training-data",
84
+ required=True,
85
+ type=click.Path(exists=True),
86
+ help="Vector file (GeoJSON/Shapefile) with labeled training geometries.",
87
+ )
88
+ @click.option(
89
+ "--class-field",
90
+ required=True,
91
+ help="Attribute column holding the real class label.",
92
+ )
93
+ @click.option(
94
+ "--output-model", "-o", required=True, help="Where to save the trained model."
95
+ )
96
+ @click.option(
97
+ "--model-type",
98
+ default="random_forest",
99
+ type=click.Choice(["random_forest", "svm"]),
100
+ show_default=True,
101
+ )
102
+ @click.option(
103
+ "--n-estimators",
104
+ default=100,
105
+ show_default=True,
106
+ type=int,
107
+ help="Random Forest tree count.",
108
+ )
109
+ @click.option(
110
+ "--test-size",
111
+ default=0.2,
112
+ show_default=True,
113
+ type=float,
114
+ help="Fraction of samples held out for real accuracy reporting.",
115
+ )
116
+ def train_cmd(
117
+ inputs,
118
+ training_data,
119
+ class_field,
120
+ output_model,
121
+ model_type,
122
+ n_estimators,
123
+ test_size,
124
+ ):
77
125
  """Train a supervised classifier from labeled vector training samples.
78
126
 
79
127
  Example: pygeofetch classify train B02.tif B03.tif B04.tif B08.tif
@@ -84,8 +132,12 @@ def train_cmd(inputs, training_data, class_field, output_model, model_type, n_es
84
132
  sys.exit(1)
85
133
  e = _engine()
86
134
  r = e.classify.train(
87
- inputs=list(inputs), training_data=training_data, class_field=class_field,
88
- output_model=output_model, model_type=model_type, n_estimators=n_estimators,
135
+ inputs=list(inputs),
136
+ training_data=training_data,
137
+ class_field=class_field,
138
+ output_model=output_model,
139
+ model_type=model_type,
140
+ n_estimators=n_estimators,
89
141
  test_size=test_size,
90
142
  )
91
143
  _pr(r, f"train ({model_type})")
@@ -93,7 +145,13 @@ def train_cmd(inputs, training_data, class_field, output_model, model_type, n_es
93
145
 
94
146
  @classify.command("predict")
95
147
  @click.argument("inputs", nargs=-1, type=click.Path(exists=True))
96
- @click.option("--model", "-m", required=True, type=click.Path(exists=True), help="A model trained via 'classify train'.")
148
+ @click.option(
149
+ "--model",
150
+ "-m",
151
+ required=True,
152
+ type=click.Path(exists=True),
153
+ help="A model trained via 'classify train'.",
154
+ )
97
155
  @click.option("--output", "-o", default=None)
98
156
  # @clip_options
99
157
  def predict_cmd(inputs, model, output, bbox, geometry, geometry_crs):
@@ -106,7 +164,11 @@ def predict_cmd(inputs, model, output, bbox, geometry, geometry_crs):
106
164
  sys.exit(1)
107
165
  e = _engine()
108
166
  r = e.classify.predict(
109
- inputs=list(inputs), model=model, output=output,
110
- bbox=bbox, geometry=geometry, geometry_crs=geometry_crs,
167
+ inputs=list(inputs),
168
+ model=model,
169
+ output=output,
170
+ bbox=bbox,
171
+ geometry=geometry,
172
+ geometry_crs=geometry_crs,
111
173
  )
112
174
  _pr(r, "predict")
@@ -22,9 +22,13 @@ def _parse_bbox(ctx, param, value):
22
22
  try:
23
23
  parts = [float(x.strip()) for x in value.split(",")]
24
24
  except ValueError:
25
- raise click.BadParameter("must be 4 comma-separated numbers: minx,miny,maxx,maxy") from None
25
+ raise click.BadParameter(
26
+ "must be 4 comma-separated numbers: minx,miny,maxx,maxy"
27
+ ) from None
26
28
  if len(parts) != 4:
27
- raise click.BadParameter("must be exactly 4 comma-separated numbers: minx,miny,maxx,maxy")
29
+ raise click.BadParameter(
30
+ "must be exactly 4 comma-separated numbers: minx,miny,maxx,maxy"
31
+ )
28
32
  return tuple(parts)
29
33
 
30
34
 
@@ -33,15 +37,21 @@ def clip_options(f):
33
37
  index command whose underlying method supports post-computation
34
38
  clipping."""
35
39
  f = click.option(
36
- "--bbox", callback=_parse_bbox, default=None,
40
+ "--bbox",
41
+ callback=_parse_bbox,
42
+ default=None,
37
43
  help="Clip the result to minx,miny,maxx,maxy (comma-separated).",
38
44
  )(f)
39
45
  f = click.option(
40
- "--geometry", default=None, type=click.Path(exists=True),
46
+ "--geometry",
47
+ default=None,
48
+ type=click.Path(exists=True),
41
49
  help="Clip the result to a GeoJSON file's geometry instead of a bbox.",
42
50
  )(f)
43
51
  f = click.option(
44
- "--geometry-crs", default="EPSG:4326", show_default=True,
52
+ "--geometry-crs",
53
+ default="EPSG:4326",
54
+ show_default=True,
45
55
  help="CRS of --bbox/--geometry coordinates.",
46
56
  )(f)
47
57
  return f
@@ -82,10 +92,17 @@ def index() -> None:
82
92
  )
83
93
  @click.option("--output", "-o", default=None)
84
94
  @click.option(
85
- "--chunked", is_flag=True,
95
+ "--chunked",
96
+ is_flag=True,
86
97
  help="Process in memory-safe tiles for large rasters (e.g. drone orthomosaics) that exceed available RAM or the 4GB GeoTIFF limit.",
87
98
  )
88
- @click.option("--tile-size", default=1024, show_default=True, type=int, help="Tile edge length in pixels when --chunked is set.")
99
+ @click.option(
100
+ "--tile-size",
101
+ default=1024,
102
+ show_default=True,
103
+ type=int,
104
+ help="Tile edge length in pixels when --chunked is set.",
105
+ )
89
106
  @clip_options
90
107
  def ndvi_cmd(red, nir, output, chunked, tile_size, bbox, geometry, geometry_crs):
91
108
  """NDVI — Normalized Difference Vegetation Index. Range: -1 to +1. Vegetation > 0.3.
@@ -95,7 +112,16 @@ def ndvi_cmd(red, nir, output, chunked, tile_size, bbox, geometry, geometry_crs)
95
112
  real, embedded band descriptions.
96
113
  """
97
114
  e = _engine()
98
- r = e.indices.ndvi(red=red, nir=nir, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
115
+ r = e.indices.ndvi(
116
+ red=red,
117
+ nir=nir,
118
+ output=output,
119
+ chunked=chunked,
120
+ tile_size=tile_size,
121
+ bbox=bbox,
122
+ geometry=geometry,
123
+ geometry_crs=geometry_crs,
124
+ )
99
125
  _pr(r, "NDVI")
100
126
 
101
127
 
@@ -103,15 +129,20 @@ def ndvi_cmd(red, nir, output, chunked, tile_size, bbox, geometry, geometry_crs)
103
129
  @click.option(
104
130
  "--rededge", required=True, type=click.Path(exists=True), help="Red edge band"
105
131
  )
106
- @click.option(
107
- "--nir", required=True, type=click.Path(exists=True), help="NIR band"
108
- )
132
+ @click.option("--nir", required=True, type=click.Path(exists=True), help="NIR band")
109
133
  @click.option("--output", "-o", default=None)
110
134
  @click.option(
111
- "--chunked", is_flag=True,
135
+ "--chunked",
136
+ is_flag=True,
112
137
  help="Process in memory-safe tiles for large rasters that exceed available RAM or the 4GB GeoTIFF limit.",
113
138
  )
114
- @click.option("--tile-size", default=1024, show_default=True, type=int, help="Tile edge length in pixels when --chunked is set.")
139
+ @click.option(
140
+ "--tile-size",
141
+ default=1024,
142
+ show_default=True,
143
+ type=int,
144
+ help="Tile edge length in pixels when --chunked is set.",
145
+ )
115
146
  @clip_options
116
147
  def ndre_cmd(rededge, nir, output, chunked, tile_size, bbox, geometry, geometry_crs):
117
148
  """NDRE — Normalized Difference Red Edge Index. Range: -1 to +1.
@@ -122,7 +153,16 @@ def ndre_cmd(rededge, nir, output, chunked, tile_size, bbox, geometry, geometry_
122
153
  both bands from one merged multi-band image.
123
154
  """
124
155
  e = _engine()
125
- r = e.indices.ndre(rededge=rededge, nir=nir, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
156
+ r = e.indices.ndre(
157
+ rededge=rededge,
158
+ nir=nir,
159
+ output=output,
160
+ chunked=chunked,
161
+ tile_size=tile_size,
162
+ bbox=bbox,
163
+ geometry=geometry,
164
+ geometry_crs=geometry_crs,
165
+ )
126
166
  _pr(r, "NDRE")
127
167
 
128
168
 
@@ -131,7 +171,9 @@ def ndre_cmd(rededge, nir, output, chunked, tile_size, bbox, geometry, geometry_
131
171
  @click.option("--red", required=True, type=click.Path(exists=True))
132
172
  @click.option("--nir", required=True, type=click.Path(exists=True))
133
173
  @click.option("--output", "-o", default=None)
134
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
174
+ @click.option(
175
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
176
+ )
135
177
  @click.option("--tile-size", default=1024, show_default=True, type=int)
136
178
  @clip_options
137
179
  def evi_cmd(blue, red, nir, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -141,7 +183,17 @@ def evi_cmd(blue, red, nir, output, chunked, tile_size, bbox, geometry, geometry
141
183
  three bands from one merged multi-band image.
142
184
  """
143
185
  e = _engine()
144
- r = e.indices.evi(blue=blue, red=red, nir=nir, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
186
+ r = e.indices.evi(
187
+ blue=blue,
188
+ red=red,
189
+ nir=nir,
190
+ output=output,
191
+ chunked=chunked,
192
+ tile_size=tile_size,
193
+ bbox=bbox,
194
+ geometry=geometry,
195
+ geometry_crs=geometry_crs,
196
+ )
145
197
  _pr(r, "EVI")
146
198
 
147
199
 
@@ -150,17 +202,31 @@ def evi_cmd(blue, red, nir, output, chunked, tile_size, bbox, geometry, geometry
150
202
  @click.option("--nir", required=True, type=click.Path(exists=True))
151
203
  @click.option("--soil-l", default=0.5, show_default=True, type=float)
152
204
  @click.option("--output", "-o", default=None)
153
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
205
+ @click.option(
206
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
207
+ )
154
208
  @click.option("--tile-size", default=1024, show_default=True, type=int)
155
209
  @clip_options
156
- def savi_cmd(red, nir, soil_l, output, chunked, tile_size, bbox, geometry, geometry_crs):
210
+ def savi_cmd(
211
+ red, nir, soil_l, output, chunked, tile_size, bbox, geometry, geometry_crs
212
+ ):
157
213
  """SAVI — Soil Adjusted Vegetation Index. Reduces soil brightness influence.
158
214
 
159
215
  Pass the SAME path to --red and --nir to auto-detect both bands
160
216
  from one merged multi-band image.
161
217
  """
162
218
  e = _engine()
163
- r = e.indices.savi(red=red, nir=nir, L=soil_l, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
219
+ r = e.indices.savi(
220
+ red=red,
221
+ nir=nir,
222
+ L=soil_l,
223
+ output=output,
224
+ chunked=chunked,
225
+ tile_size=tile_size,
226
+ bbox=bbox,
227
+ geometry=geometry,
228
+ geometry_crs=geometry_crs,
229
+ )
164
230
  _pr(r, "SAVI")
165
231
 
166
232
 
@@ -168,7 +234,9 @@ def savi_cmd(red, nir, soil_l, output, chunked, tile_size, bbox, geometry, geome
168
234
  @click.option("--green", required=True, type=click.Path(exists=True))
169
235
  @click.option("--nir", required=True, type=click.Path(exists=True))
170
236
  @click.option("--output", "-o", default=None)
171
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
237
+ @click.option(
238
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
239
+ )
172
240
  @click.option("--tile-size", default=1024, show_default=True, type=int)
173
241
  @clip_options
174
242
  def ndwi_cmd(green, nir, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -178,7 +246,16 @@ def ndwi_cmd(green, nir, output, chunked, tile_size, bbox, geometry, geometry_cr
178
246
  from one merged multi-band image.
179
247
  """
180
248
  e = _engine()
181
- r = e.indices.ndwi(green=green, nir=nir, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
249
+ r = e.indices.ndwi(
250
+ green=green,
251
+ nir=nir,
252
+ output=output,
253
+ chunked=chunked,
254
+ tile_size=tile_size,
255
+ bbox=bbox,
256
+ geometry=geometry,
257
+ geometry_crs=geometry_crs,
258
+ )
182
259
  _pr(r, "NDWI")
183
260
 
184
261
 
@@ -186,7 +263,9 @@ def ndwi_cmd(green, nir, output, chunked, tile_size, bbox, geometry, geometry_cr
186
263
  @click.option("--green", required=True, type=click.Path(exists=True))
187
264
  @click.option("--swir1", required=True, type=click.Path(exists=True))
188
265
  @click.option("--output", "-o", default=None)
189
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
266
+ @click.option(
267
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
268
+ )
190
269
  @click.option("--tile-size", default=1024, show_default=True, type=int)
191
270
  @clip_options
192
271
  def mndwi_cmd(green, swir1, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -196,7 +275,16 @@ def mndwi_cmd(green, swir1, output, chunked, tile_size, bbox, geometry, geometry
196
275
  bands from one merged multi-band image.
197
276
  """
198
277
  e = _engine()
199
- r = e.indices.mndwi(green=green, swir1=swir1, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
278
+ r = e.indices.mndwi(
279
+ green=green,
280
+ swir1=swir1,
281
+ output=output,
282
+ chunked=chunked,
283
+ tile_size=tile_size,
284
+ bbox=bbox,
285
+ geometry=geometry,
286
+ geometry_crs=geometry_crs,
287
+ )
200
288
  _pr(r, "MNDWI")
201
289
 
202
290
 
@@ -204,7 +292,9 @@ def mndwi_cmd(green, swir1, output, chunked, tile_size, bbox, geometry, geometry
204
292
  @click.option("--nir", required=True, type=click.Path(exists=True))
205
293
  @click.option("--swir1", required=True, type=click.Path(exists=True))
206
294
  @click.option("--output", "-o", default=None)
207
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
295
+ @click.option(
296
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
297
+ )
208
298
  @click.option("--tile-size", default=1024, show_default=True, type=int)
209
299
  @clip_options
210
300
  def ndbi_cmd(nir, swir1, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -214,7 +304,16 @@ def ndbi_cmd(nir, swir1, output, chunked, tile_size, bbox, geometry, geometry_cr
214
304
  from one merged multi-band image.
215
305
  """
216
306
  e = _engine()
217
- r = e.indices.ndbi(nir=nir, swir1=swir1, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
307
+ r = e.indices.ndbi(
308
+ nir=nir,
309
+ swir1=swir1,
310
+ output=output,
311
+ chunked=chunked,
312
+ tile_size=tile_size,
313
+ bbox=bbox,
314
+ geometry=geometry,
315
+ geometry_crs=geometry_crs,
316
+ )
218
317
  _pr(r, "NDBI")
219
318
 
220
319
 
@@ -222,7 +321,9 @@ def ndbi_cmd(nir, swir1, output, chunked, tile_size, bbox, geometry, geometry_cr
222
321
  @click.option("--green", required=True, type=click.Path(exists=True))
223
322
  @click.option("--swir1", required=True, type=click.Path(exists=True))
224
323
  @click.option("--output", "-o", default=None)
225
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
324
+ @click.option(
325
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
326
+ )
226
327
  @click.option("--tile-size", default=1024, show_default=True, type=int)
227
328
  @clip_options
228
329
  def ndsi_cmd(green, swir1, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -232,7 +333,16 @@ def ndsi_cmd(green, swir1, output, chunked, tile_size, bbox, geometry, geometry_
232
333
  bands from one merged multi-band image.
233
334
  """
234
335
  e = _engine()
235
- r = e.indices.ndsi(green=green, swir1=swir1, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
336
+ r = e.indices.ndsi(
337
+ green=green,
338
+ swir1=swir1,
339
+ output=output,
340
+ chunked=chunked,
341
+ tile_size=tile_size,
342
+ bbox=bbox,
343
+ geometry=geometry,
344
+ geometry_crs=geometry_crs,
345
+ )
236
346
  _pr(r, "NDSI")
237
347
 
238
348
 
@@ -240,7 +350,9 @@ def ndsi_cmd(green, swir1, output, chunked, tile_size, bbox, geometry, geometry_
240
350
  @click.option("--nir", required=True, type=click.Path(exists=True))
241
351
  @click.option("--swir1", required=True, type=click.Path(exists=True))
242
352
  @click.option("--output", "-o", default=None)
243
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
353
+ @click.option(
354
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
355
+ )
244
356
  @click.option("--tile-size", default=1024, show_default=True, type=int)
245
357
  @clip_options
246
358
  def ndmi_cmd(nir, swir1, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -250,7 +362,16 @@ def ndmi_cmd(nir, swir1, output, chunked, tile_size, bbox, geometry, geometry_cr
250
362
  from one merged multi-band image.
251
363
  """
252
364
  e = _engine()
253
- r = e.indices.ndmi(nir=nir, swir1=swir1, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
365
+ r = e.indices.ndmi(
366
+ nir=nir,
367
+ swir1=swir1,
368
+ output=output,
369
+ chunked=chunked,
370
+ tile_size=tile_size,
371
+ bbox=bbox,
372
+ geometry=geometry,
373
+ geometry_crs=geometry_crs,
374
+ )
254
375
  _pr(r, "NDMI")
255
376
 
256
377
 
@@ -258,7 +379,9 @@ def ndmi_cmd(nir, swir1, output, chunked, tile_size, bbox, geometry, geometry_cr
258
379
  @click.option("--nir", required=True, type=click.Path(exists=True))
259
380
  @click.option("--swir2", required=True, type=click.Path(exists=True))
260
381
  @click.option("--output", "-o", default=None)
261
- @click.option("--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters.")
382
+ @click.option(
383
+ "--chunked", is_flag=True, help="Process in memory-safe tiles for large rasters."
384
+ )
262
385
  @click.option("--tile-size", default=1024, show_default=True, type=int)
263
386
  @clip_options
264
387
  def nbr_cmd(nir, swir2, output, chunked, tile_size, bbox, geometry, geometry_crs):
@@ -268,7 +391,16 @@ def nbr_cmd(nir, swir2, output, chunked, tile_size, bbox, geometry, geometry_crs
268
391
  from one merged multi-band image.
269
392
  """
270
393
  e = _engine()
271
- r = e.indices.nbr(nir=nir, swir2=swir2, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
394
+ r = e.indices.nbr(
395
+ nir=nir,
396
+ swir2=swir2,
397
+ output=output,
398
+ chunked=chunked,
399
+ tile_size=tile_size,
400
+ bbox=bbox,
401
+ geometry=geometry,
402
+ geometry_crs=geometry_crs,
403
+ )
272
404
  _pr(r, "NBR")
273
405
 
274
406
 
@@ -388,15 +520,33 @@ def albedo_cmd(inputs, sensor, output):
388
520
  )
389
521
  @click.option("--output", "-o", default=None)
390
522
  @click.option(
391
- "--chunked", is_flag=True,
523
+ "--chunked",
524
+ is_flag=True,
392
525
  help="Process in memory-safe tiles for large rasters (e.g. drone orthomosaics) that exceed available RAM or the 4GB GeoTIFF limit.",
393
526
  )
394
- @click.option("--tile-size", default=1024, show_default=True, type=int, help="Tile edge length in pixels when --chunked is set.")
527
+ @click.option(
528
+ "--tile-size",
529
+ default=1024,
530
+ show_default=True,
531
+ type=int,
532
+ help="Tile edge length in pixels when --chunked is set.",
533
+ )
395
534
  @clip_options
396
- def band_math_cmd(inputs, expr, output, chunked, tile_size, bbox, geometry, geometry_crs):
535
+ def band_math_cmd(
536
+ inputs, expr, output, chunked, tile_size, bbox, geometry, geometry_crs
537
+ ):
397
538
  """Arbitrary band arithmetic. Example: --expr '(B[1]-B[0])/(B[1]+B[0])'."""
398
539
  e = _engine()
399
- r = e.indices.band_math(inputs=list(inputs), expression=expr, output=output, chunked=chunked, tile_size=tile_size, bbox=bbox, geometry=geometry, geometry_crs=geometry_crs)
540
+ r = e.indices.band_math(
541
+ inputs=list(inputs),
542
+ expression=expr,
543
+ output=output,
544
+ chunked=chunked,
545
+ tile_size=tile_size,
546
+ bbox=bbox,
547
+ geometry=geometry,
548
+ geometry_crs=geometry_crs,
549
+ )
400
550
  _pr(r, f"band-math ({expr[:40]})")
401
551
 
402
552
 
@@ -407,4 +557,4 @@ def stack_cmd(inputs, output):
407
557
  """Stack single-band rasters into a multi-band GeoTIFF."""
408
558
  e = _engine()
409
559
  r = e.indices.stack(inputs=list(inputs), output=output)
410
- _pr(r, f"stack ({len(inputs)} bands)")
560
+ _pr(r, f"stack ({len(inputs)} bands)")