fmu-sumo 2.4.3__py3-none-any.whl → 2.4.5__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.
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '2.4.3'
21
- __version_tuple__ = version_tuple = (2, 4, 3)
20
+ __version__ = version = '2.4.5'
21
+ __version_tuple__ = version_tuple = (2, 4, 5)
@@ -1,10 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
- import uuid
5
4
  import warnings
6
5
  from datetime import datetime
7
- from io import BytesIO
8
6
  from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Union
9
7
 
10
8
  import deprecation
@@ -1164,6 +1162,46 @@ class SearchContext:
1164
1162
  def grid_properties(self) -> SearchContext:
1165
1163
  return self._context_for_class("cpgrid_property")
1166
1164
 
1165
+ @property
1166
+ def parameters(self) -> SearchContext:
1167
+ return self.filter(
1168
+ complex={
1169
+ "bool": {
1170
+ "must": [
1171
+ {"term": {"data.name.keyword": "parameters"}},
1172
+ {"term": {"data.content.keyword": "parameters"}},
1173
+ ],
1174
+ "should": [
1175
+ {
1176
+ "bool": {
1177
+ "must": [
1178
+ {"term": {"class.keyword": "dictionary"}},
1179
+ {
1180
+ "exists": {
1181
+ "field": "fmu.realization.id"
1182
+ }
1183
+ },
1184
+ ]
1185
+ }
1186
+ },
1187
+ {
1188
+ "bool": {
1189
+ "must": [
1190
+ {"term": {"class.keyword": "table"}},
1191
+ {
1192
+ "exists": {
1193
+ "field": "fmu.aggregation.operation"
1194
+ }
1195
+ },
1196
+ ]
1197
+ }
1198
+ },
1199
+ ],
1200
+ "minimum_should_match": 1,
1201
+ }
1202
+ }
1203
+ )
1204
+
1167
1205
  def _get_object_by_class_and_uuid(self, cls, uuid) -> Any:
1168
1206
  obj = self.get_object(uuid)
1169
1207
  if obj.metadata["class"] != cls:
@@ -1484,12 +1522,10 @@ class SearchContext:
1484
1522
  """
1485
1523
  return await self._get_object_by_class_and_uuid_async("table", uuid)
1486
1524
 
1487
- def _verify_aggregation_operation(
1488
- self,
1489
- ) -> Tuple[Dict, List[str], List[int]]:
1490
- query = {
1525
+ def __prepare_verify_aggregation_query(self) -> Dict:
1526
+ return {
1491
1527
  "query": self._query,
1492
- "size": 1,
1528
+ "size": 0,
1493
1529
  "track_total_hits": True,
1494
1530
  "aggs": {
1495
1531
  k: {"terms": {"field": k + ".keyword", "size": 1}}
@@ -1497,85 +1533,83 @@ class SearchContext:
1497
1533
  "fmu.case.uuid",
1498
1534
  "class",
1499
1535
  "fmu.ensemble.name",
1536
+ "fmu.entity.uuid",
1500
1537
  "data.name",
1501
1538
  "data.tagname",
1502
1539
  "data.content",
1503
1540
  ]
1504
1541
  },
1505
1542
  }
1506
- sres = self._sumo.post("/search", json=query).json()
1507
- if len(sres["hits"]["hits"]) == 0:
1543
+
1544
+ def __verify_aggregation_operation(
1545
+ self, sres
1546
+ ) -> Tuple[str, str, str, str]:
1547
+ tot_hits = sres["hits"]["total"]["value"]
1548
+ if tot_hits == 0:
1508
1549
  raise Exception("No matching realizations found.")
1509
- prototype = sres["hits"]["hits"][0]
1510
1550
  conflicts = [
1511
1551
  k
1512
1552
  for (k, v) in sres["aggregations"].items()
1513
1553
  if (
1514
- ("sum_other_doc_count" in v) and (v["sum_other_doc_count"] > 0)
1554
+ ("sum_other_doc_count" in v)
1555
+ and (v["sum_other_doc_count"] > 0)
1556
+ or v["buckets"][0]["doc_count"] != tot_hits
1515
1557
  )
1516
1558
  ]
1517
1559
  if len(conflicts) > 0:
1518
1560
  raise Exception(f"Conflicting values for {conflicts}")
1561
+ entityuuid = sres["aggregations"]["fmu.entity.uuid"]["buckets"][0][
1562
+ "key"
1563
+ ]
1564
+ caseuuid = sres["aggregations"]["fmu.case.uuid"]["buckets"][0]["key"]
1565
+ ensemblename = sres["aggregations"]["fmu.ensemble.name"]["buckets"][0][
1566
+ "key"
1567
+ ]
1568
+ classname = sres["aggregations"]["class"]["buckets"][0]["key"]
1569
+ return caseuuid, classname, entityuuid, ensemblename
1519
1570
 
1520
- hits = self._search_all(select=["fmu.realization.id"])
1521
-
1522
- if any(
1523
- hit["_source"]["fmu"].get("realization") is None for hit in hits
1524
- ):
1525
- raise Exception("Selection contains non-realization data.")
1526
-
1527
- uuids = [hit["_id"] for hit in hits]
1528
- rids = [hit["_source"]["fmu"]["realization"]["id"] for hit in hits]
1529
- return prototype, uuids, rids
1571
+ def _verify_aggregation_operation(
1572
+ self, columns, operation
1573
+ ) -> Tuple[str, str, str, str]:
1574
+ assert columns is None or len(columns) == 1, (
1575
+ "Exactly one column required for collection aggregation."
1576
+ )
1577
+ sc = self if columns is None else self.filter(column=columns)
1578
+ query = sc.__prepare_verify_aggregation_query()
1579
+ sres = sc._sumo.post("/search", json=query).json()
1580
+ return sc.__verify_aggregation_operation(sres)
1530
1581
 
1531
- def _aggregate(self, columns=None, operation=None) -> objects.Child:
1532
- assert (
1533
- operation != "collection"
1534
- or columns is not None
1535
- and len(columns) == 1
1536
- ), "Exactly one column required for collection aggregation."
1537
- prototype, uuids, rids = self.filter(
1538
- column=columns
1539
- )._verify_aggregation_operation()
1582
+ def __prepare_aggregation_spec(
1583
+ self, caseuuid, classname, entityuuid, ensemblename, operation, columns
1584
+ ):
1540
1585
  spec = {
1541
- "object_ids": uuids,
1586
+ "case_uuid": caseuuid,
1587
+ "class": classname,
1588
+ "entity_uuid": entityuuid,
1589
+ "ensemble_name": ensemblename,
1590
+ "iteration_name": ensemblename,
1542
1591
  "operations": [operation],
1543
1592
  }
1544
- del prototype["_source"]["fmu"]["realization"]
1545
- del prototype["_source"]["_sumo"]
1546
- del prototype["_source"]["file"]
1547
- if "context" in prototype["_source"]["fmu"]:
1548
- prototype["_source"]["fmu"]["context"]["stage"] = "ensemble"
1549
- pass
1550
- prototype["_source"]["fmu"]["aggregation"] = {
1551
- "id": str(uuid.uuid4()),
1552
- "realization_ids": rids,
1553
- "operation": operation,
1554
- }
1555
1593
  if columns is not None:
1556
1594
  spec["columns"] = columns
1557
- cols = columns[:]
1558
- table_index = prototype["_source"]["data"].get("table_index")
1559
- if (
1560
- table_index is not None
1561
- and len(table_index) != 0
1562
- and table_index[0] not in cols
1563
- ):
1564
- cols.insert(0, table_index[0])
1565
- pass
1566
- prototype["_source"]["data"]["spec"]["columns"] = cols
1567
- pass
1595
+ return spec
1596
+
1597
+ def _aggregate(self, columns=None, operation=None) -> objects.Child:
1598
+ caseuuid, classname, entityuuid, ensemblename = (
1599
+ self._verify_aggregation_operation(columns, operation)
1600
+ )
1601
+ spec = self.__prepare_aggregation_spec(
1602
+ caseuuid, classname, entityuuid, ensemblename, operation, columns
1603
+ )
1604
+ spec["object_ids"] = self.uuids
1568
1605
  try:
1569
1606
  res = self._sumo.post("/aggregations", json=spec)
1570
1607
  except httpx.HTTPStatusError as ex:
1571
1608
  print(ex.response.reason_phrase)
1572
1609
  print(ex.response.text)
1573
1610
  raise ex
1574
- blob = BytesIO(res.content)
1575
- res = self._to_sumo(prototype, blob)
1576
- assert isinstance(res, objects.Child)
1577
- res._blob = blob
1578
- return res
1611
+ res = self._sumo.poll(res).json()
1612
+ return self._to_sumo(res)
1579
1613
 
1580
1614
  def aggregate(self, columns=None, operation=None) -> objects.Child:
1581
1615
  if len(self.hidden) > 0:
@@ -1586,103 +1620,39 @@ class SearchContext:
1586
1620
  )
1587
1621
 
1588
1622
  async def _verify_aggregation_operation_async(
1589
- self,
1590
- ) -> Tuple[Dict, List[str], List[int]]:
1591
- query = {
1592
- "query": self._query,
1593
- "size": 1,
1594
- "track_total_hits": True,
1595
- "aggs": {
1596
- k: {"terms": {"field": k + ".keyword", "size": 1}}
1597
- for k in [
1598
- "fmu.case.uuid",
1599
- "class",
1600
- "fmu.ensemble.name",
1601
- "data.name",
1602
- "data.tagname",
1603
- "data.content",
1604
- ]
1605
- },
1606
- }
1607
- sres = (await self._sumo.post_async("/search", json=query)).json()
1608
- if len(sres["hits"]["hits"]) == 0:
1609
- raise Exception("No matching realizations found.")
1610
- prototype = sres["hits"]["hits"][0]
1611
- conflicts = [
1612
- k
1613
- for (k, v) in sres["aggregations"].items()
1614
- if (
1615
- ("sum_other_doc_count" in v) and (v["sum_other_doc_count"] > 0)
1616
- )
1617
- ]
1618
- if len(conflicts) > 0:
1619
- raise Exception(f"Conflicting values for {conflicts}")
1620
-
1621
- hits = await self._search_all_async(select=["fmu.realization.id"])
1622
-
1623
- if any(
1624
- hit["_source"]["fmu"].get("realization") is None for hit in hits
1625
- ):
1626
- raise Exception("Selection contains non-realization data.")
1627
-
1628
- uuids = [hit["_id"] for hit in hits]
1629
- rids = [hit["_source"]["fmu"]["realization"]["id"] for hit in hits]
1630
- return prototype, uuids, rids
1631
-
1632
- async def _aggregate_async(
1633
- self, columns=None, operation=None
1634
- ) -> objects.Child:
1623
+ self, columns, operation
1624
+ ) -> Tuple[str, str, str, str]:
1635
1625
  assert (
1636
1626
  operation != "collection"
1637
1627
  or columns is not None
1638
1628
  and len(columns) == 1
1639
1629
  ), "Exactly one column required for collection aggregation."
1630
+ sc = self if columns is None else self.filter(column=columns)
1631
+ query = sc.__prepare_verify_aggregation_query()
1632
+ sres = (await self._sumo.post_async("/search", json=query)).json()
1633
+ return sc.__verify_aggregation_operation(sres)
1634
+
1635
+ async def _aggregate_async(
1636
+ self, columns=None, operation=None
1637
+ ) -> objects.Child:
1640
1638
  (
1641
- prototype,
1642
- uuids,
1643
- rids,
1644
- ) = await self.filter(
1645
- column=columns
1646
- )._verify_aggregation_operation_async()
1647
- spec = {
1648
- "object_ids": uuids,
1649
- "operations": [operation],
1650
- }
1651
- del prototype["_source"]["fmu"]["realization"]
1652
- del prototype["_source"]["_sumo"]
1653
- del prototype["_source"]["file"]
1654
- if "context" in prototype["_source"]["fmu"]:
1655
- prototype["_source"]["fmu"]["context"]["stage"] = "ensemble"
1656
- pass
1657
- prototype["_source"]["fmu"]["aggregation"] = {
1658
- "id": str(uuid.uuid4()),
1659
- "realization_ids": rids,
1660
- "operation": operation,
1661
- }
1662
- if columns is not None:
1663
- spec["columns"] = columns
1664
- cols = columns[:]
1665
- table_index = prototype["_source"]["data"].get("table_index")
1666
- if (
1667
- table_index is not None
1668
- and len(table_index) != 0
1669
- and table_index[0] not in cols
1670
- ):
1671
- cols.insert(0, table_index[0])
1672
- pass
1673
- prototype["_source"]["data"]["spec"]["columns"] = cols
1674
- pass
1639
+ caseuuid,
1640
+ classname,
1641
+ entityuuid,
1642
+ ensemblename,
1643
+ ) = await self._verify_aggregation_operation_async(columns, operation)
1644
+ spec = self.__prepare_aggregation_spec(
1645
+ caseuuid, classname, entityuuid, ensemblename, operation, columns
1646
+ )
1647
+ spec["object_ids"] = await self.uuids_async
1675
1648
  try:
1676
1649
  res = await self._sumo.post_async("/aggregations", json=spec)
1677
1650
  except httpx.HTTPStatusError as ex:
1678
1651
  print(ex.response.reason_phrase)
1679
1652
  print(ex.response.text)
1680
1653
  raise ex
1681
- blob = BytesIO(res.content)
1682
- res = self._to_sumo(prototype, blob)
1683
- assert isinstance(res, objects.Child)
1684
- res._blob = blob
1685
- return res
1654
+ res = self._sumo.poll(res).json()
1655
+ return self._to_sumo(res)
1686
1656
 
1687
1657
  async def aggregate_async(
1688
1658
  self, columns=None, operation=None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu-sumo
3
- Version: 2.4.3
3
+ Version: 2.4.5
4
4
  Summary: Python package for interacting with Sumo in an FMU setting
5
5
  Author: Equinor
6
6
  License: Apache License
@@ -1,7 +1,7 @@
1
1
  fmu/__init__.py,sha256=ftS-xRPSH-vU7fIHlnZQaCTWbNvs4owJivNW65kzsIM,85
2
2
  fmu/sumo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  fmu/sumo/explorer/__init__.py,sha256=Bc1wd1lQO3HP3tsVyPbqaesf2boZwGdtookWp8lmG-k,317
4
- fmu/sumo/explorer/_version.py,sha256=xLAVxNld0iPK6tqrofzfozu9ZHg4aby5Rg0HcLuAYIU,511
4
+ fmu/sumo/explorer/_version.py,sha256=agt6014xoIR-2Pjd3clvPyl78U4pI7z7EzFGI5OfP8k,511
5
5
  fmu/sumo/explorer/cache.py,sha256=uvz8TciwBnDEwJIHa9wneC0WVWuzhUqyF3dzk4kvGNk,1037
6
6
  fmu/sumo/explorer/explorer.py,sha256=_3nUTO1E_nf6jqpivjgjKcX6rX1fx_mIG76YOM8xb-8,2931
7
7
  fmu/sumo/explorer/filters.py,sha256=_t2PmHeTY9XiBvQeEGM-BpudWUaxIfyUSdNyG70xfRU,875
@@ -10,7 +10,7 @@ fmu/sumo/explorer/objects/__init__.py,sha256=72G0yfWWMTXA-oZw5GMRkrWvQqAYfadjerE
10
10
  fmu/sumo/explorer/objects/_child.py,sha256=RrH3W3GF5Nhje7VnhmlEwG_jhX0z6CloJgdGJJzk3po,6035
11
11
  fmu/sumo/explorer/objects/_document.py,sha256=uPAkNzcOk8U4LCtXthWkm7kfU9W4HYHrrqV9HERDhe8,1835
12
12
  fmu/sumo/explorer/objects/_metrics.py,sha256=WITAFAV-3VRd-AqTg0tUwWpOChW4YFfF8ffT2fvOrAo,8144
13
- fmu/sumo/explorer/objects/_search_context.py,sha256=a8RTE9mlNvHVdXbMMCsv6RF9PzYn4d4JnJZQONkuFKE,63840
13
+ fmu/sumo/explorer/objects/_search_context.py,sha256=ozyl7xUmun2kouoSnDvNhWgPK8ANJebb7KjDAN0AcEY,63162
14
14
  fmu/sumo/explorer/objects/case.py,sha256=fKp7X43ETLE1RaH3rMYxZiIuduRmf0JSnJ5gRoUgNPE,3813
15
15
  fmu/sumo/explorer/objects/cases.py,sha256=i2bnvk7NWIkzbdWMs3BXU7TCqD5tH2r7pg1m1QXUj3o,561
16
16
  fmu/sumo/explorer/objects/cpgrid.py,sha256=nuRgZ6FVEOPZT1ibd-rJhlbYYZ6BuUxXZPzovcH0kVc,2548
@@ -26,8 +26,8 @@ fmu/sumo/explorer/objects/realization.py,sha256=Th3zr_nT2I1HYHkBojOAKnf_RSIPc-Ti
26
26
  fmu/sumo/explorer/objects/realizations.py,sha256=4agtQFJ5pxLyWMeIzdJbkBMc8__Md-tZOj8Un4ol22c,1562
27
27
  fmu/sumo/explorer/objects/surface.py,sha256=zHBtjLCIfkRHBv39OeJjA9lq3puLTfTII6TndZTtxVI,1627
28
28
  fmu/sumo/explorer/objects/table.py,sha256=vLor3YTddHkDWZSMyWPQsddFNQ2_VXE_O-stmPIWIaQ,4900
29
- fmu_sumo-2.4.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
30
- fmu_sumo-2.4.3.dist-info/METADATA,sha256=g7mAuv0jCVQ3QvmrKnOCYe26sacr3DKl66X1PCoK2LU,14781
31
- fmu_sumo-2.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- fmu_sumo-2.4.3.dist-info/top_level.txt,sha256=Z-FIY3pxn0UK2Wxi9IJ7fKoLSraaxuNGi1eokiE0ShM,4
33
- fmu_sumo-2.4.3.dist-info/RECORD,,
29
+ fmu_sumo-2.4.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
30
+ fmu_sumo-2.4.5.dist-info/METADATA,sha256=ZZESEXOqjSMgM6fPAaCrC5nyr01h3q2SqZPjJktyHF0,14781
31
+ fmu_sumo-2.4.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
+ fmu_sumo-2.4.5.dist-info/top_level.txt,sha256=Z-FIY3pxn0UK2Wxi9IJ7fKoLSraaxuNGi1eokiE0ShM,4
33
+ fmu_sumo-2.4.5.dist-info/RECORD,,