Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backports version 10_2 #8503

Merged
merged 7 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions src/ert/dark_storage/endpoints/records.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import base64
import io
from itertools import chain
from typing import Any, Dict, List, Mapping, Union
from uuid import UUID, uuid4

import matplotlib.pyplot as plt
from fastapi import APIRouter, Body, Depends, File, Header, status
import numpy as np
from fastapi import APIRouter, Body, Depends, File, Header, HTTPException, status
from fastapi.responses import Response
from typing_extensions import Annotated

Expand Down Expand Up @@ -141,22 +140,22 @@ def get_ensemble_responses(
return response_map


@router.get(
"/ensembles/{ensemble_id}/records/{key}/std_dev", response_model=js.ImageOut
)
@router.get("/ensembles/{ensemble_id}/records/{key}/std_dev")
def get_std_dev(
*, storage: Storage = DEFAULT_STORAGE, ensemble_id: UUID, key: str, z: int
) -> js.ImageOut:
) -> Response:
ensemble = storage.get_ensemble(ensemble_id)
try:
da = ensemble.calculate_std_dev_for_parameter(key)["values"]
except ValueError:
return js.ImageOut(image=bytearray())
except ValueError as e:
raise HTTPException(status_code=404, detail="Data not found") from e

if z >= int(da.shape[2]):
return js.ImageOut(image=bytearray())
raise HTTPException(status_code=400, detail="Invalid z index")

data_2d = da[:, :, z]

buffer = io.BytesIO()
plt.imsave(buffer, da[:, :, z])
np.save(buffer, data_2d)

return js.ImageOut(image=base64.b64encode(buffer.getvalue()))
return Response(content=buffer.getvalue(), media_type="application/octet-stream")
2 changes: 1 addition & 1 deletion src/ert/dark_storage/json_schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
ObservationTransformationOut,
)
from .prior import Prior
from .record import ImageOut, RecordOut
from .record import RecordOut
from .update import UpdateIn, UpdateOut
5 changes: 0 additions & 5 deletions src/ert/dark_storage/json_schema/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,3 @@ class RecordOut(_Record):
name: str
userdata: Mapping[str, Any]
has_observations: Optional[bool]


@dataclass(config=ConfigDict(from_attributes=True))
class ImageOut(_Record):
image: bytes
58 changes: 41 additions & 17 deletions src/ert/gui/ertwidgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,45 @@ def wrapper(*arg: Any) -> Any:
return wrapper


# The following imports utilize the functions defined above:
from .legend import Legend # noqa
from .validationsupport import ValidationSupport # noqa
from .closabledialog import ClosableDialog # noqa
from .analysismoduleedit import AnalysisModuleEdit # noqa
from .activelabel import ActiveLabel # noqa
from .searchbox import SearchBox # noqa
from .ensembleselector import EnsembleSelector # noqa
from .ensemblelist import EnsembleList # noqa
from .checklist import CheckList # noqa
from .stringbox import StringBox # noqa
from .listeditbox import ListEditBox # noqa
from .customdialog import CustomDialog # noqa
from .summarypanel import SummaryPanel # noqa
from .pathchooser import PathChooser # noqa
from .models import TextModel # noqa
from .closabledialog import ClosableDialog
from .analysismoduleedit import AnalysisModuleEdit
from .searchbox import SearchBox
from .ensembleselector import EnsembleSelector
from .checklist import CheckList
from .stringbox import StringBox
from .listeditbox import ListEditBox
from .customdialog import CustomDialog
from .pathchooser import PathChooser
from .models import (
TextModel,
ActiveRealizationsModel,
TargetEnsembleModel,
ValueModel,
SelectableListModel,
PathModel,
)
from .copyablelabel import CopyableLabel
from .message_box import ErtMessageBox
from .copy_button import CopyButton

__all__ = ["TextModel"]
__all__ = [
"TextModel",
"ClosableDialog",
"AnalysisModuleEdit",
"SearchBox",
"EnsembleSelector",
"ActiveRealizationsModel",
"CheckList",
"StringBox",
"CopyableLabel",
"showWaitCursorWhileWaiting",
"ErtMessageBox",
"TargetEnsembleModel",
"ValueModel",
"PathModel",
"SelectableListModel",
"ListEditBox",
"CustomDialog",
"PathChooser",
"CopyButton",
]
32 changes: 0 additions & 32 deletions src/ert/gui/ertwidgets/activelabel.py

This file was deleted.

43 changes: 43 additions & 0 deletions src/ert/gui/ertwidgets/copy_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from abc import abstractmethod

from qtpy.QtCore import QTimer
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import (
QApplication,
QMessageBox,
QPushButton,
QSizePolicy,
)


class CopyButton(QPushButton):
def __init__(self) -> None:
super().__init__()
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.setIcon(QIcon("img:copy.svg"))
self.restore_timer = QTimer(self)

def restore_text() -> None:
self.setIcon(QIcon("img:copy.svg"))

self.restore_timer.timeout.connect(restore_text)

self.clicked.connect(self.copy)

@abstractmethod
def copy(self) -> None:
pass

def copy_text(self, text: str) -> None:
clipboard = QApplication.clipboard()
if clipboard:
clipboard.setText(text)
else:
QMessageBox.critical(
None,
"Error",
"Cannot copy text to clipboard because your system does not have a clipboard",
QMessageBox.Ok,
)
self.setIcon(QIcon("img:check.svg"))
self.restore_timer.start(1000)
50 changes: 15 additions & 35 deletions src/ert/gui/ertwidgets/copyablelabel.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
from os import path

from qtpy.QtCore import Qt, QTimer
from qtpy.QtGui import QIcon
from qtpy.QtCore import Qt
from qtpy.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QMessageBox,
QPushButton,
QSizePolicy,
)

from .copy_button import CopyButton

# Get the absolute path of the directory that contains the current script
current_dir = path.dirname(path.abspath(__file__))

Expand Down Expand Up @@ -63,6 +60,17 @@ def strip_run_path_magic_keywords(run_path: str) -> str:
return rp_stripped


class _CopyButton(CopyButton):
def __init__(self, label: QLabel) -> None:
super().__init__()
self.label = label

def copy(self) -> None:
self.copy_text(
strip_run_path_magic_keywords(unescape_string(self.label.text()))
)


class CopyableLabel(QHBoxLayout):
"""CopyableLabel shows a string that is copyable via
selection or clicking of a copy button"""
Expand All @@ -73,35 +81,7 @@ def __init__(self, text: str) -> None:
self.label = QLabel(f"<b>{escape_string(text)}</b>")
self.label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)

self.copy_button = QPushButton("")
self.copy_button.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.copy_button.setIcon(QIcon("img:copy.svg"))
self.restore_timer = QTimer(self)

def restore_text() -> None:
self.copy_button.setIcon(QIcon("img:copy.svg"))

self.restore_timer.timeout.connect(restore_text)

def copy_text() -> None:
text = strip_run_path_magic_keywords(unescape_string(self.label.text()))

clipboard = QApplication.clipboard()
if clipboard:
clipboard.setText(text)
else:
QMessageBox.critical(
None,
"Error",
"Cannot copy text to clipboard because your system does not have a clipboard",
QMessageBox.Ok,
)

self.copy_button.setIcon(QIcon("img:check.svg"))

self.restore_timer.start(1000)

self.copy_button.clicked.connect(copy_text)
self.copy_button = _CopyButton(self.label)

self.addWidget(self.label)
self.addWidget(self.copy_button, alignment=Qt.AlignmentFlag.AlignLeft)
114 changes: 0 additions & 114 deletions src/ert/gui/ertwidgets/ensemblelist.py

This file was deleted.

Loading
Loading