PyGeoFetch 2.0.7__tar.gz → 2.0.9__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 (144) hide show
  1. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/CHANGELOG.md +6 -6
  2. {pygeofetch-2.0.7/pygeofetch.egg-info → pygeofetch-2.0.9}/PKG-INFO +1 -1
  3. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/__init__.py +2 -2
  4. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/main.py +2 -2
  5. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/unwrap.py +50 -50
  6. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/meta.yaml +1 -1
  7. {pygeofetch-2.0.7 → pygeofetch-2.0.9/pygeofetch.egg-info}/PKG-INFO +1 -1
  8. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pyproject.toml +1 -1
  9. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/LICENSE +0 -0
  10. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/MANIFEST.in +0 -0
  11. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/README.md +0 -0
  12. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/__init__.py +0 -0
  13. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/auth_commands.py +0 -0
  14. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/config_commands.py +0 -0
  15. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/download_commands.py +0 -0
  16. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/index_commands.py +0 -0
  17. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/pipeline_process_commands.py +0 -0
  18. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/postprocess_commands.py +0 -0
  19. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/preprocess_commands.py +0 -0
  20. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/sar_commands.py +0 -0
  21. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/cli/search_commands.py +0 -0
  22. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/config/__init__.py +0 -0
  23. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/config/defaults.yaml +0 -0
  24. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/config/settings.py +0 -0
  25. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/__init__.py +0 -0
  26. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/authenticator.py +0 -0
  27. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/cache_manager.py +0 -0
  28. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/downloader.py +0 -0
  29. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/engine.py +0 -0
  30. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/logging.py +0 -0
  31. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/orbits.py +0 -0
  32. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/scheduler.py +0 -0
  33. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/core/searcher.py +0 -0
  34. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/__init__.py +0 -0
  35. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/annotation.py +0 -0
  36. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/atmosphere.py +0 -0
  37. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/coregister.py +0 -0
  38. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/deburst.py +0 -0
  39. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/esd.py +0 -0
  40. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/extraction.py +0 -0
  41. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/flatearth.py +0 -0
  42. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/geolocation.py +0 -0
  43. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/gpu.py +0 -0
  44. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/interferogram.py +0 -0
  45. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/ionosphere.py +0 -0
  46. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/splitspectrum_diagnostic.py +0 -0
  47. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/stack_selection.py +0 -0
  48. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/synthetic.py +0 -0
  49. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/timeseries.py +0 -0
  50. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/validate.py +0 -0
  51. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/visualize.py +0 -0
  52. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/insar/workflow.py +0 -0
  53. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/models/__init__.py +0 -0
  54. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/models/download_task.py +0 -0
  55. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/models/satellite_data.py +0 -0
  56. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/models/search_query.py +0 -0
  57. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/models/user_auth.py +0 -0
  58. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/__init__.py +0 -0
  59. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/base.py +0 -0
  60. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/batch.py +0 -0
  61. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/indices.py +0 -0
  62. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/pipeline.py +0 -0
  63. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/postprocessor.py +0 -0
  64. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/preprocessor.py +0 -0
  65. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processing/sar.py +0 -0
  66. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processor/__init__.py +0 -0
  67. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processor/indices.py +0 -0
  68. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processor/landsat.py +0 -0
  69. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processor/loader.py +0 -0
  70. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processor/stacker.py +0 -0
  71. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/processor/timeseries.py +0 -0
  72. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/__init__.py +0 -0
  73. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/airbus_oneatlas.py +0 -0
  74. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/alaska_satellite_facility.py +0 -0
  75. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/aws_earth.py +0 -0
  76. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/base.py +0 -0
  77. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/copernicus.py +0 -0
  78. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/digitalglobe.py +0 -0
  79. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/earth_explorer_additional.py +0 -0
  80. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/element84.py +0 -0
  81. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/eodag_provider.py +0 -0
  82. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/esa_scihub.py +0 -0
  83. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/geoserver_generic.py +0 -0
  84. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/google_earth_engine.py +0 -0
  85. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/inpe_cbers.py +0 -0
  86. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/isro_bhuvan.py +0 -0
  87. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/jaxa_earth.py +0 -0
  88. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/maxar_gbdx.py +0 -0
  89. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/nasa_earthdata.py +0 -0
  90. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/nasa_earthdata_cloud.py +0 -0
  91. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/noaa_big_data.py +0 -0
  92. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/opentopography.py +0 -0
  93. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/planet.py +0 -0
  94. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/planetary_computer.py +0 -0
  95. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/sentinel_hub.py +0 -0
  96. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/terrabotics.py +0 -0
  97. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/providers/usgs.py +0 -0
  98. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/sar/__init__.py +0 -0
  99. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/sar/_native.py +0 -0
  100. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/sar/_ost.py +0 -0
  101. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/sar/_sarxarray.py +0 -0
  102. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/sar/extraction.py +0 -0
  103. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/sar/processor.py +0 -0
  104. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/__init__.py +0 -0
  105. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/file_utils.py +0 -0
  106. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/gcp_recovery.py +0 -0
  107. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/geo_utils.py +0 -0
  108. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/logging_setup.py +0 -0
  109. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/retry_handler.py +0 -0
  110. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/utils/validators.py +0 -0
  111. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/viz/__init__.py +0 -0
  112. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/viz/map.py +0 -0
  113. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch/viz/plot.py +0 -0
  114. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch.egg-info/SOURCES.txt +0 -0
  115. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch.egg-info/dependency_links.txt +0 -0
  116. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch.egg-info/entry_points.txt +0 -0
  117. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch.egg-info/not-zip-safe +0 -0
  118. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch.egg-info/requires.txt +0 -0
  119. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/pygeofetch.egg-info/top_level.txt +0 -0
  120. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/setup.cfg +0 -0
  121. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_atmospheric_circular_regression (1).py +0 -0
  122. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_atmospheric_circular_regression.py +0 -0
  123. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_build_sbas_network.py +0 -0
  124. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_burst_metadata.py +0 -0
  125. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_burst_processing_integration.py +0 -0
  126. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_coregister_integration.py +0 -0
  127. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_coregister_upgrades.py +0 -0
  128. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_era5_atmospheric_correction.py +0 -0
  129. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_extraction.py +0 -0
  130. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_flat_earth_phase.py +0 -0
  131. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_gcp_reprojection.py +0 -0
  132. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_insar.py +0 -0
  133. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_ionosphere.py +0 -0
  134. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_models.py +0 -0
  135. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_pgv_integration_contract.py +0 -0
  136. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_provider_geometry_audit (1).py +0 -0
  137. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_provider_geometry_audit.py +0 -0
  138. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_provider_scene_disambiguation.py +0 -0
  139. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_providers.py +0 -0
  140. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_raster_collocation_integration.py +0 -0
  141. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_search_download.py +0 -0
  142. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_splitspectrum_diagnostic.py +0 -0
  143. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_utils.py +0 -0
  144. {pygeofetch-2.0.7 → pygeofetch-2.0.9}/tests/test_viz_plot.py +0 -0
@@ -1,9 +1,9 @@
1
1
  # Changelog
2
2
 
3
3
  All notable changes to PyGeoFetch are documented here.
4
- Format follows [Keep a Changelog](https://keepachangelog.com/en/2.0.7/).
4
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/2.0.9/).
5
5
 
6
- ## [2.0.7] — 2026-07-29
6
+ ## [2.0.9] — 2026-07-29
7
7
 
8
8
  ### Added
9
9
  - Major SNAPHU unwrapping improvements for urban InSAR applications
@@ -51,7 +51,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/2.0.7/).
51
51
 
52
52
  ### Migration Guide
53
53
  ```python
54
- # Before (v2.0.7)
54
+ # Before (v2.0.9)
55
55
  unwrapper = PhaseUnwrapper(cost_mode="defo", init_method="mcf")
56
56
  unwrapped = unwrapper.unwrap(phase, coherence, nlooks=2.0)
57
57
 
@@ -72,7 +72,7 @@ unwrapped = unwrapper.unwrap(
72
72
 
73
73
  ---
74
74
 
75
- ## [2.0.7] — 2026-07-12
75
+ ## [2.0.9] — 2026-07-12
76
76
 
77
77
  ### Added
78
78
  - Federated search across 22+ satellite data providers
@@ -188,8 +188,8 @@ unwrapped = unwrapper.unwrap(
188
188
 
189
189
  | Version | Date | Key Changes |
190
190
  |---------|------------|-------------|
191
- | **2.0.7** | 2026-07-29 | SNAPHU unwrapping fixes, 87.1% reliable pixels |
192
- | **2.0.7** | 2026-07-12 | 22 providers, 17 indices, Sentinel-1C/D |
191
+ | **2.0.9** | 2026-07-29 | SNAPHU unwrapping fixes, 87.1% reliable pixels |
192
+ | **2.0.9** | 2026-07-12 | 22 providers, 17 indices, Sentinel-1C/D |
193
193
  | **1.9.2** | 2026-06-15 | Batch processing, parallel downloads |
194
194
  | **1.9.1** | 2026-05-20 | 3D terrain, SNAPHU integration, time series |
195
195
  | **1.9.0** | 2026-04-25 | Initial public release |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 2.0.7
3
+ Version: 2.0.9
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
@@ -1,5 +1,5 @@
1
1
  """
2
- PyGeoFetch v2.0.7 — Universal Satellite Data Pipeline.
2
+ PyGeoFetch v2.0.9 — Universal Satellite Data Pipeline.
3
3
 
4
4
  Unified access to 22+ satellite data providers with a consistent
5
5
  Python API and CLI. Supports authentication management, federated search,
@@ -30,7 +30,7 @@ CLI::
30
30
  pygeofetch doctor
31
31
  """
32
32
 
33
- __version__ = "2.0.7"
33
+ __version__ = "2.0.9"
34
34
  __author__ = "PyGeoFetch Contributors"
35
35
  __license__ = "MIT"
36
36
 
@@ -1,5 +1,5 @@
1
1
  """
2
- PyGeoFetch CLI v2.0.7 main entry point.
2
+ PyGeoFetch CLI v2.0.9 main entry point.
3
3
 
4
4
  Full command reference:
5
5
  pygeofetch auth — credential management
@@ -71,7 +71,7 @@ def cli(
71
71
  ) -> None:
72
72
  """
73
73
  \b
74
- PyGeoFetch v2.0.7 — Universal Satellite Data Pipeline
74
+ PyGeoFetch v2.0.9 — Universal Satellite Data Pipeline
75
75
  ===========================================================
76
76
  Unified access to 22+ satellite data providers.
77
77
 
@@ -451,13 +451,13 @@ class PhaseUnwrapper:
451
451
  def _unwrap_cli(self, igram, corr, nlooks, min_conncomp_frac, min_region_size):
452
452
  """
453
453
  Fallback unwrapping using the SNAPHU CLI executable.
454
- Bypasses Python C-extension compilation issues on Windows entirely.
455
454
  Includes auto-repair for the infamous 0xC0000135 (STATUS_DLL_NOT_FOUND) error.
456
455
  """
457
456
  import numpy as np
458
457
 
459
458
  cli_path = _ensure_snaphu_cli()
460
459
  height, width = igram.shape
460
+ bin_dir = Path(cli_path).parent
461
461
 
462
462
  def _run_snaphu(tmp_dir):
463
463
  tmp = Path(tmp_dir)
@@ -467,11 +467,9 @@ class PhaseUnwrapper:
467
467
  cc_path = tmp / "conncomp.cc"
468
468
  conf_path = tmp / "snaphu.conf"
469
469
 
470
- # Write binary files
471
470
  igram.tofile(str(igram_path))
472
471
  corr.tofile(str(corr_path))
473
472
 
474
- # Write config file using relative paths to avoid Windows space issues
475
473
  nlooks_int = max(1, int(nlooks))
476
474
  conf_text = f"""INFILE igram.cpx
477
475
  INFILEFORMAT COMPLEX_DATA
@@ -489,7 +487,6 @@ class PhaseUnwrapper:
489
487
  """
490
488
  conf_path.write_text(conf_text)
491
489
 
492
- # Run SNAPHU from within the temp directory
493
490
  cmd = [cli_path, "-f", "snaphu.conf"]
494
491
  result = subprocess.run(cmd, capture_output=True, text=True, cwd=str(tmp), timeout=3600)
495
492
  return result, unw_path, cc_path
@@ -497,30 +494,23 @@ class PhaseUnwrapper:
497
494
  with tempfile.TemporaryDirectory() as tmp_dir:
498
495
  result, unw_path, cc_path = _run_snaphu(tmp_dir)
499
496
 
500
- # ═══════════════════════════════════════════════════════════════
501
497
  # AUTO-REPAIR: Catch Windows STATUS_DLL_NOT_FOUND (0xC0000135)
502
- # 3221225781 is the unsigned int representation of 0xC0000135
503
- # -1073741515 is the signed int representation. We check both.
504
- # ═══════════════════════════════════════════════════════════════
505
498
  if result.returncode in (3221225781, -1073741515):
506
499
  logger.warning(
507
500
  "SNAPHU crashed with STATUS_DLL_NOT_FOUND (0xC0000135). "
508
- "This means the Microsoft Visual C++ Redistributable is missing."
501
+ "Auto-bundling MSVC runtime DLLs..."
509
502
  )
510
- self._ensure_msvc_runtime()
503
+ self._ensure_msvc_runtime(bin_dir)
511
504
 
512
- # Retry after installation
513
- logger.info("Retrying SNAPHU after MSVC runtime installation...")
505
+ logger.info("Retrying SNAPHU with bundled DLLs...")
514
506
  result, unw_path, cc_path = _run_snaphu(tmp_dir)
515
507
 
516
508
  if result.returncode != 0:
517
509
  raise RuntimeError(f"SNAPHU CLI failed with code {result.returncode}: {result.stderr}")
518
510
 
519
- # Read outputs
520
511
  unw = np.fromfile(str(unw_path), dtype=np.float32).reshape((height, width))
521
512
  conncomp = np.fromfile(str(cc_path), dtype=np.uint32).reshape((height, width))
522
513
 
523
- # Apply reliability filtering to match Python API behavior
524
514
  total_pixels = height * width
525
515
  labels, counts = np.unique(conncomp, return_counts=True)
526
516
  for lbl, count in zip(labels, counts):
@@ -531,48 +521,58 @@ class PhaseUnwrapper:
531
521
 
532
522
  return unw, conncomp.astype(np.int32)
533
523
 
534
- def _ensure_msvc_runtime(self):
524
+ def _ensure_msvc_runtime(self, bin_dir: Path):
535
525
  """
536
- Fixes the 0xC0000135 (STATUS_DLL_NOT_FOUND) error by ensuring the
537
- Microsoft Visual C++ Redistributable is installed.
526
+ Fixes the 0xC0000135 (STATUS_DLL_NOT_FOUND) error by downloading
527
+ the required MSVC DLLs directly from NuGet (VCRuntime.140 package).
528
+ This requires ZERO admin rights and ZERO manual installation.
538
529
  """
539
- import ctypes
530
+ import shutil
531
+ import zipfile
532
+ import io
533
+ import urllib.request
540
534
 
541
- # Check if vcruntime140.dll is already available in the system PATH
542
- try:
543
- ctypes.WinDLL("vcruntime140.dll")
544
- return # Already installed
545
- except OSError:
546
- pass
535
+ required_dlls = ["vcruntime140.dll", "msvcp140.dll"]
536
+ missing = [dll for dll in required_dlls if not (bin_dir / dll).exists()]
537
+
538
+ if not missing:
539
+ return
547
540
 
548
- logger.info("Downloading official Microsoft Visual C++ Redistributable...")
549
- vc_url = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
541
+ logger.info(f"SNAPHU requires {missing}. Downloading directly from NuGet (no admin required)...")
550
542
 
551
- with tempfile.TemporaryDirectory() as tmp_dir:
552
- installer_path = Path(tmp_dir) / "vc_redist.x64.exe"
553
- try:
554
- urllib.request.urlretrieve(vc_url, str(installer_path))
555
- except Exception as e:
556
- raise RuntimeError(
557
- f"Failed to download MSVC installer: {e}\n"
558
- "Please install manually: https://aka.ms/vs/17/release/vc_redist.x64.exe"
559
- )
543
+ # NuGet packages are just zip files. We download the VCRuntime.140 package
544
+ # which contains the exact DLLs we need for x64 Windows.
545
+ nuget_url = "https://www.nuget.org/api/v2/package/VCRuntime.140"
546
+
547
+ try:
548
+ req = urllib.request.Request(nuget_url, headers={'User-Agent': 'PyGeoFetch'})
549
+ with urllib.request.urlopen(req, timeout=30) as response:
550
+ nupkg_data = response.read()
560
551
 
561
- logger.info("Installing MSVC runtime (this may prompt for Administrator permission)...")
562
- try:
563
- # /quiet = no UI, /norestart = no reboot prompt, /install = install
564
- result = subprocess.run(
565
- [str(installer_path), "/install", "/quiet", "/norestart"],
566
- timeout=120
567
- )
568
- # Return code 0 = success, 3010 = success but reboot required
569
- if result.returncode not in (0, 3010):
570
- logger.warning(f"Installer returned code {result.returncode}. You may need to install manually.")
571
- except Exception as e:
572
- raise RuntimeError(
573
- f"Failed to run MSVC installer: {e}\n"
574
- "Please install manually: https://aka.ms/vs/17/release/vc_redist.x64.exe"
575
- )
552
+ extracted = 0
553
+ with zipfile.ZipFile(io.BytesIO(nupkg_data)) as zf:
554
+ for name in zf.namelist():
555
+ # We only want the 64-bit native DLLs
556
+ if "win-x64/native/" in name and name.lower().endswith(".dll"):
557
+ dll_name = Path(name).name
558
+ if dll_name.lower() in [m.lower() for m in missing]:
559
+ with zf.open(name) as src, open(bin_dir / dll_name, "wb") as dst:
560
+ shutil.copyfileobj(src, dst)
561
+ extracted += 1
562
+
563
+ if extracted == len(missing):
564
+ logger.info(f"Successfully extracted {extracted} MSVC DLLs to {bin_dir}. Retrying SNAPHU...")
565
+ return
566
+ else:
567
+ raise RuntimeError(f"Could not find all required DLLs in the NuGet package. Found {extracted}/{len(missing)}")
568
+
569
+ except Exception as e:
570
+ raise RuntimeError(
571
+ f"Failed to download/extract MSVC runtime DLLs from NuGet: {e}\n"
572
+ "As a last resort, please install the Microsoft Visual C++ Redistributable manually from:\n"
573
+ "https://aka.ms/vs/17/release/vc_redist.x64.exe\n"
574
+ "Then restart your Jupyter kernel."
575
+ )
576
576
 
577
577
  def unwrap(
578
578
  self,
@@ -1,4 +1,4 @@
1
- {% set version = "2.0.7" %}
1
+ {% set version = "2.0.9" %}
2
2
 
3
3
  package:
4
4
  name: pygeofetch
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 2.0.7
3
+ Version: 2.0.9
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pygeofetch"
7
- version = "2.0.7"
7
+ version = "2.0.9"
8
8
  description = "Universal satellite data pipeline + geospatial processing platform"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
File without changes
File without changes
File without changes
File without changes