Search code examples
pythonc#python.netflaui

FlaUI: Unable to call any Retry method through Python.NET


I am trying to call FlaUI FlaUI.Core.Tools.Retry class method WhileNull through Python.NET (https://github.com/FlaUI/FlaUI/blob/master/src/FlaUI.Core/Tools/Retry.cs). However, I am not able to figure out how to pass method using System.Func.

The method has below signature,

public static RetryResult<T> WhileNull<T>(Func<T> checkMethod, TimeSpan? timeout = null, TimeSpan? interval = null, bool throwOnTimeout = false, bool ignoreException = false, string timeoutMessage = null)

Here is the working C# code I want to replicate in Python.NET,

using FlaUI.Core;
using FlaUI.Core.Conditions;
using FlaUI.Core.Tools;
using FlaUI.Core.Definitions;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;

var app = Application.Launch("software.exe");

var mainWindow = app.GetMainWindow(new UIA3Automation());

ConditionFactory cf = new ConditionFactory(new UIA3PropertyLibrary());
Retry.WhileNull(() => mainWindow.FindFirstDescendant(
    cf => cf.ByName("Connect")), throwOnTimeout: true);

I created the below code in Python.NET (the application launch works and I am able to get main window),

import clr
import sys
flaui_core_path = 'C:\\path\\to\\flaui.core\\dll'
flaui_uia3_path = 'C:\\path\\to\\flaui.uia3\\dll'
interop_uiautomation_path = 'C:\\path\\to\\interop.uiautomationclient\\dll'
sys.path.append(flaui_core_path)
clr.AddReference('FlaUI.Core')
sys.path.append(interop_uiautomation_path)
clr.AddReference('Interop.UIAutomationClient')
sys.path.append(flaui_uia3_path)
clr.AddReference('FlaUI.UIA3')
from FlaUI.Core import Application
from FlaUI.Core.AutomationElements import AutomationElement
from FlaUI.Core.Conditions import ConditionFactory, ConditionBase
from FlaUI.Core.Tools import Retry
from FlaUI.UIA3 import UIA3Automation
from FlaUI.UIA3 import UIA3PropertyLibrary
clr.AddReference('System')
import System

app = Application.Launch('software.exe')
main_window = app.GetMainWindow(UIA3Automation())
cf = ConditionFactory(UIA3PropertyLibrary())
def find_first_descendant():
    def cf_by_name(cf):
        return cf.ByName("Connect")
    return main_window.FindFirstDescendant(
        System.Func[ConditionFactory, ConditionBase](cf_by_name)
    )
Retry.WhileNull(System.Func[AutomationElement](find_first_descendant), throwOnTimeout=True)

The above code launches the software. However, it throws the below error after entering into Retry.WhileNull

Traceback (most recent call last):
  File ".\sample.py", line 30, in <module>
    Retry.WhileNull(System.Func[AutomationElement](find_first_descendant), throwOnTimeout=True)
TypeError: No method matches given arguments for WhileNull: (<class 'System.0, Culture=neutral, PublicKeyToken=null]]'>) 

Solution

  • Explicitly supplying function generic type argument will work:

    WhileNull[System.Int32](
      System.Func[System.Int32](my_func),
      throwOnTimeout=True)
    

    At the moment pythonnet can only resolve generics when they are used directly (e.g. if the first parameter was T, not Func<T>).