pygeofetch 2.6.2.2__tar.gz → 2.6.2.4__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 (208) hide show
  1. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/CHANGELOG.md +7 -7
  2. {pygeofetch-2.6.2.2/pygeofetch.egg-info → pygeofetch-2.6.2.4}/PKG-INFO +6 -6
  3. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/README.md +4 -4
  4. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/__init__.py +1 -1
  5. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/main.py +3 -1
  6. pygeofetch-2.6.2.4/pygeofetch/cli/optical_commands.py +105 -0
  7. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/search_commands.py +121 -8
  8. pygeofetch-2.6.2.4/pygeofetch/core/data_organizer.py +364 -0
  9. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/engine.py +7 -2
  10. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/preflight.py +136 -1
  11. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/meta.yaml +1 -1
  12. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/models/satellite_data.py +49 -0
  13. pygeofetch-2.6.2.4/pygeofetch/optical/__init__.py +27 -0
  14. pygeofetch-2.6.2.4/pygeofetch/optical/offset_tracking.py +486 -0
  15. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processor/indices.py +143 -11
  16. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/airbus_oneatlas.py +1 -1
  17. pygeofetch-2.6.2.4/pygeofetch/providers/alaska_satellite_facility.py +361 -0
  18. pygeofetch-2.6.2.4/pygeofetch/providers/digitalglobe.py +423 -0
  19. pygeofetch-2.6.2.4/pygeofetch/providers/earth_explorer_additional.py +104 -0
  20. pygeofetch-2.6.2.4/pygeofetch/providers/geoserver_generic.py +377 -0
  21. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/inpe_cbers.py +114 -96
  22. pygeofetch-2.6.2.4/pygeofetch/providers/isro_bhuvan.py +357 -0
  23. pygeofetch-2.6.2.4/pygeofetch/providers/jaxa_earth.py +276 -0
  24. pygeofetch-2.6.2.4/pygeofetch/providers/maxar_gbdx.py +298 -0
  25. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/validation/optical_validator.py +69 -33
  26. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/viz/plot.py +24 -5
  27. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4/pygeofetch.egg-info}/PKG-INFO +6 -6
  28. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch.egg-info/SOURCES.txt +19 -0
  29. pygeofetch-2.6.2.4/pygeofetch.egg-info/top_level.txt +2 -0
  30. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pyproject.toml +3 -3
  31. pygeofetch-2.6.2.4/tests/test_alaska_satellite_facility.py +217 -0
  32. pygeofetch-2.6.2.4/tests/test_build_sbas_network.py +191 -0
  33. pygeofetch-2.6.2.4/tests/test_coregister_upgrades.py +295 -0
  34. pygeofetch-2.6.2.4/tests/test_data_organizer.py +170 -0
  35. pygeofetch-2.6.2.4/tests/test_digitalglobe.py +260 -0
  36. pygeofetch-2.6.2.4/tests/test_earth_explorer_additional.py +94 -0
  37. pygeofetch-2.6.2.4/tests/test_geology_indices_and_rvi_fix.py +159 -0
  38. pygeofetch-2.6.2.4/tests/test_geoserver_generic.py +207 -0
  39. pygeofetch-2.6.2.4/tests/test_inpe_cbers.py +170 -0
  40. pygeofetch-2.6.2.4/tests/test_isro_bhuvan.py +227 -0
  41. pygeofetch-2.6.2.4/tests/test_jaxa_earth.py +173 -0
  42. pygeofetch-2.6.2.4/tests/test_optical_offset_tracking.py +183 -0
  43. pygeofetch-2.6.2.4/tests/test_optical_validator_stac.py +223 -0
  44. pygeofetch-2.6.2.4/tests/test_preflight_spatial_baseline.py +152 -0
  45. pygeofetch-2.6.2.4/tests/test_provider_geometry_audit.py +220 -0
  46. pygeofetch-2.6.2.2/pygeofetch/providers/alaska_satellite_facility.py +0 -256
  47. pygeofetch-2.6.2.2/pygeofetch/providers/digitalglobe.py +0 -254
  48. pygeofetch-2.6.2.2/pygeofetch/providers/earth_explorer_additional.py +0 -254
  49. pygeofetch-2.6.2.2/pygeofetch/providers/geoserver_generic.py +0 -256
  50. pygeofetch-2.6.2.2/pygeofetch/providers/isro_bhuvan.py +0 -254
  51. pygeofetch-2.6.2.2/pygeofetch/providers/jaxa_earth.py +0 -256
  52. pygeofetch-2.6.2.2/pygeofetch/providers/maxar_gbdx.py +0 -266
  53. pygeofetch-2.6.2.2/pygeofetch.egg-info/top_level.txt +0 -1
  54. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/LICENSE +0 -0
  55. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/MANIFEST.in +0 -0
  56. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/__init__.py +0 -0
  57. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/auth_commands.py +0 -0
  58. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/config_commands.py +0 -0
  59. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/download_commands.py +0 -0
  60. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/index_commands.py +0 -0
  61. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/monitor_commands.py +0 -0
  62. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/pipeline_process_commands.py +0 -0
  63. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/postprocess_commands.py +0 -0
  64. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/preprocess_commands.py +0 -0
  65. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/cli/sar_commands.py +0 -0
  66. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/config/__init__.py +0 -0
  67. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/config/defaults.yaml +0 -0
  68. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/config/settings.py +0 -0
  69. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/__init__.py +0 -0
  70. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/authenticator.py +0 -0
  71. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/cache_manager.py +0 -0
  72. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/downloader.py +0 -0
  73. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/logging.py +0 -0
  74. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/monitor.py +0 -0
  75. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/orbits.py +0 -0
  76. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/scheduler.py +0 -0
  77. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/searcher.py +0 -0
  78. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/core/state.py +0 -0
  79. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/__init__.py +0 -0
  80. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/analysis.py +0 -0
  81. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/annotation.py +0 -0
  82. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/atmosphere.py +0 -0
  83. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/coregister.py +0 -0
  84. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/deburst.py +0 -0
  85. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/esd.py +0 -0
  86. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/extraction.py +0 -0
  87. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/flatearth.py +0 -0
  88. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/geolocation.py +0 -0
  89. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/gpu.py +0 -0
  90. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/interferogram.py +0 -0
  91. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/ionosphere.py +0 -0
  92. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/offset_geometry.py +0 -0
  93. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/offset_tracking.py +0 -0
  94. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/provenance.py +0 -0
  95. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/ps_selection.py +0 -0
  96. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/splitspectrum_diagnostic.py +0 -0
  97. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/stack_selection.py +0 -0
  98. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/synthetic.py +0 -0
  99. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/timeseries.py +0 -0
  100. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/unwrap.py +0 -0
  101. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/validate.py +0 -0
  102. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/visualize.py +0 -0
  103. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/insar/workflow.py +0 -0
  104. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/models/__init__.py +0 -0
  105. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/models/download_task.py +0 -0
  106. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/models/search_query.py +0 -0
  107. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/models/user_auth.py +0 -0
  108. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/__init__.py +0 -0
  109. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/base.py +0 -0
  110. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/batch.py +0 -0
  111. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/indices.py +0 -0
  112. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/pipeline.py +0 -0
  113. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/postprocessor.py +0 -0
  114. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/preprocessor.py +0 -0
  115. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processing/sar.py +0 -0
  116. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processor/__init__.py +0 -0
  117. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processor/landsat.py +0 -0
  118. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processor/loader.py +0 -0
  119. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processor/stacker.py +0 -0
  120. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/processor/timeseries.py +0 -0
  121. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/__init__.py +0 -0
  122. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/aws_earth.py +0 -0
  123. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/base.py +0 -0
  124. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/copernicus.py +0 -0
  125. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/copernicus_nodes.py +0 -0
  126. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/element84.py +0 -0
  127. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/eodag_provider.py +0 -0
  128. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/esa_scihub.py +0 -0
  129. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/google_earth_engine.py +0 -0
  130. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/nasa_earthdata.py +0 -0
  131. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/nasa_earthdata_cloud.py +0 -0
  132. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/noaa_big_data.py +0 -0
  133. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/opentopography.py +0 -0
  134. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/planet.py +0 -0
  135. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/planetary_computer.py +0 -0
  136. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/sentinel_hub.py +0 -0
  137. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/terrabotics.py +0 -0
  138. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/providers/usgs.py +0 -0
  139. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/sar/__init__.py +0 -0
  140. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/sar/_native.py +0 -0
  141. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/sar/_ost.py +0 -0
  142. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/sar/_sarxarray.py +0 -0
  143. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/sar/extraction.py +0 -0
  144. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/sar/processor.py +0 -0
  145. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/__init__.py +0 -0
  146. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/file_utils.py +0 -0
  147. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/gcp_recovery.py +0 -0
  148. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/geo_utils.py +0 -0
  149. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/logging_setup.py +0 -0
  150. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/retry_handler.py +0 -0
  151. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/utils/validators.py +0 -0
  152. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/validation/__init__.py +0 -0
  153. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/viz/__init__.py +0 -0
  154. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch/viz/map.py +0 -0
  155. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch.egg-info/dependency_links.txt +0 -0
  156. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch.egg-info/entry_points.txt +0 -0
  157. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch.egg-info/not-zip-safe +0 -0
  158. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/pygeofetch.egg-info/requires.txt +0 -0
  159. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/setup.cfg +0 -0
  160. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_airbus_oneatlas.py +0 -0
  161. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_atmospheric_circular_regression.py +0 -0
  162. /pygeofetch-2.6.2.2/tests/test_build_sbas_network.py → /pygeofetch-2.6.2.4/tests/test_build_sbas_network-new.py +0 -0
  163. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_burst_metadata.py +0 -0
  164. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_burst_processing_integration.py +0 -0
  165. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_burst_sync_large_gap.py +0 -0
  166. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_burst_sync_prescreening.py +0 -0
  167. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_burst_synchronization.py +0 -0
  168. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_circuit_breaker_wiring.py +0 -0
  169. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_cli_optical_validation.py +0 -0
  170. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_copernicus_nodes.py +0 -0
  171. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_coregister_integration.py +0 -0
  172. /pygeofetch-2.6.2.2/tests/test_coregister_upgrades.py → /pygeofetch-2.6.2.4/tests/test_coregister_upgrades (1).py +0 -0
  173. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_credential_encryption.py +0 -0
  174. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_era5_atmospheric_correction.py +0 -0
  175. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_esa_scihub.py +0 -0
  176. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_extraction.py +0 -0
  177. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_flat_earth_phase.py +0 -0
  178. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_gcp_reprojection.py +0 -0
  179. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_google_earth_engine.py +0 -0
  180. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_insar.py +0 -0
  181. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_ionosphere.py +0 -0
  182. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_map_preview_consolidation.py +0 -0
  183. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_models.py +0 -0
  184. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_monitor.py +0 -0
  185. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_noaa_big_data.py +0 -0
  186. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_offset_tracking.py +0 -0
  187. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_optical_validation_wiring.py +0 -0
  188. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_optical_validator.py +0 -0
  189. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_pgv_integration_contract.py +0 -0
  190. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_pipeline_process_export.py +0 -0
  191. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_preflight_gate.py +0 -0
  192. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_provider_geometry_audit (1).py +0 -0
  193. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_provider_scene_disambiguation.py +0 -0
  194. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_providers.py +0 -0
  195. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_ps_selection.py +0 -0
  196. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_raster_collocation_integration.py +0 -0
  197. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_reference_pixel_and_despike.py +0 -0
  198. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_risk_mapping.py +0 -0
  199. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_screen_stack_orchestration.py +0 -0
  200. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_search_download.py +0 -0
  201. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_sign_convention.py +0 -0
  202. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_splitspectrum_diagnostic.py +0 -0
  203. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_stack_selection_consolidation.py +0 -0
  204. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_state.py +0 -0
  205. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_topo_r2_bug.py +0 -0
  206. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_utils.py +0 -0
  207. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_viz_plot.py +0 -0
  208. {pygeofetch-2.6.2.2 → pygeofetch-2.6.2.4}/tests/test_wls_inversion.py +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.2.1
23
+ ## [Unreleased] — v2.6.2.4.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.2.2] — 2026-08-25 (latest)
133
+ ## [2.6.2.4.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.2] — 2026-08-24
152
+ ## [2.6.2.4] — 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.2.2 — 2026-07-12"** describing 22+ providers, Sentinel-1C/1D
264
+ **"2.6.2.4.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.2.2 was
266
+ management, 17 spectral indices, and various bug fixes. **2.6.2.4.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.2.2`**, dated
410
- 2026-07-29 and 2026-07-12. **2.6.2.2 was only ever released once**,
409
+ 1. **Two different entries were both labeled `2.6.2.4.4`**, dated
410
+ 2026-07-29 and 2026-07-12. **2.6.2.4.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,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 2.6.2.2
3
+ Version: 2.6.2.4
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
@@ -26,7 +26,7 @@ License: MIT License
26
26
  SOFTWARE.
27
27
 
28
28
  Project-URL: Homepage, https://www.eocoreint.com/
29
- Project-URL: Documentation, https://pygeofetch.readthedocs.io/en/latest/
29
+ Project-URL: Documentation, https://appiahkubis14.github.io/pygeofetch-docs/
30
30
  Project-URL: Repository, https://github.com/EOCoreINT/pygeofetch
31
31
  Project-URL: Bug Tracker, https://github.com/EOCoreINT/pygeofetch/issues
32
32
  Keywords: satellite,remote-sensing,GIS,earth-observation,geospatial,SAR,Sentinel,Landsat
@@ -153,9 +153,9 @@ Dynamic: license-file
153
153
 
154
154
  [Quick Start](#-quick-start) · [Mexico City Case Study](#-case-study-mapping-mexico-city-land-subsidence-with-insar) · [Case Study Repo ↗](https://github.com/EOCoreINT/mexico-subsidence-project) · [Documentation](https://pygeofetch.readthedocs.io/en/latest/) · [Notebooks](#-notebooks)
155
155
 
156
- <br>
157
- <img src="icon/concept_a.png" alt="PyGeoFetch Logo" width="350">
158
- <br>
156
+ <!-- <br>
157
+ <img src="https://raw.githubusercontent.com/EOCoreINT/pygeofetch/refs/heads/main/icon/concept_a.png" alt="PyGeoFetch Logo" width="350">
158
+ <br> -->
159
159
 
160
160
  </div>
161
161
 
@@ -386,7 +386,7 @@ If you use PyGeoFetch in your research or operational work, please cite it using
386
386
  title = {PyGeoFetch: A Unified Python Framework for Multi-Provider Satellite Data Acquisition, Pre-download Quality Control, and Geospatial Processing},
387
387
  year = {2026},
388
388
  publisher = {Zenodo},
389
- version = {2.6.2.2},
389
+ version = {2.6.2.4.1},
390
390
  doi = {10.5281/zenodo.22087230},
391
391
  url = {https://doi.org/10.5281/zenodo.22087230}
392
392
  }
@@ -11,9 +11,9 @@
11
11
 
12
12
  [Quick Start](#-quick-start) · [Mexico City Case Study](#-case-study-mapping-mexico-city-land-subsidence-with-insar) · [Case Study Repo ↗](https://github.com/EOCoreINT/mexico-subsidence-project) · [Documentation](https://pygeofetch.readthedocs.io/en/latest/) · [Notebooks](#-notebooks)
13
13
 
14
- <br>
15
- <img src="icon/concept_a.png" alt="PyGeoFetch Logo" width="350">
16
- <br>
14
+ <!-- <br>
15
+ <img src="https://raw.githubusercontent.com/EOCoreINT/pygeofetch/refs/heads/main/icon/concept_a.png" alt="PyGeoFetch Logo" width="350">
16
+ <br> -->
17
17
 
18
18
  </div>
19
19
 
@@ -244,7 +244,7 @@ If you use PyGeoFetch in your research or operational work, please cite it using
244
244
  title = {PyGeoFetch: A Unified Python Framework for Multi-Provider Satellite Data Acquisition, Pre-download Quality Control, and Geospatial Processing},
245
245
  year = {2026},
246
246
  publisher = {Zenodo},
247
- version = {2.6.2.2},
247
+ version = {2.6.2.4.1},
248
248
  doi = {10.5281/zenodo.22087230},
249
249
  url = {https://doi.org/10.5281/zenodo.22087230}
250
250
  }
@@ -30,7 +30,7 @@ CLI::
30
30
  pygeofetch doctor
31
31
  """
32
32
 
33
- __version__ = "2.6.2.2"
33
+ __version__ = "2.6.2.4.4"
34
34
  __author__ = "PyGeoFetch Contributors"
35
35
  __license__ = "MIT"
36
36
 
@@ -26,6 +26,7 @@ from pygeofetch.cli.auth_commands import auth
26
26
  from pygeofetch.cli.config_commands import config
27
27
  from pygeofetch.cli.download_commands import download
28
28
  from pygeofetch.cli.index_commands import index
29
+ from pygeofetch.cli.optical_commands import optical
29
30
  from pygeofetch.cli.pipeline_process_commands import proc_pipeline
30
31
  from pygeofetch.cli.postprocess_commands import post
31
32
  from pygeofetch.cli.preprocess_commands import preprocess
@@ -103,6 +104,7 @@ cli.add_command(index)
103
104
  cli.add_command(post)
104
105
  cli.add_command(sar)
105
106
  cli.add_command(proc_pipeline)
107
+ cli.add_command(optical)
106
108
 
107
109
 
108
110
  # ---------------------------------------------------------------------------
@@ -919,4 +921,4 @@ def main() -> None:
919
921
 
920
922
 
921
923
  if __name__ == "__main__":
922
- main()
924
+ main()
@@ -0,0 +1,105 @@
1
+ """CLI commands for optical pixel offset tracking (POT)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+
7
+ import click
8
+ from rich.console import Console
9
+
10
+ console = Console()
11
+
12
+
13
+ @click.group()
14
+ def optical() -> None:
15
+ """Optical pixel offset tracking — measures large 2D ground
16
+ displacement via image correlation, complementing InSAR for
17
+ motion that exceeds phase InSAR's coherence limit."""
18
+
19
+
20
+ @optical.command("offset-track")
21
+ @click.option("--ref", "reference_path", required=True, type=click.Path(exists=True), help="Reference-date raster.")
22
+ @click.option("--sec", "secondary_path", required=True, type=click.Path(exists=True), help="Secondary-date raster.")
23
+ @click.option("--output", "-o", required=True, type=click.Path(), help="Output GeoTIFF (dx/dy/snr, 3 bands).")
24
+ @click.option("--band", default=1, show_default=True, type=int, help="1-based band index to correlate.")
25
+ @click.option("--window-size", default=64, show_default=True, type=int, help="Search window size, pixels.")
26
+ @click.option("--step-size", default=16, show_default=True, type=int, help="Spacing between window centers, pixels.")
27
+ @click.option("--chip-size", default=None, type=int, help="Reference template size, pixels. Default: window-size // 2.")
28
+ @click.option("--snr-threshold", default=3.0, show_default=True, type=float, help="Minimum SNR to mark a window reliable.")
29
+ @click.option("--cloud-mask", default=None, type=click.Path(exists=True), help="Real Sentinel-2 SCL raster, already aligned to --ref.")
30
+ @click.option("--water-mask-threshold", default=None, type=float, help="Mask pixels where NDWI exceeds this value (needs --green-band/--nir-band).")
31
+ @click.option("--green-band", default=None, type=int, help="1-based green band index, for --water-mask-threshold.")
32
+ @click.option("--nir-band", default=None, type=int, help="1-based NIR band index, for --water-mask-threshold.")
33
+ def offset_track_cmd(
34
+ reference_path,
35
+ secondary_path,
36
+ output,
37
+ band,
38
+ window_size,
39
+ step_size,
40
+ chip_size,
41
+ snr_threshold,
42
+ cloud_mask,
43
+ water_mask_threshold,
44
+ green_band,
45
+ nir_band,
46
+ ):
47
+ """
48
+ Measure 2D ground displacement between two optical scenes via
49
+ image correlation.
50
+
51
+ \b
52
+ Examples:
53
+ # Basic: two co-registered scenes, real cloud masking via SCL
54
+ pygeofetch optical offset-track \\
55
+ --ref before.tif --sec after.tif \\
56
+ --cloud-mask before_SCL.tif \\
57
+ --output displacement.tif
58
+
59
+ # Mining-scale displacement, larger search window
60
+ pygeofetch optical offset-track \\
61
+ --ref jan.tif --sec jun.tif \\
62
+ --window-size 96 --step-size 24 \\
63
+ --output mine_displacement.tif
64
+ """
65
+ from pygeofetch.optical.offset_tracking import compute_pixel_offsets, prepare_optical_pair
66
+
67
+ try:
68
+ ref_arr, sec_arr, ref_profile = prepare_optical_pair(
69
+ reference_path,
70
+ secondary_path,
71
+ band_index=band,
72
+ cloud_mask_path=cloud_mask,
73
+ water_mask_threshold=water_mask_threshold,
74
+ green_band_index=green_band,
75
+ nir_band_index=nir_band,
76
+ )
77
+ except ValueError as exc:
78
+ console.print(f"[red]✗[/] {exc}")
79
+ sys.exit(1)
80
+
81
+ pixel_size_m = abs(ref_profile["transform"].a)
82
+ result = compute_pixel_offsets(
83
+ ref_arr,
84
+ sec_arr,
85
+ pixel_size_m=pixel_size_m,
86
+ window_size=window_size,
87
+ step_size=step_size,
88
+ chip_size=chip_size,
89
+ snr_threshold=snr_threshold,
90
+ )
91
+
92
+ out_transform = ref_profile["transform"] * ref_profile["transform"].scale(step_size, step_size)
93
+ out_profile = dict(ref_profile)
94
+ out_profile.update(
95
+ height=result.dx.shape[0],
96
+ width=result.dx.shape[1],
97
+ transform=out_transform,
98
+ )
99
+ written = result.export_geotiff(output, out_profile)
100
+
101
+ n_reliable = int(result.reliable.sum())
102
+ n_total = int(result.reliable.size)
103
+ console.print(f"[green]✓[/] offset-track → {written}")
104
+ console.print(f" {n_reliable}/{n_total} windows reliable ({100 * n_reliable / n_total:.1f}%)")
105
+ console.print(f" window={window_size}px step={step_size}px pixel_size={pixel_size_m:.2f}m")
@@ -282,6 +282,7 @@ def search_run(
282
282
 
283
283
  sb = PyGeoFetch()
284
284
 
285
+ optical_config = None
285
286
  if validate_optical and (
286
287
  optical_max_cloud_cover,
287
288
  optical_min_coverage,
@@ -298,22 +299,48 @@ def search_run(
298
299
  overrides["required_bands"] = [
299
300
  b.strip() for b in optical_required_bands.split(",")
300
301
  ]
301
- sb.optical_validation_config = OpticalValidationConfig(**overrides)
302
+ optical_config = OpticalValidationConfig(**overrides)
303
+ sb.optical_validation_config = optical_config
302
304
 
303
305
  with console.status(
304
306
  f"[cyan]Searching {len(provider_list or [])} provider(s)...[/]"
305
307
  ):
306
- results = sb.search(
307
- query,
308
- providers=provider_list,
309
- use_cache=not no_cache,
310
- validate_optical=validate_optical,
311
- )
308
+ if validate_optical:
309
+ # Real, deliberate choice: search WITHOUT filtering here, then
310
+ # validate directly in this CLI layer, rather than calling
311
+ # search(validate_optical=True) and losing visibility into
312
+ # what got rejected and why. sb.search()'s own contract
313
+ # (returns only the passed scenes) is left untouched for
314
+ # every other caller -- this is a CLI-only reporting path,
315
+ # not a change to the library's real filtering behavior.
316
+ raw_results = sb.search(
317
+ query,
318
+ providers=provider_list,
319
+ use_cache=not no_cache,
320
+ validate_optical=False,
321
+ )
322
+ results, validation_summary = _validate_and_summarize(
323
+ sb, raw_results, query, optical_config
324
+ )
325
+ else:
326
+ results = sb.search(
327
+ query,
328
+ providers=provider_list,
329
+ use_cache=not no_cache,
330
+ validate_optical=False,
331
+ )
332
+ validation_summary = None
312
333
 
313
334
  if not results:
314
335
  console.print("[yellow]No results found.[/]")
315
336
  return
316
337
 
338
+ # Real, clean validation info + full results table, organized so the
339
+ # summary always appears before the detailed table -- not interleaved
340
+ # with save/format output below.
341
+ if validation_summary is not None:
342
+ _display_validation_summary(validation_summary)
343
+
317
344
  # Save if requested
318
345
  if output:
319
346
  out_path = Path(output)
@@ -365,6 +392,92 @@ def search_run(
365
392
  click.echo(r.id)
366
393
 
367
394
 
395
+ def _validate_and_summarize(sb, raw_results, query, optical_config):
396
+ """
397
+ Real validation pass over every raw candidate, returning both the
398
+ scenes that actually pass and a real, structured summary of what got
399
+ rejected and why -- the information sb.search(validate_optical=True)
400
+ alone discards once it returns only the filtered list.
401
+ """
402
+ from collections import Counter
403
+
404
+ from pygeofetch.validation import OpticalPreflightValidator, OpticalValidationConfig
405
+
406
+ validator = OpticalPreflightValidator(optical_config or OpticalValidationConfig())
407
+ aoi = sb._derive_aoi_polygon(query)
408
+
409
+ passed_results = []
410
+ rejection_reasons: Counter = Counter()
411
+ warning_reasons: Counter = Counter()
412
+ n_warned_but_passed = 0
413
+
414
+ for scene in raw_results:
415
+ report = validator.validate_scene(scene, aoi, query.start_date, query.end_date)
416
+ if report.passed:
417
+ passed_results.append(scene)
418
+ if report.issues:
419
+ n_warned_but_passed += 1
420
+ for issue in report.issues:
421
+ warning_reasons[issue.code] += 1
422
+ else:
423
+ for issue in report.issues:
424
+ if issue.severity == "ERROR":
425
+ rejection_reasons[issue.code] += 1
426
+
427
+ summary = {
428
+ "n_total": len(raw_results),
429
+ "n_passed": len(passed_results),
430
+ "n_rejected": len(raw_results) - len(passed_results),
431
+ "n_warned_but_passed": n_warned_but_passed,
432
+ "rejection_reasons": rejection_reasons,
433
+ "warning_reasons": warning_reasons,
434
+ }
435
+ return passed_results, summary
436
+
437
+
438
+ def _display_validation_summary(summary: dict) -> None:
439
+ """Clean, real info block summarizing optical validation -- shown
440
+ before the detailed results table, not interleaved with it."""
441
+ n_total = summary["n_total"]
442
+ n_passed = summary["n_passed"]
443
+ n_rejected = summary["n_rejected"]
444
+ pct = (100 * n_passed / n_total) if n_total else 0.0
445
+
446
+ console.print(
447
+ f"\n[bold]Optical validation:[/] {n_passed}/{n_total} scenes passed "
448
+ f"({pct:.0f}%)"
449
+ + (f", [yellow]{n_rejected} rejected[/]" if n_rejected else "")
450
+ + (
451
+ f", [cyan]{summary['n_warned_but_passed']} passed with warnings[/]"
452
+ if summary["n_warned_but_passed"]
453
+ else ""
454
+ )
455
+ )
456
+
457
+ if summary["rejection_reasons"]:
458
+ reasons_table = Table(
459
+ title="Rejection reasons", header_style="bold red", show_lines=False
460
+ )
461
+ reasons_table.add_column("Code", style="red")
462
+ reasons_table.add_column("Count", justify="right")
463
+ for code, count in summary["rejection_reasons"].most_common():
464
+ reasons_table.add_row(code, str(count))
465
+ console.print(reasons_table)
466
+
467
+ if summary["warning_reasons"]:
468
+ warn_table = Table(
469
+ title="Warnings on passed scenes",
470
+ header_style="bold yellow",
471
+ show_lines=False,
472
+ )
473
+ warn_table.add_column("Code", style="yellow")
474
+ warn_table.add_column("Count", justify="right")
475
+ for code, count in summary["warning_reasons"].most_common():
476
+ warn_table.add_row(code, str(count))
477
+ console.print(warn_table)
478
+ console.print() # real spacing before the full results table below
479
+
480
+
368
481
  def _display_table(results) -> None:
369
482
  table = Table(title=f"{len(results)} Results", header_style="bold blue")
370
483
  table.add_column("ID", style="cyan", max_width=30)
@@ -441,4 +554,4 @@ def _save_csv(results, path: Path) -> None:
441
554
  )
442
555
  writer.writeheader()
443
556
  for r in results:
444
- writer.writerow(_item_to_dict(r))
557
+ writer.writerow(_item_to_dict(r))