Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
3 changes: 2 additions & 1 deletion .github/workflows/typing-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
max-parallel: 3
matrix:
# add packages to check typing
package-name: ["geos-geomechanics", "geos-posp", "geos-timehistory", "geos-utils", "geos-xml-tools", "hdf5-wrapper"]
package-name: ["geos-geomechanics", "geos-posp", "geos-timehistory", "geos-utils", "geos-trame", "geos-xml-tools", "hdf5-wrapper"]

steps:
- uses: actions/checkout@v4
Expand All @@ -35,6 +35,7 @@ jobs:
- name: Typing check with mypy
# working-directory: ./${{ matrix.package-name }}
run: |
python -m mypy geos-trame/geos_trame/app/__main__.py --install-types --non-interactive
python -m mypy --config-file ./.mypy.ini --check-untyped-defs ./${{ matrix.package-name }}

- name: Format and linting check with ruff
Expand Down
26 changes: 16 additions & 10 deletions geos-trame/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
repos:
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
exclude: ^.*\b(schema_generated)\b.*$
entry: black --check --force-exclude

- repo: https://github.com/codespell-project/codespell
rev: v2.1.0
hooks:
- id: codespell

- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.12
hooks:
- id: ruff
args: ["--config", "./.ruff.toml"]

- repo: https://github.com/google/yapf
rev: v0.43.0
hooks:
- id: yapf
args: ["-ir", "--style", "./.style.yapf"]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.16.0
hooks:
- id: flake8
- id: mypy
additional_dependencies: [types-PyYAML]
19 changes: 0 additions & 19 deletions geos-trame/CONTRIBUTING.rst

This file was deleted.

9 changes: 9 additions & 0 deletions geos-trame/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ To be able to run the test suite, make sure to install the additionals dependenc

Then you can run the test with `pytest .`

Optional
--------

To use pre-commit hooks (ruff, mypy, yapf,...), make sure to install the dev dependencies:

.. code-block:: console

pip install -e .[dev]

Regarding GEOS
--------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
# SPDX-FileContributor: Lionel Untereiner
from pathlib import Path
from typing import Any

from trame.app import get_server
from trame_server import Server

from geos_trame.app.core import GeosTrame


def main( server=None, **kwargs ):
def main( server: Server = None, **kwargs: Any ) -> None:
"""Main function."""
# Get or create server
if server is None:
server = get_server()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@


class AlertHandler( vuetify3.VContainer ):
"""
Vuetify component used to display an alert status.
"""Vuetify component used to display an alert status.

This alert will be displayed in the bottom right corner of the screen.
It will be displayed until closed by the user or after 10 seconds if it is a success or warning.
"""

def __init__( self ):
def __init__( self ) -> None:
"""Constructor."""
super().__init__(
fluid=True,
classes="pa-0 ma-0",
Expand All @@ -31,31 +31,32 @@ def __init__( self ):

self.generate_alert_ui()

def generate_alert_ui( self ):
"""
Generate the alert UI.
def generate_alert_ui( self ) -> None:
"""Generate the alert UI.

The alert will be displayed in the bottom right corner of the screen.

Use an abritary z-index value to put the alert on top of the other components.
"""
with self:
with vuetify3.VCol( style="width: 40%; position: fixed; right: 50px; bottom: 50px; z-index: 100;", ):
vuetify3.VAlert(
style="max-height: 20vh; overflow-y: auto",
classes="ma-2",
v_for=( "(status, index) in alerts", ),
key="status",
type=( "status.type", "info" ),
text=( "status.message", "" ),
title=( "status.title", "" ),
closable=True,
click_close=( self.on_close, f"[status.id]" ),
)

def add_alert( self, type: str, title: str, message: str ):
"""
Add a status to the stack with a unique id.
with (
self,
vuetify3.VCol( style="width: 40%; position: fixed; right: 50px; bottom: 50px; z-index: 100;", ),
):
vuetify3.VAlert(
style="max-height: 20vh; overflow-y: auto",
classes="ma-2",
v_for=( "(status, index) in alerts", ),
key="status",
type=( "status.type", "info" ),
text=( "status.message", "" ),
title=( "status.title", "" ),
closable=True,
click_close=( self.on_close, "[status.id]" ),
)

def add_alert( self, type: str, title: str, message: str ) -> None:
"""Add a status to the stack with a unique id.

If there are more than 5 alerts displayed, remove the oldest.
A warning will be automatically closed after 10 seconds.
"""
Expand All @@ -77,21 +78,15 @@ def add_alert( self, type: str, title: str, message: str ):
if type == "warning":
asyncio.get_event_loop().call_later( self.__lifetime_of_alert, self.on_close, alert_id )

async def add_warning( self, title: str, message: str ):
"""
Add an alert of type "warning"
"""
async def add_warning( self, title: str, message: str ) -> None:
"""Add an alert of type 'warning'."""
self.add_alert( "warning", title, message )

async def add_error( self, title: str, message: str ):
"""
Add an alert of type "error"
"""
async def add_error( self, title: str, message: str ) -> None:
"""Add an alert of type 'error'."""
self.add_alert( "error", title, message )

def on_close( self, alert_id ):
"""
Remove in the state the alert associated to the given id.
"""
def on_close( self, alert_id: int ) -> None:
"""Remove in the state the alert associated to the given id."""
self.state.alerts = list( filter( lambda i: i[ "id" ] != alert_id, self.state.alerts ) )
self.state.flush()
82 changes: 82 additions & 0 deletions geos-trame/geos_trame/app/components/properties_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
# SPDX-FileContributor: Kitware
from typing import Any

from trame_client.widgets.core import AbstractElement
from trame_simput import get_simput_manager

from geos_trame.app.data_types.field_status import FieldStatus
from geos_trame.app.deck.tree import DeckTree
from geos_trame.app.ui.viewer.regionViewer import RegionViewer
from geos_trame.app.utils.geos_utils import group_name_ref_array_to_list

# Doc reference: https://geosx-geosx.readthedocs-hosted.com/en/latest/docs/sphinx/datastructure/CompleteXMLSchema.html
attributes_to_check = [ ( "region_attribute", str ), ( "fields_to_import", list ), ( "surfacicFieldsToImport", list ) ]


class PropertiesChecker( AbstractElement ):
"""Validity checker of properties within a deck tree."""

def __init__( self, tree: DeckTree, region_viewer: RegionViewer, **kwargs: Any ) -> None:
"""Constructor."""
super().__init__( "div", **kwargs )

self.tree = tree
self.region_viewer = region_viewer
self.simput_manager = get_simput_manager( id=self.state.sm_id )

def check_fields( self ) -> None:
"""Check all the fields in the deck_tree.

Get the names of all the cell data arrays from the input of the region viewer, then check that
all the attributes in `attributes_to_check` have a value corresponding to one of the array names.
"""
cellData = self.region_viewer.input.GetCellData()
arrayNames = [ cellData.GetArrayName( i ) for i in range( cellData.GetNumberOfArrays() ) ]
for field in self.state.deck_tree:
self.check_field( field, arrayNames )
self.state.dirty( "deck_tree" )
self.state.flush()

def check_field( self, field: dict, array_names: list[ str ] ) -> None:
"""Check that all the attributes in `attributes_to_check` have a value corresponding to one of the array names.

Set the `valid` property to the result of this check, and if necessary, indicate which properties are invalid.
"""
field[ "valid" ] = FieldStatus.VALID.value
field[ "invalid_properties" ] = []

proxy = self.simput_manager.proxymanager.get( field[ "id" ] )
if proxy is not None:
for attr, expected_type in attributes_to_check:
if attr in proxy.definition:
if ( expected_type is str and proxy[ attr ] # value is not empty (valid)
and proxy[ attr ] not in array_names # value is not in the expected names
):
field[ "invalid_properties" ].append( attr )
elif expected_type is list:
arrays: list[ str ] | None = group_name_ref_array_to_list( proxy[ attr ] )
if arrays is None:
field[ "invalid_properties" ].append( attr )
continue
for array_name in arrays:
if array_name not in array_names:
field[ "invalid_properties" ].append( attr )
break

if len( field[ "invalid_properties" ] ) != 0:
field[ "valid" ] = FieldStatus.INVALID.value
else:
field.pop( "invalid_properties", None )

if field[ "children" ] is not None:
# Parents are only valid if all children are valid
field[ "invalid_children" ] = []
for child in field[ "children" ]:
self.check_field( child, array_names )
if child[ "valid" ] == FieldStatus.INVALID.value:
field[ "valid" ] = FieldStatus.INVALID.value
field[ "invalid_children" ].append( child[ "title" ] )
if len( field[ "invalid_children" ] ) == 0:
field.pop( "invalid_children", None )
Loading