fmu-sumo 2.3.6__py3-none-any.whl → 2.3.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fmu/sumo/explorer/_version.py +2 -2
- fmu/sumo/explorer/explorer.py +6 -5
- fmu/sumo/explorer/filters.py +5 -0
- fmu/sumo/explorer/objects/__init__.py +17 -16
- fmu/sumo/explorer/objects/_child.py +5 -5
- fmu/sumo/explorer/objects/_document.py +9 -1
- fmu/sumo/explorer/objects/_search_context.py +202 -99
- fmu/sumo/explorer/objects/case.py +4 -4
- fmu/sumo/explorer/objects/cases.py +1 -1
- fmu/sumo/explorer/objects/cpgrid.py +4 -4
- fmu/sumo/explorer/objects/cpgrid_property.py +2 -2
- fmu/sumo/explorer/objects/cube.py +24 -70
- fmu/sumo/explorer/objects/dictionary.py +17 -9
- fmu/sumo/explorer/objects/iteration.py +17 -4
- fmu/sumo/explorer/objects/iterations.py +4 -6
- fmu/sumo/explorer/objects/polygons.py +1 -1
- fmu/sumo/explorer/objects/realization.py +27 -4
- fmu/sumo/explorer/objects/realizations.py +4 -6
- fmu/sumo/explorer/objects/surface.py +1 -1
- fmu/sumo/explorer/objects/table.py +1 -1
- fmu/sumo/explorer/timefilter.py +3 -2
- {fmu_sumo-2.3.6.dist-info → fmu_sumo-2.3.8.dist-info}/METADATA +3 -2
- fmu_sumo-2.3.8.dist-info/RECORD +32 -0
- {fmu_sumo-2.3.6.dist-info → fmu_sumo-2.3.8.dist-info}/WHEEL +1 -1
- fmu_sumo-2.3.6.dist-info/RECORD +0 -32
- {fmu_sumo-2.3.6.dist-info → fmu_sumo-2.3.8.dist-info/licenses}/LICENSE +0 -0
- {fmu_sumo-2.3.6.dist-info → fmu_sumo-2.3.8.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import uuid
|
|
2
4
|
import warnings
|
|
3
5
|
from datetime import datetime
|
|
4
6
|
from io import BytesIO
|
|
5
|
-
from typing import Dict, List, Tuple
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Union
|
|
6
8
|
|
|
7
9
|
import deprecation
|
|
8
10
|
import httpx
|
|
9
|
-
from sumo.wrapper import SumoClient
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
from fmu.sumo.explorer import objects
|
|
12
13
|
from fmu.sumo.explorer.cache import LRUCache
|
|
13
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from sumo.wrapper import SumoClient
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Type aliases
|
|
20
|
+
SelectArg = Union[bool, str, Dict[str, Union[str, List[str]]], List[str]]
|
|
21
|
+
|
|
14
22
|
|
|
15
23
|
def _gen_filter_none():
|
|
16
|
-
def _fn(
|
|
24
|
+
def _fn(_):
|
|
17
25
|
return None, None
|
|
18
26
|
|
|
19
27
|
return _fn
|
|
@@ -211,7 +219,7 @@ class Pit:
|
|
|
211
219
|
self._id = res.json()["id"]
|
|
212
220
|
return self
|
|
213
221
|
|
|
214
|
-
def __exit__(self,
|
|
222
|
+
def __exit__(self, *_):
|
|
215
223
|
if self._id is not None:
|
|
216
224
|
self._sumo.delete("/pit", params={"id": self._id})
|
|
217
225
|
pass
|
|
@@ -224,7 +232,7 @@ class Pit:
|
|
|
224
232
|
self._id = res.json()["id"]
|
|
225
233
|
return self
|
|
226
234
|
|
|
227
|
-
async def __aexit__(self,
|
|
235
|
+
async def __aexit__(self, *_):
|
|
228
236
|
if self._id is not None:
|
|
229
237
|
await self._sumo.delete_async("/pit", params={"id": self._id})
|
|
230
238
|
pass
|
|
@@ -257,7 +265,7 @@ class SearchContext:
|
|
|
257
265
|
self._hits = None
|
|
258
266
|
self._cache = LRUCache(capacity=200)
|
|
259
267
|
self._length = None
|
|
260
|
-
self._select = {
|
|
268
|
+
self._select: SelectArg = {
|
|
261
269
|
"excludes": ["fmu.realization.parameters"],
|
|
262
270
|
}
|
|
263
271
|
return
|
|
@@ -282,7 +290,7 @@ class SearchContext:
|
|
|
282
290
|
else:
|
|
283
291
|
return {"bool": {"must": must, "must_not": must_not}}
|
|
284
292
|
|
|
285
|
-
def _to_sumo(self, obj, blob=None):
|
|
293
|
+
def _to_sumo(self, obj, blob=None) -> objects.Document:
|
|
286
294
|
cls = obj["_source"]["class"]
|
|
287
295
|
if cls == "case":
|
|
288
296
|
return objects.Case(self._sumo, obj)
|
|
@@ -295,6 +303,8 @@ class SearchContext:
|
|
|
295
303
|
"table": objects.Table,
|
|
296
304
|
"cpgrid": objects.CPGrid,
|
|
297
305
|
"cpgrid_property": objects.CPGridProperty,
|
|
306
|
+
"iteration": objects.Iteration,
|
|
307
|
+
"realization": objects.Realization,
|
|
298
308
|
}.get(cls)
|
|
299
309
|
if constructor is None:
|
|
300
310
|
warnings.warn(f"No constructor for class {cls}")
|
|
@@ -319,7 +329,7 @@ class SearchContext:
|
|
|
319
329
|
self._length = res["count"]
|
|
320
330
|
return self._length
|
|
321
331
|
|
|
322
|
-
def __search_all(self, query, size=1000, select=False):
|
|
332
|
+
def __search_all(self, query, size: int = 1000, select: SelectArg = False):
|
|
323
333
|
all_hits = []
|
|
324
334
|
query = {
|
|
325
335
|
"query": query,
|
|
@@ -356,10 +366,12 @@ class SearchContext:
|
|
|
356
366
|
pass
|
|
357
367
|
return all_hits
|
|
358
368
|
|
|
359
|
-
def _search_all(self, select=False):
|
|
369
|
+
def _search_all(self, select: SelectArg = False):
|
|
360
370
|
return self.__search_all(query=self._query, size=1000, select=select)
|
|
361
371
|
|
|
362
|
-
async def __search_all_async(
|
|
372
|
+
async def __search_all_async(
|
|
373
|
+
self, query, size: int = 1000, select: SelectArg = False
|
|
374
|
+
):
|
|
363
375
|
all_hits = []
|
|
364
376
|
query = {
|
|
365
377
|
"query": query,
|
|
@@ -398,7 +410,7 @@ class SearchContext:
|
|
|
398
410
|
pass
|
|
399
411
|
return all_hits
|
|
400
412
|
|
|
401
|
-
async def _search_all_async(self, select=False):
|
|
413
|
+
async def _search_all_async(self, select: SelectArg = False):
|
|
402
414
|
return await self.__search_all_async(
|
|
403
415
|
query=self._query, size=1000, select=select
|
|
404
416
|
)
|
|
@@ -477,7 +489,7 @@ class SearchContext:
|
|
|
477
489
|
assert await self.length_async() == 1
|
|
478
490
|
return await self.getitem_async(0)
|
|
479
491
|
|
|
480
|
-
def select(self, sel):
|
|
492
|
+
def select(self, sel) -> SearchContext:
|
|
481
493
|
"""Specify what should be returned from elasticsearch.
|
|
482
494
|
Has the side effect of clearing the lru cache.
|
|
483
495
|
sel is either a single string value, a list of string value,
|
|
@@ -521,7 +533,7 @@ class SearchContext:
|
|
|
521
533
|
self._cache.clear()
|
|
522
534
|
return self
|
|
523
535
|
|
|
524
|
-
def get_object(self, uuid: str) ->
|
|
536
|
+
def get_object(self, uuid: str) -> objects.Document:
|
|
525
537
|
"""Get metadata object by uuid
|
|
526
538
|
|
|
527
539
|
Args:
|
|
@@ -549,7 +561,7 @@ class SearchContext:
|
|
|
549
561
|
|
|
550
562
|
return self._to_sumo(obj)
|
|
551
563
|
|
|
552
|
-
async def get_object_async(self, uuid: str) ->
|
|
564
|
+
async def get_object_async(self, uuid: str) -> objects.Document:
|
|
553
565
|
"""Get metadata object by uuid
|
|
554
566
|
|
|
555
567
|
Args:
|
|
@@ -579,6 +591,7 @@ class SearchContext:
|
|
|
579
591
|
return self._to_sumo(obj)
|
|
580
592
|
|
|
581
593
|
def _maybe_prefetch(self, index):
|
|
594
|
+
assert isinstance(self._hits, list)
|
|
582
595
|
uuid = self._hits[index]
|
|
583
596
|
if self._cache.has(uuid):
|
|
584
597
|
return
|
|
@@ -595,6 +608,7 @@ class SearchContext:
|
|
|
595
608
|
return
|
|
596
609
|
|
|
597
610
|
async def _maybe_prefetch_async(self, index):
|
|
611
|
+
assert isinstance(self._hits, list)
|
|
598
612
|
uuid = self._hits[index]
|
|
599
613
|
if self._cache.has(uuid):
|
|
600
614
|
return
|
|
@@ -613,13 +627,13 @@ class SearchContext:
|
|
|
613
627
|
def get_objects(
|
|
614
628
|
self,
|
|
615
629
|
uuids: List[str],
|
|
616
|
-
select:
|
|
630
|
+
select: SelectArg,
|
|
617
631
|
) -> List[Dict]:
|
|
618
632
|
size = (
|
|
619
633
|
1000
|
|
620
634
|
if select is False
|
|
621
635
|
else 100
|
|
622
|
-
if isinstance(select, list)
|
|
636
|
+
if isinstance(select, (list, dict))
|
|
623
637
|
else 10
|
|
624
638
|
)
|
|
625
639
|
return self.__search_all(
|
|
@@ -627,15 +641,13 @@ class SearchContext:
|
|
|
627
641
|
)
|
|
628
642
|
|
|
629
643
|
async def get_objects_async(
|
|
630
|
-
self,
|
|
631
|
-
uuids: List[str],
|
|
632
|
-
select: List[str] = None,
|
|
644
|
+
self, uuids: List[str], select: SelectArg
|
|
633
645
|
) -> List[Dict]:
|
|
634
646
|
size = (
|
|
635
647
|
1000
|
|
636
648
|
if select is False
|
|
637
649
|
else 100
|
|
638
|
-
if isinstance(select, list)
|
|
650
|
+
if isinstance(select, (list, dict))
|
|
639
651
|
else 10
|
|
640
652
|
)
|
|
641
653
|
return await self.__search_all_async(
|
|
@@ -900,8 +912,8 @@ class SearchContext:
|
|
|
900
912
|
return objects.Realizations(self, uuids)
|
|
901
913
|
|
|
902
914
|
@property
|
|
903
|
-
def template_paths(
|
|
904
|
-
return {obj.template_path for obj in
|
|
915
|
+
def template_paths(self) -> List[str]:
|
|
916
|
+
return {obj.template_path for obj in self}
|
|
905
917
|
|
|
906
918
|
@property
|
|
907
919
|
def metrics(self):
|
|
@@ -919,9 +931,9 @@ class SearchContext:
|
|
|
919
931
|
@property
|
|
920
932
|
async def timestamps_async(self) -> List[str]:
|
|
921
933
|
"""List of unique timestamps in SearchContext"""
|
|
922
|
-
ts = await self.
|
|
923
|
-
|
|
924
|
-
)
|
|
934
|
+
ts = await self.filter(
|
|
935
|
+
complex=self._timestamp_query
|
|
936
|
+
).get_field_values_async("data.time.t0.value")
|
|
925
937
|
return [datetime.fromtimestamp(t / 1000).isoformat() for t in ts]
|
|
926
938
|
|
|
927
939
|
def _extract_intervals(self, res):
|
|
@@ -987,7 +999,6 @@ class SearchContext:
|
|
|
987
999
|
f = filters.get(k)
|
|
988
1000
|
if f is None:
|
|
989
1001
|
raise Exception(f"Don't know how to generate filter for {k}")
|
|
990
|
-
pass
|
|
991
1002
|
_must, _must_not = f(v)
|
|
992
1003
|
if _must:
|
|
993
1004
|
must.append(_must)
|
|
@@ -1023,46 +1034,46 @@ class SearchContext:
|
|
|
1023
1034
|
return sc
|
|
1024
1035
|
|
|
1025
1036
|
@property
|
|
1026
|
-
def surfaces(self):
|
|
1037
|
+
def surfaces(self) -> SearchContext:
|
|
1027
1038
|
return self._context_for_class("surface")
|
|
1028
1039
|
|
|
1029
1040
|
@property
|
|
1030
|
-
def tables(self):
|
|
1041
|
+
def tables(self) -> SearchContext:
|
|
1031
1042
|
return self._context_for_class("table")
|
|
1032
1043
|
|
|
1033
1044
|
@property
|
|
1034
|
-
def cubes(self):
|
|
1045
|
+
def cubes(self) -> SearchContext:
|
|
1035
1046
|
return self._context_for_class("cube")
|
|
1036
1047
|
|
|
1037
1048
|
@property
|
|
1038
|
-
def polygons(self):
|
|
1049
|
+
def polygons(self) -> SearchContext:
|
|
1039
1050
|
return self._context_for_class("polygons")
|
|
1040
1051
|
|
|
1041
1052
|
@property
|
|
1042
|
-
def dictionaries(self):
|
|
1053
|
+
def dictionaries(self) -> SearchContext:
|
|
1043
1054
|
return self._context_for_class("dictionary")
|
|
1044
1055
|
|
|
1045
1056
|
@property
|
|
1046
|
-
def grids(self):
|
|
1057
|
+
def grids(self) -> SearchContext:
|
|
1047
1058
|
return self._context_for_class("cpgrid")
|
|
1048
1059
|
|
|
1049
1060
|
@property
|
|
1050
|
-
def grid_properties(self):
|
|
1061
|
+
def grid_properties(self) -> SearchContext:
|
|
1051
1062
|
return self._context_for_class("cpgrid_property")
|
|
1052
1063
|
|
|
1053
|
-
def _get_object_by_class_and_uuid(self, cls, uuid):
|
|
1064
|
+
def _get_object_by_class_and_uuid(self, cls, uuid) -> Any:
|
|
1054
1065
|
obj = self.get_object(uuid)
|
|
1055
1066
|
if obj.metadata["class"] != cls:
|
|
1056
1067
|
raise Exception(f"Document of type {cls} not found: {uuid}")
|
|
1057
1068
|
return obj
|
|
1058
1069
|
|
|
1059
|
-
async def _get_object_by_class_and_uuid_async(self, cls, uuid):
|
|
1070
|
+
async def _get_object_by_class_and_uuid_async(self, cls, uuid) -> Any:
|
|
1060
1071
|
obj = await self.get_object_async(uuid)
|
|
1061
1072
|
if obj.metadata["class"] != cls:
|
|
1062
1073
|
raise Exception(f"Document of type {cls} not found: {uuid}")
|
|
1063
1074
|
return obj
|
|
1064
1075
|
|
|
1065
|
-
def get_case_by_uuid(self, uuid: str):
|
|
1076
|
+
def get_case_by_uuid(self, uuid: str) -> objects.Case:
|
|
1066
1077
|
"""Get case object by uuid
|
|
1067
1078
|
|
|
1068
1079
|
Args:
|
|
@@ -1073,7 +1084,7 @@ class SearchContext:
|
|
|
1073
1084
|
"""
|
|
1074
1085
|
return self._get_object_by_class_and_uuid("case", uuid)
|
|
1075
1086
|
|
|
1076
|
-
async def get_case_by_uuid_async(self, uuid: str):
|
|
1087
|
+
async def get_case_by_uuid_async(self, uuid: str) -> objects.Case:
|
|
1077
1088
|
"""Get case object by uuid
|
|
1078
1089
|
|
|
1079
1090
|
Args:
|
|
@@ -1091,6 +1102,7 @@ class SearchContext:
|
|
|
1091
1102
|
"_source": {
|
|
1092
1103
|
"includes": [
|
|
1093
1104
|
"$schema",
|
|
1105
|
+
"class",
|
|
1094
1106
|
"source",
|
|
1095
1107
|
"version",
|
|
1096
1108
|
"access",
|
|
@@ -1101,7 +1113,7 @@ class SearchContext:
|
|
|
1101
1113
|
},
|
|
1102
1114
|
}
|
|
1103
1115
|
|
|
1104
|
-
def get_iteration_by_uuid(self, uuid: str):
|
|
1116
|
+
def get_iteration_by_uuid(self, uuid: str) -> objects.Iteration:
|
|
1105
1117
|
"""Get iteration object by uuid
|
|
1106
1118
|
|
|
1107
1119
|
Args:
|
|
@@ -1109,14 +1121,25 @@ class SearchContext:
|
|
|
1109
1121
|
|
|
1110
1122
|
Returns: iteration object
|
|
1111
1123
|
"""
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1124
|
+
try:
|
|
1125
|
+
obj = self.get_object(uuid)
|
|
1126
|
+
assert isinstance(obj, objects.Iteration)
|
|
1127
|
+
return obj
|
|
1128
|
+
except Exception:
|
|
1129
|
+
res = self._sumo.post(
|
|
1130
|
+
"/search", json=self._iteration_query(uuid)
|
|
1131
|
+
).json()
|
|
1132
|
+
hits = res["hits"]["hits"]
|
|
1133
|
+
if len(hits) == 0:
|
|
1134
|
+
raise Exception(f"Document not found: {uuid}")
|
|
1135
|
+
obj = hits[0]
|
|
1136
|
+
obj["_id"] = uuid
|
|
1137
|
+
obj["_source"]["class"] = "iteration"
|
|
1138
|
+
return self._to_sumo(obj)
|
|
1118
1139
|
|
|
1119
|
-
async def get_iteration_by_uuid_async(
|
|
1140
|
+
async def get_iteration_by_uuid_async(
|
|
1141
|
+
self, uuid: str
|
|
1142
|
+
) -> objects.Iteration:
|
|
1120
1143
|
"""Get iteration object by uuid
|
|
1121
1144
|
|
|
1122
1145
|
Args:
|
|
@@ -1124,16 +1147,25 @@ class SearchContext:
|
|
|
1124
1147
|
|
|
1125
1148
|
Returns: iteration object
|
|
1126
1149
|
"""
|
|
1127
|
-
|
|
1128
|
-
await self.
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1150
|
+
try:
|
|
1151
|
+
obj = await self.get_object_async(uuid)
|
|
1152
|
+
assert isinstance(obj, objects.Iteration)
|
|
1153
|
+
return obj
|
|
1154
|
+
except Exception:
|
|
1155
|
+
res = (
|
|
1156
|
+
await self._sumo.post_async(
|
|
1157
|
+
"/search", json=self._iteration_query(uuid)
|
|
1158
|
+
)
|
|
1159
|
+
).json()
|
|
1160
|
+
hits = res["hits"]["hits"]
|
|
1161
|
+
if len(hits) == 0:
|
|
1162
|
+
raise Exception(f"Document not found: {uuid}")
|
|
1163
|
+
obj = hits[0]
|
|
1164
|
+
obj["_id"] = uuid
|
|
1165
|
+
obj["_source"]["class"] = "iteration"
|
|
1166
|
+
return self._to_sumo(obj)
|
|
1135
1167
|
|
|
1136
|
-
def _realization_query(self, uuid):
|
|
1168
|
+
def _realization_query(self, uuid) -> Dict:
|
|
1137
1169
|
return {
|
|
1138
1170
|
"query": {
|
|
1139
1171
|
"term": {"fmu.realization.uuid.keyword": {"value": uuid}}
|
|
@@ -1142,6 +1174,7 @@ class SearchContext:
|
|
|
1142
1174
|
"_source": {
|
|
1143
1175
|
"includes": [
|
|
1144
1176
|
"$schema",
|
|
1177
|
+
"class",
|
|
1145
1178
|
"source",
|
|
1146
1179
|
"version",
|
|
1147
1180
|
"access",
|
|
@@ -1153,7 +1186,7 @@ class SearchContext:
|
|
|
1153
1186
|
},
|
|
1154
1187
|
}
|
|
1155
1188
|
|
|
1156
|
-
def get_realization_by_uuid(self, uuid: str):
|
|
1189
|
+
def get_realization_by_uuid(self, uuid: str) -> objects.Realization:
|
|
1157
1190
|
"""Get realization object by uuid
|
|
1158
1191
|
|
|
1159
1192
|
Args:
|
|
@@ -1161,14 +1194,25 @@ class SearchContext:
|
|
|
1161
1194
|
|
|
1162
1195
|
Returns: realization object
|
|
1163
1196
|
"""
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1197
|
+
try:
|
|
1198
|
+
obj = self.get_object(uuid)
|
|
1199
|
+
assert isinstance(obj, objects.Realization)
|
|
1200
|
+
return obj
|
|
1201
|
+
except Exception:
|
|
1202
|
+
res = self._sumo.post(
|
|
1203
|
+
"/search", json=self._realization_query(uuid)
|
|
1204
|
+
).json()
|
|
1205
|
+
hits = res["hits"]["hits"]
|
|
1206
|
+
if len(hits) == 0:
|
|
1207
|
+
raise Exception(f"Document not found: {uuid}")
|
|
1208
|
+
obj = hits[0]
|
|
1209
|
+
obj["_id"] = uuid
|
|
1210
|
+
obj["_source"]["class"] = "realization"
|
|
1211
|
+
return self._to_sumo(obj)
|
|
1170
1212
|
|
|
1171
|
-
async def get_realization_by_uuid_async(
|
|
1213
|
+
async def get_realization_by_uuid_async(
|
|
1214
|
+
self, uuid: str
|
|
1215
|
+
) -> objects.Realization:
|
|
1172
1216
|
"""Get realization object by uuid
|
|
1173
1217
|
|
|
1174
1218
|
Args:
|
|
@@ -1176,16 +1220,25 @@ class SearchContext:
|
|
|
1176
1220
|
|
|
1177
1221
|
Returns: realization object
|
|
1178
1222
|
"""
|
|
1179
|
-
|
|
1180
|
-
await self.
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1223
|
+
try:
|
|
1224
|
+
obj = await self.get_object_async(uuid)
|
|
1225
|
+
assert isinstance(obj, objects.Realization)
|
|
1226
|
+
return obj
|
|
1227
|
+
except Exception:
|
|
1228
|
+
res = (
|
|
1229
|
+
await self._sumo.post_async(
|
|
1230
|
+
"/search", json=self._realization_query(uuid)
|
|
1231
|
+
)
|
|
1232
|
+
).json()
|
|
1233
|
+
hits = res["hits"]["hits"]
|
|
1234
|
+
if len(hits) == 0:
|
|
1235
|
+
raise Exception(f"Document not found: {uuid}")
|
|
1236
|
+
obj = hits[0]
|
|
1237
|
+
obj["_id"] = uuid
|
|
1238
|
+
obj["_source"]["class"] = "realization"
|
|
1239
|
+
return self._to_sumo(obj)
|
|
1187
1240
|
|
|
1188
|
-
def get_surface_by_uuid(self, uuid: str):
|
|
1241
|
+
def get_surface_by_uuid(self, uuid: str) -> objects.Surface:
|
|
1189
1242
|
"""Get surface object by uuid
|
|
1190
1243
|
|
|
1191
1244
|
Args:
|
|
@@ -1196,7 +1249,7 @@ class SearchContext:
|
|
|
1196
1249
|
"""
|
|
1197
1250
|
return self._get_object_by_class_and_uuid("surface", uuid)
|
|
1198
1251
|
|
|
1199
|
-
async def get_surface_by_uuid_async(self, uuid: str):
|
|
1252
|
+
async def get_surface_by_uuid_async(self, uuid: str) -> objects.Surface:
|
|
1200
1253
|
"""Get surface object by uuid
|
|
1201
1254
|
|
|
1202
1255
|
Args:
|
|
@@ -1207,7 +1260,7 @@ class SearchContext:
|
|
|
1207
1260
|
"""
|
|
1208
1261
|
return await self._get_object_by_class_and_uuid_async("surface", uuid)
|
|
1209
1262
|
|
|
1210
|
-
def get_polygons_by_uuid(self, uuid: str):
|
|
1263
|
+
def get_polygons_by_uuid(self, uuid: str) -> objects.Polygons:
|
|
1211
1264
|
"""Get polygons object by uuid
|
|
1212
1265
|
|
|
1213
1266
|
Args:
|
|
@@ -1218,7 +1271,7 @@ class SearchContext:
|
|
|
1218
1271
|
"""
|
|
1219
1272
|
return self._get_object_by_class_and_uuid("polygons", uuid)
|
|
1220
1273
|
|
|
1221
|
-
async def get_polygons_by_uuid_async(self, uuid: str):
|
|
1274
|
+
async def get_polygons_by_uuid_async(self, uuid: str) -> objects.Polygons:
|
|
1222
1275
|
"""Get polygons object by uuid
|
|
1223
1276
|
|
|
1224
1277
|
Args:
|
|
@@ -1229,7 +1282,7 @@ class SearchContext:
|
|
|
1229
1282
|
"""
|
|
1230
1283
|
return await self._get_object_by_class_and_uuid_async("polygons", uuid)
|
|
1231
1284
|
|
|
1232
|
-
def get_table_by_uuid(self, uuid: str):
|
|
1285
|
+
def get_table_by_uuid(self, uuid: str) -> objects.Table:
|
|
1233
1286
|
"""Get table object by uuid
|
|
1234
1287
|
|
|
1235
1288
|
Args:
|
|
@@ -1240,7 +1293,7 @@ class SearchContext:
|
|
|
1240
1293
|
"""
|
|
1241
1294
|
return self._get_object_by_class_and_uuid("table", uuid)
|
|
1242
1295
|
|
|
1243
|
-
async def get_table_by_uuid_async(self, uuid: str):
|
|
1296
|
+
async def get_table_by_uuid_async(self, uuid: str) -> objects.Table:
|
|
1244
1297
|
"""Get table object by uuid
|
|
1245
1298
|
|
|
1246
1299
|
Args:
|
|
@@ -1251,7 +1304,9 @@ class SearchContext:
|
|
|
1251
1304
|
"""
|
|
1252
1305
|
return await self._get_object_by_class_and_uuid_async("table", uuid)
|
|
1253
1306
|
|
|
1254
|
-
def _verify_aggregation_operation(
|
|
1307
|
+
def _verify_aggregation_operation(
|
|
1308
|
+
self,
|
|
1309
|
+
) -> Tuple[Dict, List[str], List[int]]:
|
|
1255
1310
|
query = {
|
|
1256
1311
|
"query": self._query,
|
|
1257
1312
|
"size": 1,
|
|
@@ -1269,6 +1324,8 @@ class SearchContext:
|
|
|
1269
1324
|
},
|
|
1270
1325
|
}
|
|
1271
1326
|
sres = self._sumo.post("/search", json=query).json()
|
|
1327
|
+
if len(sres["hits"]["hits"]) == 0:
|
|
1328
|
+
raise Exception("No matching realizations found.")
|
|
1272
1329
|
prototype = sres["hits"]["hits"][0]
|
|
1273
1330
|
conflicts = [
|
|
1274
1331
|
k
|
|
@@ -1291,8 +1348,15 @@ class SearchContext:
|
|
|
1291
1348
|
rids = [hit["_source"]["fmu"]["realization"]["id"] for hit in hits]
|
|
1292
1349
|
return prototype, uuids, rids
|
|
1293
1350
|
|
|
1294
|
-
def _aggregate(self, columns=None, operation=None):
|
|
1295
|
-
|
|
1351
|
+
def _aggregate(self, columns=None, operation=None) -> objects.Child:
|
|
1352
|
+
assert (
|
|
1353
|
+
operation != "collection"
|
|
1354
|
+
or columns is not None
|
|
1355
|
+
and len(columns) == 1
|
|
1356
|
+
), "Exactly one column required for collection aggregation."
|
|
1357
|
+
prototype, uuids, rids = self.filter(
|
|
1358
|
+
column=columns
|
|
1359
|
+
)._verify_aggregation_operation()
|
|
1296
1360
|
spec = {
|
|
1297
1361
|
"object_ids": uuids,
|
|
1298
1362
|
"operations": [operation],
|
|
@@ -1330,10 +1394,11 @@ class SearchContext:
|
|
|
1330
1394
|
raise ex
|
|
1331
1395
|
blob = BytesIO(res.content)
|
|
1332
1396
|
res = self._to_sumo(prototype, blob)
|
|
1397
|
+
assert isinstance(res, objects.Child)
|
|
1333
1398
|
res._blob = blob
|
|
1334
1399
|
return res
|
|
1335
1400
|
|
|
1336
|
-
def aggregate(self, columns=None, operation=None):
|
|
1401
|
+
def aggregate(self, columns=None, operation=None) -> objects.Child:
|
|
1337
1402
|
if len(self.hidden) > 0:
|
|
1338
1403
|
return self.hidden._aggregate(columns=columns, operation=operation)
|
|
1339
1404
|
else:
|
|
@@ -1341,7 +1406,9 @@ class SearchContext:
|
|
|
1341
1406
|
columns=columns, operation=operation
|
|
1342
1407
|
)
|
|
1343
1408
|
|
|
1344
|
-
async def _verify_aggregation_operation_async(
|
|
1409
|
+
async def _verify_aggregation_operation_async(
|
|
1410
|
+
self,
|
|
1411
|
+
) -> Tuple[Dict, List[str], List[int]]:
|
|
1345
1412
|
query = {
|
|
1346
1413
|
"query": self._query,
|
|
1347
1414
|
"size": 1,
|
|
@@ -1359,6 +1426,8 @@ class SearchContext:
|
|
|
1359
1426
|
},
|
|
1360
1427
|
}
|
|
1361
1428
|
sres = (await self._sumo.post_async("/search", json=query)).json()
|
|
1429
|
+
if len(sres["hits"]["hits"]) == 0:
|
|
1430
|
+
raise Exception("No matching realizations found.")
|
|
1362
1431
|
prototype = sres["hits"]["hits"][0]
|
|
1363
1432
|
conflicts = [
|
|
1364
1433
|
k
|
|
@@ -1381,12 +1450,21 @@ class SearchContext:
|
|
|
1381
1450
|
rids = [hit["_source"]["fmu"]["realization"]["id"] for hit in hits]
|
|
1382
1451
|
return prototype, uuids, rids
|
|
1383
1452
|
|
|
1384
|
-
async def _aggregate_async(
|
|
1453
|
+
async def _aggregate_async(
|
|
1454
|
+
self, columns=None, operation=None
|
|
1455
|
+
) -> objects.Child:
|
|
1456
|
+
assert (
|
|
1457
|
+
operation != "collection"
|
|
1458
|
+
or columns is not None
|
|
1459
|
+
and len(columns) == 1
|
|
1460
|
+
), "Exactly one column required for collection aggregation."
|
|
1385
1461
|
(
|
|
1386
1462
|
prototype,
|
|
1387
1463
|
uuids,
|
|
1388
1464
|
rids,
|
|
1389
|
-
) = await self.
|
|
1465
|
+
) = await self.filter(
|
|
1466
|
+
column=columns
|
|
1467
|
+
)._verify_aggregation_operation_async()
|
|
1390
1468
|
spec = {
|
|
1391
1469
|
"object_ids": uuids,
|
|
1392
1470
|
"operations": [operation],
|
|
@@ -1424,10 +1502,13 @@ class SearchContext:
|
|
|
1424
1502
|
raise ex
|
|
1425
1503
|
blob = BytesIO(res.content)
|
|
1426
1504
|
res = self._to_sumo(prototype, blob)
|
|
1505
|
+
assert isinstance(res, objects.Child)
|
|
1427
1506
|
res._blob = blob
|
|
1428
1507
|
return res
|
|
1429
1508
|
|
|
1430
|
-
async def aggregate_async(
|
|
1509
|
+
async def aggregate_async(
|
|
1510
|
+
self, columns=None, operation=None
|
|
1511
|
+
) -> objects.Child:
|
|
1431
1512
|
length_hidden = await self.hidden.length_async()
|
|
1432
1513
|
if length_hidden > 0:
|
|
1433
1514
|
return await self.hidden._aggregate_async(
|
|
@@ -1438,33 +1519,55 @@ class SearchContext:
|
|
|
1438
1519
|
columns=columns, operation=operation
|
|
1439
1520
|
)
|
|
1440
1521
|
|
|
1441
|
-
def aggregation(self, column=None, operation=None):
|
|
1522
|
+
def aggregation(self, column=None, operation=None) -> objects.Child:
|
|
1442
1523
|
assert operation is not None
|
|
1443
1524
|
assert column is None or isinstance(column, str)
|
|
1444
1525
|
sc = self.filter(aggregation=operation, column=column)
|
|
1445
1526
|
numaggs = len(sc)
|
|
1446
1527
|
assert numaggs <= 1
|
|
1447
1528
|
if numaggs == 1:
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1529
|
+
agg = sc.single
|
|
1530
|
+
assert isinstance(agg, objects.Child)
|
|
1531
|
+
ts = agg.metadata["_sumo"]["timestamp"]
|
|
1532
|
+
reals = self.filter(
|
|
1533
|
+
realization=True,
|
|
1534
|
+
complex={"range": {"_sumo.timestamp": {"lt": ts}}},
|
|
1535
|
+
).realizationids
|
|
1536
|
+
if set(reals) == set(
|
|
1537
|
+
agg.metadata["fmu"]["aggregation"]["realization_ids"]
|
|
1538
|
+
):
|
|
1539
|
+
return agg
|
|
1540
|
+
# ELSE
|
|
1541
|
+
return self.filter(realization=True).aggregate(
|
|
1542
|
+
columns=[column] if column is not None else None,
|
|
1543
|
+
operation=operation,
|
|
1544
|
+
)
|
|
1454
1545
|
|
|
1455
|
-
async def aggregation_async(
|
|
1546
|
+
async def aggregation_async(
|
|
1547
|
+
self, column=None, operation=None
|
|
1548
|
+
) -> objects.Child:
|
|
1456
1549
|
assert operation is not None
|
|
1457
1550
|
assert column is None or isinstance(column, str)
|
|
1458
1551
|
sc = self.filter(aggregation=operation, column=column)
|
|
1459
1552
|
numaggs = await sc.length_async()
|
|
1460
1553
|
assert numaggs <= 1
|
|
1461
1554
|
if numaggs == 1:
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1555
|
+
agg = await sc.single_async
|
|
1556
|
+
assert isinstance(agg, objects.Child)
|
|
1557
|
+
ts = agg.metadata["_sumo"]["timestamp"]
|
|
1558
|
+
reals = await self.filter(
|
|
1559
|
+
realization=True,
|
|
1560
|
+
complex={"range": {"_sumo.timestamp": {"lt": ts}}},
|
|
1561
|
+
).realizationids_async
|
|
1562
|
+
if set(reals) == set(
|
|
1563
|
+
agg.metadata["fmu"]["aggregation"]["realization_ids"]
|
|
1564
|
+
):
|
|
1565
|
+
return agg
|
|
1566
|
+
# ELSE
|
|
1567
|
+
return await self.filter(realization=True).aggregate_async(
|
|
1568
|
+
columns=[column] if column is not None else None,
|
|
1569
|
+
operation=operation,
|
|
1570
|
+
)
|
|
1468
1571
|
|
|
1469
1572
|
@deprecation.deprecated(
|
|
1470
1573
|
details="Use the method 'aggregate' instead, with parameter 'operation'."
|
|
@@ -4,11 +4,11 @@ from typing import Dict
|
|
|
4
4
|
|
|
5
5
|
from sumo.wrapper import SumoClient
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
7
|
+
from ._document import Document
|
|
8
|
+
from ._search_context import SearchContext
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def _make_overview_query(id):
|
|
11
|
+
def _make_overview_query(id) -> Dict:
|
|
12
12
|
return {
|
|
13
13
|
"query": {"term": {"fmu.case.uuid.keyword": id}},
|
|
14
14
|
"aggs": {
|
|
@@ -52,7 +52,7 @@ class Case(Document, SearchContext):
|
|
|
52
52
|
self._iterations = None
|
|
53
53
|
|
|
54
54
|
@property
|
|
55
|
-
def overview(self):
|
|
55
|
+
def overview(self) -> Dict:
|
|
56
56
|
"""Overview of case contents."""
|
|
57
57
|
|
|
58
58
|
def extract_bucket_keys(bucket, name):
|