Unable to use EmbedPropertiesAttribute and ResourceOpenAttribute and others in Python

Issue with ResourceOpenAttribute and EmbedPropertiesAttribute in Python

Hello everyone,

I am currently unable to use ResourceOpenAttribute and EmbedPropertiesAttribute in Python, even though I have the latest versions of the plugins installed.

Here is a sample of the code I am working with:

Broker = opentap.property(Broker, None).add_attribute(OpenTap.Display("MQTT Broker"))\
        .add_attribute(OpenTap.ResourceOpenAttribute(OpenTap.ResourceOpenBehavior.Ignore))

Meas = opentap.property(Measurement, None).add_attribute(OpenTap.Display("Measurement"))\
        .add_attribute(OpenTap.EmbedPropertiesAttribute())

The Measurement class looks like this:

class Measurement:
    UpperLimit = None
    LowerLimit = None
    Value = None
    Verdict = None

Issue Log Excerpt:

2024-09-06 13:30:40.919831 ; Python         ; Debug       ; Loading: Demo.DemoStep
2024-09-06 13:30:40.970696 ; Python         ; Error       ; Caught exception loading Demo.DemoStep: Unable to cast object of type 'OpenTap.EmbedPropertiesAttribute' to type 'System.Type'.
2024-09-06 13:30:40.973255 ; Python         ; Debug       ; PythonException: Unable to cast object of type 'OpenTap.EmbedPropertiesAttribute' to type 'System.Type'.
2024-09-06 13:30:40.983317 ; Python         ; Debug       ;     File "\Demo\DemoStep.py", line 16, in <module>
2024-09-06 13:30:40.983317 ; Python         ; Debug       ;     class DemoStep(TestStep):
2024-09-06 13:30:40.983317 ; Python         ; Debug       ;     at Python.Runtime.PythonException.ThrowLastAsClrException()
2024-09-06 13:30:40.983317 ; Python         ; Debug       ;     at Python.Runtime.NewReferenceExtensions.BorrowOrThrow(NewReference& reference)
2024-09-06 13:30:40.983317 ; Python         ; Debug       ;     at Python.Runtime.PyModule.Import(String name)
2024-09-06 13:30:40.983317 ; Python         ; Debug       ;     at OpenTap.Python.PythonPluginProvider.Search()
2024-09-06 13:30:40.984329 ; Python         ; Debug       ; Exception caught at:
2024-09-06 13:30:40.987420 ; Python         ; Debug       ;     at Void <StartAwaitable>b__0()
2024-09-06 13:30:40.987420 ; Python         ; Debug       ;     at Void Process()
2024-09-06 13:30:40.987420 ; Python         ; Debug       ;     at Void processQueue()
2024-09-06 13:30:40.987420 ; Python         ; Debug       ;     at Void RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)

Request for Help:

I am getting the following error:

  • Unable to cast object of type ‘OpenTap.EmbedPropertiesAttribute’ to type ‘System.Type’
  • Unable to cast object of type ‘OpenTap.ResourceOpenAttribute’ to type ‘System.Type’

Any help to resolve this issue would be highly appreciated!

Thanks!

Hi @yannick.njanjo,

Did you try writing OpenTap.ResourceOpen instead of OpenTap.ResourceOpenAttribute. This might seem a bit surprising. The problem is that OpenTap.ResourceOpenAttribute will create an instance of the attribute object, which is difficult to convert back into what we need to generate the .NET class.

I think this should work:

Broker = opentap.property(Broker, None).add_attribute(OpenTap.Display("MQTT Broker"))\
        .add_attribute(OpenTap.ResourceOpen(OpenTap.ResourceOpenBehavior.Ignore))

Meas = opentap.property(Measurement, None).add_attribute(OpenTap.Display("Measurement"))\
        .add_attribute(OpenTap.EmbedProperties())

Hi Rolf,

Thanks for your reply. I figured this out but forgot to update the post as I was busy with another project.
Unfortunately, the EmbedProperties attribute still doesn’t work. When I apply it to a class attribute, it disappears from the Settings area in the editor. Without it, the setting is displayed as a serialized string, e.g., {UpperLimit=0, LowerLimit=0,...}.
Do you have any idea why this happens?

Can you show how you use it?

MV = opentap.property(Measurement, None).add_attribute(OpenTap.Display("Measurement"))\
        .add_attribute(OpenTap.EmbedProperties())

Ok, thats a start :slight_smile:

I also need to see the object you are embedding and when you create the instance of it.

Sorry it took me a few minutes. I had to rewrite it again from ‘scratch’.


"""
 An example of how to define a Python Test Step
"""
import time
import opentap
from opentap import *
import System
from System import Double, Int32, String
import OpenTap
from OpenTap import Display, Unit

VALID_DATA_TYPES = (int, float, str, bool)

class Measurement:
    _UpperLimit = opentap.property(Double, None).add_attribute(OpenTap.Display("Upper Limit"))
    _LowerLimit = opentap.property(Double, None).add_attribute(OpenTap.Display("Lower Limit"))
    _SetPoint = opentap.property(Double, None).add_attribute(OpenTap.Display("Set Point"))
    
    def __init__(self, data_type: type, unit: str):
        if data_type not in VALID_DATA_TYPES:
            raise ValueError(f"data_type must be one of the following types: {VALID_DATA_TYPES}")
        
        self._data_type = data_type             
        self._unit = unit                       
        self._value = None                      
        self._timestamp = None                  
        self._verdict = OpenTap.Verdict.NotSet  
       

    @property
    def SetPoint(self):
        return self._SetPoint

    @SetPoint.setter
    def SetPoint(self, value):
        if not isinstance(value, self._data_type):
            raise TypeError(f"SetPoint must be of type {self._data_type.__name__}")
        if self._UpperLimit is not None and value > self._UpperLimit:
            raise ValueError(f"SetPoint {value} cannot exceed UpperLimit {self._UpperLimit}")
        if self._LowerLimit is not None and value < self._LowerLimit:
            raise ValueError(f"SetPoint {value} cannot be less than LowerLimit {self._LowerLimit}")
        self._SetPoint = value

    @property
    def Value(self):
        return self._value

    @Value.setter
    def Value(self, new_value):
        if not isinstance(new_value, self._data_type):
            raise TypeError(f"Value must be of type {self._data_type.__name__}")
        self._value = new_value
        self._timestamp = time.time()

    @property
    def Verdict(self):
        return self._verdict

    @Verdict.setter
    def Verdict(self, new_verdict: OpenTap.Verdict):
        if not isinstance(new_verdict, OpenTap.Verdict):
            raise ValueError(f"Invalid verdict. Verdict must be an instance of OpenTap.Verdict")
        self._verdict = new_verdict

    @property
    def Timestamp(self):
        return self._timestamp
    
    @property
    def DataType(self) -> str:
        # return str(self._data_type).split("'")[1]
        return self._data_type.__name__
    
    @property
    def Unit(self):
        return self._unit
    
   

@attribute(Display(Name="ForumStep", Description="ForumStep Description", Group="Demo"))
class ForumStep(TestStep):

	# Add your Test Step settings here
	# Example:
	# CellSize = property(Int32, 1)\
	#		.add_attribute(Display(Name="Cell Size", Description="Size of the cell", Group="Cell Settings", Order=1))

	MV = opentap.property(Measurement, None).add_attribute(OpenTap.Display("Measurement"))\
        .add_attribute(OpenTap.EmbedProperties())

	def __init__(self):
		super().__init__()
		self.Name="ForumStep"
          
		MV = Measurement(Int32, "°C")

	def Run(self):
		# Add code here to execute when test step runs
		self.log.Info("Running ForumStep")

First thing to try: Can you try to make Measurement inherit from System.Object? It needs to be a .NET object for it to work with EmbedPropertiesAttribute.

1 Like

It worked thanks.

class Measurement(Object):