pygeofetch 0.1.1__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.
Files changed (59) hide show
  1. pygeofetch/__init__.py +39 -0
  2. pygeofetch/cli/__init__.py +1 -0
  3. pygeofetch/cli/auth_commands.py +257 -0
  4. pygeofetch/cli/config_commands.py +143 -0
  5. pygeofetch/cli/download_commands.py +272 -0
  6. pygeofetch/cli/main.py +770 -0
  7. pygeofetch/cli/search_commands.py +249 -0
  8. pygeofetch/config/__init__.py +11 -0
  9. pygeofetch/config/defaults.yaml +86 -0
  10. pygeofetch/config/settings.py +235 -0
  11. pygeofetch/core/__init__.py +18 -0
  12. pygeofetch/core/authenticator.py +428 -0
  13. pygeofetch/core/cache_manager.py +288 -0
  14. pygeofetch/core/downloader.py +354 -0
  15. pygeofetch/core/engine.py +312 -0
  16. pygeofetch/core/scheduler.py +473 -0
  17. pygeofetch/core/searcher.py +341 -0
  18. pygeofetch/models/__init__.py +44 -0
  19. pygeofetch/models/download_task.py +282 -0
  20. pygeofetch/models/satellite_data.py +395 -0
  21. pygeofetch/models/search_query.py +329 -0
  22. pygeofetch/models/user_auth.py +123 -0
  23. pygeofetch/providers/__init__.py +192 -0
  24. pygeofetch/providers/airbus_oneatlas.py +150 -0
  25. pygeofetch/providers/alaska_satellite_facility.py +150 -0
  26. pygeofetch/providers/aws_earth.py +267 -0
  27. pygeofetch/providers/base.py +306 -0
  28. pygeofetch/providers/copernicus.py +487 -0
  29. pygeofetch/providers/digitalglobe.py +150 -0
  30. pygeofetch/providers/earth_explorer_additional.py +150 -0
  31. pygeofetch/providers/element84.py +230 -0
  32. pygeofetch/providers/esa_scihub.py +150 -0
  33. pygeofetch/providers/geoserver_generic.py +150 -0
  34. pygeofetch/providers/google_earth_engine.py +150 -0
  35. pygeofetch/providers/inpe_cbers.py +150 -0
  36. pygeofetch/providers/isro_bhuvan.py +150 -0
  37. pygeofetch/providers/jaxa_earth.py +150 -0
  38. pygeofetch/providers/maxar_gbdx.py +150 -0
  39. pygeofetch/providers/nasa_earthdata.py +190 -0
  40. pygeofetch/providers/nasa_earthdata_cloud.py +345 -0
  41. pygeofetch/providers/noaa_big_data.py +150 -0
  42. pygeofetch/providers/opentopography.py +108 -0
  43. pygeofetch/providers/planet.py +369 -0
  44. pygeofetch/providers/planetary_computer.py +273 -0
  45. pygeofetch/providers/sentinel_hub.py +173 -0
  46. pygeofetch/providers/terrabotics.py +278 -0
  47. pygeofetch/providers/usgs.py +469 -0
  48. pygeofetch/utils/__init__.py +50 -0
  49. pygeofetch/utils/file_utils.py +275 -0
  50. pygeofetch/utils/geo_utils.py +240 -0
  51. pygeofetch/utils/logging_setup.py +107 -0
  52. pygeofetch/utils/retry_handler.py +225 -0
  53. pygeofetch/utils/validators.py +155 -0
  54. pygeofetch-0.1.1.dist-info/METADATA +720 -0
  55. pygeofetch-0.1.1.dist-info/RECORD +59 -0
  56. pygeofetch-0.1.1.dist-info/WHEEL +5 -0
  57. pygeofetch-0.1.1.dist-info/entry_points.txt +2 -0
  58. pygeofetch-0.1.1.dist-info/licenses/LICENSE +21 -0
  59. pygeofetch-0.1.1.dist-info/top_level.txt +1 -0
pygeofetch/__init__.py ADDED
@@ -0,0 +1,39 @@
1
+ """
2
+ pygeofetch v1.0.0 — Universal Satellite Data Pipeline.
3
+
4
+ Unified access to 22+ satellite data providers with a consistent
5
+ Python API and CLI. Supports authentication management, federated search,
6
+ parallel downloads, pipeline orchestration, and post-processing.
7
+
8
+ Quick Start::
9
+
10
+ from pygeofetch import pygeofetch
11
+
12
+ sb = pygeofetch()
13
+ sb.add_credentials("usgs", username="user", password="pass")
14
+
15
+ results = sb.search(
16
+ providers=["usgs", "copernicus", "planetary_computer"],
17
+ bbox=(-74.1, 40.6, -73.7, 40.9),
18
+ start_date="2024-01-01",
19
+ cloud_cover_max=20,
20
+ )
21
+
22
+ sb.download(results[:5], output="./data/", parallel=4)
23
+
24
+ CLI::
25
+
26
+ pygeofetch auth add usgs --username user --password pass
27
+ pygeofetch search run --bbox "-74,40,-73,41" --providers copernicus
28
+ pygeofetch download run --from-search results.geojson --output ./data/
29
+ pygeofetch status
30
+ pygeofetch doctor
31
+ """
32
+
33
+ __version__ = "1.0.0"
34
+ __author__ = "pygeofetch Contributors"
35
+ __license__ = "MIT"
36
+
37
+ from pygeofetch.core.engine import pygeofetch # noqa: F401
38
+
39
+ __all__ = ["pygeofetch", "__version__"]
@@ -0,0 +1 @@
1
+ """pygeofetch CLI package."""
@@ -0,0 +1,257 @@
1
+ """
2
+ Authentication CLI commands for pygeofetch.
3
+
4
+ Provides the ``pygeofetch auth`` command group for managing provider
5
+ credentials: adding, listing, removing, testing, and exporting them.
6
+
7
+ Usage::
8
+
9
+ pygeofetch auth add usgs --username user --password pass
10
+ pygeofetch auth add planet --api-key PL_KEY
11
+ pygeofetch auth login copernicus # interactive prompt
12
+ pygeofetch auth list
13
+ pygeofetch auth test usgs
14
+ pygeofetch auth remove planet
15
+ pygeofetch auth export --output creds_backup.json
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ import sys
22
+
23
+ import click
24
+ from rich.console import Console
25
+ from rich.table import Table
26
+
27
+ console = Console()
28
+
29
+
30
+ @click.group()
31
+ def auth() -> None:
32
+ """Manage provider authentication credentials."""
33
+
34
+
35
+ @auth.command(name="add")
36
+ @click.argument("provider")
37
+ @click.option("--username", "-u", default=None, help="Username or email.")
38
+ @click.option("--password", "-p", default=None, help="Password (prompted if omitted).")
39
+ @click.option("--api-key", "-k", default=None, help="API key (alternative to username/password).")
40
+ @click.option("--client-id", default=None, help="OAuth2 client ID.")
41
+ @click.option("--client-secret", default=None, help="OAuth2 client secret.")
42
+ @click.option("--token", default=None, help="Bearer token.")
43
+ @click.option(
44
+ "--store",
45
+ default="keyring",
46
+ type=click.Choice(["keyring", "file"]),
47
+ show_default=True,
48
+ help="Credential storage backend.",
49
+ )
50
+
51
+ def auth_add(
52
+ provider: str,
53
+ username: str | None,
54
+ password: str | None,
55
+ api_key: str | None,
56
+ client_id: str | None,
57
+ client_secret: str | None,
58
+ token: str | None,
59
+ store: str,
60
+ ) -> None:
61
+ """
62
+ Add credentials for PROVIDER.
63
+
64
+ \b
65
+ Examples:
66
+ pygeofetch auth add usgs --username samuelyamforo --password USGS@sak@2001server
67
+ pygeofetch auth add planet --api-key PL_KEY
68
+ pygeofetch auth add copernicus --username me@example.com
69
+ """
70
+ from pygeofetch.core.authenticator import AuthManager
71
+
72
+ creds: dict = {}
73
+
74
+ if api_key:
75
+ creds["api_key"] = api_key
76
+ if client_id:
77
+ creds["client_id"] = client_id
78
+ if client_secret:
79
+ creds["client_secret"] = client_secret
80
+ if token:
81
+ creds["token"] = token
82
+
83
+ if not creds and not username:
84
+ username = click.prompt(f"Username for {provider}")
85
+
86
+ if username:
87
+ creds["username"] = username
88
+ if not password and not api_key:
89
+ password = click.prompt(f"Password for {provider}", hide_input=True)
90
+ if password:
91
+ creds["password"] = password
92
+
93
+ if not creds:
94
+ console.print("[red]No credentials provided.[/]")
95
+ sys.exit(1)
96
+
97
+ mgr = AuthManager(storage_backend='file')
98
+ mgr.add_credentials(provider, **creds)
99
+ console.print(f"[green]Credentials for [bold]{provider}[/] saved.[/]")
100
+
101
+
102
+ @auth.command(name="login")
103
+ @click.argument("provider")
104
+ def auth_login(provider: str) -> None:
105
+ """
106
+ Interactive login for PROVIDER (prompts for all required fields).
107
+
108
+ \b
109
+ Example:
110
+ pygeofetch auth login copernicus
111
+ """
112
+ from pygeofetch.core.authenticator import AuthManager
113
+ from pygeofetch.providers import get_provider
114
+
115
+ prov = get_provider(provider)
116
+ caps = prov.get_capabilities()
117
+
118
+ console.print(f"\n[bold]Logging in to {caps.name}[/]\n")
119
+
120
+ creds: dict = {}
121
+
122
+ # Determine what to prompt based on auth type
123
+ auth_type = caps.auth_type if hasattr(caps, "auth_type") else "username_password"
124
+
125
+ if auth_type in ("api_key",):
126
+ creds["api_key"] = click.prompt("API Key", hide_input=True)
127
+ elif auth_type in ("oauth2_client",):
128
+ creds["client_id"] = click.prompt("Client ID")
129
+ creds["client_secret"] = click.prompt("Client Secret", hide_input=True)
130
+ else:
131
+ creds["username"] = click.prompt("Username")
132
+ creds["password"] = click.prompt("Password", hide_input=True)
133
+
134
+ mgr = AuthManager(storage_backend='file')
135
+ mgr.add_credentials(provider, creds)
136
+
137
+ console.print(f"\n[green]Credentials for [bold]{provider}[/] saved.[/]")
138
+
139
+ # Optionally verify
140
+ if click.confirm("Verify credentials now?", default=True):
141
+ try:
142
+ session = mgr.authenticate(provider)
143
+ console.print(f"[green]Authentication successful![/] Session expires: {session.expires_at}")
144
+ except Exception as exc:
145
+ console.print(f"[red]Authentication failed: {exc}[/]")
146
+
147
+
148
+ @auth.command(name="list")
149
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON.")
150
+ def auth_list(as_json: bool) -> None:
151
+ """List all stored provider credentials."""
152
+ from pygeofetch.core.authenticator import AuthManager
153
+
154
+ mgr = AuthManager(storage_backend='file')
155
+ entries = mgr.list()
156
+
157
+ if as_json:
158
+ click.echo(json.dumps(entries, indent=2, default=str))
159
+ return
160
+
161
+ if not entries:
162
+ console.print("[dim]No credentials stored.[/]")
163
+ return
164
+
165
+ table = Table(title="Stored Credentials", header_style="bold blue")
166
+ table.add_column("Provider", style="cyan")
167
+ table.add_column("Has Username", justify="center")
168
+ table.add_column("Has API Key", justify="center")
169
+ table.add_column("Has Token", justify="center")
170
+
171
+ for entry in entries:
172
+ table.add_row(
173
+ entry["provider"],
174
+ "[green]✓[/]" if entry.get("has_username") else "—",
175
+ "[green]✓[/]" if entry.get("has_api_key") else "—",
176
+ "[green]✓[/]" if entry.get("has_token") else "—",
177
+ )
178
+
179
+ console.print(table)
180
+
181
+
182
+ @auth.command(name="test")
183
+ @click.argument("provider")
184
+ def auth_test(provider: str) -> None:
185
+ """
186
+ Test stored credentials for PROVIDER by attempting authentication.
187
+
188
+ \b
189
+ Example:
190
+ pygeofetch auth test usgs
191
+ """
192
+ from pygeofetch.core.authenticator import AuthManager
193
+
194
+ console.print(f"Testing credentials for [bold]{provider}[/]...")
195
+ mgr = AuthManager(storage_backend='file')
196
+ try:
197
+ session = mgr.authenticate(provider)
198
+ console.print(f"[green]Success![/] Session valid until: {session.expires_at}")
199
+ except Exception as exc:
200
+ console.print(f"[red]Failed: {exc}[/]")
201
+ sys.exit(1)
202
+
203
+
204
+ @auth.command(name="remove")
205
+ @click.argument("provider")
206
+ @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt.")
207
+ def auth_remove(provider: str, yes: bool) -> None:
208
+ """
209
+ Remove stored credentials for PROVIDER.
210
+
211
+ \b
212
+ Example:
213
+ pygeofetch auth remove planet
214
+ """
215
+ from pygeofetch.core.authenticator import AuthManager
216
+
217
+ if not yes:
218
+ click.confirm(f"Remove credentials for {provider!r}?", abort=True)
219
+
220
+ mgr = AuthManager(storage_backend='file')
221
+ mgr.remove_credentials(provider)
222
+ console.print(f"[green]Credentials for [bold]{provider}[/] removed.[/]")
223
+
224
+
225
+ @auth.command(name="export")
226
+ @click.option("--provider", default=None, help="Export only this provider (default: all).")
227
+ @click.option(
228
+ "--output",
229
+ "-o",
230
+ default="credentials_backup.json",
231
+ show_default=True,
232
+ help="Output file path.",
233
+ )
234
+ def auth_export(provider: str | None, output: str) -> None:
235
+ """
236
+ Export stored credentials to a JSON file for backup.
237
+
238
+ WARNING: Exported file contains sensitive credentials — store securely.
239
+
240
+ \b
241
+ Example:
242
+ pygeofetch auth export --output backup.json
243
+ pygeofetch auth export --provider usgs --output usgs_creds.json
244
+ """
245
+ from pygeofetch.core.authenticator import AuthManager
246
+
247
+ mgr = AuthManager(storage_backend='file')
248
+ data = mgr.export_credentials(provider_filter=provider)
249
+
250
+ with open(output, "w") as f:
251
+ json.dump(data, f, indent=2, default=str)
252
+
253
+ console.print(
254
+ f"[yellow]WARNING: {output} contains sensitive credentials. "
255
+ "Store it securely and delete after use.[/]\n"
256
+ f"[green]Exported {len(data)} provider(s) to {output}[/]"
257
+ )
@@ -0,0 +1,143 @@
1
+ """
2
+ Configuration CLI commands for pygeofetch.
3
+
4
+ Usage::
5
+
6
+ pygeofetch config show
7
+ pygeofetch config get download.parallel
8
+ pygeofetch config set download.parallel 4
9
+ pygeofetch config path
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import sys
15
+
16
+ import click
17
+ from rich.console import Console
18
+ from rich.syntax import Syntax
19
+
20
+ console = Console()
21
+
22
+
23
+ @click.group()
24
+ def config() -> None:
25
+ """Inspect and modify pygeofetch configuration."""
26
+
27
+
28
+ @config.command(name="show")
29
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON.")
30
+ def config_show(as_json: bool) -> None:
31
+ """Show the effective configuration (all layers merged)."""
32
+ import json
33
+ from pygeofetch.config.settings import get_settings
34
+
35
+ settings = get_settings()
36
+ data = settings.model_dump()
37
+
38
+ if as_json:
39
+ click.echo(json.dumps(data, indent=2, default=str))
40
+ return
41
+
42
+ import yaml
43
+ rendered = yaml.dump(data, default_flow_style=False, sort_keys=True)
44
+ console.print(Syntax(rendered, "yaml", theme="monokai"))
45
+
46
+
47
+ @config.command(name="get")
48
+ @click.argument("key")
49
+ def config_get(key: str) -> None:
50
+ """
51
+ Get a single configuration value by dotted KEY path.
52
+
53
+ \b
54
+ Example:
55
+ pygeofetch config get download.parallel
56
+ """
57
+ from pygeofetch.config.settings import get_settings
58
+
59
+ settings = get_settings()
60
+ data = settings.model_dump()
61
+
62
+ parts = key.split(".")
63
+ value = data
64
+ for part in parts:
65
+ if isinstance(value, dict) and part in value:
66
+ value = value[part]
67
+ else:
68
+ console.print(f"[red]Key not found: {key!r}[/]")
69
+ sys.exit(1)
70
+
71
+ console.print(f"{key} = {value!r}")
72
+
73
+
74
+ @config.command(name="set")
75
+ @click.argument("key")
76
+ @click.argument("value")
77
+ def config_set(key: str, value: str) -> None:
78
+ """
79
+ Set a configuration value in the user config file.
80
+
81
+ The value is cast to int/float/bool if it looks like one; otherwise stored as string.
82
+
83
+ \b
84
+ Example:
85
+ pygeofetch config set download.parallel 4
86
+ pygeofetch config set cache.ttl_seconds 7200
87
+ """
88
+ from pygeofetch.config.settings import get_settings, save_user_config
89
+
90
+ # Try to coerce to typed value
91
+ typed_value: object = value
92
+ if value.lower() in ("true", "yes"):
93
+ typed_value = True
94
+ elif value.lower() in ("false", "no"):
95
+ typed_value = False
96
+ else:
97
+ try:
98
+ typed_value = int(value)
99
+ except ValueError:
100
+ try:
101
+ typed_value = float(value)
102
+ except ValueError:
103
+ pass # keep as string
104
+
105
+ # Build nested dict from dotted key
106
+ parts = key.split(".")
107
+ nested: dict = {}
108
+ current = nested
109
+ for i, part in enumerate(parts):
110
+ if i == len(parts) - 1:
111
+ current[part] = typed_value
112
+ else:
113
+ current[part] = {}
114
+ current = current[part]
115
+
116
+ save_user_config(nested)
117
+ console.print(f"[green]Set[/] {key} = {typed_value!r}")
118
+
119
+
120
+ @config.command(name="path")
121
+ def config_path() -> None:
122
+ """Show the location of configuration files."""
123
+ from pygeofetch.config.settings import get_config_dir
124
+
125
+ cfg_dir = get_config_dir()
126
+ console.print(f"Config directory: [cyan]{cfg_dir}[/]")
127
+ console.print(f"User config: [cyan]{cfg_dir / 'config.yaml'}[/]")
128
+ console.print(f"Credentials: [cyan]{cfg_dir / 'credentials.json'}[/]")
129
+ console.print(f"Cache: [cyan]{cfg_dir / 'cache'}[/]")
130
+
131
+
132
+ @config.command(name="reset")
133
+ @click.confirmation_option(prompt="Reset user config to defaults?")
134
+ def config_reset() -> None:
135
+ """Remove the user configuration file, restoring defaults."""
136
+ from pygeofetch.config.settings import get_config_dir
137
+
138
+ cfg_path = get_config_dir() / "config.yaml"
139
+ if cfg_path.exists():
140
+ cfg_path.unlink()
141
+ console.print(f"[green]Removed {cfg_path}[/]")
142
+ else:
143
+ console.print("[dim]No user config file found.[/]")