earthscope-sdk 0.2.0__py3-none-any.whl → 1.0.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.
Files changed (31) hide show
  1. earthscope_sdk/__init__.py +5 -1
  2. earthscope_sdk/auth/auth_flow.py +240 -346
  3. earthscope_sdk/auth/client_credentials_flow.py +42 -162
  4. earthscope_sdk/auth/device_code_flow.py +169 -213
  5. earthscope_sdk/auth/error.py +46 -0
  6. earthscope_sdk/client/__init__.py +3 -0
  7. earthscope_sdk/client/_client.py +35 -0
  8. earthscope_sdk/client/user/_base.py +39 -0
  9. earthscope_sdk/client/user/_service.py +94 -0
  10. earthscope_sdk/client/user/models.py +53 -0
  11. earthscope_sdk/common/__init__.py +0 -0
  12. earthscope_sdk/common/_sync_runner.py +141 -0
  13. earthscope_sdk/common/client.py +99 -0
  14. earthscope_sdk/common/context.py +174 -0
  15. earthscope_sdk/common/service.py +59 -0
  16. earthscope_sdk/config/__init__.py +0 -0
  17. earthscope_sdk/config/_bootstrap.py +42 -0
  18. earthscope_sdk/config/_compat.py +148 -0
  19. earthscope_sdk/config/_util.py +48 -0
  20. earthscope_sdk/config/error.py +4 -0
  21. earthscope_sdk/config/models.py +310 -0
  22. earthscope_sdk/config/settings.py +295 -0
  23. earthscope_sdk/model/secret.py +29 -0
  24. {earthscope_sdk-0.2.0.dist-info → earthscope_sdk-1.0.0.dist-info}/METADATA +147 -123
  25. earthscope_sdk-1.0.0.dist-info/RECORD +30 -0
  26. {earthscope_sdk-0.2.0.dist-info → earthscope_sdk-1.0.0.dist-info}/WHEEL +1 -1
  27. earthscope_sdk/user/user.py +0 -32
  28. earthscope_sdk-0.2.0.dist-info/RECORD +0 -12
  29. /earthscope_sdk/{user → client/user}/__init__.py +0 -0
  30. {earthscope_sdk-0.2.0.dist-info → earthscope_sdk-1.0.0.dist-info/licenses}/LICENSE +0 -0
  31. {earthscope_sdk-0.2.0.dist-info → earthscope_sdk-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,295 @@
1
+ from contextlib import suppress
2
+ from functools import cached_property
3
+ from typing import Annotated, Any, Type
4
+
5
+ from pydantic import Field, TypeAdapter, ValidationError, field_validator
6
+ from pydantic_settings import (
7
+ BaseSettings,
8
+ InitSettingsSource,
9
+ PydanticBaseSettingsSource,
10
+ SettingsConfigDict,
11
+ TomlConfigSettingsSource,
12
+ )
13
+
14
+ from earthscope_sdk.config._bootstrap import BootstrapEnvironmentSettingsSource
15
+ from earthscope_sdk.config._compat import LegacyEarthScopeCLISettingsSource
16
+ from earthscope_sdk.config._util import deep_merge, get_config_dir, slugify
17
+ from earthscope_sdk.config.error import ProfileDoesNotExistError
18
+ from earthscope_sdk.config.models import SdkBaseSettings, Tokens
19
+
20
+ _BOOTSTRAP_ENV_VAR = "ES_BOOTSTRAP_SETTINGS"
21
+ """Environment variable for bootstrapping the SDK"""
22
+
23
+ _DEFAULT_PROFILE = "default"
24
+ """Default profile name"""
25
+
26
+ _LOCAL_APP_DIR = get_config_dir(app_name="earthscope")
27
+ """Local SDK application directory"""
28
+
29
+
30
+ def _get_config_toml_path():
31
+ """
32
+ Local SDK configuration file
33
+ """
34
+ return _LOCAL_APP_DIR / "config.toml"
35
+
36
+
37
+ def _get_profile_dir(profile_name: str):
38
+ """
39
+ Retrieve the local SDK directory for the named profile
40
+ """
41
+ return _LOCAL_APP_DIR / slugify(profile_name)
42
+
43
+
44
+ def _get_profile_tokens_file(profile_name: str):
45
+ """
46
+ Retrieve the local SDK tokens file for the named profile
47
+ """
48
+ profile_dir = _get_profile_dir(profile_name)
49
+ return profile_dir / "tokens.json"
50
+
51
+
52
+ class _SdkGlobalSettings(BaseSettings):
53
+ """
54
+ EarthScope SDK global settings; not for direct use.
55
+
56
+ This class only loads settings from config.toml.
57
+ """
58
+
59
+ defaults: Annotated[
60
+ SdkBaseSettings,
61
+ Field(validation_alias="default"),
62
+ ] = {}
63
+
64
+ profile_settings_by_name: Annotated[
65
+ dict[str, SdkBaseSettings],
66
+ Field(validation_alias="profile"),
67
+ ] = {}
68
+
69
+ model_config = SettingsConfigDict(
70
+ extra="ignore",
71
+ frozen=True,
72
+ nested_model_default_partial_update=True,
73
+ populate_by_name=True,
74
+ )
75
+
76
+ def get_merged(self, profile_name: str):
77
+ """
78
+ Get profile-specific settings merged with defaults
79
+ """
80
+ try:
81
+ p = self.profile_settings_by_name[profile_name]
82
+ except KeyError:
83
+ raise ProfileDoesNotExistError(f"Profile '{profile_name}' does not exist")
84
+
85
+ defaults = self.defaults.model_dump(
86
+ exclude_none=True,
87
+ exclude_unset=True,
88
+ exclude_defaults=True,
89
+ )
90
+ profile_specific = p.model_dump(
91
+ exclude_defaults=True, # defer to top-level field defaults
92
+ exclude_unset=True, # only keep explicitly set fields
93
+ exclude_none=True,
94
+ )
95
+
96
+ # order is imporant; profile-specific args override default args
97
+ return deep_merge(defaults, profile_specific, profile_name=profile_name)
98
+
99
+ @field_validator("profile_settings_by_name", mode="before")
100
+ @classmethod
101
+ def ensure_default_profile(cls, v: dict[str, dict]):
102
+ """
103
+ Ensure the default profile exists
104
+ """
105
+ v.setdefault(_DEFAULT_PROFILE, {})
106
+ return v
107
+
108
+ @classmethod
109
+ def settings_customise_sources(cls, settings_cls: Type[BaseSettings], **_):
110
+ """
111
+ Override the loading chain to exclusively check ~/.earthscope/config.toml
112
+ """
113
+ # we get the file path dynamically to allow monkeypatching for tests
114
+ toml_path = _get_config_toml_path()
115
+ toml_settings = TomlConfigSettingsSource(settings_cls, toml_path)
116
+
117
+ return (toml_settings,)
118
+
119
+
120
+ class _GlobalSettingsSource(PydanticBaseSettingsSource):
121
+ """
122
+ This SettingsSource facilitates falling back to settings configured in config.toml
123
+ and state in tokens.json when loading the configuration chain in SdkSettings.
124
+
125
+ Consolidates merged profile state with state loaded from a profile's tokens.json file
126
+ """
127
+
128
+ def __init__(self, settings_cls, *keys: str):
129
+ super().__init__(settings_cls)
130
+ self._keys = keys
131
+
132
+ def __call__(self):
133
+ # Extract profile
134
+ profile_name = _DEFAULT_PROFILE
135
+ for k in self._keys:
136
+ with suppress(KeyError):
137
+ profile_name = self._current_state[k]
138
+ break
139
+
140
+ # Load global merged settings
141
+ merged = _SdkGlobalSettings().get_merged(profile_name)
142
+
143
+ # Load from tokens.json
144
+ tokens_json = {}
145
+ with suppress(FileNotFoundError, ValidationError):
146
+ raw = _get_profile_tokens_file(profile_name).read_bytes()
147
+ tokens = Tokens.model_validate_json(raw)
148
+ tokens_json = tokens.model_dump(
149
+ exclude_none=True,
150
+ exclude_unset=True,
151
+ exclude_defaults=True,
152
+ )
153
+
154
+ # order is imporant; init args override tokens.json args
155
+ return deep_merge({"oauth2": tokens_json}, merged)
156
+
157
+ def __repr__(self) -> str:
158
+ return f"{self.__class__.__name__}()"
159
+
160
+ def get_field_value(self, *args, **kwargs): ... # unused abstract method
161
+
162
+
163
+ class _InitSettingsWithoutDefaultSource(InitSettingsSource):
164
+ """
165
+ InitSettingsSource behavior but excludes default values & unset fields
166
+ to allow values from lower-precedence settings sources to bubble up.
167
+ """
168
+
169
+ def __init__(self, other: InitSettingsSource):
170
+ super().__init__(
171
+ other.settings_cls,
172
+ other.init_kwargs,
173
+ other.nested_model_default_partial_update,
174
+ )
175
+ self.dict_adapter = TypeAdapter(dict[str, Any])
176
+
177
+ def __call__(self) -> dict[str, Any]:
178
+ return self.dict_adapter.dump_python(
179
+ self.init_kwargs,
180
+ exclude_defaults=True,
181
+ exclude_unset=True,
182
+ )
183
+
184
+
185
+ class SdkSettings(SdkBaseSettings, BaseSettings):
186
+ """
187
+ EarthScope SDK settings.
188
+
189
+ Use `profile_name` to utilize a named profile from `~/.earthscope/config.toml`
190
+
191
+ Settings loading chain (order of precedence):
192
+ 1. arguments passed to constructor
193
+ 2. environment variables
194
+ 3. dotenv variables
195
+ 4. ~/.earthscope/config.toml
196
+ """
197
+
198
+ profile_name: Annotated[
199
+ str,
200
+ Field(validation_alias="es_profile"),
201
+ # NOTE: aliases do not include the env_prefix by default; add it explicitly
202
+ ]
203
+
204
+ model_config = SettingsConfigDict(
205
+ env_nested_delimiter="__",
206
+ env_prefix="ES_",
207
+ extra="ignore",
208
+ frozen=True,
209
+ nested_model_default_partial_update=True,
210
+ populate_by_name=True,
211
+ )
212
+
213
+ @cached_property
214
+ def profile_dir(self):
215
+ """
216
+ The path to the local SDK directory for the named profile
217
+ """
218
+ return _get_profile_dir(self.profile_name)
219
+
220
+ @cached_property
221
+ def tokens_file(self):
222
+ """
223
+ The path to the tokens file for the named profile
224
+ """
225
+ return _get_profile_tokens_file(self.profile_name)
226
+
227
+ def delete_tokens(self, missing_ok=False):
228
+ """
229
+ Delete tokens from this named profile's state
230
+
231
+ Args:
232
+ missing_ok: Whether or not to throw an error if the file does not exist
233
+
234
+ Returns:
235
+ this auth flow
236
+ """
237
+ self.tokens_file.unlink(missing_ok=missing_ok)
238
+ return self
239
+
240
+ def write_tokens(self, tokens: Tokens):
241
+ """
242
+ Write tokens to this named profile's state
243
+
244
+ Args:
245
+ tokens: the tokens to persist in local storage
246
+ """
247
+ body = tokens.model_dump_json(
248
+ include=Tokens.model_fields.keys(),
249
+ indent=2,
250
+ context="plaintext", # write SecretStr's actual values in plaintext
251
+ exclude_none=True,
252
+ )
253
+ self.tokens_file.parent.mkdir(parents=True, exist_ok=True)
254
+ self.tokens_file.write_text(body)
255
+
256
+ @classmethod
257
+ def settings_customise_sources(
258
+ cls,
259
+ settings_cls: Type[BaseSettings],
260
+ init_settings: InitSettingsSource,
261
+ env_settings: PydanticBaseSettingsSource,
262
+ dotenv_settings: PydanticBaseSettingsSource,
263
+ **_,
264
+ ):
265
+ """
266
+ Override the loading chain to additionally check ~/.earthscope/config.toml
267
+ """
268
+
269
+ # Init settings, but without defaults & unset values
270
+ init_settings = _InitSettingsWithoutDefaultSource(init_settings)
271
+
272
+ # Check for all the ways profile name may be supplied
273
+ alias = SdkSettings.model_fields["profile_name"].validation_alias
274
+ global_settings = _GlobalSettingsSource(settings_cls, "profile_name", alias)
275
+
276
+ # Check for bootstrapping configuration
277
+ bootstrap_settings = BootstrapEnvironmentSettingsSource(
278
+ settings_cls,
279
+ _BOOTSTRAP_ENV_VAR,
280
+ )
281
+
282
+ # Compatibility with earthscope-cli v0.x.x state:
283
+ # If we find this file, we only care about the access and refresh tokens
284
+ keep_keys = {"access_token", "refresh_token"}
285
+ legacy_settings = LegacyEarthScopeCLISettingsSource(settings_cls, *keep_keys)
286
+
287
+ # Order of precedence
288
+ return (
289
+ init_settings,
290
+ env_settings,
291
+ dotenv_settings,
292
+ global_settings,
293
+ legacy_settings,
294
+ bootstrap_settings,
295
+ )
@@ -0,0 +1,29 @@
1
+ from typing import Annotated
2
+
3
+ from pydantic import PlainSerializer, SerializationInfo
4
+ from pydantic import SecretStr as _SecretStr
5
+
6
+
7
+ def _dump_secret_plaintext(secret: _SecretStr, info: SerializationInfo):
8
+ """
9
+ A special field serializer to dump the actual secret value.
10
+
11
+ Only writes secret in plaintext when `info.context == "plaintext".
12
+
13
+ See [Pydantic docs](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
14
+ """
15
+
16
+ if info.context == "plaintext":
17
+ return secret.get_secret_value()
18
+
19
+ return str(secret)
20
+
21
+
22
+ SecretStr = Annotated[
23
+ _SecretStr,
24
+ PlainSerializer(
25
+ _dump_secret_plaintext,
26
+ return_type=str,
27
+ when_used="json-unless-none",
28
+ ),
29
+ ]
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: earthscope-sdk
3
- Version: 0.2.0
3
+ Version: 1.0.0
4
4
  Summary: An SDK for EarthScope API
5
- Author-email: EarthScope <software@unavco.org>
6
- License: Apache License
5
+ Author-email: EarthScope <data-help@earthscope.org>
6
+ License: Apache License
7
7
  Version 2.0, January 2004
8
8
  http://www.apache.org/licenses/
9
9
 
@@ -210,138 +210,162 @@ Classifier: License :: OSI Approved :: Apache Software License
210
210
  Classifier: Programming Language :: Python
211
211
  Classifier: Programming Language :: Python :: 3
212
212
  Classifier: Operating System :: OS Independent
213
- Requires-Python: >=3.7
213
+ Requires-Python: >=3.9
214
214
  Description-Content-Type: text/markdown
215
215
  License-File: LICENSE
216
- Requires-Dist: pyjwt (>=2.4.0)
217
- Requires-Dist: requests (>=2.27.1)
216
+ Requires-Dist: httpx>=0.27.0
217
+ Requires-Dist: pydantic-settings[toml]>=2.8.0
218
+ Requires-Dist: stamina>=24.3.0
218
219
  Provides-Extra: dev
219
- Requires-Dist: black ; extra == 'dev'
220
- Requires-Dist: bumpver ; extra == 'dev'
221
- Requires-Dist: build ; extra == 'dev'
222
- Requires-Dist: pytest ; extra == 'dev'
223
- Requires-Dist: twine ; extra == 'dev'
224
- Requires-Dist: pip-tools ; extra == 'dev'
220
+ Requires-Dist: bumpver; extra == "dev"
221
+ Requires-Dist: build; extra == "dev"
222
+ Requires-Dist: pytest; extra == "dev"
223
+ Requires-Dist: twine; extra == "dev"
224
+ Requires-Dist: pip-tools; extra == "dev"
225
+ Requires-Dist: pre-commit; extra == "dev"
226
+ Requires-Dist: pytest-httpx; extra == "dev"
227
+ Requires-Dist: pytest-asyncio; extra == "dev"
228
+ Requires-Dist: ruff; extra == "dev"
229
+ Dynamic: license-file
225
230
 
226
231
  # EarthScope SDK
227
232
 
228
- An SDK for authenticating with the EarthScope API
233
+ An SDK for interacting with EarthScope's APIs
229
234
 
230
235
  ## Getting Started
231
236
 
232
- ### USAGE
237
+ ### Installation
233
238
 
234
- 1. **(Optional) Suggest setting up and activating a python virtual environment so as not to clutter your system python**
239
+ Install from PyPI
235
240
 
236
- ```shell
237
- python3 -m venv venv
238
- . venv/bin/activate
241
+ ```shell
242
+ pip install earthscope-sdk
243
+ ```
244
+
245
+ ### Usage
246
+
247
+ For detailed usage info and examples, visit [our SDK docs](https://docs.earthscope.org/projects/SDK).
248
+
249
+ ```py
250
+ # Import and create a client
251
+ from earthscope_sdk import EarthScopeClient
252
+
253
+ client = EarthScopeClient()
254
+
255
+ # Example client method usage; retrieve your user profile
256
+ profile = client.user.get_profile()
257
+ print(profile)
258
+
259
+ # Client cleanup
260
+ client.close()
261
+ ```
262
+
263
+ #### Async Usage
264
+
265
+ There is also an `async` client available
266
+
267
+ ```py
268
+ import asyncio
269
+ from earthscope_sdk import AsyncEarthScopeClient
270
+
271
+ async def main():
272
+ client = AsyncEarthScopeClient()
273
+
274
+ profile = await client.user.get_profile()
275
+ print(profile)
276
+
277
+ await client.close()
278
+
279
+ asyncio.run(main())
280
+ ```
281
+
282
+ #### Context Managers
283
+
284
+ Client classes can also be used as context managers to ensure resource cleanup occurs.
285
+
286
+ ```py
287
+ # sync
288
+ with EarthScopeClient() as client:
289
+ client.user.get_profile()
290
+
291
+ # async
292
+ async with AsyncEarthScopeClient() as client:
293
+ await client.user.get_profile()
294
+ ```
295
+
296
+ ## Bootstrapping Authentication
297
+
298
+ There are a few methods of bootstrapping authentication for the SDK.
299
+
300
+ Once refreshable credentials are available to the SDK, it will transparently handle access token refresh on your behalf.
301
+
302
+ ### Same host
303
+
304
+ If you have the [EarthScope CLI](https://docs.earthscope.org/projects/CLI) installed on the same host that is running your application which uses `earthscope-sdk`, you can simply log in using the CLI. The CLI shares credentials and configuration with this SDK (when running on the same host).
305
+
306
+ Running `es login` will open your browser and prompt you to log in to your EarthScope account.
307
+
308
+ ```console
309
+ $ es login
310
+ Attempting to automatically open the SSO authorization page in your default browser.
311
+ If the browser does not open or you wish to use a different device to authorize this request, open the following URL:
312
+
313
+ https://login.earthscope.org/activate?user_code=ABCD-EFGH
314
+
315
+ Successful login! Access token expires at 2024-12-27 18:50:37+00:00
316
+ ```
317
+
318
+ Now when you run your application, `earthscope-sdk` will find your credentials.
319
+
320
+ ### Different hosts
321
+
322
+ Sometimes your workload runs on different hosts than your main workstation and you cannot feasibly "log in" on all of them. For example, maybe you're running many containers in your workload.
323
+
324
+ You can still use the [EarthScope CLI](https://docs.earthscope.org/projects/CLI) to facilitate auth for applications on other machines.
325
+
326
+ 1. Use the CLI on your primary workstation [as described above](#same-host) to log in.
327
+
328
+ 1. Use the CLI to retrieve your refresh token.
329
+
330
+ ```console
331
+ $ es user get-refresh-token
332
+ <your-refresh-token>
239
333
  ```
240
334
 
241
- 2. **Install earthscope-sdk**
335
+ > **Note: your refresh token should be treated as a secret credential. Anyone with a valid refresh token can use it to continually retrieve new access tokens on your behalf**.
336
+
337
+ 1. Pass this refresh token to all the hosts needing auth for the `earthscope-sdk`. For example, inject the `ES_OAUTH2__REFRESH_TOKEN` environment variable on these hosts.
242
338
 
243
339
  ```shell
244
- pip install earthscope-sdk
340
+ export ES_OAUTH2__REFRESH_TOKEN="<your-refresh-token>"
245
341
  ```
246
- For developers:
247
- ```bash
248
- pip -e install earthscope-sdk[dev]
249
- ```
250
-
251
- 3. **Create/Use required subclasses**
252
- \
253
- To use the **Device Authorization Flow** you will need to create a subclass of the DeviceCodeFlow class. Similarly, to use
254
- the **Machine-to-Machine Client Credentials Flow** you will need to create a subclass of the ClientCredientialFlow class.
255
-
256
- Simple subclasses exist for your use that you can import and use which will allow for locally loading and saving access tokens:
257
- *DeviceCodeFlowSimple* and *ClientCredentialsFlowSimple* (see below for examples on useage)
258
- <br/><br/>
259
- Creating your own subclass:
260
- \
261
- Implementing the following methods in the subclass is required:
262
- * `load_tokens` should implement the ability to load saved tokens
263
- * `save_tokens` should implement the ability to save tokens locally
264
-
265
- additionally for DeviceCodeFlow only:
266
- * `prompt_user` should provide the user with the SSO authorization uri
267
-
268
- You will need to instantiate your subclass with the following instance attributes:
269
-
270
- For DeviceCodeFlow:
271
- * `audience`, `domain`, `client_id`, and `scope`.
272
-
273
- For ClientCredentialsFlow:
274
- * `audience`, `client_credentials`, and `domain`.
275
-
276
- where client_credentials contains the machine-to-machine `client_id` and `client_secret`.
277
-
278
- These values are all obtained from [Auth0](https://manage.auth0.com/).
279
- <br/><br/>
280
- 4. **Use the SDK**
281
- \
282
- You can now use the subclasses to define actions such as logging in/out, retrieving or refreshing access tokens, etc...
283
- \
284
- **NOTE: Never share your access token or refresh tokens**
285
-
286
- Additionally, once the subclasses have been instantiated, you can pass your access token as a parameter to retrieve
287
- your user/anonymous user information using the earthscope_sdk.user.user *get_user* and *lookup_anon* functions.
288
-
289
-
290
- 5. **Example useages:**
291
- \
292
- Note: To see an example of an application using this SDK (and creating custom subclass), check out the [EarthScope CLI Repository](https://gitlab.com/earthscope/public/earthscope-cli).
293
- <br/><br/>
294
- How to use the existing simple subclass for device code flow:
295
- \
296
- *simple example python code*:
297
- ```
298
- import requests
299
- from pathlib import Path
300
-
301
- from earthscope_sdk.auth.device_code_flow import DeviceCodeFlowSimple
302
- from earthscope_sdk.auth.auth_flow import NoTokensError
303
-
304
- # choose where you want the token saved - the default file name is sso_tokens.json
305
- # if you want to keep the default name, set the path to a directory. Include a file name to rename.
306
- token_path = "/Users/my_user/token_dir"
307
-
308
- url = "https://data-idm.unavco.org/path/to/data_file"
309
- # example: "https://data-idm.unavco.org/archive/gnss/rinex/obs/2022/298/ar272980.22d.Z"
310
-
311
- # instantiate the device code flow subclass
312
- device_flow = DeviceCodeFlowSimple(Path(token_path))
313
- try:
314
- # get access token from local path
315
- device_flow.get_access_token_refresh_if_necessary()
316
- except NoTokensError:
317
- # if no token was found locally, do the device code flow
318
- device_flow.do_flow()
319
- token = device_flow.access_token
320
-
321
- # request a file and provide the token in the Authorization header
322
- file_name = Path(url).name
323
- directory_to_save_file = Path.cwd() # where you want to save the downloaded file
324
-
325
- r = requests.get(url, headers={"authorization": f"Bearer {token}"})
326
- if r.status_code == requests.codes.ok:
327
- # save the file
328
- with open(Path(directory_to_save_file / file_name), 'wb') as f:
329
- for data in r:
330
- f.write(data)
331
- else:
332
- #problem occured
333
- print(f"failure: {r.status_code}, {r.reason}")
334
- ```
335
-
336
- Instantiate the subclass and set the token_path where you want to load/save the token.
337
- If you provide only a directory, the file will be saved as sso_tokens.json.
338
- We hard-code this variable in this simple example, but we recommend setting this path as an environment variable and
339
- reading the environment varibale in your code.
340
-
341
-
342
- the **get_access_token_refresh_if_necessary** method will retrieve the token and refresh the token if it is expired.
343
- If there is no token, then the **do_flow** method will begin the device code flow and once you complete the flow,
344
- the token will be saved at the token_path. You can use the **requests** library to download the file you want
345
- (or files in a loop) and pass in the access token in the Authorization header.
346
-
347
- Learn more about [data access methods](https://www.unavco.org/data/gps-gnss/data-access-methods/data-access-methods.html).
342
+
343
+ ## SDK Settings
344
+
345
+ SDK Settings are provided via the following methods (in order of precedence):
346
+
347
+ 1. initialization arguments (e.g. via class constructors)
348
+ 1. environment variables
349
+ 1. dotenv file (.env) variables
350
+ 1. user's home directory settings files
351
+ 1. `~/.earthscope/config.toml` (for configuration)
352
+ 1. `~/.earthscope/<profile-name>/tokens.json` (for tokens)
353
+ 1. legacy EarthScope CLI v0 credentials
354
+ 1. default settings
355
+
356
+ SDK configuration is managed by the `SdkSettings` class, and calling the constructor performs this settings loading chain.
357
+
358
+ ```py
359
+ from earthscope_sdk.config.settings import SdkSettings
360
+
361
+ settings = SdkSettings() # loads settings via loading chain
362
+ ```
363
+
364
+ For more details on SDK configuration, including what options are available, see [our settings docs](docs/settings.md).
365
+
366
+ ## Contributing
367
+
368
+ For details on contributing to the EarthScope SDK, please see:
369
+
370
+ - [design docs](docs/design.md)
371
+ - [development docs](docs/development.md)
@@ -0,0 +1,30 @@
1
+ earthscope_sdk/__init__.py,sha256=8qd3PtsEHX-Z-goRaemVsakbxNxhyhOjHDKrom-E3CA,154
2
+ earthscope_sdk/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ earthscope_sdk/auth/auth_flow.py,sha256=gxJmCr5TAhMEss7RskYFCv6-D3A5h0Zw2ejeLJJ_9aI,10352
4
+ earthscope_sdk/auth/client_credentials_flow.py,sha256=GAvskuoEd6qHe-BtfGwYQisMedmSkDhagy4aRPVPri4,2494
5
+ earthscope_sdk/auth/device_code_flow.py,sha256=p53pgRQraToFwONPBj3O3DHAa4x4rE6rvygo_Bbj5_U,8394
6
+ earthscope_sdk/auth/error.py,sha256=eC33Bw1HaBEJE7-eI2krtE__5PxStc3EyiYO12v0kVw,693
7
+ earthscope_sdk/client/__init__.py,sha256=JotTr5oTiiOsUc0RTg82EVCUSg_-u80Qu_R0-crCXkY,139
8
+ earthscope_sdk/client/_client.py,sha256=ai7WdsTOYglA6bLkT-Wntvxlke6nSaGHwqrtg5PEy80,833
9
+ earthscope_sdk/client/user/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ earthscope_sdk/client/user/_base.py,sha256=8dn4pfQMwVDpF0E6dl6P6HJuNVvozUzfgUGefnPXMnw,1076
11
+ earthscope_sdk/client/user/_service.py,sha256=wRktOZF5GXajXXxij3Nkule6wvuWOV0vn4QsA1IXVHc,3063
12
+ earthscope_sdk/client/user/models.py,sha256=drZAMwOYC1NVCzBZQhNL-pPTB28SURKfoZF8HdjlIj8,1214
13
+ earthscope_sdk/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ earthscope_sdk/common/_sync_runner.py,sha256=h_A2pSEjZCLj7ov50M6cWHVoX6eXVmGzz5nX0MwLWDY,4131
15
+ earthscope_sdk/common/client.py,sha256=g5ZTNhFm33H68J9pWD5fDu760Yd5cBdfQmsbU3t8D_4,2156
16
+ earthscope_sdk/common/context.py,sha256=vrCB_Ez-98Ir7c0GrCe-g7DuRCgc9vPaoRWFYf5q8Ko,5138
17
+ earthscope_sdk/common/service.py,sha256=SCUZVJA3jFaEPeFrOf0v9osf2UpqldhlFmirOYWJjxM,1506
18
+ earthscope_sdk/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ earthscope_sdk/config/_bootstrap.py,sha256=BvDSRccvFPFRnLS4MlE7OMLGYEgxY7znxFZ6AYgxvOE,1243
20
+ earthscope_sdk/config/_compat.py,sha256=P3F5y_Kf5zp9m9uOhl1Bp3ke6expxq4Sm9AeVaBbAHk,4610
21
+ earthscope_sdk/config/_util.py,sha256=RZ6zvKrvjUkO7i69s7AVoIDhamRg4x71CAZLnucr9QM,1249
22
+ earthscope_sdk/config/error.py,sha256=jh25q-b317lAvp32WwQw0zdYoV-MxZtg-n5FgZOMymI,95
23
+ earthscope_sdk/config/models.py,sha256=CqCLF2m7cGcypsQxvrXK7BCsyv6QB3a9XmaqxYeMfaM,8684
24
+ earthscope_sdk/config/settings.py,sha256=kGsoqAgoUS2xrI0rvdqbLEsI2M0Mpbm73oEDLpJG4_Q,9205
25
+ earthscope_sdk/model/secret.py,sha256=QTyWCqXvf9ZYWaVVQcGzdt3rGtyU3sx13AlzkNE3gaU,731
26
+ earthscope_sdk-1.0.0.dist-info/licenses/LICENSE,sha256=E_MrVXxRaMQNpvZhsDuz_J9N_ux7dlL_WpYSsE391HU,11349
27
+ earthscope_sdk-1.0.0.dist-info/METADATA,sha256=9bnVpBEpd7_5IalOpORWP9cXUZVMH8ygTCK3tA-9lpA,18122
28
+ earthscope_sdk-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ earthscope_sdk-1.0.0.dist-info/top_level.txt,sha256=zTtIT9yN3JPJF7TqmTzqQcAvZZe4pAm907DLoGa5T_E,15
30
+ earthscope_sdk-1.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5