PyGeoFetch 1.0.3__tar.gz → 1.0.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 (81) hide show
  1. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/PKG-INFO +1 -1
  2. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/__init__.py +2 -2
  3. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/main.py +2 -2
  4. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/models/satellite_data.py +1 -1
  5. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/copernicus.py +129 -11
  6. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/sentinel_hub.py +1 -1
  7. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/PKG-INFO +1 -1
  8. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pyproject.toml +1 -1
  9. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/LICENSE +0 -0
  10. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/README.md +0 -0
  11. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/__init__.py +0 -0
  12. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/auth_commands.py +0 -0
  13. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/config_commands.py +0 -0
  14. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/download_commands.py +0 -0
  15. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/index_commands.py +0 -0
  16. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/pipeline_process_commands.py +0 -0
  17. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/postprocess_commands.py +0 -0
  18. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/preprocess_commands.py +0 -0
  19. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/sar_commands.py +0 -0
  20. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/cli/search_commands.py +0 -0
  21. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/config/__init__.py +0 -0
  22. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/config/defaults.yaml +0 -0
  23. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/config/settings.py +0 -0
  24. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/__init__.py +0 -0
  25. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/authenticator.py +0 -0
  26. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/cache_manager.py +0 -0
  27. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/downloader.py +0 -0
  28. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/engine.py +0 -0
  29. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/logging.py +0 -0
  30. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/orbits.py +0 -0
  31. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/scheduler.py +0 -0
  32. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/core/searcher.py +0 -0
  33. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/models/__init__.py +0 -0
  34. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/models/download_task.py +0 -0
  35. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/models/search_query.py +0 -0
  36. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/models/user_auth.py +0 -0
  37. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/__init__.py +0 -0
  38. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/base.py +0 -0
  39. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/batch.py +0 -0
  40. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/indices.py +0 -0
  41. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/pipeline.py +0 -0
  42. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/postprocessor.py +0 -0
  43. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/preprocessor.py +0 -0
  44. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/processing/sar.py +0 -0
  45. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/__init__.py +0 -0
  46. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/airbus_oneatlas.py +0 -0
  47. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/alaska_satellite_facility.py +0 -0
  48. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/aws_earth.py +0 -0
  49. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/base.py +0 -0
  50. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/digitalglobe.py +0 -0
  51. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/earth_explorer_additional.py +0 -0
  52. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/element84.py +0 -0
  53. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/esa_scihub.py +0 -0
  54. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/geoserver_generic.py +0 -0
  55. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/google_earth_engine.py +0 -0
  56. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/inpe_cbers.py +0 -0
  57. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/isro_bhuvan.py +0 -0
  58. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/jaxa_earth.py +0 -0
  59. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/maxar_gbdx.py +0 -0
  60. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/nasa_earthdata.py +0 -0
  61. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/nasa_earthdata_cloud.py +0 -0
  62. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/noaa_big_data.py +0 -0
  63. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/opentopography.py +0 -0
  64. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/planet.py +0 -0
  65. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/planetary_computer.py +0 -0
  66. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/terrabotics.py +0 -0
  67. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/providers/usgs.py +0 -0
  68. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/utils/__init__.py +0 -0
  69. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/utils/file_utils.py +0 -0
  70. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/utils/geo_utils.py +0 -0
  71. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/utils/logging_setup.py +0 -0
  72. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/utils/retry_handler.py +0 -0
  73. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch/utils/validators.py +0 -0
  74. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/SOURCES.txt +0 -0
  75. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/dependency_links.txt +0 -0
  76. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/entry_points.txt +0 -0
  77. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/not-zip-safe +0 -0
  78. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/requires.txt +0 -0
  79. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/pygeofetch.egg-info/top_level.txt +0 -0
  80. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/setup.cfg +0 -0
  81. {pygeofetch-1.0.3 → pygeofetch-1.0.4}/tests/test_pgv_integration_contract.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Universal satellite data pipeline — unified access to 22+ providers
5
5
  Author: PyGeoFetch Contributors
6
6
  License: MIT License
@@ -1,5 +1,5 @@
1
1
  """
2
- PyGeoFetch v1.0.3 — Universal Satellite Data Pipeline.
2
+ PyGeoFetch v1.0.4 — 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__ = "1.0.3"
33
+ __version__ = "1.0.4"
34
34
  __author__ = "PyGeoFetch Contributors"
35
35
  __license__ = "MIT"
36
36
 
@@ -1,5 +1,5 @@
1
1
  """
2
- PyGeoFetch CLI v1.0.3 main entry point.
2
+ PyGeoFetch CLI v1.0.4 main entry point.
3
3
 
4
4
  Full command reference:
5
5
  pygeofetch auth — credential management
@@ -59,7 +59,7 @@ def cli(ctx: click.Context, log_level: str, log_file: str, log_format: str,
59
59
  config_file: str) -> None:
60
60
  """
61
61
  \b
62
- PyGeoFetch v1.0.3 — Universal Satellite Data Pipeline
62
+ PyGeoFetch v1.0.4 — Universal Satellite Data Pipeline
63
63
  ===========================================================
64
64
  Unified access to 22+ satellite data providers.
65
65
 
@@ -290,7 +290,7 @@ class SatelliteData(BaseModel):
290
290
  """
291
291
  item: Dict[str, Any] = {
292
292
  "type": "Feature",
293
- "stac_version": "1.0.3",
293
+ "stac_version": "1.0.4",
294
294
  "stac_extensions": self.stac_extensions,
295
295
  "id": self.id,
296
296
  "geometry": self.geometry or self._bbox_to_geometry(),
@@ -91,12 +91,26 @@ class CopernicusProvider(AbstractBaseProvider):
91
91
 
92
92
  # Map user-friendly satellite names to CDSE collection names
93
93
  SATELLITE_COLLECTION_MAP = {
94
- "sentinel-1": "SENTINEL-1",
95
- "sentinel-2": "SENTINEL-2",
96
- "sentinel-3": "SENTINEL-3",
97
- "sentinel-5": "SENTINEL-5P",
94
+ # Sentinel-1 — all platform variants map to the same collection
95
+ "sentinel-1": "SENTINEL-1",
96
+ "sentinel-1a": "SENTINEL-1",
97
+ "sentinel-1b": "SENTINEL-1",
98
+ "sentinel-1c": "SENTINEL-1", # active constellation (May 2025+)
99
+ "sentinel-1d": "SENTINEL-1", # active constellation (Apr 2026+)
100
+ "s1a": "SENTINEL-1",
101
+ "s1b": "SENTINEL-1",
102
+ "s1c": "SENTINEL-1",
103
+ "s1d": "SENTINEL-1",
104
+ # Sentinel-2
105
+ "sentinel-2": "SENTINEL-2",
106
+ "sentinel-2a": "SENTINEL-2",
107
+ "sentinel-2b": "SENTINEL-2",
108
+ "sentinel-2c": "SENTINEL-2",
109
+ # Sentinel-3, 5P, 6
110
+ "sentinel-3": "SENTINEL-3",
111
+ "sentinel-5": "SENTINEL-5P",
98
112
  "sentinel-5p": "SENTINEL-5P",
99
- "sentinel-6": "SENTINEL-6",
113
+ "sentinel-6": "SENTINEL-6",
100
114
  }
101
115
 
102
116
  def authenticate(self, credentials: Credentials) -> AuthSession:
@@ -220,17 +234,41 @@ class CopernicusProvider(AbstractBaseProvider):
220
234
  return [c.upper() for c in query.collections]
221
235
 
222
236
  if not query.satellites:
223
- return ["SENTINEL-2"] # sensible default
237
+ # Use product_type to pick a sensible default collection
238
+ pt = getattr(query, "product_type", None) or ""
239
+ if pt.upper() in ("SLC", "GRD", "GRD-COG", "OCN"):
240
+ return ["SENTINEL-1"] # SAR product type → Sentinel-1
241
+ return ["SENTINEL-2"] # default for optical
224
242
 
225
243
  collections = set()
226
244
  for sat in query.satellites:
227
- sat_lower = sat.lower()
245
+ sat_lower = sat.lower().replace("-", "").replace("_", "").replace(" ", "")
246
+ sat_orig = sat.lower()
247
+ matched = False
248
+ # Try exact match first, then prefix/substring
228
249
  for key, col in self.SATELLITE_COLLECTION_MAP.items():
229
- if key in sat_lower:
250
+ key_norm = key.replace("-", "").replace("_", "")
251
+ if key_norm == sat_lower or key in sat_orig or sat_orig.startswith(key):
230
252
  collections.add(col)
253
+ matched = True
231
254
  break
255
+ if not matched:
256
+ # Fall back: if it mentions "sentinel-1" anywhere, use SENTINEL-1
257
+ if "sentinel-1" in sat_orig or sat_orig.startswith("s1"):
258
+ collections.add("SENTINEL-1")
259
+ elif "sentinel-2" in sat_orig or sat_orig.startswith("s2"):
260
+ collections.add("SENTINEL-2")
261
+ else:
262
+ # Pass through as-is (user may know the collection name)
263
+ collections.add(sat.upper())
264
+
265
+ # If no satellite matched but product_type suggests SAR, use Sentinel-1
266
+ if not collections:
267
+ pt = getattr(query, "product_type", None) or ""
268
+ if pt.upper() in ("SLC", "GRD", "GRD-COG", "OCN"):
269
+ collections.add("SENTINEL-1")
232
270
  else:
233
- collections.add(sat.upper())
271
+ collections.add("SENTINEL-2")
234
272
 
235
273
  return list(collections)
236
274
 
@@ -268,6 +306,33 @@ class CopernicusProvider(AbstractBaseProvider):
268
306
  )
269
307
  filters.append(f"({level_filter})")
270
308
 
309
+ # Product type filter (SLC, GRD, GRD-COG, OCN for Sentinel-1)
310
+ pt = getattr(query, "product_type", None)
311
+ if pt:
312
+ filters.append(
313
+ f"Attributes/OData.CSC.StringAttribute/any("
314
+ f"att:att/Name eq 'productType' and "
315
+ f"att/OData.CSC.StringAttribute/Value eq '{pt.upper()}')"
316
+ )
317
+
318
+ # Polarisation filter (VV, VH, VV+VH, HH etc.)
319
+ pol = getattr(query, "polarisation", None)
320
+ if pol:
321
+ filters.append(
322
+ f"Attributes/OData.CSC.StringAttribute/any("
323
+ f"att:att/Name eq 'polarisationChannels' and "
324
+ f"att/OData.CSC.StringAttribute/Value eq '{pol.upper()}')"
325
+ )
326
+
327
+ # Pass direction filter (ascending / descending)
328
+ pass_dir = getattr(query, "pass_direction", None)
329
+ if pass_dir:
330
+ filters.append(
331
+ f"Attributes/OData.CSC.StringAttribute/any("
332
+ f"att:att/Name eq 'orbitDirection' and "
333
+ f"att/OData.CSC.StringAttribute/Value eq '{pass_dir.upper()}')"
334
+ )
335
+
271
336
  return " and ".join(filters)
272
337
 
273
338
  def _search_collection(self, collection: str, query: SearchQuery) -> List[SatelliteData]:
@@ -334,9 +399,18 @@ class CopernicusProvider(AbstractBaseProvider):
334
399
  except (ValueError, TypeError):
335
400
  cloud_cover = None
336
401
 
337
- # Determine satellite from name
402
+ # Determine satellite platform from product name (e.g. S1C_IW_SLC...)
338
403
  satellite = "Sentinel"
339
- if name.startswith("S1"):
404
+ platform = attributes.get("platform") or attributes.get("platformShortName", "")
405
+ if name.startswith("S1C") or "SENTINEL-1C" in platform.upper():
406
+ satellite = "SENTINEL-1C"
407
+ elif name.startswith("S1D") or "SENTINEL-1D" in platform.upper():
408
+ satellite = "SENTINEL-1D"
409
+ elif name.startswith("S1A") or "SENTINEL-1A" in platform.upper():
410
+ satellite = "SENTINEL-1A"
411
+ elif name.startswith("S1B") or "SENTINEL-1B" in platform.upper():
412
+ satellite = "SENTINEL-1B"
413
+ elif name.startswith("S1"):
340
414
  satellite = "Sentinel-1"
341
415
  elif name.startswith("S2"):
342
416
  satellite = "Sentinel-2"
@@ -345,6 +419,41 @@ class CopernicusProvider(AbstractBaseProvider):
345
419
  elif name.startswith("S5P"):
346
420
  satellite = "Sentinel-5P"
347
421
 
422
+ # Extract SAR-specific attributes
423
+ # Copernicus OData attribute names (from $expand=Attributes):
424
+ product_type = attributes.get("productType") # "SLC", "GRD", "GRD-COG"
425
+ polarisation = attributes.get("polarisationChannels") # "VV VH", "HH", etc.
426
+ pass_direction = attributes.get("orbitDirection") # "ASCENDING", "DESCENDING"
427
+ rel_orbit = attributes.get("relativeOrbitNumber")
428
+ abs_orbit = attributes.get("absoluteOrbitNumber")
429
+ incidence_angle = attributes.get("incidenceAngleMax")
430
+
431
+ # Normalise polarisation to "VV+VH" style
432
+ if polarisation:
433
+ polarisation = polarisation.strip().replace(" ", "+")
434
+
435
+ # Normalise pass direction to lowercase
436
+ if pass_direction:
437
+ pass_direction = pass_direction.lower() # "ascending" / "descending"
438
+
439
+ # Parse orbit numbers to int
440
+ try:
441
+ rel_orbit = int(rel_orbit) if rel_orbit is not None else None
442
+ except (ValueError, TypeError):
443
+ rel_orbit = None
444
+ try:
445
+ abs_orbit = int(abs_orbit) if abs_orbit is not None else None
446
+ except (ValueError, TypeError):
447
+ abs_orbit = None
448
+ try:
449
+ incidence_angle = float(incidence_angle) if incidence_angle is not None else None
450
+ except (ValueError, TypeError):
451
+ incidence_angle = None
452
+
453
+ # GSD from product type
454
+ gsd_map = {"SLC": 5.0, "GRD": 10.0, "GRD-COG": 10.0, "OCN": None}
455
+ gsd_m = gsd_map.get(product_type or "", None)
456
+
348
457
  # Build assets
349
458
  assets: Dict[str, SatelliteAsset] = {}
350
459
  s3_path = product.get("S3Path")
@@ -388,6 +497,15 @@ class CopernicusProvider(AbstractBaseProvider):
388
497
  "s3_path": s3_path,
389
498
  **attributes,
390
499
  },
500
+ # SAR / platform fields (Capability 1 + 2)
501
+ product_type=product_type,
502
+ polarisation=polarisation,
503
+ pass_direction=pass_direction,
504
+ relative_orbit=rel_orbit,
505
+ orbit_number=abs_orbit,
506
+ incidence_angle=incidence_angle,
507
+ gsd_m=gsd_m,
508
+ resolution_m=gsd_m,
391
509
  )
392
510
 
393
511
  def download(
@@ -107,7 +107,7 @@ class SentinelHubProvider(AbstractBaseProvider):
107
107
  payload["filter"] = {"maxCloudCoverage": query.cloud_cover_max}
108
108
  try:
109
109
  resp = httpx.post(
110
- f"{self.BASE_URL}/api/v1/catalog/1.0.3/search",
110
+ f"{self.BASE_URL}/api/v1/catalog/1.0.4/search",
111
111
  json=payload, headers={"Authorization": f"Bearer {self._session.access_token}"},
112
112
  timeout=self.config.get("timeout", 60),
113
113
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Universal satellite data pipeline — unified access to 22+ providers
5
5
  Author: PyGeoFetch Contributors
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 = "1.0.3"
7
+ version = "1.0.4"
8
8
  description = "Universal satellite data pipeline — unified access to 22+ providers"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
File without changes
File without changes
File without changes