NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Sequence File does not run when called from Python using win32com

Environment:

TestStand 2023 Q4 32-bit

Python 3.11 32-bit

Win11 64-bit

 

I have a Python file that launches a TestStand sequence. I have a simple seq file that receives a string input and only sets the input to the output variable. This seq file works from TestStand environment both sequential model entry points and also works when called by Python module. I did this to verify the Python file used to call TestStand works with a very simple seq before calling the more complex seq file.

 

I have my main TestStand sequence file that runs when I launch from TestStand environment using both Test UUTs and Single Pass sequential model entry points BUT it hangs forever when run from Python. The seq file calls VeriStand using ASAM XIL and also calls Python modules using the configured adapter. The calling Python module uses a different virtual environment than the Python calls within TestStand. Also, the seq file calls other seq files contained within the main sequence dynamically. There are no Pop Ups or breakpoints, and it takes around 2.5 seconds to execute (I have a lot of steps skipped). When I replaced the method Execution.WaitForEndEx(-1) with a timed 60 second loop calling Execution.GetStates() every 5 seconds, I see that the run state is always executing, and the termination state is always normal.

 

What could cause this behavior?

 

Thanks

Randy

 

 

 

0 Kudos
Message 1 of 4
(140 Views)

More details:

Skipped all steps in MainSequence except for setting output parameters equal to input parameter and still hangs forever. Added a sequence_file.LoadModules(0) and UnloadModules() method calls and commented out the call to NewExecution() and sequence completes so it is an issue with executing the seq file and both load and unload return true indicating success. I thought it may not be able to load all modules but that doesn't appear to be the case.

 

Still troubleshooting to see if I can determine the root cause.

0 Kudos
Message 2 of 4
(124 Views)

I am a little confused.  In your first paragraph you were successful in calling a sequence from Python that takes an input string parameter and an output string parameter.  In your "More details" post you have a different sequence but everything is skipped except setting the output parameters.  So, aren't these two sequences basically the same except maybe the second sequence has more and/or different type of parameters?  In my limited experience calling sequences from Python is that the parameters that are being passed must exactly match the parameters in the sequence.  I suggest starting with one parameter and getting that to work, then add additional parameters one at a time.  Also, I like to add a Message Popup as the first step in the sequence to display the input parameters when debugging the sequence.

 

Below is a Python example that I created to demonstrate passing a string, number and container and then extracting the returned data:

class EngineEventHandler:
    def OnUIMessageEvent(self, uiMsgEvent):
        pass

if __name__ == '__main__':
    try:
        test_stand_engine = win32com.client.Dispatch('TestStand.Engine')
        test_stand_engine_event = win32com.client.WithEvents(test_stand_engine, EngineEventHandler)

        # Create container to pass the input and output parameters
        property_object_params = test_stand_engine.NewPropertyObject(PropertyValueTypes.PropValType_Container, False, "", 0)

        # Add the input and output parameters to the container (Apparently the order here must match the parameter order in the sequence)
        # Sequence parameters are:
        #   IN_string (string)
        #   IN_number (number)
        #   OUT_string (string)
        #   OUT_container (container containing the following)
        #     container_string (string)
        #     container_number (number)
        property_object_params.SetValString("IN_string", PropertyOptions.PropOption_InsertIfMissing, "Hello, World!")
        property_object_params.SetValNumber("IN_number", PropertyOptions.PropOption_InsertIfMissing, 123.45)
        property_object_params.SetValString("OUT_string", PropertyOptions.PropOption_InsertIfMissing, "")
        property_object_params.SetValNumber("OUT_number", PropertyOptions.PropOption_InsertIfMissing, 0.0)
        out_container = test_stand_engine.NewPropertyObject(PropertyValueTypes.PropValType_Container, False, "", 0)
        out_container.SetValString("container_string", PropertyOptions.PropOption_InsertIfMissing, "")
        out_container.SetValNumber("container_number", PropertyOptions.PropOption_InsertIfMissing, 0.0)
        property_object_params.SetPropertyObject("OUT_container", PropertyOptions.PropOption_InsertIfMissing, out_container)

        # Call MainSequence which performs the following sequence step:
        #   Parameters.OUT_string = Parameters.IN_string,
        #   Parameters.OUT_number = Parameters.IN_number,
        #   Parameters.OUT_container.container_string = Parameters.IN_string,
        #   Parameters.OUT_container.container_number = Parameters.IN_number
        sequence_file = test_stand_engine.GetSequenceFileEx(r"C:\B2\users\Vaughn\Project Base Directory\Drivers\CAN\CAN_py.seq")
        execution = test_stand_engine.NewExecution(sequence_file,
                                                   "MainSequence",
                                                   None,
                                                   False,
                                                   0,
                                                   property_object_params)
        execution.WaitForEndEx(-1)
        time.sleep(0.5)
        execution.Terminate()

        # Extract output parameters
        out_string = property_object_params.GetValString("OUT_string", 0)
        out_number = property_object_params.GetValNumber("OUT_number", 0)
        out_container = property_object_params.GetPropertyObject("OUT_container", 0)
        out_container_string = out_container.GetValString("container_string", 0)
        out_container_number = out_container.GetValNumber("container_number", 0)
        print(f"out_string = {out_string}")
        print(f"out_string = {out_number}")
        print(f"out_container_string = {out_container_string}")
        print(f"out_container_number = {out_container_number}")

        # Cleanup
        del execution
        del sequence_file
        del property_object_params

    except Exception as e:
        print(f"******************\nException Occurred\n******************")
        traceback.print_exc()

 This produces the output:

out_string = Hello, World!
out_string = 123.45
out_container_string = Hello, World!
out_container_number = 123.45

0 Kudos
Message 3 of 4
(105 Views)

The sequence that ran has a single step ... it adds the 1 to the input parameter ... I was just trying to make sure that the Python code ran a sequence file and terminated successfully. My Python code is very similar as to what you posted but I have added a lot of additional error handling and am in the process of adding a message handler that I will post here that would have shown the issue much sooner. I pass a lot of parameters of all types to my sequence from the CI/CD server and those weren't the issue.

 

I then took my main sequence that has a mix of TS steps, Python calls, VeriStand calls and tried to run it ... it hangs forever.

 

I started skipping lines to see where it broke being called using the win32com from Python. The sequence executes if I launch using the TS GUI for both the Single Pass and Test UUTs entry points of the sequential model. So the difference has to be in invoking from the GUI as opposed to Python.

 

The parameters are named correctly for those used in the main test sequence, they were used to just to verify and remove a possible error when calling the TS sequence from Python. The main sequence failed even when not using any parameters.

 

I started adding steps back in and think I have found the root cause. The TS GUI allows you to add a sequence call and select the checkbox Use Current File so that a blank field is entered into the XML file that TS generates. When running from Python it has and I do not have a handler written to handle the message from TS. When I uncheck the Use Current File and then enter the sequence file and path then it is now entered into the XML and the sequence runs when called from Python. I made a few changes in my main sequence and verified it worked and just finished checking and changing every sequence file (over 150) to uncheck and select the sequence file that is being used but have not yet re-run the main sequence from Python.

 

I had tried changing the sequence call to use New Client File and New real time sequence from the default of None but those changes made it not work from the TS GUI (or editor in this case). It was after trying those changes that I looked at the paths after unchecking the Use Current File and noticed it was either blank or had an incorrect path or even just a dir but no sequence file reference.

 

TS is very powerful but at times its documentation is very lacking. In this case I believe I found a bug so that if you create a new sequence call and use the defaults (Use Current Sequence is checked) or move a sequence from another project (where then it may not run from being called from Python.

 

Thanks

Randy

0 Kudos
Message 4 of 4
(92 Views)