mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Python: add type hinting to python code.
Types are checked using mypy. Fixes #10394.
This commit is contained in:
parent
b1157436fe
commit
7aabe8c4a8
12
.github/workflows/AppFwkUnitTest.yml
vendored
12
.github/workflows/AppFwkUnitTest.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
run: |
|
||||
execute_process(
|
||||
COMMAND cmake
|
||||
-S Fwk/AppFwk
|
||||
-S Fwk
|
||||
-B cmakebuild
|
||||
-G Ninja
|
||||
RESULT_VARIABLE result
|
||||
@ -70,13 +70,13 @@ jobs:
|
||||
- name: Run Unit Tests
|
||||
shell: bash
|
||||
run: |
|
||||
cmakebuild/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCore_UnitTests
|
||||
cmakebuild/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXml_UnitTests
|
||||
cmakebuild/cafProjectDataModel/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests
|
||||
cmakebuild/cafPdmScripting/cafPdmScripting_UnitTests/cafPdmScripting_UnitTests
|
||||
cmakebuild/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCore_UnitTests
|
||||
cmakebuild/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXml_UnitTests
|
||||
cmakebuild/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests
|
||||
cmakebuild/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests/cafPdmScripting_UnitTests
|
||||
|
||||
- name: Run Unit Tests Windows (does not work on Linux)
|
||||
if: contains( matrix.os, 'windows')
|
||||
shell: bash
|
||||
run: |
|
||||
cmakebuild/cafUserInterface/cafUserInterface_UnitTests/cafUserInterface_UnitTests
|
||||
cmakebuild/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafUserInterface_UnitTests
|
||||
|
8
.github/workflows/ResInsightWithCache.yml
vendored
8
.github/workflows/ResInsightWithCache.yml
vendored
@ -230,6 +230,14 @@ jobs:
|
||||
run: |
|
||||
cmakebuild/ApplicationExeCode/ResInsight --unittest
|
||||
|
||||
- name: (Python) Check types using mypy
|
||||
if: matrix.config.build-python-module
|
||||
shell: bash
|
||||
run: |
|
||||
${{ steps.python-path.outputs.PYTHON_EXECUTABLE }} -m pip install mypy types-protobuf
|
||||
cd GrpcInterface/Python/rips
|
||||
${{ steps.python-path.outputs.PYTHON_EXECUTABLE }} -m mypy *.py generated/generated_classes.py
|
||||
|
||||
- name: Run pytest
|
||||
if: matrix.config.build-python-module
|
||||
env:
|
||||
|
@ -16,8 +16,8 @@
|
||||
# Python version of RiaVersionInfo.h
|
||||
# Just sets version constants
|
||||
|
||||
RESINSIGHT_MAJOR_VERSION = "@RESINSIGHT_MAJOR_VERSION@"
|
||||
RESINSIGHT_MINOR_VERSION = "@RESINSIGHT_MINOR_VERSION@"
|
||||
RESINSIGHT_PATCH_VERSION = "@RESINSIGHT_PATCH_VERSION@"
|
||||
RESINSIGHT_MAJOR_VERSION : str = "@RESINSIGHT_MAJOR_VERSION@"
|
||||
RESINSIGHT_MINOR_VERSION : str = "@RESINSIGHT_MINOR_VERSION@"
|
||||
RESINSIGHT_PATCH_VERSION : str = "@RESINSIGHT_PATCH_VERSION@"
|
||||
|
||||
PYTHON_GRPC_PROTOC_VERSION = "@PYTHON_GRPC_PROTOC_VERSION@"
|
||||
PYTHON_GRPC_PROTOC_VERSION : str = "@PYTHON_GRPC_PROTOC_VERSION@"
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "RicVec3dPickEventHandler.h"
|
||||
|
||||
#include "cafCmdFeatureManager.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiPickableLineEditor.h"
|
||||
#include "cafPdmUiPushButtonEditor.h"
|
||||
#include "cafPdmUiTextEditor.h"
|
||||
@ -44,7 +45,7 @@ CAF_PDM_SOURCE_INIT( RimTextAnnotation, "RimTextAnnotation" );
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimTextAnnotation::RimTextAnnotation()
|
||||
{
|
||||
CAF_PDM_InitObject( "TextAnnotation", ":/TextAnnotation16x16.png" );
|
||||
CAF_PDM_InitScriptableObject( "TextAnnotation", ":/TextAnnotation16x16.png" );
|
||||
setUi3dEditorTypeName( RicTextAnnotation3dEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitField( &m_anchorPointXyd, "AnchorPointXyd", Vec3d::ZERO, "Anchor Point" );
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathValve.h"
|
||||
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiDateEditor.h"
|
||||
#include "cafPdmUiDoubleSliderEditor.h"
|
||||
|
||||
@ -42,7 +43,7 @@ CAF_PDM_SOURCE_INIT( RimPerforationInterval, "Perforation" );
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimPerforationInterval::RimPerforationInterval()
|
||||
{
|
||||
CAF_PDM_InitObject( "Perforation", ":/PerforationInterval16x16.png" );
|
||||
CAF_PDM_InitScriptableObject( "Perforation", ":/PerforationInterval16x16.png" );
|
||||
|
||||
CAF_PDM_InitField( &m_startMD, "StartMeasuredDepth", 0.0, "Start MD" );
|
||||
CAF_PDM_InitField( &m_endMD, "EndMeasuredDepth", 0.0, "End MD" );
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathFractureCollection.h"
|
||||
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiDoubleSliderEditor.h"
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimWellPathFracture, "WellPathFracture" );
|
||||
@ -35,7 +36,7 @@ CAF_PDM_SOURCE_INIT( RimWellPathFracture, "WellPathFracture" );
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellPathFracture::RimWellPathFracture()
|
||||
{
|
||||
CAF_PDM_InitObject( "Fracture", ":/FractureSymbol16x16.png" );
|
||||
CAF_PDM_InitScriptableObject( "Fracture", ":/FractureSymbol16x16.png" );
|
||||
|
||||
CAF_PDM_InitField( &m_measuredDepth, "MeasuredDepth", 0.0f, "Measured Depth Location" );
|
||||
m_measuredDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "RimColorLegendItem.h"
|
||||
|
||||
#include "cafPdmFieldReorderCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -34,7 +35,7 @@ CAF_PDM_SOURCE_INIT( RimColorLegend, "ColorLegend" );
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimColorLegend::RimColorLegend()
|
||||
{
|
||||
CAF_PDM_InitObject( "ColorLegend", ":/Legend.png" );
|
||||
CAF_PDM_InitScriptableObject( "ColorLegend", ":/Legend.png" );
|
||||
|
||||
CAF_PDM_InitField( &m_colorLegendName, "ColorLegendName", QString( "" ), "Color Legend Name" );
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "RimEclipseInputPropertyCollection.h"
|
||||
#include "RimReservoirCellResultsStorage.h"
|
||||
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafProgressInfo.h"
|
||||
|
||||
#include <QDir>
|
||||
@ -46,7 +47,7 @@ CAF_PDM_SOURCE_INIT( RimRoffCase, "RimRoffCase" );
|
||||
RimRoffCase::RimRoffCase()
|
||||
: RimEclipseCase()
|
||||
{
|
||||
CAF_PDM_InitObject( "RimRoffCase", ":/EclipseInput48x48.png" );
|
||||
CAF_PDM_InitScriptableObject( "RimRoffCase", ":/EclipseInput48x48.png" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -703,7 +703,6 @@ add_subdirectory(Fwk/AppFwk/cafPdmCvf)
|
||||
add_subdirectory(Fwk/AppFwk/CommonCode)
|
||||
add_subdirectory(Fwk/AppFwk/cafVizExtensions)
|
||||
|
||||
option(CAF_CVF_SCRIPTING "" ON)
|
||||
add_subdirectory(Fwk/AppFwk/cafPdmScripting)
|
||||
add_subdirectory(Fwk/AppFwk/cafCommandFeatures)
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
project(cafPdmScripting)
|
||||
|
||||
option(CAF_CVF_SCRIPTING "Enable CVF-data support in Scripting" OFF)
|
||||
|
||||
# Unity Build
|
||||
if(CAF_ENABLE_UNITY_BUILD)
|
||||
message("Cmake Unity build is enabled on : ${PROJECT_NAME}")
|
||||
@ -30,21 +28,13 @@ set(PROJECT_FILES
|
||||
cafPdmMarkdownGenerator.cpp
|
||||
cafPdmMarkdownBuilder.h
|
||||
cafPdmMarkdownBuilder.cpp
|
||||
)
|
||||
|
||||
set(CAF_LIBS cafProjectDataModel)
|
||||
|
||||
if(CAF_CVF_SCRIPTING)
|
||||
list(
|
||||
APPEND
|
||||
PROJECT_FILES
|
||||
cafPdmFieldScriptingCapabilityCvfColor3.h
|
||||
cafPdmFieldScriptingCapabilityCvfColor3.cpp
|
||||
cafPdmFieldScriptingCapabilityCvfVec3d.h
|
||||
cafPdmFieldScriptingCapabilityCvfVec3d.cpp
|
||||
)
|
||||
list(APPEND CAF_LIBS cafPdmCvf)
|
||||
endif()
|
||||
|
||||
set(CAF_LIBS cafProjectDataModel cafPdmCvf)
|
||||
|
||||
add_library(${PROJECT_NAME} ${PROJECT_FILES})
|
||||
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include "cafPdmAbstractFieldScriptingCapability.h"
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmChildField.h"
|
||||
#include "cafPdmFieldScriptingCapabilityCvfColor3.h"
|
||||
#include "cafPdmFieldScriptingCapabilityCvfVec3d.h"
|
||||
#include "cafPdmObject.h"
|
||||
#include "cafPdmObjectFactory.h"
|
||||
#include "cafPdmObjectMethod.h"
|
||||
@ -135,10 +137,10 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
auto pdmChildArrayField = dynamic_cast<const PdmChildArrayFieldHandle*>( field );
|
||||
if ( pdmValueField )
|
||||
{
|
||||
QString dataType = PdmPythonGenerator::dataTypeString( field, true );
|
||||
QString dataType = PdmPythonGenerator::dataTypeString( field, false );
|
||||
if ( field->xmlCapability()->isVectorField() )
|
||||
{
|
||||
dataType = QString( "List of %1" ).arg( dataType );
|
||||
dataType = QString( "List[%1]" ).arg( dataType );
|
||||
}
|
||||
|
||||
bool shouldBeMethod = false;
|
||||
@ -159,9 +161,10 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
.arg( comment )
|
||||
.arg( dataType );
|
||||
|
||||
QString fieldCode = QString( " def %1(self):\n%2\n return "
|
||||
"self._call_get_method(\"%3\")\n" )
|
||||
QString fieldCode = QString( " def %1(self) -> %2:\n%3\n return "
|
||||
"self._call_get_method(\"%4\")\n" )
|
||||
.arg( snake_field_name )
|
||||
.arg( dataType )
|
||||
.arg( fullComment )
|
||||
.arg( scriptability->scriptFieldName() );
|
||||
classMethodsGenerated[field->ownerClass()][snake_field_name] = fieldCode;
|
||||
@ -173,9 +176,11 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
.arg( comment )
|
||||
.arg( dataType );
|
||||
|
||||
QString fieldCode = QString( " def set_%1(self, values):\n%2\n "
|
||||
"self._call_set_method(\"%3\", values)\n" )
|
||||
QString fieldCode =
|
||||
QString( " def set_%1(self, values : %2) -> None:\n%3\n "
|
||||
"self._call_set_method(\"%4\", values)\n" )
|
||||
.arg( snake_field_name )
|
||||
.arg( dataType )
|
||||
.arg( fullComment )
|
||||
.arg( scriptability->scriptFieldName() );
|
||||
classMethodsGenerated[field->ownerClass()][QString( "set_%1" ).arg( snake_field_name )] =
|
||||
@ -186,8 +191,13 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
{
|
||||
QString valueString = getDefaultValue( field );
|
||||
|
||||
if ( valueString == "None" )
|
||||
{
|
||||
dataType = QString( "Optional[%1]" ).arg( dataType );
|
||||
}
|
||||
|
||||
QString fieldCode =
|
||||
QString( " self.%1 = %2\n" ).arg( snake_field_name ).arg( valueString );
|
||||
QString( " self.%1: %2 = %3\n" ).arg( snake_field_name ).arg( dataType ).arg( valueString );
|
||||
|
||||
QString fullComment;
|
||||
{
|
||||
@ -218,7 +228,7 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
dataTypesInChildFields.insert( scriptDataType );
|
||||
|
||||
QString commentDataType = field->xmlCapability()->isVectorField()
|
||||
? QString( "List of %1" ).arg( scriptDataType )
|
||||
? QString( "List[%1]" ).arg( scriptDataType )
|
||||
: scriptDataType;
|
||||
|
||||
QString fullComment =
|
||||
@ -228,7 +238,8 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
|
||||
if ( pdmChildField )
|
||||
{
|
||||
QString fieldCode = QString( " def %1(self):\n%2\n children = "
|
||||
QString fieldCode =
|
||||
QString( " def %1(self) -> Optional[%4]:\n%2\n children = "
|
||||
"self.children(\"%3\", %4)\n return children[0] if "
|
||||
"len(children) > 0 else None\n" )
|
||||
.arg( snake_field_name )
|
||||
@ -239,9 +250,10 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
}
|
||||
else
|
||||
{
|
||||
QString fieldCode = QString( " def %1(self):\n%2\n return "
|
||||
"self.children(\"%3\", %4)\n" )
|
||||
QString fieldCode = QString( " def %1(self) -> List[%2]:\n%3\n return "
|
||||
"self.children(\"%4\", %5)\n" )
|
||||
.arg( snake_field_name )
|
||||
.arg( scriptDataType )
|
||||
.arg( fullComment )
|
||||
.arg( scriptability->scriptFieldName() )
|
||||
.arg( scriptDataType );
|
||||
@ -269,8 +281,22 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
QStringList argumentComments;
|
||||
|
||||
outputArgumentStrings.push_back( QString( "\"%1\"" ).arg( methodName ) );
|
||||
|
||||
QString returnDataType = "None";
|
||||
QString returnComment;
|
||||
if ( method->defaultResult() ) returnComment = method->defaultResult()->xmlCapability()->classKeyword();
|
||||
if ( method->defaultResult() )
|
||||
{
|
||||
QString classKeyword = method->defaultResult()->xmlCapability()->classKeyword();
|
||||
returnComment = classKeyword;
|
||||
returnDataType = PdmObjectScriptingCapabilityRegister::scriptClassNameFromClassKeyword( classKeyword );
|
||||
|
||||
outputArgumentStrings.push_back( QString( "%1" ).arg( returnDataType ) );
|
||||
|
||||
if ( method->isNullptrValidResult() )
|
||||
{
|
||||
returnDataType = QString( "Optional[%1]" ).arg( returnDataType );
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto field : arguments )
|
||||
{
|
||||
@ -279,9 +305,13 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
auto dataType = dataTypeString( field, false );
|
||||
|
||||
bool isList = field->xmlCapability()->isVectorField();
|
||||
if ( isList ) dataType = "List of " + dataType;
|
||||
if ( isList ) dataType = QString( "List[%1]" ).arg( dataType );
|
||||
|
||||
QString defaultValue = getDefaultValue( field );
|
||||
if ( defaultValue == "None" )
|
||||
{
|
||||
dataType = QString( "Optional[%1]" ).arg( dataType );
|
||||
}
|
||||
|
||||
QString commentOrEnumDescription = field->uiCapability()->uiWhatsThis();
|
||||
|
||||
@ -293,7 +323,8 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
commentOrEnumDescription = "One of [" + enumTexts.join( ", " ) + "]";
|
||||
}
|
||||
|
||||
inputArgumentStrings.push_back( QString( "%1=%2" ).arg( argumentName ).arg( defaultValue ) );
|
||||
inputArgumentStrings.push_back(
|
||||
QString( "%1: %2=%3" ).arg( argumentName ).arg( dataType ).arg( defaultValue ) );
|
||||
outputArgumentStrings.push_back( QString( "%1=%1" ).arg( argumentName ) );
|
||||
argumentComments.push_back(
|
||||
QString( "%1 (%2): %3" ).arg( argumentName ).arg( dataType ).arg( commentOrEnumDescription ) );
|
||||
@ -304,12 +335,27 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
.arg( argumentComments.join( "\n " ) )
|
||||
.arg( returnComment );
|
||||
|
||||
QString methodCode = QString( " def %1(self, %2):\n%3\n return "
|
||||
"self._call_pdm_method(%4)\n" )
|
||||
QString methodBody = QString( "self._call_pdm_method_void(%1)" ).arg( outputArgumentStrings.join( ", " ) );
|
||||
if ( returnDataType != "None" )
|
||||
{
|
||||
if ( method->isNullptrValidResult() )
|
||||
{
|
||||
methodBody = QString( "return self._call_pdm_method_return_optional_value(%1)" )
|
||||
.arg( outputArgumentStrings.join( ", " ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
methodBody =
|
||||
QString( "return self._call_pdm_method_return_value(%1)" ).arg( outputArgumentStrings.join( ", " ) );
|
||||
}
|
||||
}
|
||||
|
||||
QString methodCode = QString( " def %1(self, %2) -> %3:\n%4\n %5\n" )
|
||||
.arg( snake_method_name )
|
||||
.arg( inputArgumentStrings.join( ", " ) )
|
||||
.arg( returnDataType )
|
||||
.arg( fullComment )
|
||||
.arg( outputArgumentStrings.join( ", " ) );
|
||||
.arg( methodBody );
|
||||
|
||||
classMethodsGenerated[classKeyword][snake_method_name] = methodCode;
|
||||
}
|
||||
@ -320,7 +366,12 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
std::set<QString> classesWritten;
|
||||
classesWritten.insert( "PdmObjectBase" );
|
||||
|
||||
out << "from __future__ import annotations\n";
|
||||
out << "from rips.pdmobject import PdmObjectBase\n";
|
||||
out << "import PdmObject_pb2\n";
|
||||
out << "import grpc\n";
|
||||
out << "from typing import Optional, Dict, List, Type\n";
|
||||
out << "\n";
|
||||
|
||||
for ( std::shared_ptr<PdmObject> object : dummyObjects )
|
||||
{
|
||||
@ -367,7 +418,9 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
classCode +=
|
||||
QString( " __custom_init__ = None #: Assign a custom init routine to be run at __init__\n\n" );
|
||||
|
||||
classCode += QString( " def __init__(self, pb2_object=None, channel=None):\n" );
|
||||
classCode +=
|
||||
QString( " def __init__(self, pb2_object: Optional[PdmObject_pb2.PdmObject]=None, channel: "
|
||||
"Optional[grpc.Channel]=None) -> None:\n" );
|
||||
if ( !scriptSuperClassNames.empty() )
|
||||
{
|
||||
// Own attributes. This initializes a lot of attributes to None.
|
||||
@ -398,15 +451,16 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
|
||||
scriptSuperClassNames.push_back( scriptClassName );
|
||||
}
|
||||
}
|
||||
out << "def class_dict():\n";
|
||||
out << " classes = {}\n";
|
||||
|
||||
out << "def class_dict() -> Dict[str, Type[PdmObjectBase]]:\n";
|
||||
out << " classes : Dict[str, Type[PdmObjectBase]] = {}\n";
|
||||
for ( QString classKeyword : classesWritten )
|
||||
{
|
||||
out << QString( " classes['%1'] = %1\n" ).arg( classKeyword );
|
||||
}
|
||||
out << " return classes\n\n";
|
||||
|
||||
out << "def class_from_keyword(class_keyword):\n";
|
||||
out << "def class_from_keyword(class_keyword : str) -> Optional[Type[PdmObjectBase]]:\n";
|
||||
out << " all_classes = class_dict()\n";
|
||||
out << " if class_keyword in all_classes.keys():\n";
|
||||
out << " return all_classes[class_keyword]\n";
|
||||
@ -449,7 +503,12 @@ QString PdmPythonGenerator::getDefaultValue( PdmFieldHandle* field )
|
||||
QTextStream valueStream( &valueString );
|
||||
scriptability->readFromField( valueStream, true, true );
|
||||
}
|
||||
if ( valueString.isEmpty() ) valueString = QString( "\"\"" );
|
||||
|
||||
if ( valueString.isEmpty() )
|
||||
{
|
||||
valueString = defaultValue;
|
||||
}
|
||||
|
||||
valueString = pythonifyDataValue( valueString );
|
||||
|
||||
defaultValue = valueString;
|
||||
@ -482,14 +541,20 @@ QString PdmPythonGenerator::dataTypeString( const PdmFieldHandle* field, bool us
|
||||
auto scriptability = field->capability<PdmAbstractFieldScriptingCapability>();
|
||||
if ( scriptability && !scriptability->enumScriptTexts().empty() ) return "str";
|
||||
|
||||
QString dataType = xmlObj->dataTypeName();
|
||||
QString dataType = PdmObjectScriptingCapabilityRegister::scriptClassNameFromClassKeyword( xmlObj->dataTypeName() );
|
||||
|
||||
std::map<QString, QString> builtins = { { QString::fromStdString( typeid( double ).name() ), "float" },
|
||||
std::map<QString, QString> builtins = {
|
||||
{ QString::fromStdString( typeid( double ).name() ), "float" },
|
||||
{ QString::fromStdString( typeid( float ).name() ), "float" },
|
||||
{ QString::fromStdString( typeid( int ).name() ), "int" },
|
||||
{ QString::fromStdString( typeid( bool ).name() ), "bool" },
|
||||
{ QString::fromStdString( typeid( time_t ).name() ), "time" },
|
||||
{ QString::fromStdString( typeid( QString ).name() ), "str" } };
|
||||
{ QString::fromStdString( typeid( time_t ).name() ), "int" },
|
||||
{ QString::fromStdString( typeid( QString ).name() ), "str" },
|
||||
{ QString::fromStdString( typeid( cvf::Vec3d ).name() ), "List[float]" },
|
||||
{ QString::fromStdString( typeid( cvf::Color3f ).name() ), "str" },
|
||||
{ QString::fromStdString( typeid( caf::FilePath ).name() ), "str" },
|
||||
{ QString::fromStdString( typeid( std::vector<double> ).name() ), "List[float]" },
|
||||
};
|
||||
|
||||
bool foundBuiltin = false;
|
||||
for ( auto builtin : builtins )
|
||||
|
@ -12,6 +12,27 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
project (TestCafAndVizFwk)
|
||||
|
||||
# ##############################################################################
|
||||
# Setup the main platform defines
|
||||
# ##############################################################################
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_definitions(-DCVF_LINUX)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
add_definitions(-DCVF_OSX)
|
||||
elseif(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
set(_HAS_STD_BYTE 0)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"-DCVF_LINUX -pipe -Wextra -Woverloaded-virtual -Wformat -Wno-unused-parameter"
|
||||
)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -g3 -O0 -DDEBUG -D_DEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNO_DEBUG")
|
||||
endif()
|
||||
|
||||
|
||||
find_package(Qt5 COMPONENTS REQUIRED Core Gui OpenGL Widgets)
|
||||
set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets)
|
||||
|
||||
|
@ -184,6 +184,7 @@ foreach(rips_proto ${GRPC_PROTO_FILES})
|
||||
${RESINSIGHT_GRPC_PYTHON_EXECUTABLE} ARGS -m grpc_tools.protoc -I
|
||||
"${rips_proto_path}" --python_out
|
||||
"${GRPC_PYTHON_SOURCE_PATH}/rips/generated" --grpc_python_out
|
||||
"${GRPC_PYTHON_SOURCE_PATH}/rips/generated" --pyi_out
|
||||
"${GRPC_PYTHON_SOURCE_PATH}/rips/generated" "${rips_proto}"
|
||||
DEPENDS "${rips_proto}"
|
||||
COMMENT "Generating ${rips_proto_python} and ${rips_grpc_python}"
|
||||
|
@ -2,3 +2,4 @@ grpcio
|
||||
grpcio-tools
|
||||
protobuf
|
||||
wheel
|
||||
typing-extensions
|
||||
|
@ -17,7 +17,9 @@ from .contour_map import EclipseContourMap, GeoMechContourMap
|
||||
from .well_log_plot import WellLogPlot
|
||||
from .simulation_well import SimulationWell
|
||||
|
||||
__all__ = []
|
||||
from typing import List
|
||||
|
||||
__all__: List[str] = []
|
||||
for key in class_dict():
|
||||
__all__.append(key)
|
||||
|
||||
|
@ -37,6 +37,7 @@ result
|
||||
|
||||
import builtins
|
||||
import grpc
|
||||
from typing import List, Tuple
|
||||
|
||||
import Case_pb2
|
||||
import Case_pb2_grpc
|
||||
@ -74,7 +75,7 @@ def __custom_init__(self, pb2_object, channel):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def __grid_count(self):
|
||||
def __grid_count(self) -> int:
|
||||
"""Get number of grids in the case"""
|
||||
try:
|
||||
return self.__case_stub.GetGridCount(self.__request()).count
|
||||
@ -125,7 +126,7 @@ def __generate_property_input_chunks(self, array, parameters):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def grid(self, index=0):
|
||||
def grid(self, index: int = 0) -> Grid:
|
||||
"""Get Grid of a given index
|
||||
|
||||
Arguments:
|
||||
@ -138,7 +139,7 @@ def grid(self, index=0):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def grids(self):
|
||||
def grids(self) -> List[Grid]:
|
||||
"""Get a list of all rips Grid objects in the case
|
||||
|
||||
Returns:
|
||||
@ -166,7 +167,7 @@ def replace(self, new_grid_file):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def cell_count(self, porosity_model="MATRIX_MODEL"):
|
||||
def cell_count(self, porosity_model: str = "MATRIX_MODEL") -> int:
|
||||
"""Get a cell count object containing number of active cells and total number of cells
|
||||
|
||||
Arguments:
|
||||
@ -193,7 +194,7 @@ def cell_count(self, porosity_model="MATRIX_MODEL"):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def cell_info_for_active_cells_async(self, porosity_model="MATRIX_MODEL"):
|
||||
def cell_info_for_active_cells_async(self, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get Stream of cell info objects for current case
|
||||
|
||||
Arguments:
|
||||
@ -213,7 +214,7 @@ def cell_info_for_active_cells_async(self, porosity_model="MATRIX_MODEL"):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def cell_info_for_active_cells(self, porosity_model="MATRIX_MODEL"):
|
||||
def cell_info_for_active_cells(self, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get list of cell info objects for current case
|
||||
|
||||
Arguments:
|
||||
@ -298,7 +299,7 @@ def reservoir_boundingbox(self):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def reservoir_depth_range(self):
|
||||
def reservoir_depth_range(self) -> Tuple[float, float]:
|
||||
"""Get the reservoir depth range
|
||||
|
||||
Returns:
|
||||
@ -604,7 +605,7 @@ def export_flow_characteristics(
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def available_properties(self, property_type, porosity_model="MATRIX_MODEL"):
|
||||
def available_properties(self, property_type, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get a list of available properties
|
||||
|
||||
For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
@ -626,7 +627,7 @@ def available_properties(self, property_type, porosity_model="MATRIX_MODEL"):
|
||||
|
||||
@add_method(Case)
|
||||
def active_cell_property_async(
|
||||
self, property_type, property_name, time_step, porosity_model="MATRIX_MODEL"
|
||||
self, property_type, property_name, time_step, porosity_model: str = "MATRIX_MODEL"
|
||||
):
|
||||
"""Get a cell property for all active cells. Async, so returns an iterator. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -655,7 +656,7 @@ def active_cell_property_async(
|
||||
|
||||
@add_method(Case)
|
||||
def active_cell_property(
|
||||
self, property_type, property_name, time_step, porosity_model="MATRIX_MODEL"
|
||||
self, property_type, property_name, time_step, porosity_model: str = "MATRIX_MODEL"
|
||||
):
|
||||
"""Get a cell property for all active cells. Sync, so returns a list. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -681,7 +682,7 @@ def active_cell_property(
|
||||
|
||||
@add_method(Case)
|
||||
def selected_cell_property_async(
|
||||
self, property_type, property_name, time_step, porosity_model="MATRIX_MODEL"
|
||||
self, property_type, property_name, time_step, porosity_model: str = "MATRIX_MODEL"
|
||||
):
|
||||
"""Get a cell property for all selected cells. Async, so returns an iterator. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -710,7 +711,7 @@ def selected_cell_property_async(
|
||||
|
||||
@add_method(Case)
|
||||
def selected_cell_property(
|
||||
self, property_type, property_name, time_step, porosity_model="MATRIX_MODEL"
|
||||
self, property_type, property_name, time_step, porosity_model: str = "MATRIX_MODEL"
|
||||
):
|
||||
"""Get a cell property for all selected cells. Sync, so returns a list. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -741,7 +742,7 @@ def grid_property_async(
|
||||
property_name,
|
||||
time_step,
|
||||
grid_index=0,
|
||||
porosity_model="MATRIX_MODEL",
|
||||
porosity_model: str = "MATRIX_MODEL",
|
||||
):
|
||||
"""Get a cell property for all grid cells. Async, so returns an iterator. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -777,7 +778,7 @@ def grid_property(
|
||||
property_name,
|
||||
time_step,
|
||||
grid_index=0,
|
||||
porosity_model="MATRIX_MODEL",
|
||||
porosity_model: str = "MATRIX_MODEL",
|
||||
):
|
||||
"""Get a cell property for all grid cells. Synchronous, so returns a list. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -808,7 +809,7 @@ def set_active_cell_property_async(
|
||||
property_type,
|
||||
property_name,
|
||||
time_step,
|
||||
porosity_model="MATRIX_MODEL",
|
||||
porosity_model: str = "MATRIX_MODEL",
|
||||
):
|
||||
"""Set cell property for all active cells Async. Takes an iterator to the input values. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -835,7 +836,12 @@ def set_active_cell_property_async(
|
||||
|
||||
@add_method(Case)
|
||||
def set_active_cell_property(
|
||||
self, values, property_type, property_name, time_step, porosity_model="MATRIX_MODEL"
|
||||
self,
|
||||
values,
|
||||
property_type,
|
||||
property_name,
|
||||
time_step,
|
||||
porosity_model: str = "MATRIX_MODEL",
|
||||
):
|
||||
"""Set a cell property for all active cells. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -869,7 +875,7 @@ def set_grid_property(
|
||||
property_name,
|
||||
time_step,
|
||||
grid_index=0,
|
||||
porosity_model="MATRIX_MODEL",
|
||||
porosity_model: str = "MATRIX_MODEL",
|
||||
):
|
||||
"""Set a cell property for all grid cells. For argument details, see :ref:`Result Definition <result-definition-label>`
|
||||
|
||||
@ -989,7 +995,7 @@ def simulation_wells(self):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def active_cell_centers_async(self, porosity_model="MATRIX_MODEL"):
|
||||
def active_cell_centers_async(self, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get a cell centers for all active cells. Async, so returns an iterator
|
||||
|
||||
Arguments:
|
||||
@ -1007,7 +1013,7 @@ def active_cell_centers_async(self, porosity_model="MATRIX_MODEL"):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def active_cell_centers(self, porosity_model="MATRIX_MODEL"):
|
||||
def active_cell_centers(self, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get a cell centers for all active cells. Synchronous, so returns a list.
|
||||
|
||||
Arguments:
|
||||
@ -1025,7 +1031,7 @@ def active_cell_centers(self, porosity_model="MATRIX_MODEL"):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def active_cell_corners_async(self, porosity_model="MATRIX_MODEL"):
|
||||
def active_cell_corners_async(self, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get a cell corners for all active cells. Async, so returns an iterator
|
||||
|
||||
Arguments:
|
||||
@ -1043,7 +1049,7 @@ def active_cell_corners_async(self, porosity_model="MATRIX_MODEL"):
|
||||
|
||||
|
||||
@add_method(Case)
|
||||
def active_cell_corners(self, porosity_model="MATRIX_MODEL"):
|
||||
def active_cell_corners(self, porosity_model: str = "MATRIX_MODEL"):
|
||||
"""Get a cell corners for all active cells. Synchronous, so returns a list.
|
||||
|
||||
Arguments:
|
||||
@ -1287,7 +1293,7 @@ def __generate_nnc_property_input_chunks(self, array, parameters):
|
||||
|
||||
@add_method(Case)
|
||||
def set_nnc_connections_values(
|
||||
self, values, property_name, time_step, porosity_model="MATRIX_MODEL"
|
||||
self, values, property_name, time_step, porosity_model: str = "MATRIX_MODEL"
|
||||
):
|
||||
"""Set nnc connection values for all connections..
|
||||
|
||||
|
@ -10,11 +10,11 @@ from .resinsight_classes import EclipseContourMap, GeoMechContourMap
|
||||
|
||||
@add_method(EclipseContourMap)
|
||||
def export_to_text(
|
||||
self,
|
||||
export_file_name="",
|
||||
export_local_coordinates=False,
|
||||
undefined_value_label="NaN",
|
||||
exclude_undefined_values=False,
|
||||
self: EclipseContourMap,
|
||||
export_file_name: str = "",
|
||||
export_local_coordinates: bool = False,
|
||||
undefined_value_label: str = "NaN",
|
||||
exclude_undefined_values: bool = False,
|
||||
):
|
||||
"""Export snapshot for the current view
|
||||
|
||||
@ -37,11 +37,11 @@ def export_to_text(
|
||||
|
||||
@add_method(GeoMechContourMap)
|
||||
def export_to_text(
|
||||
self,
|
||||
export_file_name="",
|
||||
export_local_coordinates=False,
|
||||
undefined_value_label="NaN",
|
||||
exclude_undefined_values=False,
|
||||
self: GeoMechContourMap,
|
||||
export_file_name: str = "",
|
||||
export_local_coordinates: bool = False,
|
||||
undefined_value_label: str = "NaN",
|
||||
exclude_undefined_values: bool = False,
|
||||
):
|
||||
"""Export snapshot for the current view
|
||||
|
||||
|
@ -8,6 +8,12 @@ about Case grids.
|
||||
import Case_pb2
|
||||
import Grid_pb2
|
||||
import Grid_pb2_grpc
|
||||
import Definitions_pb2
|
||||
|
||||
from typing import Tuple, Optional, List
|
||||
from grpc import Channel
|
||||
|
||||
from .case import Case
|
||||
|
||||
|
||||
class Grid:
|
||||
@ -16,15 +22,15 @@ class Grid:
|
||||
:meth:`rips.case.grids()`
|
||||
"""
|
||||
|
||||
def __init__(self, index, case, channel):
|
||||
def __init__(self, index: int, case: Case, channel: Channel) -> None:
|
||||
self.__channel = channel
|
||||
self.__stub = Grid_pb2_grpc.GridStub(self.__channel)
|
||||
|
||||
self.case = case
|
||||
self.index = index
|
||||
self.case: Case = case
|
||||
self.index: int = index
|
||||
self.cached_dimensions = None
|
||||
|
||||
def dimensions(self):
|
||||
def dimensions(self) -> Optional[Definitions_pb2.Vec3i]:
|
||||
"""The dimensions in i, j, k direction
|
||||
|
||||
Returns:
|
||||
@ -52,7 +58,7 @@ class Grid:
|
||||
for chunk in chunks:
|
||||
yield chunk
|
||||
|
||||
def cell_centers(self):
|
||||
def cell_centers(self) -> List[Definitions_pb2.Vec3d]:
|
||||
"""The cell center for all cells in given grid
|
||||
|
||||
Returns:
|
||||
@ -92,7 +98,7 @@ class Grid:
|
||||
corners.append(center)
|
||||
return corners
|
||||
|
||||
def property_data_index_from_ijk(self, i, j, k):
|
||||
def property_data_index_from_ijk(self, i: int, j: int, k: int) -> int:
|
||||
"""Compute property index from 1-based IJK cell address. Cell Property Result data is organized by I, J and K.
|
||||
|
||||
property_data_index = dims.i * dims.j * (k - 1) + dims.i * (j - 1) + (i - 1)
|
||||
@ -102,12 +108,12 @@ class Grid:
|
||||
"""
|
||||
|
||||
dims = self.dimensions()
|
||||
if dims:
|
||||
return int(dims.i * dims.j * (k - 1) + dims.i * (j - 1) + (i - 1))
|
||||
else:
|
||||
return -1
|
||||
|
||||
property_data_index = dims.i * dims.j * (k - 1) + dims.i * (j - 1) + (i - 1)
|
||||
|
||||
return property_data_index
|
||||
|
||||
def cell_count(self):
|
||||
def cell_count(self) -> int:
|
||||
"""Cell count in grid
|
||||
|
||||
Returns:
|
||||
@ -115,7 +121,7 @@ class Grid:
|
||||
"""
|
||||
|
||||
dims = self.dimensions()
|
||||
|
||||
count = dims.i * dims.j * dims.k
|
||||
|
||||
return count
|
||||
if dims:
|
||||
return int(dims.i * dims.j * dims.k)
|
||||
else:
|
||||
return 0
|
||||
|
@ -5,6 +5,7 @@ The Instance class contained have static methods launch and find for
|
||||
creating connections to ResInsight
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import socket
|
||||
import logging
|
||||
@ -27,6 +28,9 @@ from .retry_policy import ExponentialBackoffRetryPolicy
|
||||
from .grpc_retry_interceptor import RetryOnRpcErrorClientInterceptor
|
||||
from .generated.generated_classes import CommandRouter
|
||||
|
||||
from typing import List, Optional, Tuple
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
class Instance:
|
||||
"""The ResInsight Instance class. Use to launch or find existing ResInsight instances
|
||||
@ -40,13 +44,13 @@ class Instance:
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def __is_port_in_use(port):
|
||||
def __is_port_in_use(port: int) -> bool:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as my_socket:
|
||||
my_socket.settimeout(0.2)
|
||||
return my_socket.connect_ex(("localhost", port)) == 0
|
||||
|
||||
@staticmethod
|
||||
def __is_valid_port(port):
|
||||
def __is_valid_port(port: int) -> bool:
|
||||
location = "localhost:" + str(port)
|
||||
channel = grpc.insecure_channel(
|
||||
location, options=[("grpc.enable_http_proxy", False)]
|
||||
@ -59,7 +63,7 @@ class Instance:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def __read_port_number_from_file(file_path):
|
||||
def __read_port_number_from_file(file_path: str) -> int:
|
||||
retry_count = 0
|
||||
while not os.path.exists(file_path) and retry_count < 60:
|
||||
time.sleep(1)
|
||||
@ -75,7 +79,7 @@ class Instance:
|
||||
return -1
|
||||
|
||||
@staticmethod
|
||||
def __kill_process(pid):
|
||||
def __kill_process(pid: int) -> None:
|
||||
"""
|
||||
Kill the process with a given pid.
|
||||
"""
|
||||
@ -88,11 +92,11 @@ class Instance:
|
||||
|
||||
@staticmethod
|
||||
def launch(
|
||||
resinsight_executable="",
|
||||
console=False,
|
||||
launch_port=-1,
|
||||
command_line_parameters=None,
|
||||
):
|
||||
resinsight_executable: str = "",
|
||||
console: bool = False,
|
||||
launch_port: int = -1,
|
||||
command_line_parameters: List[str] = [],
|
||||
) -> Optional[Instance]:
|
||||
"""Launch a new Instance of ResInsight. This requires the environment variable
|
||||
RESINSIGHT_EXECUTABLE to be set or the parameter resinsight_executable to be provided.
|
||||
The RESINSIGHT_GRPC_PORT environment variable can be set to an alternative port number.
|
||||
@ -110,7 +114,7 @@ class Instance:
|
||||
Instance: an instance object if it worked. None if not.
|
||||
"""
|
||||
|
||||
requested_port = 50051
|
||||
requested_port: int = 50051
|
||||
port_env = os.environ.get("RESINSIGHT_GRPC_PORT")
|
||||
if port_env:
|
||||
requested_port = int(port_env)
|
||||
@ -118,29 +122,25 @@ class Instance:
|
||||
requested_port = launch_port
|
||||
|
||||
if not resinsight_executable:
|
||||
resinsight_executable = os.environ.get("RESINSIGHT_EXECUTABLE")
|
||||
if not resinsight_executable:
|
||||
resinsight_executable_from_env = os.environ.get("RESINSIGHT_EXECUTABLE")
|
||||
if not resinsight_executable_from_env:
|
||||
print(
|
||||
"ERROR: Could not launch ResInsight because the environment variable"
|
||||
" RESINSIGHT_EXECUTABLE is not set"
|
||||
)
|
||||
return None
|
||||
else:
|
||||
resinsight_executable = resinsight_executable_from_env
|
||||
|
||||
print("Trying to launch", resinsight_executable)
|
||||
|
||||
if command_line_parameters is None:
|
||||
command_line_parameters = []
|
||||
elif isinstance(command_line_parameters, str):
|
||||
command_line_parameters = [str]
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp_dir_path:
|
||||
port_number_file = tmp_dir_path + "/portnumber.txt"
|
||||
parameters = [
|
||||
parameters: List[str] = [
|
||||
"ResInsight",
|
||||
"--server",
|
||||
requested_port,
|
||||
str(requested_port),
|
||||
"--portnumberfile",
|
||||
port_number_file,
|
||||
str(port_number_file),
|
||||
] + command_line_parameters
|
||||
if console:
|
||||
print("Launching as console app")
|
||||
@ -163,7 +163,7 @@ class Instance:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def find(start_port=50051, end_port=50071):
|
||||
def find(start_port: int = 50051, end_port: int = 50071) -> Optional[Instance]:
|
||||
"""Search for an existing Instance of ResInsight by testing ports.
|
||||
|
||||
By default we search from port 50051 to 50071 or if the environment
|
||||
@ -198,7 +198,7 @@ class Instance:
|
||||
def __execute_command(self, **command_params):
|
||||
return self.commands.Execute(Commands_pb2.CommandParams(**command_params))
|
||||
|
||||
def __check_version(self):
|
||||
def __check_version(self) -> Tuple[bool, bool]:
|
||||
try:
|
||||
major_version_ok = self.major_version() == int(
|
||||
RiaVersionInfo.RESINSIGHT_MAJOR_VERSION
|
||||
@ -210,14 +210,14 @@ class Instance:
|
||||
except grpc.RpcError:
|
||||
return False, False
|
||||
|
||||
def __init__(self, port=50051, launched=False):
|
||||
"""Attempts to connect to ResInsight at aa specific port on localhost
|
||||
def __init__(self, port: int = 50051, launched: bool = False) -> None:
|
||||
"""Attempts to connect to ResInsight at a specific port on localhost
|
||||
|
||||
Args:
|
||||
port(int): port number
|
||||
"""
|
||||
logging.basicConfig()
|
||||
self.location = "localhost:" + str(port)
|
||||
self.location: str = "localhost:" + str(port)
|
||||
|
||||
self.channel = grpc.insecure_channel(
|
||||
self.location, options=[("grpc.enable_http_proxy", False)]
|
||||
@ -256,7 +256,9 @@ class Instance:
|
||||
path = os.getcwd()
|
||||
self.set_start_dir(path=path)
|
||||
|
||||
def _check_connection_and_version(self, channel, launched, location):
|
||||
def _check_connection_and_version(
|
||||
self, channel: grpc.Channel, launched: bool, location: str
|
||||
) -> None:
|
||||
connection_ok = False
|
||||
version_ok = False
|
||||
|
||||
@ -288,10 +290,10 @@ class Instance:
|
||||
self.client_version_string(),
|
||||
)
|
||||
|
||||
def __version_message(self):
|
||||
def __version_message(self) -> App_pb2.Version:
|
||||
return self.app.GetVersion(Empty())
|
||||
|
||||
def set_start_dir(self, path):
|
||||
def set_start_dir(self, path: str):
|
||||
"""Set current start directory
|
||||
|
||||
Arguments:
|
||||
@ -302,7 +304,9 @@ class Instance:
|
||||
setStartDir=Commands_pb2.FilePathRequest(path=path)
|
||||
)
|
||||
|
||||
def set_export_folder(self, export_type, path, create_folder=False):
|
||||
def set_export_folder(
|
||||
self, export_type: str, path: str, create_folder: bool = False
|
||||
):
|
||||
"""
|
||||
Set the export folder used for all export functions
|
||||
|
||||
@ -330,7 +334,7 @@ class Instance:
|
||||
)
|
||||
)
|
||||
|
||||
def set_main_window_size(self, width, height):
|
||||
def set_main_window_size(self, width: int, height: int):
|
||||
"""
|
||||
Set the main window size in pixels
|
||||
|
||||
@ -348,7 +352,7 @@ class Instance:
|
||||
)
|
||||
)
|
||||
|
||||
def set_plot_window_size(self, width, height):
|
||||
def set_plot_window_size(self, width: int, height: int):
|
||||
"""
|
||||
Set the plot window size in pixels
|
||||
|
||||
@ -365,19 +369,19 @@ class Instance:
|
||||
)
|
||||
)
|
||||
|
||||
def major_version(self):
|
||||
def major_version(self) -> int:
|
||||
"""Get an integer with the major version number"""
|
||||
return self.__version_message().major_version
|
||||
return int(self.__version_message().major_version)
|
||||
|
||||
def minor_version(self):
|
||||
def minor_version(self) -> int:
|
||||
"""Get an integer with the minor version number"""
|
||||
return self.__version_message().minor_version
|
||||
return int(self.__version_message().minor_version)
|
||||
|
||||
def patch_version(self):
|
||||
def patch_version(self) -> int:
|
||||
"""Get an integer with the patch version number"""
|
||||
return self.__version_message().patch_version
|
||||
return int(self.__version_message().patch_version)
|
||||
|
||||
def version_string(self):
|
||||
def version_string(self) -> str:
|
||||
"""Get a full version string, i.e. 2019.04.01"""
|
||||
return (
|
||||
str(self.major_version())
|
||||
@ -387,9 +391,9 @@ class Instance:
|
||||
+ str(self.patch_version())
|
||||
)
|
||||
|
||||
def client_version_string(self):
|
||||
def client_version_string(self) -> str:
|
||||
"""Get a full version string, i.e. 2019.04.01"""
|
||||
version_string = RiaVersionInfo.RESINSIGHT_MAJOR_VERSION + "."
|
||||
version_string: str = RiaVersionInfo.RESINSIGHT_MAJOR_VERSION + "."
|
||||
version_string += RiaVersionInfo.RESINSIGHT_MINOR_VERSION + "."
|
||||
version_string += RiaVersionInfo.RESINSIGHT_PATCH_VERSION
|
||||
return version_string
|
||||
@ -399,14 +403,16 @@ class Instance:
|
||||
print("Telling ResInsight to Exit")
|
||||
return self.app.Exit(Empty())
|
||||
|
||||
def is_console(self):
|
||||
def is_console(self) -> bool:
|
||||
"""Returns true if the connected ResInsight instance is a console app"""
|
||||
return self.app.GetRuntimeInfo(
|
||||
Empty()
|
||||
).app_type == App_pb2.ApplicationTypeEnum.Value("CONSOLE_APPLICATION")
|
||||
return bool(
|
||||
self.app.GetRuntimeInfo(Empty()).app_type
|
||||
== App_pb2.ApplicationTypeEnum.Value("CONSOLE_APPLICATION")
|
||||
)
|
||||
|
||||
def is_gui(self):
|
||||
def is_gui(self) -> bool:
|
||||
"""Returns true if the connected ResInsight instance is a GUI app"""
|
||||
return self.app.GetRuntimeInfo(
|
||||
Empty()
|
||||
).app_type == App_pb2.ApplicationTypeEnum.Value("GUI_APPLICATION")
|
||||
return bool(
|
||||
self.app.GetRuntimeInfo(Empty()).app_type
|
||||
== App_pb2.ApplicationTypeEnum.Value("GUI_APPLICATION")
|
||||
)
|
||||
|
65
GrpcInterface/Python/rips/mypy.ini
Normal file
65
GrpcInterface/Python/rips/mypy.ini
Normal file
@ -0,0 +1,65 @@
|
||||
[mypy]
|
||||
# General configuration
|
||||
python_version = 3.8
|
||||
show_error_codes = True
|
||||
show_column_numbers = True
|
||||
|
||||
# Try to make mypy as strict as possible
|
||||
strict = True
|
||||
ignore_missing_imports = True
|
||||
implicit_reexport = True
|
||||
allow_redefinition = False
|
||||
strict_optional = True
|
||||
warn_no_return = True
|
||||
warn_unused_configs = True
|
||||
disallow_any_generics = True
|
||||
disallow_subclassing_any = True
|
||||
disallow_untyped_calls = True
|
||||
disallow_incomplete_defs = True
|
||||
disallow_untyped_decorators = True
|
||||
no_implicit_optional = True
|
||||
warn_redundant_casts = True
|
||||
warn_return_any = True
|
||||
strict_equality = True
|
||||
|
||||
|
||||
# Explicit exceptions where type definitions are incomplete
|
||||
|
||||
[mypy-rips.grpc_retry_interceptor.*]
|
||||
disable_error_code = misc, no-untyped-def, no-untyped-call
|
||||
|
||||
[mypy-rips.pdmobject.*]
|
||||
disable_error_code = assignment, return-value, call-arg, no-untyped-def, no-untyped-call, no-any-return
|
||||
|
||||
[mypy-rips.case.*]
|
||||
disable_error_code = no-untyped-def, no-any-return
|
||||
|
||||
[mypy-rips.grid.*]
|
||||
disable_error_code = no-untyped-def, no-untyped-call
|
||||
|
||||
[mypy-rips.gridcasegroup.*]
|
||||
disable_error_code = no-any-return, no-untyped-def
|
||||
|
||||
[mypy-rips.project.*]
|
||||
disable_error_code = no-untyped-def, no-any-return, attr-defined
|
||||
|
||||
[mypy-rips.well_log_plot.*]
|
||||
disable_error_code = no-any-return
|
||||
|
||||
[mypy-rips.contour_map.*]
|
||||
disable_error_code = no-redef
|
||||
|
||||
[mypy-rips.plot.*]
|
||||
disable_error_code = no-untyped-def
|
||||
|
||||
[mypy-rips.view.*]
|
||||
disable_error_code = no-untyped-def
|
||||
|
||||
[mypy-rips.instance.*]
|
||||
disable_error_code = no-untyped-def, no-untyped-call, attr-defined
|
||||
|
||||
[mypy-rips.simulation_well.*]
|
||||
disable_error_code = no-any-return, attr-defined
|
||||
|
||||
[mypy-rips.generated.generated_classes.*]
|
||||
disable_error_code = no-any-return
|
@ -17,27 +17,39 @@ import Commands_pb2
|
||||
import Commands_pb2_grpc
|
||||
|
||||
|
||||
def camel_to_snake(name):
|
||||
from typing import Any, Callable, TypeVar, Tuple, cast, Union, List, Optional, Type
|
||||
from typing_extensions import ParamSpec, Self
|
||||
|
||||
|
||||
def camel_to_snake(name: str) -> str:
|
||||
s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
|
||||
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
|
||||
|
||||
|
||||
def snake_to_camel(name):
|
||||
def snake_to_camel(name: str) -> str:
|
||||
return "".join(word.title() for word in name.split("_"))
|
||||
|
||||
|
||||
def add_method(cls):
|
||||
def decorator(func):
|
||||
F = TypeVar("F", bound=Callable[..., Any])
|
||||
C = TypeVar("C")
|
||||
|
||||
|
||||
def add_method(cls: C) -> Callable[[F], F]:
|
||||
def decorator(func: F) -> F:
|
||||
setattr(cls, func.__name__, func)
|
||||
return func # returning func means func can still be used normally
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def add_static_method(cls):
|
||||
def decorator(func):
|
||||
P = ParamSpec("P")
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def add_static_method(cls: C) -> Callable[[Callable[P, T]], Callable[P, T]]:
|
||||
def decorator(func: Callable[P, T]) -> Callable[P, T]:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
setattr(cls, func.__name__, wrapper)
|
||||
@ -52,7 +64,9 @@ class PdmObjectBase:
|
||||
The ResInsight base class for the Project Data Model
|
||||
"""
|
||||
|
||||
def _execute_command(self, **command_params):
|
||||
__custom_init__ = None
|
||||
|
||||
def _execute_command(self, **command_params) -> Any:
|
||||
self.__warnings = []
|
||||
response, call = self._commands.Execute.with_call(
|
||||
Commands_pb2.CommandParams(**command_params)
|
||||
@ -64,7 +78,11 @@ class PdmObjectBase:
|
||||
|
||||
return response
|
||||
|
||||
def __init__(self, pb2_object, channel):
|
||||
def __init__(
|
||||
self,
|
||||
pb2_object: Optional[PdmObject_pb2.PdmObject],
|
||||
channel: Optional[grpc.Channel],
|
||||
) -> None:
|
||||
self.__warnings = []
|
||||
self.__chunk_size = 8160
|
||||
|
||||
@ -91,11 +109,11 @@ class PdmObjectBase:
|
||||
)
|
||||
self.__copy_to_pb2()
|
||||
|
||||
def copy_from(self, object):
|
||||
def copy_from(self, obj: object) -> None:
|
||||
"""Copy attribute values from object to self"""
|
||||
for attribute in dir(object):
|
||||
for attribute in dir(obj):
|
||||
if not attribute.startswith("__"):
|
||||
value = getattr(object, attribute)
|
||||
value = getattr(obj, attribute)
|
||||
# This is crucial to avoid overwriting methods
|
||||
if not callable(value):
|
||||
setattr(self, attribute, value)
|
||||
@ -103,13 +121,13 @@ class PdmObjectBase:
|
||||
self.__custom_init__(self._pb2_object, self._channel)
|
||||
self.update()
|
||||
|
||||
def warnings(self):
|
||||
def warnings(self) -> List[str]:
|
||||
return self.__warnings
|
||||
|
||||
def has_warnings(self):
|
||||
def has_warnings(self) -> bool:
|
||||
return len(self.__warnings) > 0
|
||||
|
||||
def __copy_to_pb2(self):
|
||||
def __copy_to_pb2(self) -> None:
|
||||
if self._pb2_object is not None:
|
||||
for snake_kw in dir(self):
|
||||
if not snake_kw.startswith("_"):
|
||||
@ -119,15 +137,15 @@ class PdmObjectBase:
|
||||
camel_kw = snake_to_camel(snake_kw)
|
||||
self.__set_grpc_value(camel_kw, value)
|
||||
|
||||
def pb2_object(self):
|
||||
def pb2_object(self) -> PdmObject_pb2.PdmObject:
|
||||
"""Private method"""
|
||||
return self._pb2_object
|
||||
|
||||
def channel(self):
|
||||
def channel(self) -> grpc.Channel:
|
||||
"""Private method"""
|
||||
return self._channel
|
||||
|
||||
def address(self):
|
||||
def address(self) -> Any:
|
||||
"""Get the unique address of the PdmObject
|
||||
|
||||
Returns:
|
||||
@ -136,15 +154,15 @@ class PdmObjectBase:
|
||||
|
||||
return self._pb2_object.address
|
||||
|
||||
def set_visible(self, visible):
|
||||
def set_visible(self, visible: bool) -> None:
|
||||
"""Set the visibility of the object in the ResInsight project tree"""
|
||||
self._pb2_object.visible = visible
|
||||
|
||||
def visible(self):
|
||||
def visible(self) -> bool:
|
||||
"""Get the visibility of the object in the ResInsight project tree"""
|
||||
return self._pb2_object.visible
|
||||
return bool(self._pb2_object.visible)
|
||||
|
||||
def print_object_info(self):
|
||||
def print_object_info(self) -> None:
|
||||
"""Print the structure and data content of the PdmObject"""
|
||||
print("=========== " + self.__class__.__name__ + " =================")
|
||||
print("Object Attributes: ")
|
||||
@ -164,7 +182,10 @@ class PdmObjectBase:
|
||||
if not snake_kw.startswith("_") and callable(getattr(self, snake_kw)):
|
||||
print(" " + snake_kw)
|
||||
|
||||
def __convert_from_grpc_value(self, value):
|
||||
Value = Union[bool, str, float, int, "ValueArray"]
|
||||
ValueArray = List[Value]
|
||||
|
||||
def __convert_from_grpc_value(self, value: str) -> Value:
|
||||
if value.lower() == "false":
|
||||
return False
|
||||
if value.lower() == "true":
|
||||
@ -183,7 +204,7 @@ class PdmObjectBase:
|
||||
return self.__makelist(value)
|
||||
return value
|
||||
|
||||
def __convert_to_grpc_value(self, value):
|
||||
def __convert_to_grpc_value(self, value: Any) -> str:
|
||||
if isinstance(value, bool):
|
||||
if value:
|
||||
return "true"
|
||||
@ -197,15 +218,15 @@ class PdmObjectBase:
|
||||
return "[" + ", ".join(list_of_values) + "]"
|
||||
return str(value)
|
||||
|
||||
def __get_grpc_value(self, camel_keyword):
|
||||
def __get_grpc_value(self, camel_keyword: str) -> Value:
|
||||
return self.__convert_from_grpc_value(
|
||||
self._pb2_object.parameters[camel_keyword]
|
||||
)
|
||||
|
||||
def __set_grpc_value(self, camel_keyword, value):
|
||||
def __set_grpc_value(self, camel_keyword: str, value: str) -> None:
|
||||
self._pb2_object.parameters[camel_keyword] = self.__convert_to_grpc_value(value)
|
||||
|
||||
def set_value(self, snake_keyword, value):
|
||||
def set_value(self, snake_keyword: str, value: object) -> None:
|
||||
"""Set the value associated with the provided keyword and updates ResInsight
|
||||
|
||||
Arguments:
|
||||
@ -217,10 +238,10 @@ class PdmObjectBase:
|
||||
setattr(self, snake_keyword, value)
|
||||
self.update()
|
||||
|
||||
def __islist(self, value):
|
||||
def __islist(self, value: str) -> bool:
|
||||
return value.startswith("[") and value.endswith("]")
|
||||
|
||||
def __makelist(self, list_string):
|
||||
def __makelist(self, list_string: str) -> Value:
|
||||
list_string = list_string.lstrip("[")
|
||||
list_string = list_string.rstrip("]")
|
||||
if not list_string:
|
||||
@ -232,7 +253,13 @@ class PdmObjectBase:
|
||||
values.append(self.__convert_from_grpc_value(string))
|
||||
return values
|
||||
|
||||
def __from_pb2_to_resinsight_classes(self, pb2_object_list, super_class_definition):
|
||||
D = TypeVar("D")
|
||||
|
||||
def __from_pb2_to_resinsight_classes(
|
||||
self,
|
||||
pb2_object_list: List[PdmObject_pb2.PdmObject],
|
||||
super_class_definition: Type[D],
|
||||
) -> List[D]:
|
||||
pdm_object_list = []
|
||||
from .generated.generated_classes import class_from_keyword
|
||||
|
||||
@ -241,13 +268,15 @@ class PdmObjectBase:
|
||||
if child_class_definition is None:
|
||||
child_class_definition = super_class_definition
|
||||
|
||||
assert child_class_definition is not None
|
||||
pdm_object = child_class_definition(
|
||||
pb2_object=pb2_object, channel=self.channel()
|
||||
)
|
||||
|
||||
pdm_object_list.append(pdm_object)
|
||||
return pdm_object_list
|
||||
|
||||
def descendants(self, class_definition):
|
||||
def descendants(self, class_definition: Type[D]) -> List[D]:
|
||||
"""Get a list of all project tree descendants matching the class keyword
|
||||
Arguments:
|
||||
class_definition[class]: A class definition matching the type of class wanted
|
||||
@ -269,7 +298,7 @@ class PdmObjectBase:
|
||||
return [] # Valid empty result
|
||||
raise e
|
||||
|
||||
def children(self, child_field, class_definition):
|
||||
def children(self, child_field: str, class_definition: Type[D]) -> List[D]:
|
||||
"""Get a list of all direct project tree children inside the provided child_field
|
||||
Arguments:
|
||||
child_field[str]: A field name
|
||||
@ -287,7 +316,9 @@ class PdmObjectBase:
|
||||
return []
|
||||
raise e
|
||||
|
||||
def add_new_object(self, class_definition, child_field=""):
|
||||
def add_new_object(
|
||||
self, class_definition: Type[D], child_field: str = ""
|
||||
) -> Optional[D]:
|
||||
"""Create and add an object to the specified child field
|
||||
Arguments:
|
||||
class_definition[class]: Class definition of the object to create
|
||||
@ -311,18 +342,18 @@ class PdmObjectBase:
|
||||
child_class_definition = class_from_keyword(pb2_object.class_keyword)
|
||||
|
||||
if child_class_definition is None:
|
||||
child_class_definition = class_keyword
|
||||
child_class_definition = class_definition
|
||||
|
||||
assert child_class_definition.__name__ == class_definition.__name__
|
||||
pdm_object = class_definition(pb2_object=pb2_object, channel=self.channel())
|
||||
|
||||
pdm_object = child_class_definition(
|
||||
pb2_object=pb2_object, channel=self.channel()
|
||||
)
|
||||
return pdm_object
|
||||
except grpc.RpcError as e:
|
||||
if e.code() == grpc.StatusCode.NOT_FOUND:
|
||||
return None
|
||||
raise e
|
||||
|
||||
def ancestor(self, class_definition):
|
||||
def ancestor(self, class_definition: Type[D]) -> Optional[D]:
|
||||
"""Find the first ancestor that matches the provided class_keyword
|
||||
Arguments:
|
||||
class_definition[class]: A class definition matching the type of class wanted
|
||||
@ -330,35 +361,27 @@ class PdmObjectBase:
|
||||
assert inspect.isclass(class_definition)
|
||||
|
||||
class_keyword = class_definition.__name__
|
||||
from .generated.generated_classes import class_from_keyword
|
||||
|
||||
request = PdmObject_pb2.PdmParentObjectRequest(
|
||||
object=self._pb2_object, parent_keyword=class_keyword
|
||||
)
|
||||
try:
|
||||
pb2_object = self._pdm_object_stub.GetAncestorPdmObject(request)
|
||||
child_class_definition = class_from_keyword(pb2_object.class_keyword)
|
||||
|
||||
if child_class_definition is None:
|
||||
child_class_definition = class_definition
|
||||
|
||||
pdm_object = child_class_definition(
|
||||
pb2_object=pb2_object, channel=self.channel()
|
||||
)
|
||||
pdm_object = class_definition(pb2_object=pb2_object, channel=self.channel())
|
||||
return pdm_object
|
||||
except grpc.RpcError as e:
|
||||
if e.code() == grpc.StatusCode.NOT_FOUND:
|
||||
return None
|
||||
raise e
|
||||
|
||||
def _call_get_method_async(self, method_name):
|
||||
def _call_get_method_async(self, method_name: str):
|
||||
request = PdmObject_pb2.PdmObjectGetterRequest(
|
||||
object=self._pb2_object, method=method_name
|
||||
)
|
||||
for chunk in self._pdm_object_stub.CallPdmObjectGetter(request):
|
||||
yield chunk
|
||||
|
||||
def _call_get_method(self, method_name):
|
||||
def _call_get_method(self, method_name: str):
|
||||
all_values = []
|
||||
generator = self._call_get_method_async(method_name)
|
||||
for chunk in generator:
|
||||
@ -413,7 +436,7 @@ class PdmObjectBase:
|
||||
chunk = PdmObject_pb2.PdmObjectSetterChunk()
|
||||
yield chunk
|
||||
|
||||
def _call_set_method(self, method_name, values):
|
||||
def _call_set_method(self, method_name: str, values) -> None:
|
||||
method_request = PdmObject_pb2.PdmObjectGetterRequest(
|
||||
object=self._pb2_object, method=method_name
|
||||
)
|
||||
@ -422,7 +445,42 @@ class PdmObjectBase:
|
||||
if reply.accepted_value_count < len(values):
|
||||
raise IndexError
|
||||
|
||||
def _call_pdm_method(self, method_name, **kwargs):
|
||||
def _call_pdm_method_void(self, method_name: str, **kwargs: Any) -> None:
|
||||
pb2_params = PdmObject_pb2.PdmObject(class_keyword=method_name)
|
||||
for key, value in kwargs.items():
|
||||
pb2_params.parameters[snake_to_camel(key)] = self.__convert_to_grpc_value(
|
||||
value
|
||||
)
|
||||
request = PdmObject_pb2.PdmObjectMethodRequest(
|
||||
object=self._pb2_object, method=method_name, params=pb2_params
|
||||
)
|
||||
|
||||
self._pdm_object_stub.CallPdmObjectMethod(request)
|
||||
|
||||
X = TypeVar("X")
|
||||
|
||||
def _call_pdm_method_return_value(
|
||||
self, method_name: str, class_definition: Type[X], **kwargs: Any
|
||||
) -> X:
|
||||
pb2_params = PdmObject_pb2.PdmObject(class_keyword=method_name)
|
||||
for key, value in kwargs.items():
|
||||
pb2_params.parameters[snake_to_camel(key)] = self.__convert_to_grpc_value(
|
||||
value
|
||||
)
|
||||
request = PdmObject_pb2.PdmObjectMethodRequest(
|
||||
object=self._pb2_object, method=method_name, params=pb2_params
|
||||
)
|
||||
|
||||
pb2_object = self._pdm_object_stub.CallPdmObjectMethod(request)
|
||||
|
||||
pdm_object = class_definition(pb2_object=pb2_object, channel=self.channel())
|
||||
return pdm_object
|
||||
|
||||
O = TypeVar("O")
|
||||
|
||||
def _call_pdm_method_return_optional_value(
|
||||
self, method_name: str, class_definition: Type[O], **kwargs: Any
|
||||
) -> Optional[O]:
|
||||
pb2_params = PdmObject_pb2.PdmObject(class_keyword=method_name)
|
||||
for key, value in kwargs.items():
|
||||
pb2_params.parameters[snake_to_camel(key)] = self.__convert_to_grpc_value(
|
||||
@ -440,12 +498,11 @@ class PdmObjectBase:
|
||||
if child_class_definition is None:
|
||||
return None
|
||||
|
||||
pdm_object = child_class_definition(
|
||||
pb2_object=pb2_object, channel=self.channel()
|
||||
)
|
||||
assert class_definition.__name__ == child_class_definition.__name__
|
||||
pdm_object = class_definition(pb2_object=pb2_object, channel=self.channel())
|
||||
return pdm_object
|
||||
|
||||
def update(self):
|
||||
def update(self) -> None:
|
||||
"""Sync all fields from the Python Object to ResInsight"""
|
||||
self.__copy_to_pb2()
|
||||
if self._pdm_object_stub is not None:
|
||||
|
@ -17,16 +17,18 @@ from Definitions_pb2 import Empty
|
||||
import Project_pb2_grpc
|
||||
import Project_pb2
|
||||
import PdmObject_pb2
|
||||
from .resinsight_classes import Project, PlotWindow, WellPath, SummaryCase
|
||||
from .resinsight_classes import Project, PlotWindow, WellPath, SummaryCase, Reservoir
|
||||
|
||||
from typing import Optional, List
|
||||
|
||||
|
||||
@add_method(Project)
|
||||
def __custom_init__(self, pb2_object, channel):
|
||||
def __custom_init__(self, pb2_object, channel: grpc.Channel) -> None:
|
||||
self._project_stub = Project_pb2_grpc.ProjectStub(self._channel)
|
||||
|
||||
|
||||
@add_static_method(Project)
|
||||
def create(channel):
|
||||
def create(channel: grpc.Channel) -> Project:
|
||||
project_stub = Project_pb2_grpc.ProjectStub(channel)
|
||||
pb2_object = project_stub.GetPdmObject(Empty())
|
||||
return Project(pb2_object, channel)
|
||||
@ -56,13 +58,13 @@ def save(self, path=""):
|
||||
|
||||
|
||||
@add_method(Project)
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close the current project (and open new blank project)"""
|
||||
self._execute_command(closeProject=Empty())
|
||||
|
||||
|
||||
@add_method(Project)
|
||||
def load_case(self, path, grid_only=False):
|
||||
def load_case(self: Project, path: str, grid_only: bool = False) -> Reservoir:
|
||||
"""Load a new grid case from the given file path
|
||||
|
||||
Arguments:
|
||||
@ -77,7 +79,7 @@ def load_case(self, path, grid_only=False):
|
||||
|
||||
|
||||
@add_method(Project)
|
||||
def selected_cases(self):
|
||||
def selected_cases(self) -> List[Case]:
|
||||
"""Get a list of all grid cases selected in the project tree
|
||||
|
||||
Returns:
|
||||
@ -91,17 +93,17 @@ def selected_cases(self):
|
||||
|
||||
|
||||
@add_method(Project)
|
||||
def cases(self):
|
||||
def cases(self: Project) -> List[Reservoir]:
|
||||
"""Get a list of all grid cases in the project
|
||||
|
||||
Returns:
|
||||
A list of :class:`rips.generated.generated_classes.Case`
|
||||
"""
|
||||
return self.descendants(Case)
|
||||
return self.descendants(Reservoir)
|
||||
|
||||
|
||||
@add_method(Project)
|
||||
def case(self, case_id):
|
||||
def case(self: Project, case_id: int) -> Optional[Reservoir]:
|
||||
"""Get a specific grid case from the provided case Id
|
||||
|
||||
Arguments:
|
||||
|
0
GrpcInterface/Python/rips/py.typed
Normal file
0
GrpcInterface/Python/rips/py.typed
Normal file
@ -6,7 +6,7 @@ import random
|
||||
|
||||
class RetryPolicy(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def sleep(self, retry_num):
|
||||
def sleep(self, retry_num: int) -> None:
|
||||
"""
|
||||
How long to sleep in milliseconds.
|
||||
:param retry_num: the number of retry (starting from zero)
|
||||
@ -14,14 +14,14 @@ class RetryPolicy(abc.ABC):
|
||||
assert retry_num >= 0
|
||||
|
||||
@abc.abstractmethod
|
||||
def time_out_message(self):
|
||||
def time_out_message(self) -> str:
|
||||
"""
|
||||
Generate a error message for user on time out.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def num_retries(self):
|
||||
def num_retries(self) -> int:
|
||||
"""
|
||||
Max number retries.
|
||||
"""
|
||||
@ -29,29 +29,34 @@ class RetryPolicy(abc.ABC):
|
||||
|
||||
|
||||
class FixedRetryPolicy(RetryPolicy):
|
||||
def __init__(self, sleep_time=1000, max_num_retries=10):
|
||||
def __init__(self, sleep_time: int = 1000, max_num_retries: int = 10):
|
||||
"""
|
||||
Create a fixed time retry policy.
|
||||
:param sleep_time: time to sleep in milliseconds.
|
||||
:param max_num_retries: max number of retries.
|
||||
"""
|
||||
self.sleep_time = sleep_time
|
||||
self.max_num_retries = max_num_retries
|
||||
self.sleep_time: int = sleep_time
|
||||
self.max_num_retries: int = max_num_retries
|
||||
|
||||
def sleep(self, retry_num):
|
||||
def sleep(self, retry_num: int) -> None:
|
||||
time.sleep(self.sleep_time / 1000)
|
||||
|
||||
def time_out_message(self):
|
||||
def time_out_message(self) -> str:
|
||||
return "Tried {} times with {} milliseconds apart.".format(
|
||||
self.max_num_retries, self.sleep_time
|
||||
)
|
||||
|
||||
def num_retries(self):
|
||||
def num_retries(self) -> int:
|
||||
return self.max_num_retries
|
||||
|
||||
|
||||
class ExponentialBackoffRetryPolicy(RetryPolicy):
|
||||
def __init__(self, min_backoff=200, max_backoff=10000, max_num_retries=20):
|
||||
def __init__(
|
||||
self,
|
||||
min_backoff: int = 200,
|
||||
max_backoff: int = 10000,
|
||||
max_num_retries: int = 20,
|
||||
):
|
||||
"""
|
||||
Create a truncated exponential backoff policy.
|
||||
See: https://en.wikipedia.org/wiki/Exponential_backoff
|
||||
@ -59,12 +64,12 @@ class ExponentialBackoffRetryPolicy(RetryPolicy):
|
||||
:param max_backoff: maximum time to sleep in milliseconds.
|
||||
:param max_num_retries: max number of retries.
|
||||
"""
|
||||
self.min_backoff = min_backoff
|
||||
self.max_backoff = max_backoff
|
||||
self.max_num_retries = max_num_retries
|
||||
self.multiplier = 2
|
||||
self.min_backoff: int = min_backoff
|
||||
self.max_backoff: int = max_backoff
|
||||
self.max_num_retries: int = max_num_retries
|
||||
self.multiplier: int = 2
|
||||
|
||||
def sleep(self, retry_num):
|
||||
def sleep(self, retry_num: int) -> None:
|
||||
# Add a random component to avoid synchronized retries
|
||||
wiggle = random.randint(0, 100)
|
||||
sleep_ms = min(
|
||||
@ -72,12 +77,12 @@ class ExponentialBackoffRetryPolicy(RetryPolicy):
|
||||
)
|
||||
time.sleep(sleep_ms / 1000)
|
||||
|
||||
def time_out_message(self):
|
||||
def time_out_message(self) -> str:
|
||||
return (
|
||||
"Tried {} times with increasing delay (from {} to {} milliseconds).".format(
|
||||
self.max_num_retries, self.min_backoff, self.max_backoff
|
||||
)
|
||||
)
|
||||
|
||||
def num_retries(self):
|
||||
def num_retries(self) -> int:
|
||||
return self.max_num_retries
|
||||
|
@ -8,21 +8,27 @@ import SimulationWell_pb2_grpc
|
||||
|
||||
import Properties_pb2
|
||||
import Properties_pb2_grpc
|
||||
import PdmObject_pb2
|
||||
|
||||
from .resinsight_classes import SimulationWell
|
||||
|
||||
from .case import Case
|
||||
from .pdmobject import PdmObjectBase, add_method
|
||||
|
||||
import rips.case
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
@add_method(SimulationWell)
|
||||
def __custom_init__(self, pb2_object, channel):
|
||||
self._simulation_well_stub = SimulationWell_pb2_grpc.SimulationWellStub(channel)
|
||||
def __custom_init__(
|
||||
self: SimulationWell, pb2_object: PdmObject_pb2.PdmObject, channel: grpc.Channel
|
||||
) -> None:
|
||||
self.__simulation_well_stub = SimulationWell_pb2_grpc.SimulationWellStub(channel)
|
||||
|
||||
|
||||
@add_method(SimulationWell)
|
||||
def status(self, timestep):
|
||||
def status(
|
||||
self: SimulationWell, timestep: int
|
||||
) -> List[SimulationWell_pb2.SimulationWellStatus]:
|
||||
"""Get simulation well status
|
||||
|
||||
**SimulationWellStatus class description**::
|
||||
@ -39,11 +45,13 @@ def status(self, timestep):
|
||||
sim_well_request = SimulationWell_pb2.SimulationWellRequest(
|
||||
case_id=self.case().id, well_name=self.name, timestep=timestep
|
||||
)
|
||||
return self._simulation_well_stub.GetSimulationWellStatus(sim_well_request)
|
||||
return self.__simulation_well_stub.GetSimulationWellStatus(sim_well_request)
|
||||
|
||||
|
||||
@add_method(SimulationWell)
|
||||
def cells(self, timestep):
|
||||
def cells(
|
||||
self: SimulationWell, timestep: int
|
||||
) -> List[SimulationWell_pb2.SimulationWellCellInfo]:
|
||||
"""Get reservoir cells the simulation well is defined for
|
||||
|
||||
**SimulationWellCellInfo class description**::
|
||||
@ -66,9 +74,9 @@ def cells(self, timestep):
|
||||
sim_well_request = SimulationWell_pb2.SimulationWellRequest(
|
||||
case_id=self.case().id, well_name=self.name, timestep=timestep
|
||||
)
|
||||
return self._simulation_well_stub.GetSimulationWellCells(sim_well_request).data
|
||||
return self.__simulation_well_stub.GetSimulationWellCells(sim_well_request).data
|
||||
|
||||
|
||||
@add_method(SimulationWell)
|
||||
def case(self):
|
||||
return self.ancestor(rips.case.Case)
|
||||
def case(self: SimulationWell) -> Optional[Case]:
|
||||
return self.ancestor(Case)
|
||||
|
@ -140,10 +140,6 @@ def test_PdmObject(rips_instance, initialize_test):
|
||||
assert case.__class__.__name__ == "EclipseCase"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform.startswith("linux"),
|
||||
reason="Brugge is currently exceptionally slow on Linux",
|
||||
)
|
||||
def test_brugge_0010(rips_instance, initialize_test):
|
||||
case_path = dataroot.PATH + "/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID"
|
||||
case = rips_instance.project.load_case(path=case_path)
|
||||
@ -157,10 +153,6 @@ def test_brugge_0010(rips_instance, initialize_test):
|
||||
assert len(days_since_start) == 11
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform.startswith("linux"),
|
||||
reason="Brugge is currently exceptionally slow on Linux",
|
||||
)
|
||||
def test_replaceCase(rips_instance, initialize_test):
|
||||
project = rips_instance.project.open(
|
||||
dataroot.PATH + "/TEST10K_FLT_LGR_NNC/10KWithWellLog.rsp"
|
||||
@ -192,10 +184,6 @@ def test_loadNonExistingCase(rips_instance, initialize_test):
|
||||
assert rips_instance.project.load_case(case_path)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform.startswith("linux"),
|
||||
reason="Brugge is currently exceptionally slow on Linux",
|
||||
)
|
||||
def test_exportFlowCharacteristics(rips_instance, initialize_test):
|
||||
case_path = dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID"
|
||||
case = rips_instance.project.load_case(case_path)
|
||||
|
@ -3,8 +3,6 @@ import os
|
||||
from typing import Any, Dict, List, TypedDict
|
||||
import math
|
||||
|
||||
from generated.generated_classes import Case
|
||||
|
||||
sys.path.insert(1, os.path.join(sys.path[0], "../../"))
|
||||
import rips
|
||||
|
||||
@ -69,7 +67,7 @@ def test_10k(rips_instance, initialize_test):
|
||||
check_corner(cell_corners[cell_index].c7, expected_corners[7])
|
||||
|
||||
|
||||
def check_reek_grid_box(case: Case):
|
||||
def check_reek_grid_box(case: rips.Case):
|
||||
assert len(case.grids()) == 1
|
||||
grid = case.grid(index=0)
|
||||
|
||||
@ -107,7 +105,7 @@ def test_load_grdecl_grid(rips_instance, initialize_test):
|
||||
|
||||
|
||||
def verify_load_grid_and_separate_properties(
|
||||
case: Case, property_name_and_paths: NameAndPath
|
||||
case: rips.Reservoir, property_name_and_paths: NameAndPath
|
||||
):
|
||||
# Load case without properties
|
||||
available_properties = case.available_properties("INPUT_PROPERTY")
|
||||
|
@ -54,10 +54,6 @@ def test_well_log_plots(rips_instance, initialize_test):
|
||||
assert plot2.depth_type == "TRUE_VERTICAL_DEPTH_RKB"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform.startswith("linux"),
|
||||
reason="Brugge is currently exceptionally slow on Linux",
|
||||
)
|
||||
def test_loadGridCaseGroup(rips_instance, initialize_test):
|
||||
case_paths = []
|
||||
case_paths.append(dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID")
|
||||
|
@ -10,10 +10,6 @@ import rips
|
||||
import dataroot
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform.startswith("linux"),
|
||||
reason="Brugge is currently exceptionally slow on Linux",
|
||||
)
|
||||
def test_create_and_export_surface(rips_instance, initialize_test):
|
||||
case_path = dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID"
|
||||
case = rips_instance.project.load_case(path=case_path)
|
||||
|
@ -8,17 +8,19 @@ from .plot import Plot
|
||||
from .pdmobject import PdmObjectBase, add_method
|
||||
from .resinsight_classes import WellLogPlot
|
||||
|
||||
from typing import List
|
||||
|
||||
|
||||
@add_method(WellLogPlot)
|
||||
def export_data_as_las(
|
||||
self,
|
||||
export_folder,
|
||||
file_prefix="",
|
||||
export_tvdrkb=False,
|
||||
capitalize_file_names=False,
|
||||
resample_interval=0.0,
|
||||
convert_to_standard_units=False,
|
||||
):
|
||||
self: WellLogPlot,
|
||||
export_folder: str,
|
||||
file_prefix: str = "",
|
||||
export_tvdrkb: bool = False,
|
||||
capitalize_file_names: bool = False,
|
||||
resample_interval: float = 0.0,
|
||||
convert_to_standard_units: bool = False,
|
||||
) -> List[str]:
|
||||
"""Export LAS file(s) for the current plot
|
||||
|
||||
Arguments:
|
||||
@ -48,8 +50,11 @@ def export_data_as_las(
|
||||
|
||||
@add_method(WellLogPlot)
|
||||
def export_data_as_ascii(
|
||||
self, export_folder, file_prefix="", capitalize_file_names=False
|
||||
):
|
||||
self: WellLogPlot,
|
||||
export_folder: str,
|
||||
file_prefix: str = "",
|
||||
capitalize_file_names: bool = False,
|
||||
) -> List[str]:
|
||||
"""Export LAS file(s) for the current plot
|
||||
|
||||
Arguments:
|
||||
|
@ -18,6 +18,6 @@ setup(
|
||||
url='http://www.resinsight.org',
|
||||
license=license,
|
||||
packages=['rips'],
|
||||
package_data={'rips': ['*.py', 'generated/*.py', 'PythonExamples/*.py', 'tests/*.py']},
|
||||
package_data={'rips': ['py.typed', '*.py', 'generated/*.py', 'PythonExamples/*.py', 'tests/*.py']},
|
||||
install_requires=['grpcio', 'protobuf', 'wheel']
|
||||
)
|
Loading…
Reference in New Issue
Block a user