earthscope-sdk 0.2.1__tar.gz → 1.0.0b0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/PKG-INFO +138 -117
  2. earthscope_sdk-1.0.0b0/README.md +141 -0
  3. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/pyproject.toml +22 -16
  4. earthscope_sdk-1.0.0b0/src/earthscope_sdk/__init__.py +5 -0
  5. earthscope_sdk-1.0.0b0/src/earthscope_sdk/auth/auth_flow.py +318 -0
  6. earthscope_sdk-1.0.0b0/src/earthscope_sdk/auth/client_credentials_flow.py +80 -0
  7. earthscope_sdk-1.0.0b0/src/earthscope_sdk/auth/device_code_flow.py +241 -0
  8. earthscope_sdk-1.0.0b0/src/earthscope_sdk/auth/error.py +46 -0
  9. earthscope_sdk-1.0.0b0/src/earthscope_sdk/client/__init__.py +3 -0
  10. earthscope_sdk-1.0.0b0/src/earthscope_sdk/client/_client.py +35 -0
  11. earthscope_sdk-1.0.0b0/src/earthscope_sdk/client/user/_base.py +39 -0
  12. earthscope_sdk-1.0.0b0/src/earthscope_sdk/client/user/_service.py +94 -0
  13. earthscope_sdk-1.0.0b0/src/earthscope_sdk/client/user/models.py +53 -0
  14. earthscope_sdk-1.0.0b0/src/earthscope_sdk/common/__init__.py +0 -0
  15. earthscope_sdk-1.0.0b0/src/earthscope_sdk/common/_sync_runner.py +141 -0
  16. earthscope_sdk-1.0.0b0/src/earthscope_sdk/common/client.py +99 -0
  17. earthscope_sdk-1.0.0b0/src/earthscope_sdk/common/context.py +174 -0
  18. earthscope_sdk-1.0.0b0/src/earthscope_sdk/common/service.py +54 -0
  19. earthscope_sdk-1.0.0b0/src/earthscope_sdk/config/__init__.py +0 -0
  20. earthscope_sdk-1.0.0b0/src/earthscope_sdk/config/_compat.py +148 -0
  21. earthscope_sdk-1.0.0b0/src/earthscope_sdk/config/_util.py +48 -0
  22. earthscope_sdk-1.0.0b0/src/earthscope_sdk/config/error.py +4 -0
  23. earthscope_sdk-1.0.0b0/src/earthscope_sdk/config/models.py +208 -0
  24. earthscope_sdk-1.0.0b0/src/earthscope_sdk/config/settings.py +284 -0
  25. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/src/earthscope_sdk.egg-info/PKG-INFO +138 -117
  26. earthscope_sdk-1.0.0b0/src/earthscope_sdk.egg-info/SOURCES.txt +36 -0
  27. earthscope_sdk-1.0.0b0/src/earthscope_sdk.egg-info/requires.txt +12 -0
  28. earthscope_sdk-1.0.0b0/tests/test_auth.py +204 -0
  29. earthscope_sdk-1.0.0b0/tests/test_client.py +130 -0
  30. earthscope_sdk-1.0.0b0/tests/test_context.py +116 -0
  31. earthscope_sdk-1.0.0b0/tests/test_settings.py +427 -0
  32. earthscope-sdk-0.2.1/README.md +0 -122
  33. earthscope-sdk-0.2.1/src/earthscope_sdk/__init__.py +0 -1
  34. earthscope-sdk-0.2.1/src/earthscope_sdk/auth/auth_flow.py +0 -441
  35. earthscope-sdk-0.2.1/src/earthscope_sdk/auth/client_credentials_flow.py +0 -190
  36. earthscope-sdk-0.2.1/src/earthscope_sdk/auth/device_code_flow.py +0 -294
  37. earthscope-sdk-0.2.1/src/earthscope_sdk/user/user.py +0 -24
  38. earthscope-sdk-0.2.1/src/earthscope_sdk.egg-info/SOURCES.txt +0 -16
  39. earthscope-sdk-0.2.1/src/earthscope_sdk.egg-info/requires.txt +0 -10
  40. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/LICENSE +0 -0
  41. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/setup.cfg +0 -0
  42. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/setup.py +0 -0
  43. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/src/earthscope_sdk/auth/__init__.py +0 -0
  44. {earthscope-sdk-0.2.1/src/earthscope_sdk → earthscope_sdk-1.0.0b0/src/earthscope_sdk/client}/user/__init__.py +0 -0
  45. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/src/earthscope_sdk.egg-info/dependency_links.txt +0 -0
  46. {earthscope-sdk-0.2.1 → earthscope_sdk-1.0.0b0}/src/earthscope_sdk.egg-info/top_level.txt +0 -0
@@ -1,8 +1,8 @@
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>
5
+ Author-email: EarthScope <data-help@earthscope.org>
6
6
  License: Apache License
7
7
  Version 2.0, January 2004
8
8
  http://www.apache.org/licenses/
@@ -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
219
  Requires-Dist: bumpver; extra == "dev"
221
220
  Requires-Dist: build; extra == "dev"
222
221
  Requires-Dist: pytest; extra == "dev"
223
222
  Requires-Dist: twine; extra == "dev"
224
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,141 @@
1
+ # EarthScope SDK
2
+
3
+ An SDK for interacting with EarthScope's APIs
4
+
5
+ ## Getting Started
6
+
7
+ ### Installation
8
+
9
+ Install from PyPI
10
+
11
+ ```shell
12
+ pip install earthscope-sdk
13
+ ```
14
+
15
+ ### Usage
16
+
17
+ For detailed usage options and examples, visit [our usage docs](docs/usage.md).
18
+
19
+ ```py
20
+ # Import and create a client
21
+ from earthscope_sdk import EarthScopeClient
22
+
23
+ client = EarthScopeClient()
24
+
25
+ # Example client method usage; retrieve your user profile
26
+ profile = client.user.get_profile()
27
+ print(profile)
28
+
29
+ # Client cleanup
30
+ client.close()
31
+ ```
32
+
33
+ #### Async Usage
34
+
35
+ There is also an `async` client available
36
+
37
+ ```py
38
+ import asyncio
39
+ from earthscope_sdk import AsyncEarthScopeClient
40
+
41
+ async def main():
42
+ client = AsyncEarthScopeClient()
43
+
44
+ profile = await client.user.get_profile()
45
+ print(profile)
46
+
47
+ await client.close()
48
+
49
+ asyncio.run(main())
50
+ ```
51
+
52
+ #### Context Managers
53
+
54
+ Client classes can also be used as context managers to ensure resource cleanup occurs.
55
+
56
+ ```py
57
+ # sync
58
+ with EarthScopeClient() as client:
59
+ client.user.get_profile()
60
+
61
+ # async
62
+ async with AsyncEarthScopeClient() as client:
63
+ await client.user.get_profile()
64
+ ```
65
+
66
+ ## Bootstrapping Authentication
67
+
68
+ There are a few methods of bootstrapping authentication for the SDK.
69
+
70
+ Once refreshable credentials are available to the SDK, it will transparently handle access token refresh on your behalf.
71
+
72
+ ### Same host
73
+
74
+ 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).
75
+
76
+ Running `es login` will open your browser and prompt you to log in to your EarthScope account.
77
+
78
+ ```console
79
+ $ es login
80
+ Attempting to automatically open the SSO authorization page in your default browser.
81
+ If the browser does not open or you wish to use a different device to authorize this request, open the following URL:
82
+
83
+ https://login.earthscope.org/activate?user_code=ABCD-EFGH
84
+
85
+ Successful login! Access token expires at 2024-12-27 18:50:37+00:00
86
+ ```
87
+
88
+ Now when you run your application, `earthscope-sdk` will find your credentials.
89
+
90
+ ### Different hosts
91
+
92
+ 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.
93
+
94
+ You can still use the [EarthScope CLI](TODO) to facilitate auth for applications on other machines.
95
+
96
+ 1. Use the CLI on your primary workstation [as described above](#same-host) to log in.
97
+
98
+ 1. Use the CLI to retrieve your refresh token.
99
+
100
+ ```console
101
+ $ es user get-refresh-token
102
+ <your-refresh-token>
103
+ ```
104
+
105
+ > **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**.
106
+
107
+ 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.
108
+
109
+ ```shell
110
+ export ES_OAUTH2__REFRESH_TOKEN="<your-refresh-token>"
111
+ ```
112
+
113
+ ## SDK Settings
114
+
115
+ SDK Settings are provided via the following methods (in order of precedence):
116
+
117
+ 1. initialization arguments (e.g. via class constructors)
118
+ 1. environment variables
119
+ 1. dotenv file (.env) variables
120
+ 1. user's home directory settings files
121
+ 1. `~/.earthscope/config.toml` (for configuration)
122
+ 1. `~/.earthscope/<profile-name>/tokens.json` (for tokens)
123
+ 1. legacy EarthScope CLI v0 credentials
124
+ 1. default settings
125
+
126
+ SDK configuration is managed by the `SdkSettings` class, and calling the constructor performs this settings loading chain.
127
+
128
+ ```py
129
+ from earthscope_sdk.config.settings import SdkSettings
130
+
131
+ settings = SdkSettings() # loads settings via loading chain
132
+ ```
133
+
134
+ For more details on SDK configuration, including what options are available, see [our settings docs](docs/settings.md).
135
+
136
+ ## Contributing
137
+
138
+ For details on contributing to the EarthScope SDK, please see:
139
+
140
+ - [design docs](docs/design.md)
141
+ - [development docs](docs/development.md)
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "earthscope-sdk"
7
- version = "0.2.1"
7
+ version = "1.0.0b0"
8
8
  description = "An SDK for EarthScope API"
9
9
  readme = "README.md"
10
- authors = [{ name = "EarthScope", email = "software@unavco.org"}]
11
- license = { file = "LICENSE"}
10
+ authors = [{ name = "EarthScope", email = "data-help@earthscope.org" }]
11
+ license = { file = "LICENSE" }
12
12
  classifiers = [
13
13
  "License :: OSI Approved :: Apache Software License",
14
14
  "Programming Language :: Python",
@@ -17,29 +17,35 @@ classifiers = [
17
17
  ]
18
18
 
19
19
  #Suggestion not to pin dependencies since the package should work in many different python environments
20
- dependencies = [
21
- "pyjwt >= 2.4.0",
22
- "requests >= 2.27.1"
23
- ]
24
- requires-python = ">=3.7"
20
+ dependencies = ["httpx>=0.27.0", "pydantic-settings[toml]>=2.7.0"]
21
+ requires-python = ">=3.9"
25
22
 
26
23
  [project.optional-dependencies]
27
- dev = ["black", "bumpver", "build", "pytest", "twine", "pip-tools"]
24
+ dev = [
25
+ "bumpver",
26
+ "build",
27
+ "pytest",
28
+ "twine",
29
+ "pip-tools",
30
+ "pytest-httpx",
31
+ "pytest-asyncio",
32
+ "ruff",
33
+ ]
28
34
 
29
35
  [project.urls]
30
36
  Homepage = "https://gitlab.com/earthscope/public/earthscope-sdk"
31
37
 
32
38
  [tool.bumpver]
33
- current_version = "0.2.1"
34
- version_pattern = "MAJOR.MINOR.PATCH"
35
- commit_message = "bump version {old_version} -> {new_version}"
39
+ current_version = "1.0.0b0"
40
+ version_pattern = "MAJOR.MINOR.PATCH[PYTAGNUM]"
41
+ commit_message = "chore: bump version {old_version} -> {new_version}"
36
42
  commit = true
37
43
  tag = true
38
44
  push = false
39
45
 
40
46
  [tool.bumpver.file_patterns]
41
- "pyproject.toml" = [
42
- 'current_version = "{version}"',
43
- 'version = "{version}"',
44
- ]
47
+ "pyproject.toml" = ['current_version = "{version}"', 'version = "{version}"']
45
48
  "src/earthscope_sdk/__init__.py" = ["{version}"]
49
+
50
+ [tool.pytest.ini_options]
51
+ asyncio_default_fixture_loop_scope = "function"
@@ -0,0 +1,5 @@
1
+ __version__ = "1.0.0b0"
2
+
3
+ from earthscope_sdk.client import AsyncEarthScopeClient, EarthScopeClient
4
+
5
+ __all__ = ["AsyncEarthScopeClient", "EarthScopeClient"]