diff --git a/geos-geomechanics/src/geos/geomechanics/model/MohrCircle.py b/geos-geomechanics/src/geos/geomechanics/model/MohrCircle.py index b0916da13..665554fa8 100644 --- a/geos-geomechanics/src/geos/geomechanics/model/MohrCircle.py +++ b/geos-geomechanics/src/geos/geomechanics/model/MohrCircle.py @@ -39,6 +39,7 @@ center: float = mohrCircle.getCircleCenter() """ +loggerTitle : str = "MohrCircle" class MohrCircle: diff --git a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py index 0874c3540..a3ccc032f 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py @@ -87,7 +87,7 @@ def fillPartialAttributes( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "fillPartialAttributes", True ) + logger = getLogger( "fillPartialAttributes") # Check if the input mesh is inherited from vtkMultiBlockDataSet. if not isinstance( multiBlockDataSet, vtkMultiBlockDataSet ): @@ -178,7 +178,7 @@ def fillAllPartialAttributes( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "fillAllPartialAttributes", True ) + logger = getLogger( "fillAllPartialAttributes") logger.warning( "The filling value for the attributes is depending of the type of attribute's data:\n0 for uint data,\n-1 for int data,\nnan for float data." @@ -260,7 +260,7 @@ def createConstantAttribute( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "createConstantAttribute", True ) + logger = getLogger( "createConstantAttribute") # Deals with multiBlocksDataSets. if isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): @@ -307,7 +307,7 @@ def createConstantAttributeMultiBlock( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "createConstantAttributeMultiBlock", True ) + logger = getLogger( "createConstantAttributeMultiBlock") # Check if the input mesh is inherited from vtkMultiBlockDataSet. if not isinstance( multiBlockDataSet, vtkMultiBlockDataSet ): @@ -376,7 +376,7 @@ def createConstantAttributeDataSet( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "createConstantAttributeDataSet", True ) + logger = getLogger( "createConstantAttributeDataSet") # Check if all the values of listValues have the same type. valueType: type = type( listValues[ 0 ] ) @@ -458,7 +458,7 @@ def createAttribute( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "createAttribute", True ) + logger = getLogger( "createAttribute") # Check if the input mesh is inherited from vtkDataSet. if not isinstance( dataSet, vtkDataSet ): @@ -568,7 +568,7 @@ def copyAttribute( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "copyAttribute", True ) + logger = getLogger( "copyAttribute") # Check if the multiBlockDataSetFrom is inherited from vtkMultiBlockDataSet. if not isinstance( multiBlockDataSetFrom, vtkMultiBlockDataSet ): @@ -650,7 +650,7 @@ def copyAttributeDataSet( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "copyAttributeDataSet", True ) + logger = getLogger( "copyAttributeDataSet") # Check if the dataSetFrom is inherited from vtkDataSet. if not isinstance( dataSetFrom, vtkDataSet ): @@ -724,7 +724,7 @@ def transferAttributeToDataSetWithElementMap( """ # Check if an external logger is given. if logger is None: - logger = getLogger( "transferAttributeToDataSetWithElementMap", True ) + logger = getLogger( "transferAttributeToDataSetWithElementMap") if flatIdDataSetTo not in elementMap: logger.error( f"The map is incomplete, there is no data for the final mesh (flat index { flatIdDataSetTo })." ) @@ -825,8 +825,8 @@ def transferAttributeWithElementMap( bool: True if transfer successfully ended. """ # Check if an external logger is given. - if logger is None: - logger = getLogger( "transferAttributeWithElementMap", True ) + if logger is None:# + logger = getLogger( "transferAttributeWithElementMap") if isinstance( meshTo, vtkDataSet ): return transferAttributeToDataSetWithElementMap( meshFrom, diff --git a/geos-mesh/src/geos/mesh/utils/genericHelpers.py b/geos-mesh/src/geos/mesh/utils/genericHelpers.py index de11a4023..57bf29f45 100644 --- a/geos-mesh/src/geos/mesh/utils/genericHelpers.py +++ b/geos-mesh/src/geos/mesh/utils/genericHelpers.py @@ -641,7 +641,7 @@ def computeSurfaceTextureCoordinates( # Need to compute texture coordinates required for tangent calculation vtkErrorLogger: Logger if logger is None: - vtkErrorLogger = getLogger( "Compute Surface Texture Coordinates vtkError Logger", True ) + vtkErrorLogger = getLogger( "Compute Surface Texture Coordinates vtkError Logger") else: vtkErrorLogger = logging.getLogger( f"{ logger.name } vtkError Logger" ) vtkErrorLogger.setLevel( logging.INFO ) diff --git a/geos-processing/pyproject.toml b/geos-processing/pyproject.toml index 3d947f672..226e33fe4 100644 --- a/geos-processing/pyproject.toml +++ b/geos-processing/pyproject.toml @@ -19,6 +19,7 @@ maintainers = [ {name = "Alexandre Benedicto", email = "alexandre.benedicto@external.totalenergies.com" }, {name = "Romain Baville", email = "romain.baville@external.totalenergies.com" }, {name = "Paloma Martinez", email = "paloma.martinez@external.totalenergies.com" }, + {name = "Jacques Franc", email = "jacques.franc@external.totalenergies.com" }, ] license = {text = "Apache-2.0"} classifiers = [ diff --git a/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py b/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py index 9eb7aa6fe..d075d5dd2 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py @@ -4,7 +4,6 @@ # ruff: noqa: E402 # disable Module level import not at top of file import numpy as np import numpy.typing as npt -import logging from typing_extensions import Self, Union from vtkmodules.vtkCommonDataModel import vtkDataSet, vtkMultiBlockDataSet from geos.mesh.utils.arrayModifiers import transferAttributeWithElementMap @@ -41,7 +40,6 @@ attributeNames: set[ str ] # Optional inputs. onPoints: bool # defaults to False - speHandler: bool # defaults to False # Instantiate the filter attributeMappingFilter: AttributeMapping = AttributeMapping( @@ -49,13 +47,8 @@ meshTo, attributeNames, onPoints, - speHandler, ) - # Set the handler of yours (only if speHandler is True). - yourHandler: logging.Handler - attributeMappingFilter.setLoggerHandler( yourHandler ) - # Do calculations. attributeMappingFilter.applyFilter() """ @@ -71,7 +64,6 @@ def __init__( meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ], attributeNames: set[ str ], onPoints: bool = False, - speHandler: bool = False, ) -> None: """Transfer global attributes from a source mesh to a final mesh. @@ -97,27 +89,7 @@ def __init__( self.ElementMap: dict[ int, npt.NDArray[ np.int64 ] ] = {} # Logger. - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) - - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, - be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if not self.logger.hasHandlers(): - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler'" - " to True during the filter initialization." ) + self.logger: Logger = getLogger( loggerTitle ) def getElementMap( self: Self ) -> dict[ int, npt.NDArray[ np.int64 ] ]: """Getter of the element mapping dictionary. diff --git a/geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py b/geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py index 6b95fbbae..2a52e1a80 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache 2.0 # SPDX-FileCopyrightText: Copyright 2023-2025 TotalEnergies # SPDX-FileContributor: Jacques Franc -import logging import numpy as np import numpy.typing as npt @@ -218,7 +217,7 @@ def __getFramePoints( self, vpts: vtkPoints ) -> tuple[ vtkPoints, vtkPoints ]: class ClipToMainFrame( vtkTransformFilter ): """Filter to clip a mesh to the main frame using ClipToMainFrame class.""" - def __init__( self, speHandler: bool = False, **properties: str ) -> None: + def __init__( self, **properties: str ) -> None: """Initialize the ClipToMainFrame Filter with optional speHandler args and forwarding properties to main class. Args: @@ -228,12 +227,7 @@ def __init__( self, speHandler: bool = False, **properties: str ) -> None: """ super().__init__( **properties ) # Logger. - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) + self.logger: Logger = getLogger( loggerTitle ) def ComputeTransform( self ) -> None: """Update the transformation.""" @@ -254,21 +248,7 @@ def ComputeTransform( self ) -> None: clip.Update() self.SetTransform( clip ) - - def SetLoggerHandler( self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, - be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if not self.logger.hasHandlers(): - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True" - " during the filter initialization." ) + self.logger.info( f"{self.logger.name} applied successfully." ) def __locate_reference_point( self, multiBlockDataSet: vtkMultiBlockDataSet ) -> int: """Locate the block to use as reference for the transformation. diff --git a/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py index 85e1fc74b..7902ef3d5 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py @@ -50,7 +50,6 @@ valueNpType: type nbComponents: int componentNames: tuple[ str, ... ] - speHandler: bool # Instantiate the filter createConstantAttributePerRegionFilter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion( @@ -61,7 +60,6 @@ valueNpType, nbComponents, componentNames, - speHandler, ) # Set your handler (only if speHandler is True). @@ -86,7 +84,6 @@ def __init__( valueNpType: type = np.float32, nbComponents: int = 1, componentNames: tuple[ str, ...] = (), # noqa: C408 - speHandler: bool = False, ) -> None: """Create an attribute with constant value per region. @@ -123,33 +120,13 @@ def __init__( # Check if the new component have default values (information for the output message). self.useDefaultValue: bool = False - # Warnings counter. - self.counter: CountWarningHandler = CountWarningHandler() - self.counter.setLevel( logging.INFO ) - # Logger. - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) + self.logger: Logger = getLogger( loggerTitle ) # Warnings counter. - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, - be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if not self.logger.hasHandlers(): - self.logger.addHandler( handler ) - else: - # This warning does not count for the number of warning created during the application of the filter. - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True" - " during the filter initialization." ) + self.counter: CountWarningHandler = CountWarningHandler() + self.counter.setLevel( logging.INFO ) + # Add the handler to count warnings messages. + self.logger.addHandler( self.counter ) def applyFilter( self: Self ) -> bool: """Create a constant attribute per region in the mesh. @@ -159,9 +136,6 @@ def applyFilter( self: Self ) -> bool: """ self.logger.info( f"Apply filter { self.logger.name }." ) - # Add the handler to count warnings messages. - self.logger.addHandler( self.counter ) - # Check the validity of the attribute region. if self.onPoints is None: self.logger.error( f"{ self.regionName } is not in the mesh." ) diff --git a/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py b/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py index feb561984..2fce123c9 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py @@ -5,10 +5,11 @@ from typing_extensions import Self from typing import Union, Any -from geos.utils.Logger import logging, Logger, getLogger +from geos.utils.Logger import getLogger from geos.mesh.utils.arrayModifiers import fillPartialAttributes from geos.mesh.utils.arrayHelpers import getAttributePieceInfo +# from geos.utils.details import addLogSupport from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet __doc__ = """ @@ -61,7 +62,6 @@ def __init__( self: Self, multiBlockDataSet: vtkMultiBlockDataSet, dictAttributesValues: dict[ str, Union[ list[ Any ], None ] ], - speHandler: bool = False, ) -> None: """Fill partial attributes with constant value per component. @@ -74,37 +74,12 @@ def __init__( Args: multiBlockDataSet (vtkMultiBlockDataSet): The mesh where to fill the attribute. - dictAttributesValues (dict[str, Any]): The dictionary with the attribute to fill as keys - and the list of filling values as values. - speHandler (bool, optional): True to use a specific handler, False to use the internal handler. - Defaults to False. + dictAttributesValues (dict[str, Any]): The dictionary with the attribute to fill as keys and the list of filling values as items. """ + self.logger = getLogger( loggerTitle ) self.multiBlockDataSet: vtkMultiBlockDataSet = multiBlockDataSet self.dictAttributesValues: dict[ str, Union[ list[ Any ], None ] ] = dictAttributesValues - # Logger. - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) - - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, - be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if not self.logger.hasHandlers(): - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True" - " during the filter initialization." ) - def applyFilter( self: Self ) -> bool: """Create a constant attribute per region in the mesh. diff --git a/geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py b/geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py index 9bcfa5736..81b89629f 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py @@ -2,7 +2,6 @@ # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. # SPDX-FileContributor: Paloma Martinez # ruff: noqa: E402 # disable Module level import not at top of file -import logging from typing_extensions import Self @@ -65,7 +64,6 @@ class MergeBlockEnhanced: def __init__( self: Self, inputMesh: vtkMultiBlockDataSet, - speHandler: bool = False, ) -> None: """Merge a multiblock dataset and keep the partial attributes in the output mesh. @@ -83,26 +81,7 @@ def __init__( self.outputMesh: vtkUnstructuredGrid = vtkUnstructuredGrid() # Logger - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) - - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if not self.logger.hasHandlers(): - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True" - " during the filter initialization." ) + self.logger: Logger = getLogger( loggerTitle ) def applyFilter( self: Self ) -> None: """Merge the blocks of a multiblock dataset mesh. diff --git a/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py b/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py index 8cbe9d026..1718ac8ae 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. # SPDX-FileContributor: Antoine Mazuyer, Martin Lemay -import logging import numpy as np import numpy.typing as npt from typing_extensions import Self @@ -47,12 +46,12 @@ outputMesh: vtkUnstructuredGrid = splitMeshFilter.getOutput() """ -loggerTitle: str = "Split Mesh" +loggerTitle: str = "SplitMesh" class SplitMesh(): - def __init__( self, inputMesh: vtkUnstructuredGrid, speHandler: bool = False ) -> None: + def __init__( self, inputMesh: vtkUnstructuredGrid ) -> None: """SplitMesh filter splits each cell using edge centers. Args: @@ -66,32 +65,11 @@ def __init__( self, inputMesh: vtkUnstructuredGrid, speHandler: bool = False ) - self.points: vtkPoints self.originalId: vtkIdTypeArray self.cellTypes: list[ int ] - self.speHandler: bool = speHandler - self.handler: None | logging.Handler = None + #subordonate filter + self.cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( self.inputMesh ) # Logger - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) - self.logger.propagate = False - - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - self.handler = handler - if len( self.logger.handlers ) == 0: - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True" - " during the filter initialization." ) + self.logger: Logger = getLogger( loggerTitle ) def applyFilter( self: Self ) -> bool: """Apply the filter SplitMesh. @@ -186,13 +164,9 @@ def _getCellCounts( self: Self ) -> CellTypeCounts: Returns: CellTypeCounts: cell type counts """ - cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( - self.inputMesh, self.speHandler ) - if self.speHandler and len( cellTypeCounterEnhancedFilter.logger.handlers ) == 0: - cellTypeCounterEnhancedFilter.setLoggerHandler( self.handler ) - if not cellTypeCounterEnhancedFilter.applyFilter(): + if not self.cellTypeCounterEnhancedFilter.applyFilter(): raise - return cellTypeCounterEnhancedFilter.GetCellTypeCountsObject() + return self.cellTypeCounterEnhancedFilter.GetCellTypeCountsObject() def _addMidPoint( self: Self, ptA: int, ptB: int ) -> int: """Add a point at the center of the edge defined by input point ids. diff --git a/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py b/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py index 053404699..270864f39 100644 --- a/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py +++ b/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py @@ -84,15 +84,9 @@ # Define filter inputs mesh: vtkUnstructuredGrid computeAdvancedProperties: bool # optional, defaults to False - speHandler: bool # optional, defaults to False - loggerName: str # Defaults to "Geomechanics Calculator" # Instantiate the filter - geomechanicsCalculatorFilter: GeomechanicsCalculator = GeomechanicsCalculator( mesh, computeAdvancedProperties, speHandler ) - - # Use your own handler (if speHandler is True) - yourHandler: logging.Handler - geomechanicsCalculatorFilter.setLoggerHandler( yourHandler ) + geomechanicsCalculatorFilter: GeomechanicsCalculator = GeomechanicsCalculator( mesh, computeAdvancedProperties ) # Change the physical constants if needed ## For the basic properties @@ -167,6 +161,9 @@ ADVANCED_PROPERTIES: tuple[ AttributeEnum, ...] = ( CRITICAL_TOTAL_STRESS_RATIO, TOTAL_STRESS_RATIO_THRESHOLD, CRITICAL_PORE_PRESSURE, CRITICAL_PORE_PRESSURE_THRESHOLD ) + + +loggerTitle: str = "Geomechanics Calculator" class GeomechanicsCalculator: @@ -684,8 +681,6 @@ def __init__( self: Self, mesh: vtkUnstructuredGrid, computeAdvancedProperties: bool = False, - loggerName: str = "Geomechanics Calculator", - speHandler: bool = False, ) -> None: """VTK Filter to perform geomechanics properties computation. @@ -695,8 +690,6 @@ def __init__( Defaults to False. loggerName (str, optional): Name of the filter logger. Defaults to "Geomechanics Calculator". - speHandler (bool, optional): True to use a specific handler, False to use the internal handler. - Defaults to False. """ self.output: vtkUnstructuredGrid = mesh.NewInstance() self.output.DeepCopy( mesh ) @@ -711,12 +704,7 @@ def __init__( self._attributesToCreate: list[ AttributeEnum ] = [] # Logger. - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerName, True ) - else: - self.logger = logging.getLogger( loggerName ) - self.logger.setLevel( logging.INFO ) + self.logger: Logger = getLogger( loggerTitle ) def applyFilter( self: Self ) -> None: """Compute the geomechanics properties and create attributes on the mesh.""" diff --git a/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py b/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py index 62fcd013a..f04dd4dd0 100644 --- a/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py +++ b/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py @@ -2,7 +2,6 @@ # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. # SPDX-FileContributor: Martin Lemay, Paloma Martinez # ruff: noqa: E402 # disable Module level import not at top of file -import logging import numpy as np from typing_extensions import Self, Union @@ -99,7 +98,7 @@ class SurfaceGeomechanics: - def __init__( self: Self, surfacicMesh: vtkPolyData, speHandler: bool = False ) -> None: + def __init__( self: Self, surfacicMesh: vtkPolyData ) -> None: """Vtk filter to compute geomechanical surfacic attributes. Input and Output objects are a vtkPolydata with surfaces @@ -111,14 +110,10 @@ def __init__( self: Self, surfacicMesh: vtkPolyData, speHandler: bool = False ) Defaults to False. """ # Logger - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) + self.logger: Logger = getLogger( loggerTitle ) # Input surfacic mesh + print( surfacicMesh ) if not surfacicMesh.IsA( "vtkPolyData" ): self.logger.error( f"Input surface is expected to be a vtkPolyData, not a {type(surfacicMesh)}." ) self.inputMesh: vtkPolyData = surfacicMesh @@ -141,21 +136,6 @@ def __init__( self: Self, surfacicMesh: vtkPolyData, speHandler: bool = False ) # New created attributes names self.newAttributeNames: set[ str ] = set() - def SetLoggerHandler( self: Self, handler: Logger ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if not self.logger.hasHandlers(): - self.logger.addHandler( handler ) - else: - self.logger.warning( - "The logger already has an handler, to use yours set the argument 'speHandler' to True during the filter initialization." - ) - def SetSurfaceName( self: Self, name: str ) -> None: """Set a name for the input surface. For logging purpose only. diff --git a/geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py b/geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py index 3aa8953ac..4a105e39f 100644 --- a/geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py +++ b/geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. # SPDX-FileContributor: Antoine Mazuyer, Martin Lemay -import logging from typing_extensions import Self from vtkmodules.vtkCommonCore import vtkIntArray @@ -49,7 +48,6 @@ class CellTypeCounterEnhanced(): def __init__( self: Self, inputMesh: vtkUnstructuredGrid, - speHandler: bool = False, ) -> None: """CellTypeCounterEnhanced filter computes mesh stats. @@ -63,28 +61,7 @@ def __init__( self._counts: CellTypeCounts = CellTypeCounts() # Logger. - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) - self.logger.propagate = False - - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, - be sure to have at least the same 4 levels. - - Args: - handler (logging.Handler): The handler to add. - """ - if len( self.logger.handlers ) == 0: - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler'" - " to True during the filter initialization." ) + self.logger: Logger = getLogger( loggerTitle ) def applyFilter( self: Self ) -> bool: """Apply CellTypeCounterEnhanced filter. diff --git a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py index 6c454c69e..b2832ccf4 100644 --- a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py +++ b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. # SPDX-FileContributor: Antoine Mazuyer, Martin Lemay, Paloma Martinez -import logging import numpy as np import numpy.typing as npt from typing import Optional, cast @@ -95,13 +94,11 @@ class MeshQualityEnhanced(): def __init__( self: Self, inputMesh: vtkUnstructuredGrid, - speHandler: bool = False, ) -> None: """Enhanced vtkMeshQuality filter. Args: inputMesh (vtkUnstructuredGrid): Input mesh - speHandler (bool, optional): True to use a specific handler, False to use the internal handler. Defaults to False. """ self.inputMesh: vtkUnstructuredGrid = inputMesh @@ -125,32 +122,11 @@ def __init__( self._allCellTypesExtended: tuple[ int, ...] = getAllCellTypesExtended() self._allCellTypes: tuple[ int, ...] = getAllCellTypes() - # Logger. - self.speHandler: bool = speHandler - self.handler: None | logging.Handler = None - self.logger: Logger - if not speHandler: - self.logger = getLogger( loggerTitle, True ) - else: - self.logger = logging.getLogger( loggerTitle ) - self.logger.setLevel( logging.INFO ) - self.logger.propagate = False - - def setLoggerHandler( self: Self, handler: logging.Handler ) -> None: - """Set a specific handler for the filter logger. - - In this filter 4 log levels are use, .info, .error, .warning and .critical, - be sure to have at least the same 4 levels. + #deps + self.cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( self._outputMesh ) - Args: - handler (logging.Handler): The handler to add. - """ - self.handler = handler - if len( self.logger.handlers ) == 0: - self.logger.addHandler( handler ) - else: - self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler'" - " to True during the filter initialization." ) + # Logger. + self.logger: Logger = getLogger( loggerTitle ) def GetQualityMetricSummary( self: Self ) -> QualityMetricSummary: """Get QualityMetricSummary object. @@ -322,14 +298,10 @@ def getOutput( self: Self ) -> vtkUnstructuredGrid: def _computeCellTypeCounts( self: Self ) -> None: """Compute cell type counts.""" - cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( - self._outputMesh, self.speHandler ) - if self.speHandler and len( cellTypeCounterEnhancedFilter.logger.handlers ) == 0: - cellTypeCounterEnhancedFilter.setLoggerHandler( self.handler ) - if not cellTypeCounterEnhancedFilter.applyFilter(): + if not self.cellTypeCounterEnhancedFilter.applyFilter(): raise - counts: CellTypeCounts = cellTypeCounterEnhancedFilter.GetCellTypeCountsObject() + counts: CellTypeCounts = self.cellTypeCounterEnhancedFilter.GetCellTypeCountsObject() if counts is None: raise AttributeError( "CellTypeCounts is undefined" ) diff --git a/geos-pv/pyproject.toml b/geos-pv/pyproject.toml index 7a79bc45e..a943ee653 100644 --- a/geos-pv/pyproject.toml +++ b/geos-pv/pyproject.toml @@ -9,7 +9,9 @@ description = "geos-pv is a Python package that gathers Paraview plugins and ded authors = [{name = "GEOS Contributors" }] maintainers = [{name = "Alexandre Benedicto", email = "alexandre.benedicto@external.totalenergies.com" }, {name = "Romain Baville", email = "romain.baville@external.totalenergies.com" }, - {name = "Paloma Martinez", email = "paloma.martinez@external.totalenergies.com" }] + {name = "Paloma Martinez", email = "paloma.martinez@external.totalenergies.com" }, + {name = "Jacques Franc", email = "jacques.franc@external.totalenergies.com" }, + ] license = {text = "Apache-2.0"} classifiers = [ "Development Status :: 4 - Beta", diff --git a/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py b/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py index a8dfc28c2..b09642df6 100644 --- a/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py +++ b/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py @@ -14,13 +14,11 @@ update_paths() -from geos.processing.generic_processing_tools.AttributeMapping import AttributeMapping +from geos.processing.generic_processing_tools.AttributeMapping import AttributeMapping, loggerTitle +from geos.utils.Logger import addPluginLogSupport from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy, ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, -) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py from vtkmodules.vtkCommonCore import ( vtkInformation, @@ -69,6 +67,7 @@ dataTypes=[ "vtkDataSet", "vtkMultiBlockDataSet" ], composite_data_supported=True, ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVAttributeMapping( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -189,10 +188,7 @@ def RequestData( outData.ShallowCopy( meshTo ) attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, outData, set( self.attributeNames ), - self.onPoints, True ) - - if not attributeMappingFilter.logger.hasHandlers(): - attributeMappingFilter.setLoggerHandler( VTKHandler() ) + self.onPoints ) attributeMappingFilter.applyFilter() self.clearAttributeNames = True diff --git a/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py b/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py index ad237bd83..4bb4ecc71 100644 --- a/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py +++ b/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py @@ -9,7 +9,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy ) -from paraview.detail.loghandler import VTKHandler # type: ignore[import-not-found] from vtkmodules.vtkCommonCore import vtkInformation, vtkInformationVector from vtkmodules.vtkCommonDataModel import vtkPointSet, vtkTable @@ -21,8 +20,9 @@ update_paths() -from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced +from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced, loggerTitle from geos.mesh.model.CellTypeCounts import CellTypeCounts +from geos.utils.Logger import addPluginLogSupport __doc__ = """ The ``Cell Type Counter Enhanced`` filter computes cell type counts. Counts can be exported into a file easily. @@ -43,6 +43,7 @@ dataTypes=[ "vtkUnstructuredGrid" ], composite_data_supported=True, ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVCellTypeCounterEnhanced( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -132,9 +133,7 @@ def RequestData( assert inputMesh is not None, "Input server mesh is null." assert outputTable is not None, "Output pipeline is null." - cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( inputMesh, True ) - if len( cellTypeCounterEnhancedFilter.logger.handlers ) == 0: - cellTypeCounterEnhancedFilter.setLoggerHandler( VTKHandler() ) + cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( inputMesh ) if cellTypeCounterEnhancedFilter.applyFilter(): outputTable.ShallowCopy( cellTypeCounterEnhancedFilter.getOutput() ) diff --git a/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py b/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py index 1e52b0509..43d9201f4 100644 --- a/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py +++ b/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py @@ -8,9 +8,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, ) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, -) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py from vtkmodules.vtkCommonDataModel import ( vtkMultiBlockDataSet, ) @@ -23,7 +20,8 @@ update_paths() from geos.pv.utils.details import ( SISOFilter, FilterCategory ) -from geos.processing.generic_processing_tools.ClipToMainFrame import ClipToMainFrame +from geos.processing.generic_processing_tools.ClipToMainFrame import ClipToMainFrame, loggerTitle, getLogger +from geos.utils.Logger import Logger, addPluginLogSupport __doc__ = """ Clip the input mesh to the main frame applying the correct LandmarkTransform @@ -39,13 +37,13 @@ @SISOFilter( category=FilterCategory.GEOS_UTILS, decoratedLabel="Clip to the main frame", decoratedType=[ "vtkMultiBlockDataSet", "vtkDataSet" ] ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVClipToMainFrame( VTKPythonAlgorithmBase ): def __init__( self ) -> None: """Init motherclass, filter and logger.""" - self._realFilter = ClipToMainFrame( speHandler=True ) - if not self._realFilter.logger.hasHandlers(): - self._realFilter.SetLoggerHandler( VTKHandler() ) + self._realFilter = ClipToMainFrame() + self.logger: Logger = getLogger( loggerTitle ) def ApplyFilter( self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMultiBlockDataSet ) -> None: """Is applying CreateConstantAttributePerRegion filter. @@ -55,6 +53,8 @@ def ApplyFilter( self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMultiBloc outputMesh : A mesh transformed. """ # struct + self.logger.info( f"Applying plugin {self.logger.name}." ) + self._realFilter.SetInputData( inputMesh ) self._realFilter.ComputeTransform() self._realFilter.Update() diff --git a/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py b/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py index 895df71e5..e7ca6e63b 100644 --- a/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py +++ b/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py @@ -12,9 +12,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smproperty, ) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, -) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py import vtkmodules.util.numpy_support as vnp @@ -28,7 +25,8 @@ update_paths() -from geos.processing.generic_processing_tools.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion +from geos.processing.generic_processing_tools.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion, loggerTitle +from geos.utils.Logger import addPluginLogSupport from geos.pv.utils.details import SISOFilter, FilterCategory @@ -57,6 +55,7 @@ @SISOFilter( category=FilterCategory.GEOS_PROP, decoratedLabel="Create Constant Attribute Per Region", decoratedType=[ "vtkMultiBlockDataSet", "vtkDataSet" ] ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVCreateConstantAttributePerRegion( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -73,9 +72,6 @@ def __init__( self: Self ) -> None: self.nbComponents: int = 1 self.componentNames: tuple[ str, ...] = () - # Use the handler of paraview for the log. - self.speHandler: bool = True - # Settings of the attribute with the region indexes: @smproperty.stringvector( name="ChooseRegionAttribute", @@ -291,12 +287,8 @@ def ApplyFilter( self, inputMesh: vtkDataSet, outputMesh: vtkDataSet ) -> None: self.valueNpType, self.nbComponents, self.componentNames, - self.speHandler, ) - if not createConstantAttributePerRegionFilter.logger.hasHandlers(): - createConstantAttributePerRegionFilter.setLoggerHandler( VTKHandler() ) - createConstantAttributePerRegionFilter.applyFilter() self.clearDictRegion = True diff --git a/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py b/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py index 80d8fb937..4a7971ce6 100644 --- a/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py +++ b/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py @@ -10,10 +10,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smproperty, ) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, -) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py - from vtkmodules.vtkCommonDataModel import ( vtkMultiBlockDataSet, ) @@ -25,7 +21,9 @@ update_paths() from geos.pv.utils.details import SISOFilter, FilterCategory -from geos.processing.generic_processing_tools.FillPartialArrays import FillPartialArrays +from geos.processing.generic_processing_tools.FillPartialArrays import FillPartialArrays, loggerTitle + +from geos.utils.Logger import addPluginLogSupport __doc__ = """ Fill partial arrays of input mesh. @@ -46,6 +44,7 @@ @SISOFilter( category=FilterCategory.GEOS_UTILS, decoratedLabel="Fill Partial Arrays", decoratedType="vtkMultiBlockDataSet" ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVFillPartialArrays( VTKPythonAlgorithmBase ): def __init__( self: Self, ) -> None: @@ -105,12 +104,8 @@ def ApplyFilter( self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMultiBloc fillPartialArraysFilter: FillPartialArrays = FillPartialArrays( outputMesh, self.dictAttributesValues, - speHandler=True, ) - if not fillPartialArraysFilter.logger.hasHandlers(): - fillPartialArraysFilter.setLoggerHandler( VTKHandler() ) - fillPartialArraysFilter.applyFilter() self.clearDictAttributesValues = True diff --git a/geos-pv/src/geos/pv/plugins/PVGeomechanicsCalculator.py b/geos-pv/src/geos/pv/plugins/PVGeomechanicsCalculator.py index 829eeaa91..cae518611 100644 --- a/geos-pv/src/geos/pv/plugins/PVGeomechanicsCalculator.py +++ b/geos-pv/src/geos/pv/plugins/PVGeomechanicsCalculator.py @@ -11,9 +11,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smproperty ) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler -) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py from vtkmodules.vtkCommonDataModel import ( vtkUnstructuredGrid, vtkMultiBlockDataSet ) @@ -31,8 +28,9 @@ WATER_DENSITY, ) from geos.mesh.utils.multiblockHelpers import ( getBlockElementIndexesFlatten, getBlockNameFromIndex ) -from geos.processing.post_processing.GeomechanicsCalculator import GeomechanicsCalculator +from geos.processing.post_processing.GeomechanicsCalculator import GeomechanicsCalculator, loggerTitle from geos.pv.utils.details import ( SISOFilter, FilterCategory ) +from geos.utils.Logger import addPluginLogSupport __doc__ = """ PVGeomechanicsCalculator is a paraview plugin that allows to compute additional geomechanics properties from existing ones in the mesh. @@ -81,6 +79,7 @@ @SISOFilter( category=FilterCategory.GEOS_GEOMECHANICS, decoratedLabel="GEOS Geomechanics Calculator", decoratedType=[ "vtkUnstructuredGrid", "vtkMultiBlockDataSet" ] ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVGeomechanicsCalculator( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -244,11 +243,10 @@ def ApplyFilter( geomechanicsCalculatorFilter = GeomechanicsCalculator( outputMesh, self.computeAdvancedProperties, - speHandler=True, ) - if not geomechanicsCalculatorFilter.logger.hasHandlers(): - geomechanicsCalculatorFilter.setLoggerHandler( VTKHandler() ) + # if not geomechanicsCalculatorFilter.logger.hasHandlers(): + # geomechanicsCalculatorFilter.setLoggerHandler( GEOSHandler() ) geomechanicsCalculatorFilter.physicalConstants.grainBulkModulus = self.grainBulkModulus geomechanicsCalculatorFilter.physicalConstants.specificDensity = self.specificDensity @@ -262,18 +260,16 @@ def ApplyFilter( for blockIndex in volumeBlockIndexes: volumeBlock: vtkUnstructuredGrid = vtkUnstructuredGrid.SafeDownCast( outputMesh.GetDataSet( blockIndex ) ) - volumeBlockName: str = getBlockNameFromIndex( outputMesh, blockIndex ) - filterName: str = f"Geomechanics Calculator for the block { volumeBlockName }" + # volumeBlockName: str = getBlockNameFromIndex( outputMesh, blockIndex ) + # filterName: str = f"Geomechanics Calculator for the block { volumeBlockName }" geomechanicsCalculatorFilter = GeomechanicsCalculator( volumeBlock, self.computeAdvancedProperties, - filterName, - True, ) - if not geomechanicsCalculatorFilter.logger.hasHandlers(): - geomechanicsCalculatorFilter.setLoggerHandler( VTKHandler() ) + # if not geomechanicsCalculatorFilter.logger.hasHandlers(): + # geomechanicsCalculatorFilter.setLoggerHandler( GEOSHandler() ) geomechanicsCalculatorFilter.physicalConstants.grainBulkModulus = self.grainBulkModulus geomechanicsCalculatorFilter.physicalConstants.specificDensity = self.specificDensity diff --git a/geos-pv/src/geos/pv/plugins/PVGeomechanicsWorkflow.py b/geos-pv/src/geos/pv/plugins/PVGeomechanicsWorkflow.py index 992a73020..4617c585d 100644 --- a/geos-pv/src/geos/pv/plugins/PVGeomechanicsWorkflow.py +++ b/geos-pv/src/geos/pv/plugins/PVGeomechanicsWorkflow.py @@ -31,8 +31,8 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smproperty, smproxy ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler ) + +from geos.utils.Logger import GEOSHandler __doc__ = """ PVGeomechanicsWorkflow is a Paraview plugin that executes multiple plugins: @@ -141,7 +141,7 @@ def __init__( self: Self ) -> None: self.logger = logging.getLogger( loggerTitle ) self.logger.setLevel( logging.INFO ) - self.logger.addHandler( VTKHandler() ) + self.logger.addHandler( GEOSHandler() ) self.logger.info( f"Apply plugin { self.logger.name }." ) diff --git a/geos-pv/src/geos/pv/plugins/PVGeosBlockExtractAndMerge.py b/geos-pv/src/geos/pv/plugins/PVGeosBlockExtractAndMerge.py index c779c5eb1..7b054cb4c 100644 --- a/geos-pv/src/geos/pv/plugins/PVGeosBlockExtractAndMerge.py +++ b/geos-pv/src/geos/pv/plugins/PVGeosBlockExtractAndMerge.py @@ -32,8 +32,7 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smproperty, smproxy ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler ) +from geos.utils.Logger import GEOSHandler __doc__ = """ PVGeosBlockExtractAndMerge is a Paraview plugin processing the input mesh at the current time in two steps: @@ -116,7 +115,7 @@ def __init__( self: Self ) -> None: self.logger = logging.getLogger( loggerTitle ) self.logger.setLevel( logging.INFO ) - self.logger.addHandler( VTKHandler() ) + self.logger.addHandler( GEOSHandler() ) self.logger.propagate = False self.logger.info( f"Apply plugin { self.logger.name }." ) diff --git a/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py b/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py index 3ebcd7ebb..22760a271 100644 --- a/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py +++ b/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py @@ -10,8 +10,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy, ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, ) from vtkmodules.vtkCommonCore import ( vtkInformation, vtkInformationVector, @@ -29,7 +27,8 @@ update_paths() -from geos.processing.generic_processing_tools.MergeBlockEnhanced import MergeBlockEnhanced +from geos.processing.generic_processing_tools.MergeBlockEnhanced import MergeBlockEnhanced, loggerTitle +from geos.utils.Logger import addPluginLogSupport __doc__ = """ Merge Blocks Keeping Partial Attributes is a Paraview plugin filter that allows to merge blocks from a multiblock dataset while keeping partial attributes. @@ -60,6 +59,7 @@ @smhint.xml( '' ) @smproperty.input( name="Input", port_index=0, label="Input" ) @smdomain.datatype( dataTypes=[ "vtkMultiBlockDataSet" ], composite_data_supported=True ) +@addPluginLogSupport( loggerTitles=[ loggerTitle, f"{loggerTitle}.vtkErrorLogger" ] ) class PVMergeBlocksEnhanced( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -117,10 +117,7 @@ def RequestData( assert inputMesh is not None, "Input mesh is null." assert outputMesh is not None, "Output pipeline is null." - mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( inputMesh, True ) - - if not mergeBlockEnhancedFilter.logger.hasHandlers(): - mergeBlockEnhancedFilter.setLoggerHandler( VTKHandler() ) + mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( inputMesh ) try: mergeBlockEnhancedFilter.applyFilter() diff --git a/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py b/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py index 9384f92fb..87a037258 100644 --- a/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py +++ b/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py @@ -8,7 +8,6 @@ from typing_extensions import Self, Optional from paraview.util.vtkAlgorithm import VTKPythonAlgorithmBase, smdomain, smproperty # type: ignore[import-not-found] -from paraview.detail.loghandler import VTKHandler # type: ignore[import-not-found] # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py from vtkmodules.vtkCommonCore import vtkDataArraySelection @@ -22,7 +21,8 @@ update_paths() from geos.mesh.model.QualityMetricSummary import QualityMetricSummary -from geos.processing.pre_processing.MeshQualityEnhanced import MeshQualityEnhanced +from geos.processing.pre_processing.MeshQualityEnhanced import MeshQualityEnhanced, loggerTitle +from geos.processing.pre_processing.CellTypeCounterEnhanced import loggerTitle as cloggerTitle from geos.mesh.stats.meshQualityMetricHelpers import ( getQualityMetricsOther, getQualityMeasureNameFromIndex, getQualityMeasureIndexFromName, getQuadQualityMeasure, getTriangleQualityMeasure, getCommonPolygonQualityMeasure, @@ -32,6 +32,7 @@ from geos.pv.utils.checkboxFunction import createModifiedCallback # type: ignore[attr-defined] from geos.pv.utils.paraviewTreatments import getArrayChoices from geos.pv.utils.details import ( SISOFilter, FilterCategory ) +from geos.utils.Logger import addPluginLogSupport, GEOSHandler __doc__ = """ The ``Mesh Quality Enhanced`` filter computes requested mesh quality metrics on meshes. Both surfaces and volumic metrics can be computed with this plugin. @@ -59,6 +60,7 @@ @SISOFilter( category=FilterCategory.GEOS_QC, decoratedLabel="Mesh Quality Enhanced", decoratedType="vtkUnstructuredGrid" ) +@addPluginLogSupport( loggerTitles=[ loggerTitle, cloggerTitle ] ) class PVMeshQualityEnhanced( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -228,9 +230,7 @@ def ApplyFilter( self, inputMesh: vtkUnstructuredGrid, outputMesh: vtkUnstructur self._getQualityMetricsToUse( self._HexQualityMetric ) ) otherMetrics: set[ int ] = self._getQualityMetricsToUse( self._commonMeshQualityMetric ) - meshQualityEnhancedFilter: MeshQualityEnhanced = MeshQualityEnhanced( inputMesh, True ) - if len( meshQualityEnhancedFilter.logger.handlers ) == 0: - meshQualityEnhancedFilter.setLoggerHandler( VTKHandler() ) + meshQualityEnhancedFilter: MeshQualityEnhanced = MeshQualityEnhanced( inputMesh ) meshQualityEnhancedFilter.SetCellQualityMetrics( triangleMetrics=triangleMetrics, quadMetrics=quadMetrics, tetraMetrics=tetraMetrics, diff --git a/geos-pv/src/geos/pv/plugins/PVMohrCirclePlot.py b/geos-pv/src/geos/pv/plugins/PVMohrCirclePlot.py index d6efdfd57..791f01802 100644 --- a/geos-pv/src/geos/pv/plugins/PVMohrCirclePlot.py +++ b/geos-pv/src/geos/pv/plugins/PVMohrCirclePlot.py @@ -15,8 +15,7 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy, ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, ) + from typing_extensions import Self from vtkmodules.vtkCommonCore import vtkDataArraySelection as vtkDAS @@ -31,13 +30,12 @@ update_paths() -from geos.geomechanics.model.MohrCircle import MohrCircle +from geos.geomechanics.model.MohrCircle import MohrCircle, loggerTitle from geos.utils.enumUnits import Pressure, enumerationDomainUnit from geos.utils.GeosOutputsConstants import ( FAILURE_ENVELOPE, GeosMeshOutputsEnum, ) -from geos.utils.Logger import CustomLoggerFormatter from geos.utils.PhysicalConstants import ( DEFAULT_FRICTION_ANGLE_DEG, DEFAULT_FRICTION_ANGLE_RAD, @@ -61,6 +59,7 @@ optionEnumToXml, ) from geos.pv.utils.mohrCircles.functionsMohrCircle import StressConventionEnum +from geos.utils.Logger import ( addPluginLogSupport, getLogger ) __doc__ = """ PVMohrCirclePlot is a ParaView plugin that allows to compute and plot @@ -112,6 +111,7 @@ dataTypes=[ "vtkUnstructuredGrid" ], composite_data_supported=False, ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVMohrCirclePlot( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -185,15 +185,7 @@ def __init__( self: Self ) -> None: # Request data processing step - incremented each time RequestUpdateExtent is called self.requestDataStep: int = -1 - - # Logger - self.logger: logging.Logger = logging.getLogger( "MohrCircle" ) - self.logger.setLevel( logging.INFO ) - if not self.logger.hasHandlers(): - handler = VTKHandler() - handler.setFormatter( CustomLoggerFormatter( False ) ) - - self.logger.addHandler( handler ) + self.logger: Logger = getLogger( loggerTitle ) @smproperty.xml( """ None: @@ -50,9 +51,7 @@ def ApplyFilter( self: Self, inputMesh: vtkPointSet, outputMesh: vtkPointSet ) - inputMesh(vtkPointSet): Input mesh. outputMesh: Output mesh. """ - splitMeshFilter: SplitMesh = SplitMesh( inputMesh, True ) - if len( splitMeshFilter.logger.handlers ) == 0: - splitMeshFilter.setLoggerHandler( VTKHandler() ) + splitMeshFilter: SplitMesh = SplitMesh( inputMesh ) if splitMeshFilter.applyFilter(): outputMesh.ShallowCopy( splitMeshFilter.getOutput() ) diff --git a/geos-pv/src/geos/pv/plugins/PVSurfaceGeomechanics.py b/geos-pv/src/geos/pv/plugins/PVSurfaceGeomechanics.py index 3999d620c..c26395fb3 100644 --- a/geos-pv/src/geos/pv/plugins/PVSurfaceGeomechanics.py +++ b/geos-pv/src/geos/pv/plugins/PVSurfaceGeomechanics.py @@ -10,8 +10,6 @@ from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found] VTKPythonAlgorithmBase, smdomain, smproperty, ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, ) # update sys.path to load all GEOS Python Package dependencies geos_pv_path: Path = Path( __file__ ).parent.parent.parent.parent.parent @@ -25,7 +23,9 @@ DEFAULT_FRICTION_ANGLE_DEG, DEFAULT_ROCK_COHESION, ) -from geos.processing.post_processing.SurfaceGeomechanics import SurfaceGeomechanics +from geos.processing.post_processing.SurfaceGeomechanics import SurfaceGeomechanics, loggerTitle +from geos.utils.Logger import addPluginLogSupport + from geos.mesh.utils.multiblockHelpers import ( getBlockElementIndexesFlatten, getBlockFromFlatIndex, @@ -62,6 +62,7 @@ @SISOFilter( category=FilterCategory.GEOS_GEOMECHANICS, decoratedLabel="Geos Surface Geomechanics", decoratedType="vtkMultiBlockDataSet" ) +@addPluginLogSupport( loggerTitles=[ loggerTitle ] ) class PVSurfaceGeomechanics( VTKPythonAlgorithmBase ): def __init__( self: Self ) -> None: @@ -129,10 +130,8 @@ def ApplyFilter( self: Self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMul for blockIndex in surfaceBlockIndexes: surfaceBlock: vtkPolyData = vtkPolyData.SafeDownCast( getBlockFromFlatIndex( outputMesh, blockIndex ) ) - sgFilter: SurfaceGeomechanics = SurfaceGeomechanics( surfaceBlock, True ) + sgFilter: SurfaceGeomechanics = SurfaceGeomechanics( surfaceBlock ) sgFilter.SetSurfaceName( f"blockIndex {blockIndex}" ) - if not sgFilter.logger.hasHandlers(): - sgFilter.SetLoggerHandler( VTKHandler() ) sgFilter.SetRockCohesion( self._getRockCohesion() ) sgFilter.SetFrictionAngle( self._getFrictionAngle() ) diff --git a/geos-pv/src/geos/pv/pythonViewUtils/Figure2DGenerator.py b/geos-pv/src/geos/pv/pythonViewUtils/Figure2DGenerator.py index 00eceded7..a04a24a99 100755 --- a/geos-pv/src/geos/pv/pythonViewUtils/Figure2DGenerator.py +++ b/geos-pv/src/geos/pv/pythonViewUtils/Figure2DGenerator.py @@ -129,7 +129,7 @@ def changeAxisLimits( self: Self ) -> None: ax.set_ylim( ymin, ymax ) def getFigure( self: Self ) -> figure.Figure: - """access the m_fig attribute. + """Access the m_fig attribute. Returns: figure.Figure: Figure containing all the plots. diff --git a/geos-pv/src/geos/pv/pythonViewUtils/functionsFigure2DGenerator.py b/geos-pv/src/geos/pv/pythonViewUtils/functionsFigure2DGenerator.py index 113953416..c0077180f 100755 --- a/geos-pv/src/geos/pv/pythonViewUtils/functionsFigure2DGenerator.py +++ b/geos-pv/src/geos/pv/pythonViewUtils/functionsFigure2DGenerator.py @@ -615,7 +615,8 @@ def propertiesPerIdentifier( propertyNames: list[ str ] ) -> dict[ str, list[ st Args: propertyNames (list[str]): Property names. - Example + + Example: .. code-block:: python @@ -628,7 +629,8 @@ def propertiesPerIdentifier( propertyNames: list[ str ] ) -> dict[ str, list[ st Returns: dict[str, list[str]]: Property identifiers. - Example + + Example: .. code-block:: python @@ -663,7 +665,8 @@ def associationIdentifiers( propertyNames: list[ str ] ) -> dict[ str, dict[ str Args: propertyNames (list[str]): Property names. - Example + + Example: .. code-block:: python @@ -692,7 +695,8 @@ def associationIdentifiers( propertyNames: list[ str ] ) -> dict[ str, dict[ str Returns: dict[str, dict[str, list[str]]]: Property identifiers. - Example + + Example: .. code-block:: python @@ -1303,7 +1307,6 @@ def findPhasesLabel( label: str ) -> list[ str ]: # if legendLabel.startswith(pattern): # return legendLabel[len(pattern):] # return legendLabel - """ Other 2D tools for simplest figures """ diff --git a/geos-pv/src/geos/pv/utils/paraviewTreatments.py b/geos-pv/src/geos/pv/utils/paraviewTreatments.py index 36aad6b1b..72a17d9aa 100644 --- a/geos-pv/src/geos/pv/utils/paraviewTreatments.py +++ b/geos-pv/src/geos/pv/utils/paraviewTreatments.py @@ -8,13 +8,11 @@ import numpy as np import numpy.typing as npt -import pandas as pd # type: ignore[import-untyped] +import pandas as pd # type: ignore[import-untypedGEOSFormatter ] from paraview.simple import ( # type: ignore[import-not-found] FindSource, GetActiveView, GetAnimationScene, GetDisplayProperties, GetSources, servermanager, ) -from paraview.detail.loghandler import ( # type: ignore[import-not-found] - VTKHandler, ) import vtkmodules.util.numpy_support as vnp from vtkmodules.vtkCommonCore import ( vtkDataArray, @@ -37,7 +35,7 @@ ComponentNameEnum, GeosMeshOutputsEnum, ) -from geos.utils.Logger import ( CustomLoggerFormatter ) +from geos.utils.Logger import ( GEOSFormatter, GEOSHandler ) from geos.mesh.utils.multiblockModifiers import mergeBlocks # valid sources for Python view configurator @@ -487,8 +485,8 @@ def getVtkOriginalCellIds( mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSe logger = logging.getLogger( "getVtkOriginalCellIds" ) if not logger.hasHandlers(): - handler = VTKHandler() - handler.setFormatter( CustomLoggerFormatter( False ) ) + handler = GEOSHandler() + handler.setFormatter( GEOSFormatter() ) logger.addHandler( handler ) # Merge blocks for vtkCompositeDataSet diff --git a/geos-pv/src/geos/pv/utils/workflowFunctions.py b/geos-pv/src/geos/pv/utils/workflowFunctions.py index 28602fce0..23804d566 100644 --- a/geos-pv/src/geos/pv/utils/workflowFunctions.py +++ b/geos-pv/src/geos/pv/utils/workflowFunctions.py @@ -8,7 +8,7 @@ from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet -from paraview.detail.loghandler import ( VTKHandler ) # type: ignore[import-not-found] +from geos.utils.Logger import GEOSHandler def doExtractAndMerge( @@ -35,7 +35,7 @@ def doExtractAndMerge( extractWell=extractWell, speHandler=True ) if not blockExtractor.logger.hasHandlers(): - blockExtractor.setLoggerHandler( VTKHandler() ) + blockExtractor.setLoggerHandler( GEOSHandler() ) blockExtractor.applyFilter() # recover output objects from GeosBlockExtractor filter and merge internal blocks @@ -76,7 +76,7 @@ def mergeBlocksFilter( loggerName = f"GEOS Block Merge for the domain { domainToMerge }." mergeBlockFilter: GeosBlockMerge = GeosBlockMerge( mesh, convertSurfaces, True, loggerName ) if not mergeBlockFilter.logger.hasHandlers(): - mergeBlockFilter.setLoggerHandler( VTKHandler() ) + mergeBlockFilter.setLoggerHandler( GEOSHandler() ) mergeBlockFilter.applyFilter() mergedBlocks: vtkMultiBlockDataSet = vtkMultiBlockDataSet() mergedBlocks.ShallowCopy( mergeBlockFilter.getOutput() ) diff --git a/geos-utils/pyproject.toml b/geos-utils/pyproject.toml index bc11980d8..947439145 100644 --- a/geos-utils/pyproject.toml +++ b/geos-utils/pyproject.toml @@ -17,7 +17,9 @@ description = "geos-utils is a Python package that gathers utilities common to a authors = [{name = "GEOS Contributors" }] maintainers = [{name = "Alexandre Benedicto", email = "alexandre.benedicto@external.totalenergies.com" }, {name = "Romain Baville", email = "romain.baville@external.totalenergies.com" }, - {name = "Paloma Martinez", email = "paloma.martinez@external.totalenergies.com" }] + {name = "Paloma Martinez", email = "paloma.martinez@external.totalenergies.com" }, + {name = "Jacques Franc", email = "jacques.franc@external.totalenergies.com" }, + ] license = {text = "Apache-2.0"} classifiers = [ "Development Status :: 4 - Beta", diff --git a/geos-utils/src/geos/utils/Logger.py b/geos-utils/src/geos/utils/Logger.py index 099ce9077..04a5209bd 100644 --- a/geos-utils/src/geos/utils/Logger.py +++ b/geos-utils/src/geos/utils/Logger.py @@ -2,14 +2,17 @@ # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. # SPDX-FileContributor: Martin Lemay, Romain Baville, Jacques Franc import logging -from typing import Any, Union, Generator +from typing import Any, Generator from typing_extensions import Self +from functools import wraps +from typing import Type, TypeVar, Callable import os import re import tempfile from contextlib import contextmanager +from vtkmodules.vtkCommonCore import vtkLogger from geos.utils.Errors import VTKError __doc__ = """ @@ -41,6 +44,36 @@ """ +## decorators +T = TypeVar( 'T' ) + + +def addPluginLogSupport( loggerTitles: list ) -> Callable[ [ Type[ T ] ], Type[ T ] ]: + """Decorator to add logger support in the class following existing architecture. + + Args: + loggerTitle (str): Title to display in the logger + """ + + def decorator( cls: Type[ T ] ) -> Type[ T ]: + original_init = cls.__init__ + + @wraps( original_init ) + def new_init( self: T, *args: Any, **kwargs: Any ) -> None: + original_init( self, *args, **kwargs ) + + for logger in loggerTitles: + for hdlr in list( filter( lambda x: not isinstance( x, GEOSHandler ), getLogger(logger).handlers ) ): + getLogger(logger).removeHandler( hdlr ) + + + + cls.__init__ = new_init # type: ignore[assignment] + + return cls + + return decorator + class RegexExceptionFilter( logging.Filter ): """Class to regexp VTK messages rethrown into logger by VTKCaptureLog. @@ -97,6 +130,7 @@ def VTKCaptureLog() -> Generator[ Any, Any, Any ]: os.close( savedStderrFd ) +## helpers class CountWarningHandler( logging.Handler ): """Create an handler to count the warnings logged.""" @@ -149,22 +183,8 @@ def results( self: logging.Logger, message: str, *args: Any, **kws: Any ) -> Non Logger = logging.Logger # logger type -class CustomLoggerFormatter( logging.Formatter ): - """Custom formatter for the logger. - - .. WARNING:: Colors do not work in the output message window of Paraview. - - To use it: +class GEOSFormatter( logging.Formatter ): - .. code-block:: python - - logger = logging.getLogger( "Logger name", use_color=False ) - # Ensure handler is added only once, e.g., by checking logger.handlers - if not logger.handlers: - ch = logging.StreamHandler() - ch.setFormatter(CustomLoggerFormatter()) - logger.addHandler(ch) - """ # define color codes green: str = "\x1b[32;20m" grey: str = "\x1b[38;20m" @@ -174,73 +194,75 @@ class CustomLoggerFormatter( logging.Formatter ): reset: str = "\x1b[0m" # define prefix of log messages - format1: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" - format2: str = ( "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" ) + format_short: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + format_long: str = ( "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" ) format_results: str = "%(name)s - %(levelname)s - %(message)s" - #: format for each logger output type with colors - FORMATS_COLOR: dict[ int, str ] = { - DEBUG: grey + format2 + reset, - INFO: green + format1 + reset, - WARNING: yellow + format1 + reset, - ERROR: red + format1 + reset, - CRITICAL: bold_red + format2 + reset, - RESULTS_LEVEL_NUM: green + format_results + reset, - } - #: format for each logger output type without colors (e.g., for Paraview) - FORMATS_PLAIN: dict[ int, str ] = { - DEBUG: format2, - INFO: format1, - WARNING: format1, - ERROR: format1, - CRITICAL: format2, - RESULTS_LEVEL_NUM: format_results, - } - - # Pre-compiled formatters for efficiency - _compiled_formatters: dict[ int, logging.Formatter ] = { - level: logging.Formatter( fmt ) - for level, fmt in FORMATS_PLAIN.items() + _formatDict: dict[ int, str ] = { + DEBUG: grey + format_long + reset, + INFO: green + format_short + reset, + WARNING: yellow + format_short + reset, + ERROR: red + format_short + reset, + CRITICAL: bold_red + format_long + reset, + RESULTS_LEVEL_NUM: green + format_results + reset, } - _compiled_color_formatters: dict[ int, logging.Formatter ] = { - level: logging.Formatter( fmt ) - for level, fmt in FORMATS_COLOR.items() - } + def format( self: Self, record: logging.LogRecord ) -> str: + """Fomat using the above described format in color and style.""" + return logging.Formatter( fmt=self._formatDict.get( record.levelno ) ).format( record ) + + @staticmethod + def TrimColor( msg: str ) -> str: + """Helper function to discard bash color tag when throwing to vtk logger logic (C/C++).""" + return msg[ 8:-4 ] + + +class GEOSHandler( logging.StreamHandler ): + + @staticmethod + def get_vtk_level( level: int ) -> int: + """Translate logging levels to vtk taxonomy.""" + if level >= ERROR: + return vtkLogger.VERBOSITY_ERROR + elif level >= WARNING: + return vtkLogger.VERBOSITY_WARNING + elif level >= INFO: + return vtkLogger.VERBOSITY_INFO + elif level >= DEBUG: + return vtkLogger.VERBOSITY_TRACE + else: + return vtkLogger.VERBOSITY_MAX - def __init__( self: Self, use_color: bool = False ) -> None: - """Initialize the log formatter. + def emit( self: Self, record: logging.LogRecord ) -> None: + """Overload of emit to display in the Command Output windows UI.""" + try: + msg = self.format( record ) + lvl = GEOSHandler.get_vtk_level( record.levelno ) - Args: - use_color (bool): If True, use color-coded log formatters. - Defaults to False. - """ - super().__init__() - if use_color: - self.active_formatters = self._compiled_color_formatters - else: - self.active_formatters = self._compiled_formatters + from vtkmodules.vtkCommonCore import vtkOutputWindow as win + outwin = win.GetInstance() + if outwin: + #see https://www.paraview.org/paraview-docs/v5.13.3/python/_modules/paraview/detail/loghandler.html#VTKHandler + prevMode = outwin.GetDisplayMode() + outwin.SetDisplayModeToNever() - def format( self: Self, record: logging.LogRecord ) -> str: - """Return the format according to input record. + if lvl == vtkLogger.VERBOSITY_ERROR: + outwin.DisplayErrorText( GEOSFormatter.TrimColor( msg ) ) + elif lvl == vtkLogger.VERBOSITY_WARNING: + outwin.DisplayWarningText( GEOSFormatter.TrimColor( msg ) ) + elif lvl == vtkLogger.VERBOSITY_INFO: + outwin.DisplayText( GEOSFormatter.TrimColor( msg ) ) + elif lvl == vtkLogger.VERBOSITY_TRACE: + outwin.DisplayDebugText( GEOSFormatter.TrimColor( msg ) ) - Args: - record (logging.LogRecord): record + outwin.SetDisplayMode( prevMode ) - Returns: - str: format as a string - """ - # Defaulting to plain formatters as per original logic - log_fmt_obj: Union[ logging.Formatter, None ] = self.active_formatters.get( record.levelno ) - if log_fmt_obj: - return log_fmt_obj.format( record ) - else: - # Fallback for unknown levels or if a level is missing in the map - return logging.Formatter().format( record ) + except Exception: + self.handleError( record ) -def getLogger( title: str, use_color: bool = False ) -> Logger: +def getLogger( title: str ) -> Logger: """Return the Logger with pre-defined configuration. This function is now idempotent regarding handler addition. @@ -276,13 +298,21 @@ def getLogger( title: str, use_color: bool = False ) -> Logger: logger = logging.getLogger( title ) # Only configure the logger (add handlers, set level) if it hasn't been configured before. if len( logger.handlers ) == 0: - logger.setLevel( INFO ) # Set the desired default level for this logger + logger.setLevel( DEBUG ) # Set the desired default level for this logger # Create and add the stream handler - ch = logging.StreamHandler() - ch.setFormatter( CustomLoggerFormatter( use_color ) ) # Use your custom formatter - logger.addHandler( ch ) + geos_handler = GEOSHandler() + geos_handler.setFormatter( GEOSFormatter() ) + geos_handler.setLevel( logger.getEffectiveLevel() ) + logger.addHandler( geos_handler ) + + cli_handle = logging.StreamHandler() + cli_handle.setFormatter( GEOSFormatter() ) + cli_handle.setLevel( logger.getEffectiveLevel() ) + logger.addHandler( cli_handle ) + # Optional: Prevent messages from propagating to the root logger's handlers - logger.propagate = False + logger.propagate = True + # If you need to ensure a certain level is set every time getLogger is called, # even if handlers were already present, you can set the level outside the 'if' block. # However, typically, setLevel is part of the initial handler configuration.