sumo-wrapper-python 1.0.24__tar.gz → 1.0.26__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.

Files changed (46) hide show
  1. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/PKG-INFO +1 -1
  2. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/_auth_provider.py +14 -0
  3. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/_version.py +9 -4
  4. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/login.py +0 -12
  5. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/sumo_client.py +69 -2
  6. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo_wrapper_python.egg-info/PKG-INFO +1 -1
  7. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/tests/test_sumo_thin_client.py +16 -3
  8. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/tests/testdata/surface.yml +1 -1
  9. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.github/workflows/build_docs.yaml +0 -0
  10. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.github/workflows/linting.yml +0 -0
  11. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.github/workflows/publish_release.yml +0 -0
  12. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.github/workflows/pytest.yml +0 -0
  13. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.gitignore +0 -0
  14. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.pre-commit-config.yaml +0 -0
  15. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/.readthedocs.yaml +0 -0
  16. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/CONTRIBUTING.md +0 -0
  17. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/LICENSE +0 -0
  18. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/README.md +0 -0
  19. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/SECURITY.md +0 -0
  20. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/Makefile +0 -0
  21. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/_static/equinor-logo.png +0 -0
  22. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/_static/equinor-logo2.jpg +0 -0
  23. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/_static/equinor_logo.jpg +0 -0
  24. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/_static/equinor_logo_only.jpg +0 -0
  25. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/_templates/layout.html +0 -0
  26. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/api.rst +0 -0
  27. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/conf.py +0 -0
  28. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/index.rst +0 -0
  29. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/make.bat +0 -0
  30. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/docs/sumo-wrapper-python.rst +0 -0
  31. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/pyproject.toml +0 -0
  32. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/setup.cfg +0 -0
  33. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/__init__.py +0 -0
  34. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/__init__.py +0 -0
  35. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/_blob_client.py +0 -0
  36. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/_decorators.py +0 -0
  37. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/_logging.py +0 -0
  38. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/_retry_strategy.py +0 -0
  39. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo/wrapper/config.py +0 -0
  40. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo_wrapper_python.egg-info/SOURCES.txt +0 -0
  41. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo_wrapper_python.egg-info/dependency_links.txt +0 -0
  42. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo_wrapper_python.egg-info/entry_points.txt +0 -0
  43. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo_wrapper_python.egg-info/requires.txt +0 -0
  44. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/src/sumo_wrapper_python.egg-info/top_level.txt +0 -0
  45. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/tests/conftest.py +0 -0
  46. {sumo_wrapper_python-1.0.24 → sumo_wrapper_python-1.0.26}/tests/testdata/case.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: sumo-wrapper-python
3
- Version: 1.0.24
3
+ Version: 1.0.26
4
4
  Summary: Python wrapper for the Sumo API
5
5
  Author: Equinor
6
6
  License: Apache License
@@ -1,10 +1,12 @@
1
1
  import errno
2
2
  import json
3
3
  import os
4
+ import platform
4
5
  import stat
5
6
  import sys
6
7
  import time
7
8
  from datetime import datetime, timedelta, timezone
9
+ from pathlib import Path
8
10
  from urllib.parse import parse_qs
9
11
 
10
12
  import jwt
@@ -441,6 +443,18 @@ def get_auth_provider(
441
443
  pass
442
444
  # ELSE
443
445
  if interactive:
446
+ lockfile_path = Path.home() / ".config/chromium/SingletonLock"
447
+
448
+ if Path(lockfile_path).is_symlink() and not str(
449
+ Path(lockfile_path).resolve()
450
+ ).__contains__(platform.node()):
451
+ # https://github.com/equinor/sumo-wrapper-python/issues/193
452
+ print(
453
+ "\n\n\033[1mDetected chromium lockfile for different node; using firefox to authenticate.\033[0m"
454
+ )
455
+ os.environ["BROWSER"] = "firefox"
456
+ pass
457
+
444
458
  return AuthProviderInteractive(client_id, authority, resource_id)
445
459
  # ELSE
446
460
  if devicecode:
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '1.0.24'
16
- __version_tuple__ = version_tuple = (1, 0, 24)
20
+ __version__ = version = '1.0.26'
21
+ __version_tuple__ = version_tuple = (1, 0, 26)
@@ -1,7 +1,5 @@
1
1
  import logging
2
- import platform
3
2
  from argparse import ArgumentParser
4
- from pathlib import Path
5
3
 
6
4
  from sumo.wrapper import SumoClient
7
5
 
@@ -69,16 +67,6 @@ def main():
69
67
  if mode != "silent":
70
68
  print("Login to Sumo environment: " + env)
71
69
 
72
- if mode == "interactive":
73
- lockfile_path = Path.home() / ".config/chromium/SingletonLock"
74
-
75
- if Path(lockfile_path).is_symlink() and not str(
76
- Path(lockfile_path).resolve()
77
- ).__contains__(platform.node()):
78
- # https://github.com/equinor/sumo-wrapper-python/issues/193
79
- is_interactive = False
80
- is_devicecode = True
81
-
82
70
  sumo = SumoClient(
83
71
  env,
84
72
  interactive=is_interactive,
@@ -2,6 +2,7 @@ import asyncio
2
2
  import contextlib
3
3
  import logging
4
4
  import re
5
+ import time
5
6
 
6
7
  import httpx
7
8
  import jwt
@@ -372,7 +373,7 @@ class SumoClient:
372
373
  params: query parameters, as dictionary
373
374
 
374
375
  Returns:
375
- Sumo JSON resposne as a dictionary
376
+ Sumo JSON response as a dictionary
376
377
 
377
378
  Examples:
378
379
  Deleting object::
@@ -401,6 +402,46 @@ class SumoClient:
401
402
 
402
403
  return retryer(_delete)
403
404
 
405
+ def _get_retry_details(self, response_in):
406
+ assert response_in.status_code == 202, (
407
+ "Incorrect status code; expcted 202"
408
+ )
409
+ headers = response_in.headers
410
+ location = headers.get("location")
411
+ assert location is not None, "Missing header: Location"
412
+ assert location.startswith(self.base_url)
413
+ retry_after = headers.get("retry-after")
414
+ assert retry_after is not None, "Missing header: Retry-After"
415
+ location = location[len(self.base_url) :]
416
+ retry_after = int(retry_after)
417
+ return location, retry_after
418
+
419
+ def poll(
420
+ self, response_in: httpx.Response, timeout=None
421
+ ) -> httpx.Response:
422
+ """Poll a specific endpoint until a result is obtained.
423
+
424
+ Args:
425
+ response_in: httpx.Response from a previous request, with 'location' and 'retry-after' headers.
426
+
427
+ Returns:
428
+ A new httpx.response object.
429
+ """
430
+ location, retry_after = self._get_retry_details(response_in)
431
+ expiry = time.time() + timeout if timeout is not None else None
432
+ while True:
433
+ time.sleep(retry_after)
434
+ response = self.get(location)
435
+ if response.status_code != 202:
436
+ return response
437
+ if expiry is not None and time.time() > expiry:
438
+ raise httpx.TimeoutException(
439
+ "No response within specified timeout."
440
+ )
441
+ location, retry_after = self._get_retry_details(response)
442
+ pass
443
+ return None # should never get here.
444
+
404
445
  def getLogger(self, name):
405
446
  """Gets a logger object that sends log objects into the message_log
406
447
  index for the Sumo instance.
@@ -642,7 +683,7 @@ class SumoClient:
642
683
  params: query parameters, as dictionary
643
684
 
644
685
  Returns:
645
- Sumo JSON resposne as a dictionary
686
+ Sumo JSON response as a dictionary
646
687
 
647
688
  Examples:
648
689
  Deleting object::
@@ -670,3 +711,29 @@ class SumoClient:
670
711
  retryer = self._retry_strategy.make_retryer_async()
671
712
 
672
713
  return await retryer(_delete)
714
+
715
+ async def poll_async(
716
+ self, response_in: httpx.Response, timeout=None
717
+ ) -> httpx.Response:
718
+ """Poll a specific endpoint until a result is obtained.
719
+
720
+ Args:
721
+ response_in: httpx.Response from a previous request, with 'location' and 'retry-after' headers.
722
+
723
+ Returns:
724
+ A new httpx.response object.
725
+ """
726
+ location, retry_after = self._get_retry_details(response_in)
727
+ expiry = time.time() + timeout if timeout is not None else None
728
+ while True:
729
+ await asyncio.sleep(retry_after)
730
+ response = await self.get_async(location)
731
+ if response.status_code != 202:
732
+ return response
733
+ if expiry is not None and time.time() > expiry:
734
+ raise httpx.TimeoutException(
735
+ "No response within specified timeout."
736
+ )
737
+ location, retry_after = self._get_retry_details(response)
738
+ pass
739
+ return None # should never get here.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: sumo-wrapper-python
3
- Version: 1.0.24
3
+ Version: 1.0.26
4
4
  Summary: Python wrapper for the Sumo API
5
5
  Author: Equinor
6
6
  License: Apache License
@@ -112,9 +112,13 @@ def test_upload_search_delete_ensemble_child(token):
112
112
 
113
113
  fmu_surface_metadata["fmu"]["case"]["uuid"] = case_uuid
114
114
 
115
- response_surface = _upload_child_level_json(
116
- conn=sumo_client, parent_id=case_id, json=fmu_surface_metadata
117
- )
115
+ try:
116
+ response_surface = _upload_child_level_json(
117
+ conn=sumo_client, parent_id=case_id, json=fmu_surface_metadata
118
+ )
119
+ except Exception as ex:
120
+ print(ex.response.text)
121
+ raise ex
118
122
 
119
123
  assert 200 <= response_surface.status_code <= 202
120
124
  assert isinstance(response_surface.json(), dict)
@@ -237,3 +241,12 @@ def test_upload_duplicate_ensemble(token):
237
241
  # Search for ensemble
238
242
  with pytest.raises(Exception):
239
243
  assert _download_object(conn, object_id=case_id2)
244
+
245
+
246
+ def test_poll(token):
247
+ conn = SumoClient(env="dev", token=token)
248
+ res = conn.get("/admin/index/orphans")
249
+ res2 = conn.poll(res)
250
+ assert res2.status_code == 200
251
+ indexorphans = res2.json()
252
+ assert isinstance(indexorphans, list)
@@ -75,7 +75,7 @@ fmu:
75
75
  file:
76
76
  relative_path: realization-33/iter-0/share/results/maps/volantis_gp_base--amplitude.gri # case-relative
77
77
  absolute_path: /some/absolute/path//realization-33/iter-0/share/results/maps/volantis_gp_base--amplitude.gri
78
- checksum_md5: kjhsdfvsdlfk23knerknvk23 # checksum of the file, not the data.
78
+ checksum_md5: 0123456789abcdef0123456789abcdef # checksum of the file, not the data.
79
79
 
80
80
  data: # The data block describes the actual data (e.g. surface). Only present in data objects
81
81