EqualUNOObjects() for Python?

Basic has EqualUNOObjects().

How could I test for equality in python for UNO objects?

For instance if I want to find a control in a form such as a button:

def get_control_index(form: XForm, ctl: Any) -> int:
    if ctl is None:
        return -1
    for i in range(form.getCount()):
        obj = form.getByIndex(i)
        # this comparison is not correct and needs to be fixed
        if obj == ctl:
            return i
    return -1

in Python : Programming with Python there is no Python equivalent for EqualUnoObjects. What is the problem with the == in python? Compile time error, runtime error, or the control is not found?

Hmm… could EqualUNOObjects be invoked from python using XScript? See: Retrieving LibreOffice Basic Scripts

Yes, you could write a basic macro and call it with the objects as parameters.
Again, what is the problem with ==?
Can you post a minimum viable python sample?

There are few reason I would like to compare for equality.
I am developing OOO Development Tools

This is one example I need to convet to python.

Function FindShapeForControl(oDrawPage, oControl)
  Dim i
  Dim oShape
  For i = 0 To oDrawPage.getCount()
    oShape = oDrawPage.getByIndex(i)
    If oShape.supportsService("com.sun.star.drawing.ControlShape") Then
      If EqualUNOObjects(oControl, oShape.Control) Then
        FindShapeForControl = oShape
        Exit Function
      End If
    End If
  Next
End Function

In sbunoobj.cxx (revision ff23937c) - OpenGrok cross reference for /core/basic/source/classes/sbunoobj.cxx (line 3127) it looks like the comparison is made on an Any type (getUnoAny). In getUnoAny (line 2823) XMaterialHolder and XInvocation are used, which should also be available for Python. So if there is a problem with == (Again, what is the problem?) I am optimistic that a proper python implementation of EqalUnoObjects is possible

Thanks, I will study this and see what I can come up with.

PyUNO_cmp implements Python comparison (== / !=) the same way as EqualUnoObjects (implementation is here). It is done by comparing the two Anys, that, when hold a Reference, is equivalent to comparison of the references.

I was under the impression that it was not possible to compare pyuno object in python using the ==.
Did I missunderstand?

I went from this mess:

def get_control_index(form: XForm, ctl: FormCtlBase | XControlModel) -> int:
    if ctl is None:
        return -1
    x_ctl = ctl.get_control().getModel() if mInfo.Info.is_instance(ctl, FormCtlBase) else ctl
    model = cast(Any, mLo.Lo.qi(XControlModel, x_ctl))
    if model is None:
        return -1
    try:
        imp_name = model.ImplementationName
        name = model.Name
    except Exception:
        return -1
    if not name:
        return -1
    ic = mLo.Lo.qi(XIndexContainer, form, True)
    for i in range(ic.getCount()):
        obj = ic.getByIndex(i)
        obj_model = cast(Any, mLo.Lo.qi(XControlModel, obj))
        if obj_model is None:
            continue
        try:
            if obj_model.ImplementationName == imp_name and obj_model.Name == name:
                return i
        except Exception:
            continue
    return -1

to this:

def get_control_index(form: XForm, ctl: FormCtlBase | XControlModel) -> int:
    if ctl is None:
        return -1
    x_ctl = ctl.get_control().getModel() if mInfo.Info.is_instance(ctl, FormCtlBase) else ctl
    ic = mLo.Lo.qi(XIndexContainer, form, True)
    for i in range(ic.getCount()):
        obj = ic.getByIndex(i)
        if x_ctl == obj:
            return i
    return -1

It seems to work. Is this correct?

I have provided you with the specific links to the implementation, together with the explanation.
The Python == operator is implemented for custom types using PyTypeObject (see tp_richcompare); in PyUno (LibreOffice Python bridge), PyUNO_cmp implements that; it compares the objects that it wraps, the same way as the EqualUnoObjects Basic function does.

I don’t know what was the basis of the " it was not possible to compare pyuno object in python using the ==" understanding that you had. You have replaced the convoluted piece in your code with the plain ==, and you see it works. I can only say that this is what I was talking about.

But this doesn’t mean that you will find it (or EqualUnoObjects) behave as you expect in all cases. What they both do is compare if the two underlying references are pointing to the same UNO object. But consider this case: you call something like

a = sheet.getCellRangeByPosition(0,0,1,1)
b = sheet.getCellRangeByPosition(0,0,1,1)

The two objects refer to the same range on the same sheet. But they are the two different UNO objects, each created on demand, inside the getCellRangeByPosition call: see the return new ScCellRangeObj there. The objects are physically different; so both the Python’s a == b, and Basoc’s EqualUnoObjects(a, b) will give false.

This depends on how some specific functionality is implemented internally in LibreOffice. Some objects in the LibreOffice core are UNO objects themselves; then all references will point to the same actual implementation (like with a sheet object). Sometimes, there is no object in the core (like there’s no range object for A1:B2, until user wanted it - indeed, there is a huge number of possible ranges); so UNO objects are only created on demand, and there may be “twin” objects describing “same” thing. Indeed, it would be a natural wish to make improvements, like extending equality checks specifically for such objects, or implementing a way to avoid creation of a duplicated object, when there already is an identical object … everything is possible in software, just someone have to implement that. I write all this, just to set correct expectations.

1 Like

All this information is very helpful.

Thank you so much.
The short of it is you answered my question.
The long of it is, must be aware of what object are being compared.