Is it possible to transfer a struct from Python to StarBasic?

Hi,

in StarBasic I could create a “Struct” like:

Private Type Test
  sString          As String
  bBool            As Boolean
  iInteger         As Integer
End Type

How can I create such a structure in Python, transfer it to Basic and access it as usual? As I understand, such a structure is not a UNO object, correct?

The Python code should ideally be located in a document and not in an extension

BTW: is it possible (in that context)

  • create “user-defined objects” in Python, for using in Basic?
  • create own UNO Objects (IDL\RDB) for storing and using in Documents?

I am grateful for any information.

Ralf

The only way I have seen this sort of thing done is to add an UNO service with an extension, for example UNO component packaging - Apache OpenOffice Wiki. It requires a .xcu file to define the implementation, so I’m not sure how that would work when bundled inside a document.

Related: Detailed tutorial regarding LibreOffice to Python macro writing, especially for Calc - #34 by Villeroy

Thank you, I will pursue these approaches and then comment on them again. Currently I have the following test code:

StarBasic

Private Sub Test()

  Dim s$, sLF$, sTypeName$, sType$, oReflection, bInterfaces As Boolean, Test_Type As New _Test_Type : sLF = Chr(10)

  With Test_Type
    .sString  = "Hallo"
    .bBool    = True
    .iInteger = 1
  End With

  ' Anm.: "stolen" from xray code
  oReflection = CreateUnoService("com.sun.star.reflection.CoreReflection")
  sTypeName   = oReflection.getType(Test_Type).Name

  sType       = Script.Py_Utils_MyMacros("fnc_test_object", Array(Test_Type))

  s = "Info"                                     & sLF & _
      "  TypeName:    " & TypeName(Test_Type)    & sLF & _
      "  IsObject:    " & IsObject(Test_Type)    & sLF & _
      "  IsUnoStruct: " & IsUnoStruct(Test_Type) & sLF & _
      "Reflection"                               & sLF & _
      "  TypeName:    " & sTypeName              & sLF & _
      "Python"                                   & sLF & _
      "  Type:        " & sType

  Call Tools.Dialog_MessageBox(s)
 
End Sub
Python
def fnc_test_object(xxx) -> str:
    t = type(xxx)
    s: str = t.__name__
    return s

With this Output:


Output_My_MsgBox

Well, I made an example extension. However you probably wouldn’t want to actually do this. If you are looking for something like a dictionary to use in Basic, then there are many better ways. See libreoffice - simplest Unostructure that supports he getByName - Stack Overflow.

Anyway, here is the python code for my example extension. Of course, it would make more sense to use a python dictionary, but the question asked about a struct, so here it is.

import uno
import unohelper
from com.sun.star.container import XMap
 
class FlexibleStruct:
    pass

class StructDemo(unohelper.Base, XMap):
    def __init__(self, ctx):
        self.ctx = ctx
        self.values = FlexibleStruct()
        self.KeyType = str
        self.ValueType = str
 
    def clear(self):
        self.values = FlexibleStruct()

    def get(self, Key):
        return getattr(self.values, Key)

    def put(self, Key, Value):
        setattr(self.values, Key, Value)

    def remove(self, Key):
        delattr(self.values, Key)

    def containsKey(self, Key):
        return hasattr(self.values, Key)

    def containsValue(self, Value):
        return False

def testdemo(ctx=None):
    if ctx is None:
        ctx = XSCRIPTCONTEXT.getComponentContext()
    demo = StructDemo(ctx)
    demo.put("a", 3)
    display_quick_message(demo.get("a"))

def display_quick_message(message):
    raise Exception("[message={}]".format(message))

g_exportedScripts = (
    testdemo,
    )

IMPL_NAME = "name.JimK.StructDemo"
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
        StructDemo, IMPL_NAME, (IMPL_NAME,),)

And here is the Basic code that calls it.

	demo = CreateUnoService("name.JimK.StructDemo")
	demo.put("animal1", "hamster")
	demo.put("animal2", "guinea pig")
	MsgBox(demo.get("animal2"))

There are also some XML files which may be needed, such as manifest.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE manifest:manifest PUBLIC "-//OpenOffice.org//DTD Manifest 1.0//EN" "Manifest.dtd">
<manifest:manifest xmlns:manifest="http://openoffice.org/2001/manifest">
    <!-- Files that describe the extension -->
    <manifest:file-entry
     manifest:full-path="Addons.xcu"
     manifest:media-type="application/vnd.sun.star.configuration-data"/>
    <manifest:file-entry
     manifest:full-path="pkg-desc/pkg-description.txt"
     manifest:media-type="application/vnd.sun.star.package-bundle-description"/>
    <manifest:file-entry
     manifest:full-path="StructDemo.py"
     manifest:media-type="application/vnd.sun.star.uno-component;type=Python"/>
</manifest:manifest>

Also description.xml:

<?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://openoffice.org/extensions/description/2006"
    xmlns:xlink="http://www.w3.org/1999/xlink">
  <version value="1.0" />
  <identifier value="name.JimK.StructDemo"/>
  <dependencies>
    <OpenOffice.org-minimal-version value="3.0" d:name="OpenOffice.org 3.0"/>
  </dependencies>
  <display-name>
    <name lang="en">Example Struct</name>
  </display-name>
</description>
1 Like

That looks very interesting to me. :slight_smile: Is it possible, to see the variant with a Dictionary by you? Then I’ll try to recreate both constructs and give feedback. Many thx

A python dictionary should be used instead of the FlexibleStruct class. You can see that the code below looks better than what is shown in my answer.

def __init__(self, ctx):
    ...
    self.values = {}
    ...

def get(self, Key):
    return self.values[Key]

Let me know if you get stuck building the extension. I tried to attach the actual example .oxt file but it is (understandably so) not one of the permitted file types.

One more comment about something that perhaps wasn’t clear in my example code. A struct normally looks like this in python:

class Test:
    def __init__(self):
        self.sString = ""
        self.bBool = False
        self.iInteger = 0

t = Test()
t.bBool = True

Hopefully this helps show how FlexibleStruct works in my answer. In python, structs are really classes that happen to be given particular members, not the same as structs in other languages.

Can you try to rename the .oxt to a .txt file?

struct.ott (2.5 KB)

Okay, here it is. Unzip to see the files. To install in LibreOffice, change .ott to .oxt.

Let’s see if this generates a meta discussion on whether this should be allowed. :slight_smile: