2019-09-23 04:50:33 -05:00
|
|
|
# pylint: disable=no-self-use
|
|
|
|
"""
|
|
|
|
ResInsight caf::PdmObject connection module
|
|
|
|
"""
|
2020-01-21 01:48:56 -06:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
from functools import partial, wraps
|
2020-01-21 01:48:56 -06:00
|
|
|
import grpc
|
2020-02-21 05:10:02 -06:00
|
|
|
import re
|
|
|
|
import builtins
|
|
|
|
import importlib
|
|
|
|
import inspect
|
|
|
|
import sys
|
2020-01-21 01:48:56 -06:00
|
|
|
|
2019-09-23 04:50:33 -05:00
|
|
|
import rips.generated.PdmObject_pb2 as PdmObject_pb2
|
|
|
|
import rips.generated.PdmObject_pb2_grpc as PdmObject_pb2_grpc
|
|
|
|
import rips.generated.Commands_pb2 as Cmd
|
|
|
|
import rips.generated.Commands_pb2_grpc as CmdRpc
|
2020-02-21 05:10:02 -06:00
|
|
|
from rips.generated.pdm_objects import PdmObject
|
2019-06-10 13:42:20 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
def camel_to_snake(name):
|
|
|
|
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 add_method(cls):
|
|
|
|
def decorator(func):
|
|
|
|
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):
|
|
|
|
@wraps(func)
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
setattr(cls, func.__name__, wrapper)
|
|
|
|
# Note we are not binding func, but wrapper which accepts self but does exactly the same as func
|
|
|
|
return func # returning func means func can still be used normally
|
|
|
|
return decorator
|
2019-09-23 04:50:33 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def _execute_command(self, **command_params):
|
|
|
|
self.__warnings = []
|
|
|
|
response, call = self._commands.Execute.with_call(Cmd.CommandParams(**command_params))
|
|
|
|
for key, value in call.trailing_metadata():
|
|
|
|
value = value.replace(';;', '\n')
|
|
|
|
if key == 'warning':
|
|
|
|
self.__warnings.append(value)
|
2019-10-09 02:21:28 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
return response
|
2019-09-23 04:50:33 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def __custom_init__(self, pb2_object, channel):
|
|
|
|
self.__warnings = []
|
|
|
|
self.__keyword_translation = {}
|
|
|
|
|
|
|
|
if pb2_object is not None:
|
2019-09-23 04:50:33 -05:00
|
|
|
self._pb2_object = pb2_object
|
2020-02-21 05:10:02 -06:00
|
|
|
else:
|
|
|
|
self._pb2_object = PdmObject_pb2.PdmObject(class_keyword=self.__class__.__name__)
|
|
|
|
|
|
|
|
self._channel = channel
|
|
|
|
|
|
|
|
if self.pb2_object() is not None and self.channel() is not None:
|
|
|
|
if self.channel() is not None:
|
|
|
|
self._pdm_object_stub = PdmObject_pb2_grpc.PdmObjectServiceStub(self.channel())
|
|
|
|
self._commands = CmdRpc.CommandsStub(self.channel())
|
|
|
|
|
|
|
|
for camel_keyword in self._pb2_object.parameters:
|
|
|
|
snake_keyword = camel_to_snake(camel_keyword)
|
|
|
|
setattr(self, snake_keyword, self.__get_grpc_value(camel_keyword))
|
|
|
|
self.__keyword_translation[snake_keyword] = camel_keyword
|
|
|
|
self._superclasses = self.superclasses()
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def copy_from(self, object):
|
|
|
|
"""Copy attribute values from object to self
|
|
|
|
"""
|
|
|
|
for attribute in dir(object):
|
|
|
|
if not attribute.startswith('__'):
|
|
|
|
value = getattr(object, attribute)
|
|
|
|
if not callable(value):
|
|
|
|
setattr(self, attribute, value)
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def cast(self, class_definition):
|
|
|
|
if class_definition.__name__ == self.class_keyword() or class_definition.__name__ in self._superclasses:
|
|
|
|
new_object = class_definition(self.pb2_object(), self.channel())
|
|
|
|
new_object.copy_from(self)
|
|
|
|
return new_object
|
|
|
|
return None
|
2019-10-09 02:21:28 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def warnings(self):
|
|
|
|
return self.__warnings
|
2020-01-21 01:48:56 -06:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
|
|
|
|
def has_warnings(self):
|
|
|
|
return len(self.__warnings) > 0
|
2019-10-09 02:21:28 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def pb2_object(self):
|
|
|
|
""" Private method"""
|
|
|
|
return self._pb2_object
|
2019-09-23 04:50:33 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def channel(self):
|
|
|
|
""" Private method"""
|
|
|
|
return self._channel
|
2019-09-23 08:26:49 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def address(self):
|
|
|
|
"""Get the unique address of the PdmObject
|
2019-09-23 08:26:49 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
Returns:
|
|
|
|
A 64-bit unsigned integer address
|
|
|
|
"""
|
2019-10-09 03:51:24 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
return self._pb2_object.address
|
2019-09-23 04:50:33 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def class_keyword(self):
|
|
|
|
"""Get the class keyword in the ResInsight Data Model for the given PdmObject"""
|
|
|
|
return self._pb2_object.class_keyword
|
2019-07-31 04:02:42 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def set_visible(self, visible):
|
|
|
|
"""Set the visibility of the object in the ResInsight project tree"""
|
|
|
|
self._pb2_object.visible = visible
|
2019-06-10 13:42:20 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def visible(self):
|
|
|
|
"""Get the visibility of the object in the ResInsight project tree"""
|
|
|
|
return self._pb2_object.visible
|
2019-06-10 13:42:20 -05:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def print_object_info(self):
|
|
|
|
"""Print the structure and data content of the PdmObject"""
|
|
|
|
print("=========== " + self.class_keyword() + " =================")
|
|
|
|
print("Object Attributes: ")
|
|
|
|
for snake_kw, camel_kw in self.__keyword_translation.items():
|
|
|
|
print(" " + snake_kw + " [" + type(getattr(self, snake_kw)).__name__ +
|
|
|
|
"]: " + str(getattr(self, snake_kw)))
|
|
|
|
print("Object Methods:")
|
|
|
|
for method in dir(self):
|
|
|
|
if not method.startswith("_") and callable(getattr(self, method)):
|
|
|
|
print (" " + method)
|
2020-01-28 08:48:50 -06:00
|
|
|
|
2020-02-21 05:10:02 -06:00
|
|
|
@add_method(PdmObject)
|
|
|
|
def __convert_from_grpc_value(self, value):
|
|
|
|
if value.lower() == 'false':
|
|
|
|
return False
|
|
|
|
if value.lower() == 'true':
|
|
|
|
return True
|
|
|
|
try:
|
|
|
|
int_val = int(value)
|
|
|
|
return int_val
|
|
|
|
except ValueError:
|
2019-09-23 04:50:33 -05:00
|
|
|
try:
|
2020-02-21 05:10:02 -06:00
|
|
|
float_val = float(value)
|
|
|
|
return float_val
|
2019-09-23 04:50:33 -05:00
|
|
|
except ValueError:
|
2020-02-21 05:10:02 -06:00
|
|
|
# We may have a string. Strip internal start and end quotes
|
|
|
|
value = value.strip('\"')
|
|
|
|
if self.__islist(value):
|
|
|
|
return self.__makelist(value)
|
|
|
|
return value
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def __convert_to_grpc_value(self, value):
|
|
|
|
if isinstance(value, bool):
|
|
|
|
if value:
|
|
|
|
return "true"
|
|
|
|
return "false"
|
|
|
|
if isinstance(value, list):
|
|
|
|
list_of_strings = []
|
|
|
|
for val in value:
|
|
|
|
list_of_strings.append(self.__convert_to_grpc_value('\"' + val + '\"'))
|
|
|
|
return "[" + ", ".join(list_of_strings) + "]"
|
|
|
|
return str(value)
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def __get_grpc_value(self, camel_keyword):
|
|
|
|
return self.__convert_from_grpc_value(self._pb2_object.parameters[camel_keyword])
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def __set_grpc_value(self, camel_keyword, value):
|
|
|
|
self._pb2_object.parameters[camel_keyword] = self.__convert_to_grpc_value(value)
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def set_value(self, snake_keyword, value):
|
|
|
|
"""Set the value associated with the provided keyword and updates ResInsight
|
|
|
|
Arguments:
|
|
|
|
keyword(str): A string containing the parameter keyword
|
|
|
|
value(varying): A value matching the type of the parameter.
|
|
|
|
See keyword documentation and/or print_object_info() to find
|
|
|
|
the correct data type.
|
|
|
|
"""
|
|
|
|
setattr(self, snake_keyword, value)
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def __islist(self, value):
|
|
|
|
return value.startswith("[") and value.endswith("]")
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def __makelist(self, list_string):
|
|
|
|
list_string = list_string.lstrip("[")
|
|
|
|
list_string = list_string.rstrip("]")
|
|
|
|
strings = list_string.split(", ")
|
|
|
|
values = []
|
|
|
|
for string in strings:
|
|
|
|
values.append(self.__convert_from_grpc_value(string))
|
|
|
|
return values
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def descendants(self, class_keyword_or_class):
|
|
|
|
"""Get a list of all project tree descendants matching the class keyword
|
|
|
|
Arguments:
|
|
|
|
class_keyword_or_class[str/Class]: A class keyword matching the type of class wanted or a Class definition
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A list of PdmObjects matching the keyword provided
|
|
|
|
"""
|
|
|
|
class_definition = PdmObject
|
|
|
|
class_keyword = ""
|
|
|
|
if isinstance(class_keyword_or_class, str):
|
|
|
|
class_keyword = class_keyword_or_class
|
|
|
|
else:
|
|
|
|
assert(inspect.isclass(class_keyword_or_class))
|
|
|
|
class_keyword = class_keyword_or_class.__name__
|
|
|
|
class_definition = class_keyword_or_class
|
|
|
|
|
|
|
|
request = PdmObject_pb2.PdmDescendantObjectRequest(
|
|
|
|
object=self._pb2_object, child_keyword=class_keyword)
|
|
|
|
object_list = self._pdm_object_stub.GetDescendantPdmObjects(
|
|
|
|
request).objects
|
|
|
|
child_list = []
|
|
|
|
for pb2_object in object_list:
|
|
|
|
pdm_object = PdmObject(pb2_object=pb2_object, channel=self.channel())
|
|
|
|
if class_definition.__name__ == PdmObject.__name__:
|
|
|
|
child_list.append(pdm_object)
|
|
|
|
else:
|
|
|
|
casted_object = pdm_object.cast(class_definition)
|
|
|
|
if casted_object:
|
|
|
|
child_list.append(casted_object)
|
|
|
|
return child_list
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def children(self, child_field, class_definition=PdmObject):
|
|
|
|
"""Get a list of all direct project tree children inside the provided child_field
|
|
|
|
Arguments:
|
|
|
|
child_field[str]: A field name
|
|
|
|
Returns:
|
|
|
|
A list of PdmObjects inside the child_field
|
|
|
|
"""
|
|
|
|
request = PdmObject_pb2.PdmChildObjectRequest(object=self._pb2_object,
|
|
|
|
child_field=child_field)
|
|
|
|
try:
|
|
|
|
object_list = self._pdm_object_stub.GetChildPdmObjects(request).objects
|
2019-09-19 06:48:03 -05:00
|
|
|
child_list = []
|
2020-02-21 05:10:02 -06:00
|
|
|
for pb2_object in object_list:
|
|
|
|
pdm_object = PdmObject(pb2_object=pb2_object, channel=self.channel())
|
|
|
|
if class_definition.__name__ == PdmObject.__name__:
|
|
|
|
child_list.append(pdm_object)
|
|
|
|
else:
|
|
|
|
child_list.append(pdm_object.cast(class_definition))
|
2019-09-19 06:48:03 -05:00
|
|
|
return child_list
|
2020-02-21 05:10:02 -06:00
|
|
|
except grpc.RpcError as e:
|
|
|
|
if e.code() == grpc.StatusCode.NOT_FOUND:
|
|
|
|
return []
|
|
|
|
raise e
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def ancestor(self, class_keyword_or_class):
|
|
|
|
"""Find the first ancestor that matches the provided class_keyword
|
|
|
|
Arguments:
|
|
|
|
class_keyword_or_class[str/Class]: A class keyword matching the type of class wanted or a Class definition
|
|
|
|
"""
|
|
|
|
class_definition = PdmObject
|
|
|
|
class_keyword = ""
|
|
|
|
if isinstance(class_keyword_or_class, str):
|
|
|
|
class_keyword = class_keyword_or_class
|
|
|
|
else:
|
|
|
|
assert(inspect.isclass(class_keyword_or_class))
|
|
|
|
class_keyword = class_keyword_or_class.__name__
|
|
|
|
class_definition = class_keyword_or_class
|
|
|
|
|
|
|
|
request = PdmObject_pb2.PdmParentObjectRequest(
|
|
|
|
object=self._pb2_object, parent_keyword=class_keyword)
|
|
|
|
try:
|
|
|
|
pb2_object = self._pdm_object_stub.GetAncestorPdmObject(request)
|
|
|
|
pdm_object = PdmObject(pb2_object=pb2_object,
|
|
|
|
channel=self._channel)
|
|
|
|
if class_definition.__name__ == PdmObject.__name__:
|
|
|
|
return pdm_object
|
|
|
|
else:
|
|
|
|
return pdm_object.cast(class_definition)
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
if e.code() == grpc.StatusCode.NOT_FOUND:
|
|
|
|
return None
|
|
|
|
raise e
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def update(self):
|
|
|
|
"""Sync all fields from the Python Object to ResInsight"""
|
|
|
|
if self._pdm_object_stub is not None and self._pb2_object is not None:
|
|
|
|
for snake_kw, camel_kw in self.__keyword_translation.items():
|
|
|
|
self.__set_grpc_value(camel_kw, getattr(self, snake_kw))
|
2019-09-19 06:48:03 -05:00
|
|
|
|
2019-09-23 04:50:33 -05:00
|
|
|
self._pdm_object_stub.UpdateExistingPdmObject(self._pb2_object)
|
2020-02-21 05:10:02 -06:00
|
|
|
else:
|
|
|
|
raise Exception("Object is not connected to GRPC service so cannot update ResInsight")
|
|
|
|
|
|
|
|
@add_method(PdmObject)
|
|
|
|
def superclasses(self):
|
|
|
|
names = []
|
|
|
|
mod = importlib.import_module("rips.generated.pdm_objects")
|
|
|
|
for name, obj in inspect.getmembers(mod):
|
|
|
|
if (inspect.isclass(obj) and name == self.class_keyword()):
|
|
|
|
class_hierarchy = inspect.getmro(obj)
|
|
|
|
for cls in class_hierarchy:
|
|
|
|
names.append(cls.__name__)
|
|
|
|
return names
|