sumo-wrapper-python 1.0.8__tar.gz → 1.0.9__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.
Potentially problematic release.
This version of sumo-wrapper-python might be problematic. Click here for more details.
- sumo_wrapper_python-1.0.9/.github/workflows/build_docs.yaml +34 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/.github/workflows/linting.yml +4 -4
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/.github/workflows/publish_release.yml +2 -2
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/.github/workflows/pytest.yml +3 -3
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/.gitignore +0 -1
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/PKG-INFO +9 -154
- sumo_wrapper_python-1.0.9/README.md +10 -0
- sumo_wrapper_python-1.0.9/docs/_static/equinor-logo.png +0 -0
- sumo_wrapper_python-1.0.9/docs/_static/equinor-logo2.jpg +0 -0
- sumo_wrapper_python-1.0.9/docs/_static/equinor_logo.jpg +0 -0
- sumo_wrapper_python-1.0.9/docs/_static/equinor_logo_only.jpg +0 -0
- sumo_wrapper_python-1.0.9/docs/_templates/layout.html +17 -0
- sumo_wrapper_python-1.0.9/docs/api.rst +9 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/docs/conf.py +14 -12
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/docs/index.rst +5 -14
- sumo_wrapper_python-1.0.9/docs/sumo-wrapper-python.rst +129 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/pyproject.toml +7 -1
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/_auth_provider.py +60 -20
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/_decorators.py +6 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/_logging.py +3 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/_version.py +2 -2
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/login.py +5 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/sumo_client.py +21 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/PKG-INFO +9 -154
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/SOURCES.txt +8 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/requires.txt +3 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/tests/testdata/surface.yml +4 -1
- sumo-wrapper-python-1.0.8/README.md +0 -158
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/.flake8 +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/.readthedocs.yaml +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/CONTRIBUTING.md +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/LICENSE +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/SECURITY.md +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/conftest.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/docs/Makefile +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/docs/make.bat +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/setup.cfg +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/__init__.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/__init__.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/_blob_client.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/_retry_strategy.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo/wrapper/config.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/dependency_links.txt +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/entry_points.txt +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/top_level.txt +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/tests/test_sumo_thin_client.py +0 -0
- {sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/tests/testdata/case.yml +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Build the docs here, to show errors.
|
|
2
|
+
# The actual deployment of docs is configured in ReadTheDocs.org.
|
|
3
|
+
|
|
4
|
+
name: Build and deploy docs
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
push:
|
|
10
|
+
branches: [main]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build_pywheels:
|
|
14
|
+
name: Build docs with Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
matrix:
|
|
18
|
+
python-version: ["3.10"]
|
|
19
|
+
os: [ubuntu-latest]
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
|
|
29
|
+
- name: Install and build docs
|
|
30
|
+
run: |
|
|
31
|
+
pip install pip -U && pip install wheel -U
|
|
32
|
+
pip install .[docs]
|
|
33
|
+
pip list
|
|
34
|
+
sphinx-build docs build/sphinx/html
|
|
@@ -11,9 +11,9 @@ jobs:
|
|
|
11
11
|
matrix:
|
|
12
12
|
python-version: ["3.8"]
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
15
|
- name: Set up Python ${{ matrix.python-version }}
|
|
16
|
-
uses: actions/setup-python@
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
17
|
with:
|
|
18
18
|
python-version: ${{ matrix.python-version }}
|
|
19
19
|
- uses: psf/black@stable
|
|
@@ -26,9 +26,9 @@ jobs:
|
|
|
26
26
|
matrix:
|
|
27
27
|
python-version: ["3.8"]
|
|
28
28
|
steps:
|
|
29
|
-
- uses: actions/checkout@
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
30
|
- name: Set up Python ${{ matrix.python-version }}
|
|
31
|
-
uses: actions/setup-python@
|
|
31
|
+
uses: actions/setup-python@v5
|
|
32
32
|
with:
|
|
33
33
|
python-version: ${{ matrix.python-version }}
|
|
34
34
|
- name: Install dependencies
|
|
@@ -21,17 +21,17 @@ jobs:
|
|
|
21
21
|
id-token: write
|
|
22
22
|
|
|
23
23
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
25
|
|
|
26
26
|
- name: Azure Login
|
|
27
|
-
uses: Azure/login@
|
|
27
|
+
uses: Azure/login@v2
|
|
28
28
|
with:
|
|
29
29
|
client-id: f96c150d-cacf-4257-9cc9-54b2c68ec4ce
|
|
30
30
|
tenant-id: 3aa4a235-b6e2-48d5-9195-7fcf05b459b0
|
|
31
31
|
subscription-id: 87897772-fb27-495f-ae40-486a2df57baa
|
|
32
32
|
|
|
33
33
|
- name: Set up Python
|
|
34
|
-
uses: actions/setup-python@
|
|
34
|
+
uses: actions/setup-python@v5
|
|
35
35
|
with:
|
|
36
36
|
python-version: ${{ matrix.python-version }}
|
|
37
37
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sumo-wrapper-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.9
|
|
4
4
|
Summary: Python wrapper for the Sumo API
|
|
5
5
|
Author: Equinor
|
|
6
6
|
License: Apache License
|
|
@@ -223,162 +223,17 @@ Requires-Dist: PyYAML; extra == "test"
|
|
|
223
223
|
Provides-Extra: docs
|
|
224
224
|
Requires-Dist: sphinx; extra == "docs"
|
|
225
225
|
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
226
|
+
Requires-Dist: autoapi; extra == "docs"
|
|
227
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
228
|
+
Requires-Dist: sphinxcontrib-apidoc; extra == "docs"
|
|
226
229
|
|
|
227
230
|
# sumo-wrapper-python
|
|
228
231
|
|
|
229
|
-
|
|
232
|
+
[](https://sumo-wrapper-python.readthedocs.io/en/latest/?badge=latest)
|
|
230
233
|
|
|
231
|
-
|
|
234
|
+
## Documentation and guidelines
|
|
235
|
+
[sumo-wrapper-python documentation](https://sumo-wrapper-python.readthedocs.io/en/latest/)
|
|
232
236
|
|
|
233
|
-
##
|
|
237
|
+
## Contribute
|
|
238
|
+
[Contribution guidelines](./CONTRIBUTING.md)
|
|
234
239
|
|
|
235
|
-
pip install sumo-wrapper-python
|
|
236
|
-
|
|
237
|
-
For internal Equinor users, this package is available through the Komodo
|
|
238
|
-
distribution.
|
|
239
|
-
|
|
240
|
-
# Table of contents
|
|
241
|
-
|
|
242
|
-
- [sumo-wrapper-python](#sumo-wrapper-python)
|
|
243
|
-
- [Install:](#install)
|
|
244
|
-
- [Table of contents](#table-of-contents)
|
|
245
|
-
- [SumoClient](#sumoclient)
|
|
246
|
-
- [Initialization](#initialization)
|
|
247
|
-
- [Parameters](#parameters)
|
|
248
|
-
- [`token` logic](#token-logic)
|
|
249
|
-
- [Methods](#methods)
|
|
250
|
-
- [get(path, \*\*params)](#getpath-params)
|
|
251
|
-
- [post(path, json, blob, params)](#postpath-json-blob-params)
|
|
252
|
-
- [put(path, json, blob)](#putpath-json-blob)
|
|
253
|
-
- [delete(path)](#deletepath)
|
|
254
|
-
- [Async methods](#async-methods)
|
|
255
|
-
|
|
256
|
-
# SumoClient
|
|
257
|
-
|
|
258
|
-
A thin wrapper class for the Sumo API.
|
|
259
|
-
|
|
260
|
-
### Initialization
|
|
261
|
-
|
|
262
|
-
```python
|
|
263
|
-
from sumo.wrapper import SumoClient
|
|
264
|
-
|
|
265
|
-
sumo = SumoClient(env="dev")
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Parameters
|
|
269
|
-
|
|
270
|
-
```python
|
|
271
|
-
class SumoClient:
|
|
272
|
-
def __init__(
|
|
273
|
-
self,
|
|
274
|
-
env:str,
|
|
275
|
-
token:str=None,
|
|
276
|
-
interactive:bool=False,
|
|
277
|
-
verbosity:str="CRITICAL"
|
|
278
|
-
):
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
- `env`: sumo environment
|
|
282
|
-
- `token`: bearer token or refresh token
|
|
283
|
-
- `interactive`: use interactive flow when authenticating
|
|
284
|
-
- `verbosity`: "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
|
|
285
|
-
|
|
286
|
-
###### `token` logic
|
|
287
|
-
|
|
288
|
-
If an access token is provided in the `token` parameter, it will be used as long
|
|
289
|
-
as it's valid. An error will be raised when it expires.
|
|
290
|
-
|
|
291
|
-
If we are unable to decode the provided `token` as a JWT, we treat it as a
|
|
292
|
-
refresh token and attempt to use it to retrieve an access token.
|
|
293
|
-
|
|
294
|
-
If no `token` is provided, an authentication code flow/interactive flow is
|
|
295
|
-
triggered to retrieve a token.
|
|
296
|
-
|
|
297
|
-
## Methods
|
|
298
|
-
|
|
299
|
-
`SumoClient` has one method for each HTTP-method that is used in the sumo-core
|
|
300
|
-
API. See examples of how to use these methods below.
|
|
301
|
-
|
|
302
|
-
All methods accepts a path argument. Path parameters can be interpolated into
|
|
303
|
-
the path string. Example:
|
|
304
|
-
|
|
305
|
-
```python
|
|
306
|
-
object_id = "1234"
|
|
307
|
-
|
|
308
|
-
# GET/objects('{obejctid}')
|
|
309
|
-
sumo.get(f"/objects('{object_id}')")
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### get(path, \*\*params)
|
|
313
|
-
|
|
314
|
-
Performs a GET-request to sumo-core. Accepts query parameters as keyword
|
|
315
|
-
arguments.
|
|
316
|
-
|
|
317
|
-
```python
|
|
318
|
-
# Retrieve userdata
|
|
319
|
-
user_data = sumo.get("/userdata")
|
|
320
|
-
|
|
321
|
-
# Search for objects
|
|
322
|
-
results = sumo.get("/search",
|
|
323
|
-
query="class:surface",
|
|
324
|
-
size:3,
|
|
325
|
-
select=["_id"]
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
# Get object by id
|
|
329
|
-
object_id = "159405ba-0046-b321-55ce-542f383ba5c7"
|
|
330
|
-
|
|
331
|
-
obj = sumo.get(f"/objects('{object_id}')")
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### post(path, json, blob, params)
|
|
335
|
-
|
|
336
|
-
Performs a POST-request to sumo-core. Accepts json and blob, but not both at the
|
|
337
|
-
same time.
|
|
338
|
-
|
|
339
|
-
```python
|
|
340
|
-
# Upload new parent object
|
|
341
|
-
parent_object = sumo.post("/objects", json=parent_meta_data)
|
|
342
|
-
|
|
343
|
-
# Upload child object
|
|
344
|
-
parent_id = parent_object["_id"]
|
|
345
|
-
|
|
346
|
-
child_object = sumo.post(f"/objects('{parent_id}')", json=child_meta_data)
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
### put(path, json, blob)
|
|
350
|
-
|
|
351
|
-
Performs a PUT-request to sumo-core. Accepts json and blob, but not both at the
|
|
352
|
-
same time.
|
|
353
|
-
|
|
354
|
-
```python
|
|
355
|
-
# Upload blob to child object
|
|
356
|
-
child_id = child_object["_id"]
|
|
357
|
-
|
|
358
|
-
sumo.put(f"/objects('{child_id}')/blob", blob=blob)
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### delete(path)
|
|
362
|
-
|
|
363
|
-
Performs a DELETE-request to sumo-core.
|
|
364
|
-
|
|
365
|
-
```python
|
|
366
|
-
# Delete blob
|
|
367
|
-
sumo.delete(f"/objects('{child_id}')/blob")
|
|
368
|
-
|
|
369
|
-
# Delete child object
|
|
370
|
-
sumo.delete(f"/objects('{child_id}')")
|
|
371
|
-
|
|
372
|
-
# Delete parent object
|
|
373
|
-
sumo.delete(f"/objects('{parent_id}')")
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
## Async methods
|
|
377
|
-
|
|
378
|
-
`SumoClient` also has *async* alternatives `get_async`, `post_async`, `put_async` and `delete_async`.
|
|
379
|
-
These accept the same parameters as their synchronous counterparts, but have to be *awaited*.
|
|
380
|
-
|
|
381
|
-
```python
|
|
382
|
-
# Retrieve userdata
|
|
383
|
-
user_data = await sumo.get_async("/userdata")
|
|
384
|
-
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# sumo-wrapper-python
|
|
2
|
+
|
|
3
|
+
[](https://sumo-wrapper-python.readthedocs.io/en/latest/?badge=latest)
|
|
4
|
+
|
|
5
|
+
## Documentation and guidelines
|
|
6
|
+
[sumo-wrapper-python documentation](https://sumo-wrapper-python.readthedocs.io/en/latest/)
|
|
7
|
+
|
|
8
|
+
## Contribute
|
|
9
|
+
[Contribution guidelines](./CONTRIBUTING.md)
|
|
10
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{% extends "!layout.html" %}
|
|
2
|
+
{% block footer %} {{ super() }}
|
|
3
|
+
|
|
4
|
+
<style>
|
|
5
|
+
/* Sidebar header (and topbar for mobile) */
|
|
6
|
+
.wy-side-nav-search, .wy-nav-top {
|
|
7
|
+
background: #ff1243;
|
|
8
|
+
}
|
|
9
|
+
/* Sidebar */
|
|
10
|
+
.wy-nav-side {
|
|
11
|
+
background: #474747;
|
|
12
|
+
}
|
|
13
|
+
.wy-side-nav-search > div.version {
|
|
14
|
+
color: white;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
{% endblock %}
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
15
|
|
|
16
|
-
sys.path.insert(0, os.path.abspath(
|
|
16
|
+
sys.path.insert(0, os.path.abspath("../src/"))
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
# -- Project information -----------------------------------------------------
|
|
20
20
|
|
|
21
|
-
project =
|
|
22
|
-
copyright =
|
|
23
|
-
author =
|
|
21
|
+
project = "sumo-wrapper-python"
|
|
22
|
+
copyright = "2024, Sudo Team @ Equinor"
|
|
23
|
+
author = "Sudo Team @ Equinor"
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# -- General configuration ---------------------------------------------------
|
|
@@ -28,15 +28,18 @@ author = 'Sudo Team @ Equinor'
|
|
|
28
28
|
# Add any Sphinx extension module names here, as strings. They can be
|
|
29
29
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
30
30
|
# ones.
|
|
31
|
-
extensions = [
|
|
31
|
+
extensions = [
|
|
32
|
+
"sphinx.ext.napoleon",
|
|
33
|
+
"sphinx.ext.autodoc",
|
|
34
|
+
]
|
|
32
35
|
|
|
33
36
|
# Add any paths that contain templates here, relative to this directory.
|
|
34
|
-
templates_path = [
|
|
37
|
+
templates_path = ["_templates"]
|
|
35
38
|
|
|
36
39
|
# List of patterns, relative to source directory, that match files and
|
|
37
40
|
# directories to ignore when looking for source files.
|
|
38
41
|
# This pattern also affects html_static_path and html_extra_path.
|
|
39
|
-
exclude_patterns = [
|
|
42
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
# -- Options for HTML output -------------------------------------------------
|
|
@@ -44,13 +47,12 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
|
44
47
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
45
48
|
# a list of builtin themes.
|
|
46
49
|
#
|
|
47
|
-
html_theme =
|
|
50
|
+
html_theme = "sphinx_rtd_theme"
|
|
51
|
+
html_logo = "_static/equinor-logo2.jpg"
|
|
48
52
|
|
|
49
|
-
html_theme_options = {
|
|
50
|
-
"style_nav_header_background": "#C0C0C0",
|
|
51
|
-
}
|
|
52
53
|
|
|
53
54
|
# Add any paths that contain custom static files (such as style sheets) here,
|
|
54
55
|
# relative to this directory. They are copied after the builtin static files,
|
|
55
56
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
56
|
-
html_static_path = [
|
|
57
|
+
html_static_path = ["_static"]
|
|
58
|
+
|
|
@@ -3,22 +3,13 @@
|
|
|
3
3
|
You can adapt this file completely to your liking, but it should at least
|
|
4
4
|
contain the root `toctree` directive.
|
|
5
5
|
|
|
6
|
-
sumo-wrapper-python
|
|
7
|
-
|
|
6
|
+
Welcome to sumo-wrapper-python's documentation!
|
|
7
|
+
===============================================
|
|
8
8
|
|
|
9
9
|
.. toctree::
|
|
10
10
|
:maxdepth: 2
|
|
11
11
|
:caption: Contents:
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
:show-inheritance:
|
|
17
|
-
|
|
18
|
-
..
|
|
19
|
-
Indices and tables
|
|
20
|
-
==================
|
|
21
|
-
|
|
22
|
-
* :ref:`genindex`
|
|
23
|
-
* :ref:`modindex`
|
|
24
|
-
* :ref:`search`
|
|
13
|
+
self
|
|
14
|
+
sumo-wrapper-python
|
|
15
|
+
api
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
sumo-wrapper-python
|
|
2
|
+
###################
|
|
3
|
+
|
|
4
|
+
Short introduction
|
|
5
|
+
*******************
|
|
6
|
+
|
|
7
|
+
A thin python wrapper class that can be used by Sumo client applications to
|
|
8
|
+
communicate with the Sumo core server. It has methods for GET, PUT, POST and DELETE,
|
|
9
|
+
and handles authentication and automatic network retries.
|
|
10
|
+
|
|
11
|
+
This is low-level and close to the Sumo API and primarily intended for developers.
|
|
12
|
+
For usage in the FMU context, the higher-level alternative
|
|
13
|
+
`fmu-sumo <https://fmu-sumo.readthedocs.io>`_ is recommended.
|
|
14
|
+
|
|
15
|
+
The Sumo API is described at
|
|
16
|
+
`https://main-sumo-prod.radix.equinor.com/swagger-ui/ <https://main-sumo-prod.radix.equinor.com/swagger-ui/>`_
|
|
17
|
+
|
|
18
|
+
The data model and schema is described at
|
|
19
|
+
`https://fmu-dataio.readthedocs.io/en/latest/datamodel.html <https://fmu-dataio.readthedocs.io/en/latest/datamodel.html>`_
|
|
20
|
+
|
|
21
|
+
Information on Sumo can be found `here <https://doc-sumo-doc-prod.radix.equinor.com/>`_
|
|
22
|
+
|
|
23
|
+
Preconditions
|
|
24
|
+
*************
|
|
25
|
+
|
|
26
|
+
Access
|
|
27
|
+
------
|
|
28
|
+
|
|
29
|
+
For internal Equinor users: Apply for access to Sumo in Equinor AccessIT, search for Sumo.
|
|
30
|
+
|
|
31
|
+
Install
|
|
32
|
+
*******
|
|
33
|
+
|
|
34
|
+
For internal Equinor users, this package is included in the Komodo distribution.
|
|
35
|
+
For other use cases it can be pip installed directly from PyPI:
|
|
36
|
+
|
|
37
|
+
.. code-block::
|
|
38
|
+
|
|
39
|
+
pip install sumo-wrapper-python
|
|
40
|
+
|
|
41
|
+
Initialization
|
|
42
|
+
**************
|
|
43
|
+
|
|
44
|
+
.. code-block:: python
|
|
45
|
+
|
|
46
|
+
from sumo.wrapper import SumoClient
|
|
47
|
+
|
|
48
|
+
Sumo = SumoClient()
|
|
49
|
+
|
|
50
|
+
`token` logic
|
|
51
|
+
*************
|
|
52
|
+
|
|
53
|
+
No token provided: this will trigger
|
|
54
|
+
an authentication process and then handles token, token refresh and
|
|
55
|
+
re-authentication as automatic as possible. This would be the most common
|
|
56
|
+
usecase.
|
|
57
|
+
|
|
58
|
+
If an access token is provided in the `token` parameter, it will be used as long
|
|
59
|
+
as it's valid. An error will be raised when it expires.
|
|
60
|
+
|
|
61
|
+
If we are unable to decode the provided `token` as a JWT, we treat it as a
|
|
62
|
+
refresh token and attempt to use it to retrieve an access token.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
Methods
|
|
66
|
+
*******
|
|
67
|
+
|
|
68
|
+
`SumoClient` has one method for each HTTP-method that is used in the Sumo
|
|
69
|
+
API: GET, PUT, POST and DELETE. In addition a method to get a blob client
|
|
70
|
+
which handles blob contents.
|
|
71
|
+
|
|
72
|
+
The methods accepts a path argument. A path is the path to a
|
|
73
|
+
Sumo `API <https://main-sumo-prod.radix.equinor.com/swagger-ui/>`_ method, for
|
|
74
|
+
example "/search" or "/smda/countries". Path parameters can be added into
|
|
75
|
+
the path string, for example
|
|
76
|
+
|
|
77
|
+
.. code-block:: python
|
|
78
|
+
|
|
79
|
+
f"/objects('{case_uuid}')/search"
|
|
80
|
+
|
|
81
|
+
The Sumo API documentation is available from the Swagger button in
|
|
82
|
+
the Sumo frontend, or you can use this link:
|
|
83
|
+
`https://main-sumo-prod.radix.equinor.com/swagger-ui/ <https://main-sumo-prod.radix.equinor.com/swagger-ui/>`_.
|
|
84
|
+
|
|
85
|
+
Async methods
|
|
86
|
+
*************
|
|
87
|
+
|
|
88
|
+
`SumoClient` also has *async* alternatives `get_async`, `post_async`, `put_async` and `delete_async`.
|
|
89
|
+
These accept the same parameters as their synchronous counterparts, but have to be *awaited*.
|
|
90
|
+
|
|
91
|
+
Usage and examples
|
|
92
|
+
******************
|
|
93
|
+
|
|
94
|
+
.. code-block:: python
|
|
95
|
+
|
|
96
|
+
from sumo.wrapper import SumoClient
|
|
97
|
+
sumo = SumoClient()
|
|
98
|
+
|
|
99
|
+
# The line above will trigger the authentication process, and
|
|
100
|
+
# the behaviour depends on how long since your last login.
|
|
101
|
+
# It could re-use existing login or it could take you through
|
|
102
|
+
# a full Microsoft authentication process including
|
|
103
|
+
# username, password, two-factor.
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# List your Sumo permissions:
|
|
107
|
+
print("My permissions:", sumo.get("/userpermissions").json())
|
|
108
|
+
|
|
109
|
+
# Get the first case from the list of cases you have access to:
|
|
110
|
+
case = sumo.get("/searchroot").json()["hits"]["hits"][0]
|
|
111
|
+
print("Case metadata:", case["_source"])
|
|
112
|
+
case_uuid = case["_source"]["fmu"]["case"]["uuid"]
|
|
113
|
+
print("Case uuid: ", case_uuid)
|
|
114
|
+
|
|
115
|
+
# Get the first child object:
|
|
116
|
+
child = sumo.get(f"/objects('{case_uuid}')/search").json()["hits"]["hits"][0]
|
|
117
|
+
print("Child metadata", child["_source"])
|
|
118
|
+
child_uuid = child["_id"]
|
|
119
|
+
print("Child uuid: ", child_uuid)
|
|
120
|
+
|
|
121
|
+
# Get the binary of the child
|
|
122
|
+
binary_object = sumo.get(f"/objects('{child_uuid}')/blob").content
|
|
123
|
+
print("Size of child binary object:", len(binary_object))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
.. toctree::
|
|
127
|
+
:maxdepth: 2
|
|
128
|
+
:caption: Contents:
|
|
129
|
+
|
|
@@ -32,7 +32,13 @@ dependencies = [
|
|
|
32
32
|
|
|
33
33
|
[project.optional-dependencies]
|
|
34
34
|
test = ["pytest", "PyYAML"]
|
|
35
|
-
docs = [
|
|
35
|
+
docs = [
|
|
36
|
+
"sphinx",
|
|
37
|
+
"sphinx-rtd-theme",
|
|
38
|
+
"autoapi",
|
|
39
|
+
"sphinx-autodoc-typehints",
|
|
40
|
+
"sphinxcontrib-apidoc",
|
|
41
|
+
]
|
|
36
42
|
|
|
37
43
|
[project.urls]
|
|
38
44
|
Repository = "https://github.com/equinor/sumo-wrapper-python"
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
from pathlib import Path
|
|
1
3
|
import msal
|
|
2
4
|
import os
|
|
3
5
|
from datetime import datetime, timedelta
|
|
@@ -34,6 +36,9 @@ class AuthProvider:
|
|
|
34
36
|
self._resource_id = resource_id
|
|
35
37
|
self._scope = scope_for_resource(resource_id)
|
|
36
38
|
self._app = None
|
|
39
|
+
self._login_timeout_minutes = 5
|
|
40
|
+
os.system("") # Ensure color init on all platforms (win10)
|
|
41
|
+
|
|
37
42
|
return
|
|
38
43
|
|
|
39
44
|
@tn.retry(
|
|
@@ -57,7 +62,11 @@ class AuthProvider:
|
|
|
57
62
|
return result["access_token"]
|
|
58
63
|
|
|
59
64
|
def get_authorization(self):
|
|
60
|
-
|
|
65
|
+
token = self.get_token()
|
|
66
|
+
if token is None:
|
|
67
|
+
return ""
|
|
68
|
+
|
|
69
|
+
return {"Authorization": "Bearer " + token}
|
|
61
70
|
|
|
62
71
|
pass
|
|
63
72
|
|
|
@@ -195,25 +204,24 @@ class AuthProviderInteractive(AuthProvider):
|
|
|
195
204
|
)
|
|
196
205
|
def login(self):
|
|
197
206
|
scopes = [self._scope + " offline_access"]
|
|
198
|
-
login_timeout_minutes = 7
|
|
199
|
-
os.system("") # Ensure color init on all platforms (win10)
|
|
200
207
|
print(
|
|
201
208
|
"\n\n \033[31m NOTE! \033[0m"
|
|
202
209
|
+ " Please login to Equinor Azure to enable Sumo access: "
|
|
203
|
-
+ "we
|
|
210
|
+
+ "we are opening a login web-page for you in your browser."
|
|
204
211
|
+ "\nYou should complete your login within "
|
|
205
|
-
+ str(
|
|
212
|
+
+ str(self._login_timeout_minutes)
|
|
206
213
|
+ " minutes, "
|
|
207
214
|
+ "that is before "
|
|
208
215
|
+ str(
|
|
209
216
|
(
|
|
210
|
-
datetime.now()
|
|
217
|
+
datetime.now()
|
|
218
|
+
+ timedelta(minutes=self._login_timeout_minutes)
|
|
211
219
|
).strftime("%H:%M:%S")
|
|
212
220
|
)
|
|
213
221
|
)
|
|
214
222
|
try:
|
|
215
223
|
result = self._app.acquire_token_interactive(
|
|
216
|
-
scopes, timeout=(
|
|
224
|
+
scopes, timeout=(self._login_timeout_minutes * 60)
|
|
217
225
|
)
|
|
218
226
|
if "error" in result:
|
|
219
227
|
print(
|
|
@@ -230,7 +238,9 @@ class AuthProviderInteractive(AuthProvider):
|
|
|
230
238
|
return
|
|
231
239
|
|
|
232
240
|
protect_token_cache(self._resource_id, ".token")
|
|
233
|
-
print(
|
|
241
|
+
print(
|
|
242
|
+
"Equinor Azure login for Sumo access was successful (interactive)"
|
|
243
|
+
)
|
|
234
244
|
return
|
|
235
245
|
|
|
236
246
|
pass
|
|
@@ -261,24 +271,47 @@ class AuthProviderDeviceCode(AuthProvider):
|
|
|
261
271
|
before_sleep=_log_retry_info,
|
|
262
272
|
)
|
|
263
273
|
def login(self):
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
274
|
+
try:
|
|
275
|
+
scopes = [self._scope + " offline_access"]
|
|
276
|
+
flow = self._app.initiate_device_flow(scopes)
|
|
277
|
+
if "error" in flow:
|
|
278
|
+
print(
|
|
279
|
+
"\n\n \033[31m"
|
|
280
|
+
+ "Failed to initiate device-code login. Err: %s"
|
|
281
|
+
+ "\033[0m" % json.dumps(flow, indent=4)
|
|
282
|
+
)
|
|
283
|
+
return
|
|
284
|
+
flow["expires_at"] = (
|
|
285
|
+
int(time.time()) + self._login_timeout_minutes * 60
|
|
270
286
|
)
|
|
271
287
|
|
|
272
|
-
|
|
273
|
-
|
|
288
|
+
print(
|
|
289
|
+
"\033[31m"
|
|
290
|
+
+ " NOTE! Please login to Equinor Azure to enable Sumo access:"
|
|
291
|
+
+ flow["message"]
|
|
292
|
+
+ " \033[0m"
|
|
293
|
+
+ "\nYou should complete your login within a few minutes"
|
|
294
|
+
)
|
|
295
|
+
result = self._app.acquire_token_by_device_flow(flow)
|
|
274
296
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
297
|
+
if "error" in result:
|
|
298
|
+
print(
|
|
299
|
+
"\n\n \033[31m Error during Equinor Azure login "
|
|
300
|
+
"for Sumo access: \033[0m"
|
|
301
|
+
)
|
|
302
|
+
print("Err: ", json.dumps(result, indent=4))
|
|
303
|
+
return
|
|
304
|
+
except Exception:
|
|
305
|
+
print(
|
|
306
|
+
"\n\n \033[31m Failed Equinor Azure login for Sumo access, "
|
|
307
|
+
"one possible reason is timeout \033[0m"
|
|
279
308
|
)
|
|
309
|
+
return
|
|
280
310
|
|
|
281
311
|
protect_token_cache(self._resource_id, ".token")
|
|
312
|
+
print(
|
|
313
|
+
"Equinor Azure login for Sumo access was successful (device-code)"
|
|
314
|
+
)
|
|
282
315
|
|
|
283
316
|
return
|
|
284
317
|
|
|
@@ -384,4 +417,11 @@ def get_auth_provider(
|
|
|
384
417
|
):
|
|
385
418
|
return AuthProviderManaged(resource_id)
|
|
386
419
|
# ELSE
|
|
420
|
+
lockfile_path = Path.home() / ".config/chromium/SingletonLock"
|
|
421
|
+
if Path(lockfile_path).is_symlink() and not str(
|
|
422
|
+
Path(lockfile_path).resolve()
|
|
423
|
+
).__contains__(platform.node()):
|
|
424
|
+
# https://github.com/equinor/sumo-wrapper-python/issues/193
|
|
425
|
+
return AuthProviderDeviceCode(client_id, authority, resource_id)
|
|
426
|
+
# ELSE
|
|
387
427
|
return AuthProviderInteractive(client_id, authority, resource_id)
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
# For sphinx:
|
|
2
|
+
from functools import wraps
|
|
3
|
+
|
|
4
|
+
|
|
1
5
|
def raise_for_status(func):
|
|
6
|
+
@wraps(func)
|
|
2
7
|
def wrapper(*args, **kwargs):
|
|
3
8
|
# FIXME: in newer versions of httpx, raise_for_status() is chainable,
|
|
4
9
|
# so we could simply write
|
|
@@ -11,6 +16,7 @@ def raise_for_status(func):
|
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
def raise_for_status_async(func):
|
|
19
|
+
@wraps(func)
|
|
14
20
|
async def wrapper(*args, **kwargs):
|
|
15
21
|
# FIXME: in newer versions of httpx, raise_for_status() is chainable,
|
|
16
22
|
# so we could simply write
|
|
@@ -20,6 +20,9 @@ class LogHandlerSumo(logging.Handler):
|
|
|
20
20
|
"funcname": record.funcName,
|
|
21
21
|
"linenumber": record.lineno,
|
|
22
22
|
}
|
|
23
|
+
if "objectUuid" in record.__dict__.keys():
|
|
24
|
+
json["objectUuid"] = record.__dict__.get("objectUuid")
|
|
25
|
+
|
|
23
26
|
self._sumoClient.post("/message-log/new", json=json)
|
|
24
27
|
except Exception:
|
|
25
28
|
# Never fail on logging
|
|
@@ -74,6 +74,11 @@ def main():
|
|
|
74
74
|
if args.print_token:
|
|
75
75
|
print(f"TOKEN: {token}")
|
|
76
76
|
|
|
77
|
+
if token is not None:
|
|
78
|
+
print("Successfully logged in to Sumo environment: " + env)
|
|
79
|
+
else:
|
|
80
|
+
print("Failed login to Sumo environment: " + env)
|
|
81
|
+
|
|
77
82
|
|
|
78
83
|
if __name__ == "__main__":
|
|
79
84
|
main()
|
|
@@ -84,6 +84,27 @@ class SumoClient:
|
|
|
84
84
|
access_token=access_token,
|
|
85
85
|
devicecode=devicecode,
|
|
86
86
|
)
|
|
87
|
+
if (
|
|
88
|
+
self.auth.get_token() is None
|
|
89
|
+
and refresh_token is None
|
|
90
|
+
and access_token is None
|
|
91
|
+
):
|
|
92
|
+
print("\n \033[31m !!! Falling back to device-code login:\033[0m")
|
|
93
|
+
self.auth = get_auth_provider(
|
|
94
|
+
client_id=APP_REGISTRATION[env]["CLIENT_ID"],
|
|
95
|
+
authority=f"{AUTHORITY_HOST_URI}/{TENANT_ID}",
|
|
96
|
+
resource_id=APP_REGISTRATION[env]["RESOURCE_ID"],
|
|
97
|
+
interactive=False,
|
|
98
|
+
refresh_token=None,
|
|
99
|
+
access_token=None,
|
|
100
|
+
devicecode=True,
|
|
101
|
+
)
|
|
102
|
+
if self.auth.get_token() is None:
|
|
103
|
+
print(
|
|
104
|
+
"\n\n \033[31m "
|
|
105
|
+
+ "NOTE! Login failed/timed out. Giving up."
|
|
106
|
+
+ "\033[0m"
|
|
107
|
+
)
|
|
87
108
|
|
|
88
109
|
if env == "localhost":
|
|
89
110
|
self.base_url = "http://localhost:8084/api/v1"
|
{sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sumo-wrapper-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.9
|
|
4
4
|
Summary: Python wrapper for the Sumo API
|
|
5
5
|
Author: Equinor
|
|
6
6
|
License: Apache License
|
|
@@ -223,162 +223,17 @@ Requires-Dist: PyYAML; extra == "test"
|
|
|
223
223
|
Provides-Extra: docs
|
|
224
224
|
Requires-Dist: sphinx; extra == "docs"
|
|
225
225
|
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
226
|
+
Requires-Dist: autoapi; extra == "docs"
|
|
227
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
228
|
+
Requires-Dist: sphinxcontrib-apidoc; extra == "docs"
|
|
226
229
|
|
|
227
230
|
# sumo-wrapper-python
|
|
228
231
|
|
|
229
|
-
|
|
232
|
+
[](https://sumo-wrapper-python.readthedocs.io/en/latest/?badge=latest)
|
|
230
233
|
|
|
231
|
-
|
|
234
|
+
## Documentation and guidelines
|
|
235
|
+
[sumo-wrapper-python documentation](https://sumo-wrapper-python.readthedocs.io/en/latest/)
|
|
232
236
|
|
|
233
|
-
##
|
|
237
|
+
## Contribute
|
|
238
|
+
[Contribution guidelines](./CONTRIBUTING.md)
|
|
234
239
|
|
|
235
|
-
pip install sumo-wrapper-python
|
|
236
|
-
|
|
237
|
-
For internal Equinor users, this package is available through the Komodo
|
|
238
|
-
distribution.
|
|
239
|
-
|
|
240
|
-
# Table of contents
|
|
241
|
-
|
|
242
|
-
- [sumo-wrapper-python](#sumo-wrapper-python)
|
|
243
|
-
- [Install:](#install)
|
|
244
|
-
- [Table of contents](#table-of-contents)
|
|
245
|
-
- [SumoClient](#sumoclient)
|
|
246
|
-
- [Initialization](#initialization)
|
|
247
|
-
- [Parameters](#parameters)
|
|
248
|
-
- [`token` logic](#token-logic)
|
|
249
|
-
- [Methods](#methods)
|
|
250
|
-
- [get(path, \*\*params)](#getpath-params)
|
|
251
|
-
- [post(path, json, blob, params)](#postpath-json-blob-params)
|
|
252
|
-
- [put(path, json, blob)](#putpath-json-blob)
|
|
253
|
-
- [delete(path)](#deletepath)
|
|
254
|
-
- [Async methods](#async-methods)
|
|
255
|
-
|
|
256
|
-
# SumoClient
|
|
257
|
-
|
|
258
|
-
A thin wrapper class for the Sumo API.
|
|
259
|
-
|
|
260
|
-
### Initialization
|
|
261
|
-
|
|
262
|
-
```python
|
|
263
|
-
from sumo.wrapper import SumoClient
|
|
264
|
-
|
|
265
|
-
sumo = SumoClient(env="dev")
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Parameters
|
|
269
|
-
|
|
270
|
-
```python
|
|
271
|
-
class SumoClient:
|
|
272
|
-
def __init__(
|
|
273
|
-
self,
|
|
274
|
-
env:str,
|
|
275
|
-
token:str=None,
|
|
276
|
-
interactive:bool=False,
|
|
277
|
-
verbosity:str="CRITICAL"
|
|
278
|
-
):
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
- `env`: sumo environment
|
|
282
|
-
- `token`: bearer token or refresh token
|
|
283
|
-
- `interactive`: use interactive flow when authenticating
|
|
284
|
-
- `verbosity`: "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
|
|
285
|
-
|
|
286
|
-
###### `token` logic
|
|
287
|
-
|
|
288
|
-
If an access token is provided in the `token` parameter, it will be used as long
|
|
289
|
-
as it's valid. An error will be raised when it expires.
|
|
290
|
-
|
|
291
|
-
If we are unable to decode the provided `token` as a JWT, we treat it as a
|
|
292
|
-
refresh token and attempt to use it to retrieve an access token.
|
|
293
|
-
|
|
294
|
-
If no `token` is provided, an authentication code flow/interactive flow is
|
|
295
|
-
triggered to retrieve a token.
|
|
296
|
-
|
|
297
|
-
## Methods
|
|
298
|
-
|
|
299
|
-
`SumoClient` has one method for each HTTP-method that is used in the sumo-core
|
|
300
|
-
API. See examples of how to use these methods below.
|
|
301
|
-
|
|
302
|
-
All methods accepts a path argument. Path parameters can be interpolated into
|
|
303
|
-
the path string. Example:
|
|
304
|
-
|
|
305
|
-
```python
|
|
306
|
-
object_id = "1234"
|
|
307
|
-
|
|
308
|
-
# GET/objects('{obejctid}')
|
|
309
|
-
sumo.get(f"/objects('{object_id}')")
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### get(path, \*\*params)
|
|
313
|
-
|
|
314
|
-
Performs a GET-request to sumo-core. Accepts query parameters as keyword
|
|
315
|
-
arguments.
|
|
316
|
-
|
|
317
|
-
```python
|
|
318
|
-
# Retrieve userdata
|
|
319
|
-
user_data = sumo.get("/userdata")
|
|
320
|
-
|
|
321
|
-
# Search for objects
|
|
322
|
-
results = sumo.get("/search",
|
|
323
|
-
query="class:surface",
|
|
324
|
-
size:3,
|
|
325
|
-
select=["_id"]
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
# Get object by id
|
|
329
|
-
object_id = "159405ba-0046-b321-55ce-542f383ba5c7"
|
|
330
|
-
|
|
331
|
-
obj = sumo.get(f"/objects('{object_id}')")
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### post(path, json, blob, params)
|
|
335
|
-
|
|
336
|
-
Performs a POST-request to sumo-core. Accepts json and blob, but not both at the
|
|
337
|
-
same time.
|
|
338
|
-
|
|
339
|
-
```python
|
|
340
|
-
# Upload new parent object
|
|
341
|
-
parent_object = sumo.post("/objects", json=parent_meta_data)
|
|
342
|
-
|
|
343
|
-
# Upload child object
|
|
344
|
-
parent_id = parent_object["_id"]
|
|
345
|
-
|
|
346
|
-
child_object = sumo.post(f"/objects('{parent_id}')", json=child_meta_data)
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
### put(path, json, blob)
|
|
350
|
-
|
|
351
|
-
Performs a PUT-request to sumo-core. Accepts json and blob, but not both at the
|
|
352
|
-
same time.
|
|
353
|
-
|
|
354
|
-
```python
|
|
355
|
-
# Upload blob to child object
|
|
356
|
-
child_id = child_object["_id"]
|
|
357
|
-
|
|
358
|
-
sumo.put(f"/objects('{child_id}')/blob", blob=blob)
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### delete(path)
|
|
362
|
-
|
|
363
|
-
Performs a DELETE-request to sumo-core.
|
|
364
|
-
|
|
365
|
-
```python
|
|
366
|
-
# Delete blob
|
|
367
|
-
sumo.delete(f"/objects('{child_id}')/blob")
|
|
368
|
-
|
|
369
|
-
# Delete child object
|
|
370
|
-
sumo.delete(f"/objects('{child_id}')")
|
|
371
|
-
|
|
372
|
-
# Delete parent object
|
|
373
|
-
sumo.delete(f"/objects('{parent_id}')")
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
## Async methods
|
|
377
|
-
|
|
378
|
-
`SumoClient` also has *async* alternatives `get_async`, `post_async`, `put_async` and `delete_async`.
|
|
379
|
-
These accept the same parameters as their synchronous counterparts, but have to be *awaited*.
|
|
380
|
-
|
|
381
|
-
```python
|
|
382
|
-
# Retrieve userdata
|
|
383
|
-
user_data = await sumo.get_async("/userdata")
|
|
384
|
-
```
|
{sumo-wrapper-python-1.0.8 → sumo_wrapper_python-1.0.9}/src/sumo_wrapper_python.egg-info/SOURCES.txt
RENAMED
|
@@ -7,13 +7,21 @@ README.md
|
|
|
7
7
|
SECURITY.md
|
|
8
8
|
conftest.py
|
|
9
9
|
pyproject.toml
|
|
10
|
+
.github/workflows/build_docs.yaml
|
|
10
11
|
.github/workflows/linting.yml
|
|
11
12
|
.github/workflows/publish_release.yml
|
|
12
13
|
.github/workflows/pytest.yml
|
|
13
14
|
docs/Makefile
|
|
15
|
+
docs/api.rst
|
|
14
16
|
docs/conf.py
|
|
15
17
|
docs/index.rst
|
|
16
18
|
docs/make.bat
|
|
19
|
+
docs/sumo-wrapper-python.rst
|
|
20
|
+
docs/_static/equinor-logo.png
|
|
21
|
+
docs/_static/equinor-logo2.jpg
|
|
22
|
+
docs/_static/equinor_logo.jpg
|
|
23
|
+
docs/_static/equinor_logo_only.jpg
|
|
24
|
+
docs/_templates/layout.html
|
|
17
25
|
src/sumo/__init__.py
|
|
18
26
|
src/sumo/wrapper/__init__.py
|
|
19
27
|
src/sumo/wrapper/_auth_provider.py
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# sumo-wrapper-python
|
|
2
|
-
|
|
3
|
-
Python wrappers for Sumo APIs
|
|
4
|
-
|
|
5
|
-
Want to contribute? Read our [contributing](./CONTRIBUTING.md) guidelines
|
|
6
|
-
|
|
7
|
-
## Install:
|
|
8
|
-
|
|
9
|
-
pip install sumo-wrapper-python
|
|
10
|
-
|
|
11
|
-
For internal Equinor users, this package is available through the Komodo
|
|
12
|
-
distribution.
|
|
13
|
-
|
|
14
|
-
# Table of contents
|
|
15
|
-
|
|
16
|
-
- [sumo-wrapper-python](#sumo-wrapper-python)
|
|
17
|
-
- [Install:](#install)
|
|
18
|
-
- [Table of contents](#table-of-contents)
|
|
19
|
-
- [SumoClient](#sumoclient)
|
|
20
|
-
- [Initialization](#initialization)
|
|
21
|
-
- [Parameters](#parameters)
|
|
22
|
-
- [`token` logic](#token-logic)
|
|
23
|
-
- [Methods](#methods)
|
|
24
|
-
- [get(path, \*\*params)](#getpath-params)
|
|
25
|
-
- [post(path, json, blob, params)](#postpath-json-blob-params)
|
|
26
|
-
- [put(path, json, blob)](#putpath-json-blob)
|
|
27
|
-
- [delete(path)](#deletepath)
|
|
28
|
-
- [Async methods](#async-methods)
|
|
29
|
-
|
|
30
|
-
# SumoClient
|
|
31
|
-
|
|
32
|
-
A thin wrapper class for the Sumo API.
|
|
33
|
-
|
|
34
|
-
### Initialization
|
|
35
|
-
|
|
36
|
-
```python
|
|
37
|
-
from sumo.wrapper import SumoClient
|
|
38
|
-
|
|
39
|
-
sumo = SumoClient(env="dev")
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Parameters
|
|
43
|
-
|
|
44
|
-
```python
|
|
45
|
-
class SumoClient:
|
|
46
|
-
def __init__(
|
|
47
|
-
self,
|
|
48
|
-
env:str,
|
|
49
|
-
token:str=None,
|
|
50
|
-
interactive:bool=False,
|
|
51
|
-
verbosity:str="CRITICAL"
|
|
52
|
-
):
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
- `env`: sumo environment
|
|
56
|
-
- `token`: bearer token or refresh token
|
|
57
|
-
- `interactive`: use interactive flow when authenticating
|
|
58
|
-
- `verbosity`: "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
|
|
59
|
-
|
|
60
|
-
###### `token` logic
|
|
61
|
-
|
|
62
|
-
If an access token is provided in the `token` parameter, it will be used as long
|
|
63
|
-
as it's valid. An error will be raised when it expires.
|
|
64
|
-
|
|
65
|
-
If we are unable to decode the provided `token` as a JWT, we treat it as a
|
|
66
|
-
refresh token and attempt to use it to retrieve an access token.
|
|
67
|
-
|
|
68
|
-
If no `token` is provided, an authentication code flow/interactive flow is
|
|
69
|
-
triggered to retrieve a token.
|
|
70
|
-
|
|
71
|
-
## Methods
|
|
72
|
-
|
|
73
|
-
`SumoClient` has one method for each HTTP-method that is used in the sumo-core
|
|
74
|
-
API. See examples of how to use these methods below.
|
|
75
|
-
|
|
76
|
-
All methods accepts a path argument. Path parameters can be interpolated into
|
|
77
|
-
the path string. Example:
|
|
78
|
-
|
|
79
|
-
```python
|
|
80
|
-
object_id = "1234"
|
|
81
|
-
|
|
82
|
-
# GET/objects('{obejctid}')
|
|
83
|
-
sumo.get(f"/objects('{object_id}')")
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### get(path, \*\*params)
|
|
87
|
-
|
|
88
|
-
Performs a GET-request to sumo-core. Accepts query parameters as keyword
|
|
89
|
-
arguments.
|
|
90
|
-
|
|
91
|
-
```python
|
|
92
|
-
# Retrieve userdata
|
|
93
|
-
user_data = sumo.get("/userdata")
|
|
94
|
-
|
|
95
|
-
# Search for objects
|
|
96
|
-
results = sumo.get("/search",
|
|
97
|
-
query="class:surface",
|
|
98
|
-
size:3,
|
|
99
|
-
select=["_id"]
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
# Get object by id
|
|
103
|
-
object_id = "159405ba-0046-b321-55ce-542f383ba5c7"
|
|
104
|
-
|
|
105
|
-
obj = sumo.get(f"/objects('{object_id}')")
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### post(path, json, blob, params)
|
|
109
|
-
|
|
110
|
-
Performs a POST-request to sumo-core. Accepts json and blob, but not both at the
|
|
111
|
-
same time.
|
|
112
|
-
|
|
113
|
-
```python
|
|
114
|
-
# Upload new parent object
|
|
115
|
-
parent_object = sumo.post("/objects", json=parent_meta_data)
|
|
116
|
-
|
|
117
|
-
# Upload child object
|
|
118
|
-
parent_id = parent_object["_id"]
|
|
119
|
-
|
|
120
|
-
child_object = sumo.post(f"/objects('{parent_id}')", json=child_meta_data)
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### put(path, json, blob)
|
|
124
|
-
|
|
125
|
-
Performs a PUT-request to sumo-core. Accepts json and blob, but not both at the
|
|
126
|
-
same time.
|
|
127
|
-
|
|
128
|
-
```python
|
|
129
|
-
# Upload blob to child object
|
|
130
|
-
child_id = child_object["_id"]
|
|
131
|
-
|
|
132
|
-
sumo.put(f"/objects('{child_id}')/blob", blob=blob)
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### delete(path)
|
|
136
|
-
|
|
137
|
-
Performs a DELETE-request to sumo-core.
|
|
138
|
-
|
|
139
|
-
```python
|
|
140
|
-
# Delete blob
|
|
141
|
-
sumo.delete(f"/objects('{child_id}')/blob")
|
|
142
|
-
|
|
143
|
-
# Delete child object
|
|
144
|
-
sumo.delete(f"/objects('{child_id}')")
|
|
145
|
-
|
|
146
|
-
# Delete parent object
|
|
147
|
-
sumo.delete(f"/objects('{parent_id}')")
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Async methods
|
|
151
|
-
|
|
152
|
-
`SumoClient` also has *async* alternatives `get_async`, `post_async`, `put_async` and `delete_async`.
|
|
153
|
-
These accept the same parameters as their synchronous counterparts, but have to be *awaited*.
|
|
154
|
-
|
|
155
|
-
```python
|
|
156
|
-
# Retrieve userdata
|
|
157
|
-
user_data = await sumo.get_async("/userdata")
|
|
158
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|