PyGeoFetch 2.2.0__py3-none-any.whl → 2.4.0__py3-none-any.whl

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.
pygeofetch/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- PyGeoFetch v2.2.0 — Universal Satellite Data Pipeline.
2
+ PyGeoFetch v2.4.0 — 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.2.0"
33
+ __version__ = "2.4.0"
34
34
  __author__ = "PyGeoFetch Contributors"
35
35
  __license__ = "MIT"
36
36
 
pygeofetch/cli/main.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- PyGeoFetch CLI v2.2.0 main entry point.
2
+ PyGeoFetch CLI v2.4.0 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.2.0 — Universal Satellite Data Pipeline
74
+ PyGeoFetch v2.4.0 — Universal Satellite Data Pipeline
75
75
  ===========================================================
76
76
  Unified access to 22+ satellite data providers.
77
77
 
@@ -356,6 +356,7 @@ class PhaseUnwrapper:
356
356
 
357
357
  def _unwrap_cli(self, igram, corr, nlooks, min_conncomp_frac, min_region_size):
358
358
  import numpy as np
359
+ import os
359
360
  cli_path = _ensure_snaphu_cli()
360
361
  height, width = igram.shape
361
362
  bin_dir = Path(cli_path).parent
@@ -370,6 +371,7 @@ class PhaseUnwrapper:
370
371
  igram.tofile(str(igram_path))
371
372
  corr.tofile(str(corr_path))
372
373
  nlooks_int = max(1, int(nlooks))
374
+
373
375
  conf_text = f"""INFILE igram.cpx
374
376
  INFILEFORMAT COMPLEX_DATA
375
377
  CORRFILE corr.cor
@@ -377,7 +379,6 @@ CORRFILEFORMAT FLOAT_DATA
377
379
  OUTFILE unw.unw
378
380
  OUTFILEFORMAT FLOAT_DATA
379
381
  CONNCOMPFILE conncomp.cc
380
- CONNCOMPOUTFORMAT UINT_DATA
381
382
  LINELENGTH {width}
382
383
  STATCOSTMODE {self._cost_mode.upper()}
383
384
  INITMETHOD {self._init_method.upper()}
@@ -401,8 +402,44 @@ NLOOKSAZ {nlooks_int}
401
402
  if result.returncode != 0:
402
403
  raise RuntimeError(f"SNAPHU CLI failed with code {result.returncode}: {result.stderr}")
403
404
 
404
- unw = np.fromfile(str(unw_path), dtype=np.float32).reshape((height, width))
405
- conncomp = np.fromfile(str(cc_path), dtype=np.uint32).reshape((height, width))
405
+ # ═══════════════════════════════════════════════════════════════
406
+ # SMART FILE READER (Handles Windows Port Quirks)
407
+ # ═══════════════════════════════════════════════════════════════
408
+ expected_pixels = height * width
409
+
410
+ # 1. Read Unwrapped Phase (Usually FLOAT_DATA = 4 bytes)
411
+ unw_size = os.path.getsize(str(unw_path))
412
+ unw_dtype = np.float32 if unw_size <= expected_pixels * 4 else np.float64
413
+ unw = np.fromfile(str(unw_path), dtype=unw_dtype)
414
+
415
+ # 2. Read Connected Components (Adapts to 1-byte, 2-byte, or 4-byte formats)
416
+ cc_size = os.path.getsize(str(cc_path))
417
+ if cc_size >= expected_pixels * 4:
418
+ cc_dtype = np.uint32
419
+ elif cc_size >= expected_pixels * 2:
420
+ cc_dtype = np.uint16
421
+ else:
422
+ cc_dtype = np.uint8 # The Windows port default
423
+
424
+ conncomp = np.fromfile(str(cc_path), dtype=cc_dtype)
425
+
426
+ # 3. Auto-heal the Windows "off-by-one" truncation bug
427
+ if conncomp.size < expected_pixels:
428
+ logger.warning(
429
+ "SNAPHU conncomp file is %d elements, expected %d. Padding missing bytes with 0 "
430
+ "(known Windows port truncation quirk).", conncomp.size, expected_pixels
431
+ )
432
+ conncomp = np.pad(conncomp, (0, expected_pixels - conncomp.size), mode='constant', constant_values=0)
433
+ elif conncomp.size > expected_pixels:
434
+ conncomp = conncomp[:expected_pixels]
435
+
436
+ if unw.size < expected_pixels:
437
+ unw = np.pad(unw, (0, expected_pixels - unw.size), mode='constant', constant_values=0)
438
+ elif unw.size > expected_pixels:
439
+ unw = unw[:expected_pixels]
440
+
441
+ unw = unw.reshape((height, width))
442
+ conncomp = conncomp.reshape((height, width))
406
443
 
407
444
  total_pixels = height * width
408
445
  labels, counts = np.unique(conncomp, return_counts=True)
@@ -411,6 +448,7 @@ NLOOKSAZ {nlooks_int}
411
448
  if count < min_region_size or (count / total_pixels) < min_conncomp_frac:
412
449
  conncomp[conncomp == lbl] = 0
413
450
  return unw, conncomp.astype(np.int32)
451
+
414
452
 
415
453
  def _ensure_runtime_dlls(self, bin_dir: Path):
416
454
  import shutil, zipfile, io, urllib.request
@@ -585,4 +623,59 @@ NLOOKSAZ {nlooks_int}
585
623
 
586
624
  def _np(self):
587
625
  import numpy as np
588
- return np
626
+ return np
627
+
628
+
629
+ import shutil
630
+ import subprocess
631
+ import logging
632
+ import sys
633
+
634
+ logger = logging.getLogger(__name__)
635
+
636
+ def verify_snaphu_ready():
637
+ """
638
+ Proactively checks for snaphu availability to assure the user
639
+ that no manual installation is required.
640
+ """
641
+ # 1. Check for the standard SNAPHU binary in the system PATH
642
+ snaphu_bin = shutil.which("snaphu")
643
+ if snaphu_bin:
644
+ # Optional: Verify the binary actually executes and isn't just a broken alias
645
+ try:
646
+ subprocess.run(
647
+ ["snaphu"],
648
+ stdout=subprocess.DEVNULL,
649
+ stderr=subprocess.DEVNULL,
650
+ timeout=3
651
+ )
652
+ except Exception:
653
+ pass # Snaphu without args prints usage to stderr and exits; this is expected.
654
+
655
+ msg = f"✅ Success: snaphu binary detected at '{snaphu_bin}'. No manual installation needed."
656
+ print(msg)
657
+ logger.info(msg)
658
+ return True
659
+
660
+ # 2. Fallback: Check if it's available as a Python package/module
661
+ try:
662
+ import snaphu # or pysnaphu, depending on your wrapper
663
+ msg = "✅ Success: snaphu Python module detected. No manual installation needed."
664
+ print(msg)
665
+ logger.info(msg)
666
+ return True
667
+ except ImportError:
668
+ pass
669
+
670
+ # 3. If neither is found, handle the failure gracefully
671
+ msg = "❌ snaphu not found in PATH or Python environment. Phase unwrapping will fail."
672
+ print(msg)
673
+ logger.warning(msg)
674
+ return False
675
+
676
+ # --- Embed this early in your notebook or pipeline ---
677
+ snaphu_is_ready = verify_snaphu_ready()
678
+
679
+ if not snaphu_is_ready:
680
+ # Decide how to handle the missing dependency (see questions below)
681
+ pass
pygeofetch/meta.yaml CHANGED
@@ -1,4 +1,4 @@
1
- {% set version = "2.2.0" %}
1
+ {% set version = "2.4.0" %}
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.2.0
3
+ Version: 2.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
@@ -91,8 +91,8 @@ Requires-Dist: sidecar>=0.6.0; extra == "viz"
91
91
  Requires-Dist: bokeh>=3.0.0; extra == "viz"
92
92
  Requires-Dist: seaborn>=0.12.0; extra == "viz"
93
93
  Requires-Dist: plotly>=5.14.0; extra == "viz"
94
- Requires-Dist: whitebox>=2.3.0; extra == "viz"
95
- Requires-Dist: whiteboxgui>=2.3.0; extra == "viz"
94
+ Requires-Dist: whitebox>=2.4.0; extra == "viz"
95
+ Requires-Dist: whiteboxgui>=2.4.0; extra == "viz"
96
96
  Requires-Dist: geemap>=0.28.0; extra == "viz"
97
97
  Requires-Dist: osmnx>=1.9.4; extra == "viz"
98
98
  Requires-Dist: contextily>=1.9.4; extra == "viz"
@@ -1,11 +1,11 @@
1
- pygeofetch/__init__.py,sha256=jurp6U54bXzlI1qAgbCOJeKvCi8dtqTXmKp8rBQiy9Y,1990
2
- pygeofetch/meta.yaml,sha256=MoNY3MjPluP_qRarrEL6rVciSWxkqI5M5AcuFs0nYR8,1280
1
+ pygeofetch/__init__.py,sha256=_bHgoiQ6l5aQR6GOuqKKte2bqg51iJPILBNzLROiZUg,1990
2
+ pygeofetch/meta.yaml,sha256=_3LO3mdYsaEWdrrwTP6ITyr57YTTJmweff4ja5aqKmk,1280
3
3
  pygeofetch/cli/__init__.py,sha256=QZMIIHEgmjGFieucqq9fZ5uephxP9-jdu1s8Q4qqw8o,30
4
4
  pygeofetch/cli/auth_commands.py,sha256=YqbrN_BYcAYCaUIYLpSJ_VIw35tKFUiD9Kc55SWbDWg,7742
5
5
  pygeofetch/cli/config_commands.py,sha256=1Pps0HLCLPODMlM6SFV8ru3IKCDpexSTz8uKIXvIIF8,3918
6
6
  pygeofetch/cli/download_commands.py,sha256=reQ9vmA50mj1zqechjLHAOe_cjBfa1miqfWa8UiIlxU,11741
7
7
  pygeofetch/cli/index_commands.py,sha256=IoLGrsSU-lTcBitFFsg8EtucqSKZtNL-0ODj_I8Twew,10020
8
- pygeofetch/cli/main.py,sha256=losmzWULoADQJNRMLoM3VcEFagnVlHZwr2LapikShjc,30335
8
+ pygeofetch/cli/main.py,sha256=ABJstgL_Z0wE7f-eSl8m6a3KEpaue54P5XG_M2W0Gac,30335
9
9
  pygeofetch/cli/pipeline_process_commands.py,sha256=OvuouT35zZlrC-7hWAJRfaY_aUNk4ScK0Fia9WVB_Gw,6904
10
10
  pygeofetch/cli/postprocess_commands.py,sha256=kof_f-kjjvYl5eqPqrcNHSOUM_qVkGdSh6-N4vcx2y4,5825
11
11
  pygeofetch/cli/preprocess_commands.py,sha256=cFp1VR03Q1pmCwiBWYmS5lXF3NOnzVAq3XgrZh3rBdU,8696
@@ -42,7 +42,7 @@ pygeofetch/insar/splitspectrum_diagnostic.py,sha256=_IlfBs__BW7Yz2RwdmWxfrOspe67
42
42
  pygeofetch/insar/stack_selection.py,sha256=FaRBXDNnLwwiXPGeALSW1AaUdpLFOEepVTgEGVfNC4o,37555
43
43
  pygeofetch/insar/synthetic.py,sha256=FazdaG_u3GR1qk8022T92W2uxDJPg7OJaUSGY0wR0pw,16248
44
44
  pygeofetch/insar/timeseries.py,sha256=jXAYCFV5-m1Zv6kErlg4CWntpOSCKE8BR5qJru6GH7Q,60155
45
- pygeofetch/insar/unwrap.py,sha256=v2BnxRGoIEtIivHAUsfmSOnlHuKGxz_TEpH_9FdkDuU,29663
45
+ pygeofetch/insar/unwrap.py,sha256=zXw2WJwMQJS1gSR1L5L7DUfG1XD-Al9YZ2LnDJqJQEU,33444
46
46
  pygeofetch/insar/validate.py,sha256=BZaVvaPNllfDzoPwat0vDA4do6H5xh5Ju_g4r5YNogE,10110
47
47
  pygeofetch/insar/visualize.py,sha256=OxaQCUyRPKdikk5eQToGaXEtnN5RHEFEUMTD4O0-1iQ,8320
48
48
  pygeofetch/insar/workflow.py,sha256=8IxGgabdz9fDLoGAVrJRCdw16GP3sSDSoFPXyv1RXcg,11713
@@ -108,9 +108,9 @@ pygeofetch/utils/validators.py,sha256=f-k3mGFP4byjimyDymhPEdsz5I16jZacx1HSnwrARj
108
108
  pygeofetch/viz/__init__.py,sha256=xf2C9IL4n3bv3oxk8RYkogq7nkuNyt18V-urAoXWRQY,449
109
109
  pygeofetch/viz/map.py,sha256=vYO99NvTumCAVXVtXcEzMx_cpmH-FvSVNWl8X0PNSgE,15494
110
110
  pygeofetch/viz/plot.py,sha256=I16rdOWb80gcjYDsDvTMzuyek7QHgUNOQxY2RejBAPs,53675
111
- pygeofetch-2.2.0.dist-info/licenses/LICENSE,sha256=zavMyhODD6NvZTmmKFEtATrngwY4CU_NEtY7lhjxGnI,1075
112
- pygeofetch-2.2.0.dist-info/METADATA,sha256=uOiBAvdS4nR6X0Y8x63RAbHjJh3kg0IT4UIRE9vWqoM,43254
113
- pygeofetch-2.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
114
- pygeofetch-2.2.0.dist-info/entry_points.txt,sha256=dHiUXLF5xNJ8vgtXZoUQNleEMQUeDPZiKQOE1tW8SDY,55
115
- pygeofetch-2.2.0.dist-info/top_level.txt,sha256=rOmnZargIfNk99fwVOqt6OJyJvpSTBBAYO5HU37yhHk,11
116
- pygeofetch-2.2.0.dist-info/RECORD,,
111
+ pygeofetch-2.4.0.dist-info/licenses/LICENSE,sha256=zavMyhODD6NvZTmmKFEtATrngwY4CU_NEtY7lhjxGnI,1075
112
+ pygeofetch-2.4.0.dist-info/METADATA,sha256=pDlu8XZmm0G3xTLHpf3tf5F9K2uAn1kiojbZ9651Qmk,43254
113
+ pygeofetch-2.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
114
+ pygeofetch-2.4.0.dist-info/entry_points.txt,sha256=dHiUXLF5xNJ8vgtXZoUQNleEMQUeDPZiKQOE1tW8SDY,55
115
+ pygeofetch-2.4.0.dist-info/top_level.txt,sha256=rOmnZargIfNk99fwVOqt6OJyJvpSTBBAYO5HU37yhHk,11
116
+ pygeofetch-2.4.0.dist-info/RECORD,,