earthscope-cli 1.1.0__tar.gz → 1.1.2__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 (29) hide show
  1. earthscope_cli-1.1.2/PKG-INFO +121 -0
  2. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/pyproject.toml +7 -7
  3. earthscope_cli-1.1.2/src/earthscope_cli/__init__.py +1 -0
  4. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/common.py +1 -4
  5. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/debug.py +1 -5
  6. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/dropoff/render.py +43 -1
  7. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/dropoff/typer.py +52 -4
  8. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/dropoff/util.py +49 -0
  9. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/login.py +1 -4
  10. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/main.py +1 -4
  11. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/user.py +1 -5
  12. earthscope_cli-1.1.2/src/earthscope_cli.egg-info/PKG-INFO +121 -0
  13. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli.egg-info/requires.txt +3 -3
  14. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/tests/test_dropoff.py +167 -4
  15. earthscope_cli-1.1.0/PKG-INFO +0 -323
  16. earthscope_cli-1.1.0/src/earthscope_cli/__init__.py +0 -1
  17. earthscope_cli-1.1.0/src/earthscope_cli.egg-info/PKG-INFO +0 -323
  18. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/LICENSE +0 -0
  19. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/README.md +0 -0
  20. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/setup.cfg +0 -0
  21. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/setup.py +0 -0
  22. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli/util.py +0 -0
  23. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli.egg-info/SOURCES.txt +0 -0
  24. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli.egg-info/dependency_links.txt +0 -0
  25. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli.egg-info/entry_points.txt +0 -0
  26. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/src/earthscope_cli.egg-info/top_level.txt +0 -0
  27. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/tests/test_cli.py +0 -0
  28. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/tests/test_login.py +0 -0
  29. {earthscope_cli-1.1.0 → earthscope_cli-1.1.2}/tests/test_user.py +0 -0
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: earthscope-cli
3
+ Version: 1.1.2
4
+ Summary: A CLI for the EarthScope API
5
+ Author-email: EarthScope <data-help@earthscope.org>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://gitlab.com/earthscope/public/earthscope-cli
8
+ Classifier: Programming Language :: Python
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: typer<0.24.0
15
+ Requires-Dist: typer-di>=0.1.3
16
+ Requires-Dist: earthscope-sdk>=1.3.1
17
+ Requires-Dist: rich>=13.8.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: black; extra == "dev"
20
+ Requires-Dist: bumpver; extra == "dev"
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: pre-commit; extra == "dev"
23
+ Requires-Dist: pytest; extra == "dev"
24
+ Requires-Dist: twine>=6.0.1; extra == "dev"
25
+ Requires-Dist: pip-tools; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # EarthScope CLI
29
+
30
+ A CLI for interacting with EarthScope's APIs
31
+
32
+ ## Getting Started
33
+
34
+ ### Requirements
35
+
36
+ To use the CLI you must have:
37
+
38
+ - Registered an account with Earthscope ([sign up now](https://earthscope.org/user/login)). See [here](https://www.earthscope.org/data/authentication) for more information
39
+ - Python >= 3.9
40
+
41
+ ### Installation
42
+
43
+ Install from PyPI
44
+
45
+ ```shell
46
+ pip install earthscope-cli
47
+ ```
48
+
49
+ ### Usage
50
+
51
+ A new `es` command is available in your terminal. Use `--help` with any command to explore commands and options.
52
+
53
+ ```shell
54
+ es --help
55
+ es user --help
56
+ ```
57
+
58
+ #### Login to your EarthScope account
59
+
60
+ ```shell
61
+ es login
62
+ ```
63
+
64
+ This will open your browser to a confirmation page with the same code shown on your command line.
65
+ If you are on a device that does not have a web browser, you can copy the displayed url in a browser on another device (personal computer, mobile device, etc...) and complete the confirmation there.
66
+
67
+ The `es login` command will save your token locally. If this token is deleted, you will need to re-authenticate (login) to retrieve your token again.
68
+
69
+ #### Get your access token
70
+
71
+ ```shell
72
+ es user get-access-token
73
+ ```
74
+
75
+ The `get-access-token` command will display your access token. If your access token is close to expiration or expired,
76
+ the default behavior is to automatically refresh your token.
77
+
78
+ If you want to manually refresh your token:
79
+
80
+ ```shell
81
+ es user refresh-access-token
82
+ ```
83
+
84
+ Never share your tokens. If you think your token has been compromised, please revoke your refresh token and re-authenticate (login):
85
+
86
+ ```shell
87
+ es user revoke-refresh-token
88
+ es login
89
+ ```
90
+
91
+ #### Get your user profile
92
+
93
+ ```shell
94
+ es user get-profile
95
+ ```
96
+
97
+ ## Documentation
98
+
99
+ For detailed usage examples, authentication guides, and advanced features, see the [full documentation](https://docs.earthscope.org/projects/CLI).
100
+
101
+ ## EarthScope SDK
102
+
103
+ If you would like to use EarthScope APIs from python, please use the [earthscope-sdk](https://gitlab.com/earthscope/public/earthscope-sdk/) directly.
104
+
105
+ ## FAQ/troubleshooting
106
+
107
+ - **How long does my access token last?**
108
+ - Your access token lasts 24 hours. Your refresh token can be used to refresh your access token.
109
+ - **How long does my refresh token last?**
110
+ - Your refresh token will never expire - unless you are inactive (do not use it) for one year.
111
+ If it does expire, you will need to re-authenticate to get a new access and refresh token.
112
+ - **What is a refresh token and how does the CLI use it?**
113
+ - A refresh token is a special token that is used to renew your access token without you needing to log in again.
114
+ The refresh token is obtained from your access token, and using the `es user get-access-token` command will automatically
115
+ renew your access token if it is close to expiration. You can 'manually' refresh your access token by using the command `es user refresh-access-token`.
116
+ If your access token is compromised, you can revoke your refresh token using `es user revoke-refresh-token`. Once your access token expires,
117
+ it can no longer be renewed and you will need to re-login.
118
+ - **Should I hard-code my access token into my script?**
119
+ - No. We recommend you use the cli commands to retrieve your access tokens in your scripts.
120
+ This way your access token will not be compromised by anyone viewing your script.
121
+ The access token only lasts 24 hours and cannot be used afterwards unless refreshed.
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "earthscope-cli"
7
- version = "1.1.0"
7
+ version = "1.1.2"
8
8
  description = "A CLI for the EarthScope API"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "EarthScope", email = "data-help@earthscope.org" }]
11
- license = { file = "LICENSE" }
11
+ license = "Apache-2.0"
12
+ license-files = ["LICENSE"]
12
13
  classifiers = [
13
- "License :: OSI Approved :: Apache Software License",
14
14
  "Programming Language :: Python",
15
15
  "Programming Language :: Python :: 3",
16
16
  "Operating System :: OS Independent",
@@ -18,9 +18,9 @@ classifiers = [
18
18
 
19
19
  #Suggestion not to pin dependencies since the package should work in many different python environments
20
20
  dependencies = [
21
- "typer-slim>=0.17.3",
21
+ "typer<0.24.0",
22
22
  "typer-di>=0.1.3",
23
- "earthscope-sdk>=1.3.0",
23
+ "earthscope-sdk>=1.3.1",
24
24
  "rich>=13.8.0",
25
25
  ]
26
26
  requires-python = ">=3.9"
@@ -32,7 +32,7 @@ dev = [
32
32
  "build",
33
33
  "pre-commit",
34
34
  "pytest",
35
- "twine",
35
+ "twine>=6.0.1",
36
36
  "pip-tools",
37
37
  ]
38
38
 
@@ -43,7 +43,7 @@ Homepage = "https://gitlab.com/earthscope/public/earthscope-cli"
43
43
  es = "earthscope_cli.main:app"
44
44
 
45
45
  [tool.bumpver]
46
- current_version = "1.1.0"
46
+ current_version = "1.1.2"
47
47
  version_pattern = "MAJOR.MINOR.PATCH[PYTAGNUM]"
48
48
  commit_message = "chore: bump version {old_version} -> {new_version}"
49
49
  commit = true
@@ -0,0 +1 @@
1
+ __version__ = "1.1.2"
@@ -1,12 +1,9 @@
1
- from contextlib import suppress
2
1
  from typing import Annotated, Optional
3
2
 
4
3
  import typer
4
+ from rich import print
5
5
  from typer_di import Depends
6
6
 
7
- with suppress(ModuleNotFoundError):
8
- from rich import print
9
-
10
7
  GLOBAL_HELP_PANEL = "Global Options"
11
8
 
12
9
 
@@ -1,13 +1,9 @@
1
- from contextlib import suppress
2
-
3
1
  import typer
2
+ from rich import print
4
3
  from typer_di import Depends, TyperDI
5
4
 
6
5
  from earthscope_cli.common import get_sdk
7
6
 
8
- with suppress(ModuleNotFoundError):
9
- from rich import print
10
-
11
7
  app = TyperDI()
12
8
 
13
9
 
@@ -2,7 +2,7 @@ import threading
2
2
  from typing import Dict, List, Optional
3
3
 
4
4
  from earthscope_sdk.client.dropoff._multipart_uploader import UploadStatus
5
- from earthscope_sdk.client.dropoff.models import DropoffObject
5
+ from earthscope_sdk.client.dropoff.models import DropoffObject, DropoffSummary
6
6
  from rich import print
7
7
  from rich.console import Group
8
8
  from rich.live import Live
@@ -84,6 +84,31 @@ def print_dropoff_objects_table(
84
84
  print()
85
85
 
86
86
 
87
+ def print_dropoff_summary(summary: DropoffSummary, *, prefix: Optional[str] = None):
88
+ if not summary.status_counts:
89
+ print(f"[yellow]No objects found in prefix '{prefix}'")
90
+ return
91
+
92
+ title = "Dropoff Summary"
93
+ if prefix:
94
+ title += f" for {prefix}"
95
+
96
+ table = Table(
97
+ title=title,
98
+ show_header=True,
99
+ title_style="bold magenta",
100
+ header_style="bold magenta",
101
+ )
102
+ table.add_column("Status")
103
+ table.add_column("Count")
104
+ for status in summary.status_counts:
105
+ table.add_row(status.status, str(status.count))
106
+
107
+ print()
108
+ print(table)
109
+ print()
110
+
111
+
87
112
  class AggregateBytesColumn(ProgressColumn):
88
113
  """
89
114
  Custom column that shows aggregate bytes across all uploads.
@@ -181,6 +206,23 @@ class CompositeProgressBarColumn(ProgressColumn):
181
206
  return result
182
207
 
183
208
 
209
+ class UploadSummary:
210
+ def __init__(self, total: int, succeeded: int):
211
+ self.total = total
212
+ self.succeeded = succeeded
213
+ self.failed = total - succeeded
214
+
215
+ def print(self):
216
+ color = (
217
+ "green"
218
+ if self.failed == 0
219
+ else ("red" if self.succeeded == 0 else "yellow")
220
+ )
221
+ print(
222
+ f"[{color}]Summary: {self.succeeded}/{self.total} files succeeded, {self.failed} failed"
223
+ )
224
+
225
+
184
226
  class ConcurrentUploadProgressDisplay:
185
227
  """
186
228
  Rich progress display for concurrent file uploads.
@@ -12,13 +12,17 @@ from typer_di import Depends, TyperDI
12
12
  from earthscope_cli.common import get_sdk_refreshed
13
13
  from earthscope_cli.dropoff.render import (
14
14
  ConcurrentUploadProgressDisplay,
15
+ UploadSummary,
15
16
  print_dropoff_objects_table,
17
+ print_dropoff_summary,
16
18
  )
17
19
  from earthscope_cli.dropoff.util import (
18
20
  DropoffOptions,
21
+ FilterOptions,
19
22
  collect_files,
20
23
  get_category,
21
24
  get_dropoff_options,
25
+ get_filter_options,
22
26
  )
23
27
 
24
28
  app = TyperDI()
@@ -67,10 +71,38 @@ def get_object_history(
67
71
  print(f"[yellow]No history found for category '{cat_str}' with key '{key}'")
68
72
 
69
73
 
74
+ @app.command(name="get-summary")
75
+ def get_summary(
76
+ sdk: Annotated[EarthScopeClient, Depends(get_sdk_refreshed)],
77
+ options: Annotated[DropoffOptions, Depends(get_dropoff_options)],
78
+ filters: Annotated[FilterOptions, Depends(get_filter_options)],
79
+ prefix: Annotated[
80
+ str,
81
+ typer.Option(help="The prefix of the objects to get the summary for"),
82
+ ],
83
+ ):
84
+ """
85
+ Get a summary of a dropoff prefix.
86
+
87
+ es dropoff get-summary -c <type> --prefix <prefix>
88
+ es dropoff get-summary -c miniseed --prefix demo/
89
+ es dropoff get-summary -c miniseed --prefix demo/ --submitted-after 2025-01-01T00:00:00Z
90
+ es dropoff get-summary -c miniseed --prefix demo/ --submitted-before 2025-12-31T23:59:59Z
91
+ """
92
+ result = sdk.dropoff.get_summary(
93
+ category=options.category.value,
94
+ prefix=prefix,
95
+ submitted_after=filters.submitted_after,
96
+ submitted_before=filters.submitted_before,
97
+ )
98
+ print_dropoff_summary(result, prefix=prefix)
99
+
100
+
70
101
  @app.command(name="list-objects")
71
102
  def list_objects(
72
103
  sdk: Annotated[EarthScopeClient, Depends(get_sdk_refreshed)],
73
104
  options: Annotated[DropoffOptions, Depends(get_dropoff_options)],
105
+ filters: Annotated[FilterOptions, Depends(get_filter_options)],
74
106
  prefix: Annotated[
75
107
  str,
76
108
  typer.Option(help="Filter by object prefix"),
@@ -83,12 +115,18 @@ def list_objects(
83
115
  es dropoff list-objects -c miniseed
84
116
  es dropoff list-objects -c miniseed --prefix demo/
85
117
  es dropoff list-objects -c miniseed --offset 100 --limit 100
118
+ es dropoff list-objects -c miniseed --status FAILED
119
+ es dropoff list-objects -c miniseed --submitted-after 2025-01-01T00:00:00Z
120
+ es dropoff list-objects -c miniseed --submitted-before 2025-12-31T23:59:59Z
86
121
  """
87
122
  result = sdk.dropoff.list_objects(
88
123
  category=options.category.value,
89
124
  prefix=prefix,
90
125
  offset=options.offset,
91
126
  limit=options.limit,
127
+ submitted_after=filters.submitted_after,
128
+ submitted_before=filters.submitted_before,
129
+ status=filters.status,
92
130
  )
93
131
 
94
132
  suffix = ""
@@ -104,7 +142,9 @@ def list_objects(
104
142
  next_offset=result.offset + result.limit,
105
143
  )
106
144
 
107
- print(f"[yellow]No objects found for category '{cat_str}'{suffix}")
145
+ print(
146
+ f"[yellow]No objects matched specified criteria: category='{cat_str}', prefix='{prefix}', offset={options.offset}, limit={options.limit}', submitted_after={filters.submitted_after}, submitted_before={filters.submitted_before}, status={filters.status}'"
147
+ )
108
148
 
109
149
 
110
150
  @app.command(name="upload")
@@ -176,22 +216,27 @@ def upload(
176
216
  don't overwrite each other and maintains meaningful organization in S3.
177
217
  """
178
218
  # Parse the input path to get a list of files
219
+ total_collected = 0
220
+ succeeded = 0
179
221
  files: list[tuple[Path, str]] = []
180
222
  for p, k in collect_files(paths):
223
+ total_collected += 1
181
224
  try:
182
225
  Validator(p, category=category).validate_all()
183
226
  except Exception as e:
184
227
  print(f"[red]{e}")
185
- raise typer.Exit(code=1)
186
228
  else:
187
229
  files.append((p, k))
188
230
 
189
231
  if not files:
190
- print(f"[red]No files found in paths: {paths}")
232
+ paths_str = ", ".join(str(p) for p in paths)
233
+ print(f"[red]No valid {category.value} files found in paths: {paths_str}")
234
+ UploadSummary(total=total_collected, succeeded=succeeded).print()
191
235
  raise typer.Exit(code=1)
192
236
 
237
+ display = ConcurrentUploadProgressDisplay(len(files))
193
238
  try:
194
- with ConcurrentUploadProgressDisplay(len(files)) as display:
239
+ with display:
195
240
  sdk.dropoff.put_objects(
196
241
  objects=files,
197
242
  category=category,
@@ -203,3 +248,6 @@ def upload(
203
248
  except KeyboardInterrupt:
204
249
  print()
205
250
  print("[yellow]Upload interrupted. Use the same command to resume the upload.")
251
+ finally:
252
+ succeeded = len(display.completed_files)
253
+ UploadSummary(total=total_collected, succeeded=succeeded).print()
@@ -18,6 +18,13 @@ class PaginationOptions:
18
18
  limit: int
19
19
 
20
20
 
21
+ @dataclass
22
+ class FilterOptions:
23
+ submitted_before: Optional[datetime] = None
24
+ submitted_after: Optional[datetime] = None
25
+ status: Optional[str] = None
26
+
27
+
21
28
  @dataclass
22
29
  class DropoffOptions(PaginationOptions):
23
30
  category: DropoffCategory
@@ -86,6 +93,48 @@ def get_category(
86
93
  return DropoffCategory(cat_str)
87
94
 
88
95
 
96
+ def get_filter_options(
97
+ submitted_after: Annotated[
98
+ Optional[datetime],
99
+ typer.Option(
100
+ "--submitted-after",
101
+ help="Filter results submitted after this datetime (ISO 8601)",
102
+ formats=[
103
+ "%Y-%m-%dT%H:%M:%S%z",
104
+ "%Y-%m-%dT%H:%M:%SZ",
105
+ "%Y-%m-%d%z",
106
+ "%Y-%m-%dZ",
107
+ ],
108
+ ),
109
+ ] = None,
110
+ submitted_before: Annotated[
111
+ Optional[datetime],
112
+ typer.Option(
113
+ "--submitted-before",
114
+ help="Filter results submitted before this datetime (ISO 8601)",
115
+ formats=[
116
+ "%Y-%m-%dT%H:%M:%S%z",
117
+ "%Y-%m-%dT%H:%M:%SZ",
118
+ "%Y-%m-%d%z",
119
+ "%Y-%m-%dZ",
120
+ ],
121
+ ),
122
+ ] = None,
123
+ status: Annotated[
124
+ Optional[str],
125
+ typer.Option(
126
+ "--status",
127
+ help="Filter results by status",
128
+ ),
129
+ ] = None,
130
+ ) -> FilterOptions:
131
+ return FilterOptions(
132
+ submitted_before=submitted_before,
133
+ submitted_after=submitted_after,
134
+ status=status,
135
+ )
136
+
137
+
89
138
  def get_dropoff_options(
90
139
  category: Annotated[DropoffCategory, Depends(get_category)],
91
140
  offset: Annotated[
@@ -1,15 +1,12 @@
1
- from contextlib import suppress
2
1
  from textwrap import dedent
3
2
  from typing import TYPE_CHECKING
4
3
 
5
4
  import typer
5
+ from rich import print
6
6
  from typer_di import Depends, TyperDI
7
7
 
8
8
  from earthscope_cli.common import get_sdk
9
9
 
10
- with suppress(ModuleNotFoundError):
11
- from rich import print
12
-
13
10
  if TYPE_CHECKING:
14
11
  from earthscope_sdk import EarthScopeClient
15
12
 
@@ -1,4 +1,3 @@
1
- from contextlib import suppress
2
1
  from typing import Annotated
3
2
 
4
3
  import typer
@@ -10,15 +9,13 @@ from earthscope_sdk.auth.error import (
10
9
  NoTokensError,
11
10
  UnauthorizedError,
12
11
  )
12
+ from rich import print
13
13
 
14
14
  from earthscope_cli import __version__ as cli_version
15
15
  from earthscope_cli import debug, login, user
16
16
  from earthscope_cli.dropoff.typer import app as dropoff_app
17
17
  from earthscope_cli.util import ErrorHandlingTyper
18
18
 
19
- with suppress(ModuleNotFoundError):
20
- from rich import print
21
-
22
19
  app = ErrorHandlingTyper(
23
20
  pretty_exceptions_enable=False,
24
21
  )
@@ -1,14 +1,10 @@
1
- from contextlib import suppress
2
-
3
1
  import typer
2
+ from rich import print
4
3
  from typer_di import Depends, TyperDI
5
4
 
6
5
  from earthscope_cli import login
7
6
  from earthscope_cli.common import get_sdk, get_sdk_refreshed
8
7
 
9
- with suppress(ModuleNotFoundError):
10
- from rich import print
11
-
12
8
  app = TyperDI()
13
9
 
14
10
  # Register aliases to login/logout
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: earthscope-cli
3
+ Version: 1.1.2
4
+ Summary: A CLI for the EarthScope API
5
+ Author-email: EarthScope <data-help@earthscope.org>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://gitlab.com/earthscope/public/earthscope-cli
8
+ Classifier: Programming Language :: Python
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: typer<0.24.0
15
+ Requires-Dist: typer-di>=0.1.3
16
+ Requires-Dist: earthscope-sdk>=1.3.1
17
+ Requires-Dist: rich>=13.8.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: black; extra == "dev"
20
+ Requires-Dist: bumpver; extra == "dev"
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: pre-commit; extra == "dev"
23
+ Requires-Dist: pytest; extra == "dev"
24
+ Requires-Dist: twine>=6.0.1; extra == "dev"
25
+ Requires-Dist: pip-tools; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # EarthScope CLI
29
+
30
+ A CLI for interacting with EarthScope's APIs
31
+
32
+ ## Getting Started
33
+
34
+ ### Requirements
35
+
36
+ To use the CLI you must have:
37
+
38
+ - Registered an account with Earthscope ([sign up now](https://earthscope.org/user/login)). See [here](https://www.earthscope.org/data/authentication) for more information
39
+ - Python >= 3.9
40
+
41
+ ### Installation
42
+
43
+ Install from PyPI
44
+
45
+ ```shell
46
+ pip install earthscope-cli
47
+ ```
48
+
49
+ ### Usage
50
+
51
+ A new `es` command is available in your terminal. Use `--help` with any command to explore commands and options.
52
+
53
+ ```shell
54
+ es --help
55
+ es user --help
56
+ ```
57
+
58
+ #### Login to your EarthScope account
59
+
60
+ ```shell
61
+ es login
62
+ ```
63
+
64
+ This will open your browser to a confirmation page with the same code shown on your command line.
65
+ If you are on a device that does not have a web browser, you can copy the displayed url in a browser on another device (personal computer, mobile device, etc...) and complete the confirmation there.
66
+
67
+ The `es login` command will save your token locally. If this token is deleted, you will need to re-authenticate (login) to retrieve your token again.
68
+
69
+ #### Get your access token
70
+
71
+ ```shell
72
+ es user get-access-token
73
+ ```
74
+
75
+ The `get-access-token` command will display your access token. If your access token is close to expiration or expired,
76
+ the default behavior is to automatically refresh your token.
77
+
78
+ If you want to manually refresh your token:
79
+
80
+ ```shell
81
+ es user refresh-access-token
82
+ ```
83
+
84
+ Never share your tokens. If you think your token has been compromised, please revoke your refresh token and re-authenticate (login):
85
+
86
+ ```shell
87
+ es user revoke-refresh-token
88
+ es login
89
+ ```
90
+
91
+ #### Get your user profile
92
+
93
+ ```shell
94
+ es user get-profile
95
+ ```
96
+
97
+ ## Documentation
98
+
99
+ For detailed usage examples, authentication guides, and advanced features, see the [full documentation](https://docs.earthscope.org/projects/CLI).
100
+
101
+ ## EarthScope SDK
102
+
103
+ If you would like to use EarthScope APIs from python, please use the [earthscope-sdk](https://gitlab.com/earthscope/public/earthscope-sdk/) directly.
104
+
105
+ ## FAQ/troubleshooting
106
+
107
+ - **How long does my access token last?**
108
+ - Your access token lasts 24 hours. Your refresh token can be used to refresh your access token.
109
+ - **How long does my refresh token last?**
110
+ - Your refresh token will never expire - unless you are inactive (do not use it) for one year.
111
+ If it does expire, you will need to re-authenticate to get a new access and refresh token.
112
+ - **What is a refresh token and how does the CLI use it?**
113
+ - A refresh token is a special token that is used to renew your access token without you needing to log in again.
114
+ The refresh token is obtained from your access token, and using the `es user get-access-token` command will automatically
115
+ renew your access token if it is close to expiration. You can 'manually' refresh your access token by using the command `es user refresh-access-token`.
116
+ If your access token is compromised, you can revoke your refresh token using `es user revoke-refresh-token`. Once your access token expires,
117
+ it can no longer be renewed and you will need to re-login.
118
+ - **Should I hard-code my access token into my script?**
119
+ - No. We recommend you use the cli commands to retrieve your access tokens in your scripts.
120
+ This way your access token will not be compromised by anyone viewing your script.
121
+ The access token only lasts 24 hours and cannot be used afterwards unless refreshed.
@@ -1,6 +1,6 @@
1
- typer-slim>=0.17.3
1
+ typer<0.24.0
2
2
  typer-di>=0.1.3
3
- earthscope-sdk>=1.3.0
3
+ earthscope-sdk>=1.3.1
4
4
  rich>=13.8.0
5
5
 
6
6
  [dev]
@@ -9,5 +9,5 @@ bumpver
9
9
  build
10
10
  pre-commit
11
11
  pytest
12
- twine
12
+ twine>=6.0.1
13
13
  pip-tools