earthscope-sdk 0.2.1__py3-none-any.whl → 1.0.0b0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,284 @@
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._compat import LegacyEarthScopeCLISettingsSource
15
+ from earthscope_sdk.config._util import deep_merge, get_config_dir, slugify
16
+ from earthscope_sdk.config.error import ProfileDoesNotExistError
17
+ from earthscope_sdk.config.models import SdkBaseSettings, Tokens
18
+
19
+ _DEFAULT_PROFILE = "default"
20
+ """Default profile name"""
21
+
22
+ _LOCAL_APP_DIR = get_config_dir(app_name="earthscope")
23
+ """Local SDK application directory"""
24
+
25
+
26
+ def _get_config_toml_path():
27
+ """
28
+ Local SDK configuration file
29
+ """
30
+ return _LOCAL_APP_DIR / "config.toml"
31
+
32
+
33
+ def _get_profile_dir(profile_name: str):
34
+ """
35
+ Retrieve the local SDK directory for the named profile
36
+ """
37
+ return _LOCAL_APP_DIR / slugify(profile_name)
38
+
39
+
40
+ def _get_profile_tokens_file(profile_name: str):
41
+ """
42
+ Retrieve the local SDK tokens file for the named profile
43
+ """
44
+ profile_dir = _get_profile_dir(profile_name)
45
+ return profile_dir / "tokens.json"
46
+
47
+
48
+ class _SdkGlobalSettings(BaseSettings):
49
+ """
50
+ EarthScope SDK global settings; not for direct use.
51
+
52
+ This class only loads settings from config.toml.
53
+ """
54
+
55
+ defaults: Annotated[
56
+ SdkBaseSettings,
57
+ Field(validation_alias="default"),
58
+ ] = {}
59
+
60
+ profile_settings_by_name: Annotated[
61
+ dict[str, SdkBaseSettings],
62
+ Field(validation_alias="profile"),
63
+ ] = {}
64
+
65
+ model_config = SettingsConfigDict(
66
+ extra="ignore",
67
+ frozen=True,
68
+ nested_model_default_partial_update=True,
69
+ populate_by_name=True,
70
+ )
71
+
72
+ def get_merged(self, profile_name: str):
73
+ """
74
+ Get profile-specific settings merged with defaults
75
+ """
76
+ try:
77
+ p = self.profile_settings_by_name[profile_name]
78
+ except KeyError:
79
+ raise ProfileDoesNotExistError(f"Profile '{profile_name}' does not exist")
80
+
81
+ defaults = self.defaults.model_dump(
82
+ exclude_none=True,
83
+ exclude_unset=True,
84
+ exclude_defaults=True,
85
+ )
86
+ profile_specific = p.model_dump(
87
+ exclude_defaults=True, # defer to top-level field defaults
88
+ exclude_unset=True, # only keep explicitly set fields
89
+ exclude_none=True,
90
+ )
91
+
92
+ # order is imporant; profile-specific args override default args
93
+ return deep_merge(defaults, profile_specific, profile_name=profile_name)
94
+
95
+ @field_validator("profile_settings_by_name", mode="before")
96
+ @classmethod
97
+ def ensure_default_profile(cls, v: dict[str, dict]):
98
+ """
99
+ Ensure the default profile exists
100
+ """
101
+ v.setdefault(_DEFAULT_PROFILE, {})
102
+ return v
103
+
104
+ @classmethod
105
+ def settings_customise_sources(cls, settings_cls: Type[BaseSettings], **_):
106
+ """
107
+ Override the loading chain to exclusively check ~/.earthscope/config.toml
108
+ """
109
+ # we get the file path dynamically to allow monkeypatching for tests
110
+ toml_path = _get_config_toml_path()
111
+ toml_settings = TomlConfigSettingsSource(settings_cls, toml_path)
112
+
113
+ return (toml_settings,)
114
+
115
+
116
+ class _GlobalSettingsSource(PydanticBaseSettingsSource):
117
+ """
118
+ This SettingsSource facilitates falling back to settings configured in config.toml
119
+ and state in tokens.json when loading the configuration chain in SdkSettings.
120
+
121
+ Consolidates merged profile state with state loaded from a profile's tokens.json file
122
+ """
123
+
124
+ def __init__(self, settings_cls, *keys: str):
125
+ super().__init__(settings_cls)
126
+ self._keys = keys
127
+
128
+ def __call__(self):
129
+ # Extract profile
130
+ profile_name = _DEFAULT_PROFILE
131
+ for k in self._keys:
132
+ with suppress(KeyError):
133
+ profile_name = self._current_state[k]
134
+ break
135
+
136
+ # Load global merged settings
137
+ merged = _SdkGlobalSettings().get_merged(profile_name)
138
+
139
+ # Load from tokens.json
140
+ tokens_json = {}
141
+ with suppress(FileNotFoundError, ValidationError):
142
+ raw = _get_profile_tokens_file(profile_name).read_bytes()
143
+ tokens = Tokens.model_validate_json(raw)
144
+ tokens_json = tokens.model_dump(
145
+ exclude_none=True,
146
+ exclude_unset=True,
147
+ exclude_defaults=True,
148
+ )
149
+
150
+ # order is imporant; init args override tokens.json args
151
+ return deep_merge({"oauth2": tokens_json}, merged)
152
+
153
+ def __repr__(self) -> str:
154
+ return f"{self.__class__.__name__}()"
155
+
156
+ def get_field_value(self, *args, **kwargs): ... # unused abstract method
157
+
158
+
159
+ class _InitSettingsWithoutDefaultSource(InitSettingsSource):
160
+ """
161
+ InitSettingsSource behavior but excludes default values & unset fields
162
+ to allow values from lower-precedence settings sources to bubble up.
163
+ """
164
+
165
+ def __init__(self, other: InitSettingsSource):
166
+ super().__init__(
167
+ other.settings_cls,
168
+ other.init_kwargs,
169
+ other.nested_model_default_partial_update,
170
+ )
171
+ self.dict_adapter = TypeAdapter(dict[str, Any])
172
+
173
+ def __call__(self) -> dict[str, Any]:
174
+ return self.dict_adapter.dump_python(
175
+ self.init_kwargs,
176
+ exclude_defaults=True,
177
+ exclude_unset=True,
178
+ )
179
+
180
+
181
+ class SdkSettings(SdkBaseSettings, BaseSettings):
182
+ """
183
+ EarthScope SDK settings.
184
+
185
+ Use `profile_name` to utilize a named profile from `~/.earthscope/config.toml`
186
+
187
+ Settings loading chain (order of precedence):
188
+ 1. arguments passed to constructor
189
+ 2. environment variables
190
+ 3. dotenv variables
191
+ 4. ~/.earthscope/config.toml
192
+ """
193
+
194
+ profile_name: Annotated[
195
+ str,
196
+ Field(validation_alias="es_profile"),
197
+ # NOTE: aliases do not include the env_prefix by default; add it explicitly
198
+ ]
199
+
200
+ model_config = SettingsConfigDict(
201
+ env_nested_delimiter="__",
202
+ env_prefix="ES_",
203
+ extra="ignore",
204
+ frozen=True,
205
+ nested_model_default_partial_update=True,
206
+ populate_by_name=True,
207
+ )
208
+
209
+ @cached_property
210
+ def profile_dir(self):
211
+ """
212
+ The path to the local SDK directory for the named profile
213
+ """
214
+ return _get_profile_dir(self.profile_name)
215
+
216
+ @cached_property
217
+ def tokens_file(self):
218
+ """
219
+ The path to the tokens file for the named profile
220
+ """
221
+ return _get_profile_tokens_file(self.profile_name)
222
+
223
+ def delete_tokens(self, missing_ok=False):
224
+ """
225
+ Delete tokens from this named profile's state
226
+
227
+ Args:
228
+ missing_ok: Whether or not to throw an error if the file does not exist
229
+
230
+ Returns:
231
+ this auth flow
232
+ """
233
+ self.tokens_file.unlink(missing_ok=missing_ok)
234
+ return self
235
+
236
+ def write_tokens(self, tokens: Tokens):
237
+ """
238
+ Write tokens to this named profile's state
239
+
240
+ Args:
241
+ tokens: the tokens to persist in local storage
242
+ """
243
+ body = tokens.model_dump_json(
244
+ include=Tokens.model_fields.keys(),
245
+ indent=2,
246
+ context="plaintext", # write SecretStr's actual values in plaintext
247
+ exclude_none=True,
248
+ )
249
+ self.tokens_file.parent.mkdir(parents=True, exist_ok=True)
250
+ self.tokens_file.write_text(body)
251
+
252
+ @classmethod
253
+ def settings_customise_sources(
254
+ cls,
255
+ settings_cls: Type[BaseSettings],
256
+ init_settings: InitSettingsSource,
257
+ env_settings: PydanticBaseSettingsSource,
258
+ dotenv_settings: PydanticBaseSettingsSource,
259
+ **_,
260
+ ):
261
+ """
262
+ Override the loading chain to additionally check ~/.earthscope/config.toml
263
+ """
264
+
265
+ # Init settings, but without defaults & unset values
266
+ init_settings = _InitSettingsWithoutDefaultSource(init_settings)
267
+
268
+ # Check for all the ways profile name may be supplied
269
+ alias = SdkSettings.model_fields["profile_name"].validation_alias
270
+ global_settings = _GlobalSettingsSource(settings_cls, "profile_name", alias)
271
+
272
+ # Compatibility with earthscope-cli v0.x.x state:
273
+ # If we find this file, we only care about the access and refresh tokens
274
+ keep_keys = {"access_token", "refresh_token"}
275
+ legacy_settings = LegacyEarthScopeCLISettingsSource(settings_cls, *keep_keys)
276
+
277
+ # Order of precedence
278
+ return (
279
+ init_settings,
280
+ env_settings,
281
+ dotenv_settings,
282
+ global_settings,
283
+ legacy_settings,
284
+ )
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: earthscope-sdk
3
- Version: 0.2.1
3
+ Version: 1.0.0b0
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,159 @@ 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.7.0
218
218
  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'
219
+ Requires-Dist: bumpver; extra == "dev"
220
+ Requires-Dist: build; extra == "dev"
221
+ Requires-Dist: pytest; extra == "dev"
222
+ Requires-Dist: twine; extra == "dev"
223
+ Requires-Dist: pip-tools; extra == "dev"
224
+ Requires-Dist: pytest-httpx; extra == "dev"
225
+ Requires-Dist: pytest-asyncio; extra == "dev"
226
+ Requires-Dist: ruff; extra == "dev"
225
227
 
226
228
  # EarthScope SDK
227
229
 
228
- An SDK for authenticating with the EarthScope API
230
+ An SDK for interacting with EarthScope's APIs
229
231
 
230
232
  ## Getting Started
231
233
 
232
- ### USAGE
234
+ ### Installation
233
235
 
234
- 1. **(Optional) Suggest setting up and activating a python virtual environment so as not to clutter your system python**
236
+ Install from PyPI
235
237
 
236
- ```shell
237
- python3 -m venv venv
238
- . venv/bin/activate
238
+ ```shell
239
+ pip install earthscope-sdk
240
+ ```
241
+
242
+ ### Usage
243
+
244
+ For detailed usage options and examples, visit [our usage docs](docs/usage.md).
245
+
246
+ ```py
247
+ # Import and create a client
248
+ from earthscope_sdk import EarthScopeClient
249
+
250
+ client = EarthScopeClient()
251
+
252
+ # Example client method usage; retrieve your user profile
253
+ profile = client.user.get_profile()
254
+ print(profile)
255
+
256
+ # Client cleanup
257
+ client.close()
258
+ ```
259
+
260
+ #### Async Usage
261
+
262
+ There is also an `async` client available
263
+
264
+ ```py
265
+ import asyncio
266
+ from earthscope_sdk import AsyncEarthScopeClient
267
+
268
+ async def main():
269
+ client = AsyncEarthScopeClient()
270
+
271
+ profile = await client.user.get_profile()
272
+ print(profile)
273
+
274
+ await client.close()
275
+
276
+ asyncio.run(main())
277
+ ```
278
+
279
+ #### Context Managers
280
+
281
+ Client classes can also be used as context managers to ensure resource cleanup occurs.
282
+
283
+ ```py
284
+ # sync
285
+ with EarthScopeClient() as client:
286
+ client.user.get_profile()
287
+
288
+ # async
289
+ async with AsyncEarthScopeClient() as client:
290
+ await client.user.get_profile()
291
+ ```
292
+
293
+ ## Bootstrapping Authentication
294
+
295
+ There are a few methods of bootstrapping authentication for the SDK.
296
+
297
+ Once refreshable credentials are available to the SDK, it will transparently handle access token refresh on your behalf.
298
+
299
+ ### Same host
300
+
301
+ If you have the [EarthScope CLI](TODO) 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).
302
+
303
+ Running `es login` will open your browser and prompt you to log in to your EarthScope account.
304
+
305
+ ```console
306
+ $ es login
307
+ Attempting to automatically open the SSO authorization page in your default browser.
308
+ If the browser does not open or you wish to use a different device to authorize this request, open the following URL:
309
+
310
+ https://login.earthscope.org/activate?user_code=ABCD-EFGH
311
+
312
+ Successful login! Access token expires at 2024-12-27 18:50:37+00:00
313
+ ```
314
+
315
+ Now when you run your application, `earthscope-sdk` will find your credentials.
316
+
317
+ ### Different hosts
318
+
319
+ 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.
320
+
321
+ You can still use the [EarthScope CLI](TODO) to facilitate auth for applications on other machines.
322
+
323
+ 1. Use the CLI on your primary workstation [as described above](#same-host) to log in.
324
+
325
+ 1. Use the CLI to retrieve your refresh token.
326
+
327
+ ```console
328
+ $ es user get-refresh-token
329
+ <your-refresh-token>
239
330
  ```
240
331
 
241
- 2. **Install earthscope-sdk**
332
+ > **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**.
333
+
334
+ 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
335
 
243
336
  ```shell
244
- pip install earthscope-sdk
337
+ export ES_OAUTH2__REFRESH_TOKEN="<your-refresh-token>"
245
338
  ```
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 usage:**
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.unavco.org/path/to/data_file"
309
- # example: "https://data.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).
339
+
340
+ ## SDK Settings
341
+
342
+ SDK Settings are provided via the following methods (in order of precedence):
343
+
344
+ 1. initialization arguments (e.g. via class constructors)
345
+ 1. environment variables
346
+ 1. dotenv file (.env) variables
347
+ 1. user's home directory settings files
348
+ 1. `~/.earthscope/config.toml` (for configuration)
349
+ 1. `~/.earthscope/<profile-name>/tokens.json` (for tokens)
350
+ 1. legacy EarthScope CLI v0 credentials
351
+ 1. default settings
352
+
353
+ SDK configuration is managed by the `SdkSettings` class, and calling the constructor performs this settings loading chain.
354
+
355
+ ```py
356
+ from earthscope_sdk.config.settings import SdkSettings
357
+
358
+ settings = SdkSettings() # loads settings via loading chain
359
+ ```
360
+
361
+ For more details on SDK configuration, including what options are available, see [our settings docs](docs/settings.md).
362
+
363
+ ## Contributing
364
+
365
+ For details on contributing to the EarthScope SDK, please see:
366
+
367
+ - [design docs](docs/design.md)
368
+ - [development docs](docs/development.md)
@@ -0,0 +1,28 @@
1
+ earthscope_sdk/__init__.py,sha256=6InyrqE0KEsb_XBBKCbUIb8s0LTJ6N20HFsrO-rHVtI,156
2
+ earthscope_sdk/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ earthscope_sdk/auth/auth_flow.py,sha256=HZyLrt8o3I-0KC7XRg9W0n2NAVXX7EOl9pG-5blv7sA,9613
4
+ earthscope_sdk/auth/client_credentials_flow.py,sha256=1GyDSIR1OgYP4u0xZoTov1u_YhY1AzHFpOcBCzY1h6E,2769
5
+ earthscope_sdk/auth/device_code_flow.py,sha256=dC5Ffj3HzBguRxSHCZYvTe1MD3C-iKf2AlanGuRKNvI,7922
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=nut1Ojsksohqy3X3L5FPDQ-rh-BmHLJ6sId5xVqLal0,1050
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=qBz6OV8rQf3WQojubEVfQ4HYeeKNN3_uIcXuOdvfH8w,1287
18
+ earthscope_sdk/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ earthscope_sdk/config/_compat.py,sha256=P3F5y_Kf5zp9m9uOhl1Bp3ke6expxq4Sm9AeVaBbAHk,4610
20
+ earthscope_sdk/config/_util.py,sha256=RZ6zvKrvjUkO7i69s7AVoIDhamRg4x71CAZLnucr9QM,1249
21
+ earthscope_sdk/config/error.py,sha256=jh25q-b317lAvp32WwQw0zdYoV-MxZtg-n5FgZOMymI,95
22
+ earthscope_sdk/config/models.py,sha256=CarL0O6RjFtufsc-q7g61uBEvETLjQr6HSmjCc0EVig,5775
23
+ earthscope_sdk/config/settings.py,sha256=I2DwEvfmETcaYbSvUybs0EIih0yiJO9D46WnWzKPqbo,8812
24
+ earthscope_sdk-1.0.0b0.dist-info/LICENSE,sha256=E_MrVXxRaMQNpvZhsDuz_J9N_ux7dlL_WpYSsE391HU,11349
25
+ earthscope_sdk-1.0.0b0.dist-info/METADATA,sha256=jbeHzNrmHRZUGOFai1WmCDK1CQ-kWSbIsaNRjHq_WhA,17935
26
+ earthscope_sdk-1.0.0b0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
27
+ earthscope_sdk-1.0.0b0.dist-info/top_level.txt,sha256=zTtIT9yN3JPJF7TqmTzqQcAvZZe4pAm907DLoGa5T_E,15
28
+ earthscope_sdk-1.0.0b0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,24 +0,0 @@
1
- import requests
2
- import os
3
-
4
- from typing import List
5
-
6
- API_BASE_URL = os.environ.get("API_BASE_URL", "https://www.earthscope.org/api/v0")
7
-
8
-
9
- def get_user(access_token: str):
10
- r = requests.get(
11
- f"{API_BASE_URL}/user",
12
- headers={"authorization": f"Bearer {access_token}"},
13
- )
14
-
15
- try:
16
- rjson = r.json()
17
- if r.status_code == 200:
18
- return rjson
19
- error = rjson.get("detail") or rjson.get("message") or rjson
20
- except Exception:
21
- r.raise_for_status()
22
- error = r.text
23
-
24
- raise RuntimeError(error)
@@ -1,12 +0,0 @@
1
- earthscope_sdk/__init__.py,sha256=HfjVOrpTnmZ-xVFCYSVmX50EXaBQeJteUHG-PD6iQs8,22
2
- earthscope_sdk/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- earthscope_sdk/auth/auth_flow.py,sha256=xky9ee8p3-lm-c-8rfnNXWSrPBLW3MG-sHDhjlvzohQ,11701
4
- earthscope_sdk/auth/client_credentials_flow.py,sha256=G4NeWLtKoDZlbx7Fk6TY5fNaGXf3E43YMQcI3vFVsYE,5602
5
- earthscope_sdk/auth/device_code_flow.py,sha256=tl87wYYVqWkM4gJ33735jccpqYqX7P1g_TDo8YAM5rk,9149
6
- earthscope_sdk/user/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- earthscope_sdk/user/user.py,sha256=bCYbvq02bCKMJVYfbj3lpmO1VjTUgNDL4w4PiGvhuG8,566
8
- earthscope_sdk-0.2.1.dist-info/LICENSE,sha256=E_MrVXxRaMQNpvZhsDuz_J9N_ux7dlL_WpYSsE391HU,11349
9
- earthscope_sdk-0.2.1.dist-info/METADATA,sha256=hl1yJ3NWUZWhZPJ4cPqhw4iRMWKxDkqqaRXqROMLLrk,18756
10
- earthscope_sdk-0.2.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
11
- earthscope_sdk-0.2.1.dist-info/top_level.txt,sha256=zTtIT9yN3JPJF7TqmTzqQcAvZZe4pAm907DLoGa5T_E,15
12
- earthscope_sdk-0.2.1.dist-info/RECORD,,
File without changes