Hello Alfredo,

The code you have attached uses some odd parameter values for loadComponentFromURL() that is not found neither in documentation nor in LibreOffice source code, like "private:factory/sform":

See possible values in:

LibreOffice Developer's Guide: Chapter 6 - Office Development
https://wiki.documentfoundation.org/Documentation/DevGuide/Office_Development

I suggest that you look into the existing SDK examples. In the examples, you will find various Python examples that you can modify and tailor according to what you want.

You can even start with LibreOffice BASIC, and if the script worked as intended, port it to Python. This example BASIC code opens TestDB.odb from home folder. You can change it to match where the file is located on your Windows machine. Then, it uses a dispatch command to open the form editor:

UNO Dispatch Commands:
https://wiki.documentfoundation.org/Development/DispatchCommands

Sub Main
Set oDoc = StarDesktop.loadComponentFromURL("file:///~/TestDB.odb", "_blank", 0, Array()) Set oDispatch = CreateUnoService("com.sun.star.frame.DispatchHelper")
    Set oDocCtrl = oDoc.getCurrentController()
    Set oDocFrame = oDocCtrl.getFrame()
oDispatch.executeDispatch(oDocFrame, ".uno:DBNewForm", "", 0, Array())
End Sub

Similarly, you can modify odk/examples/DevelopersGuide/FirstSteps/FirstLoadComponent/python/FirstLoadComponent.py to match what you want. I could do that by adding these 4 lines of code:

base_component = desktop.loadComponentFromURL("file:///~/TestDB.odb", "_blank", 0, tuple())
        base_frame = base_component.CurrentController.Frame
dispatcher = srv_mgr.createInstanceWithContext('com.sun.star.frame.DispatchHelper', remote_context) dispatcher.executeDispatch(base_frame, '.uno:DBNewForm', '', 0, ())

The resulting Python code is attached. Please let me know if these examples correctly match what you wanted.

Regards,
Hossein

On 08.10.2025 10:01, Alfredo Cacace wrote:
Hello LibreOffice development community,

I am developing a Python-based automation pipeline to programmatically
create a full LibreOffice Base (.odb) database with a Firebird
embedded engine. While the SQL-based creation of tables, views, and
triggers via the UNO API is working reliably, I have encountered
significant and seemingly undocumented issues specifically when trying
to programmatically create new, empty Form documents and insert them
into the .odb container.

My goal is to achieve a "zero-intervention" setup script, but this
specific step is proving to be a major roadblock. I am hoping to get
definitive guidance on the correct, stable API sequence to achieve
this.

Environment:

        *

Operating System: Windows 11 Pro 64-bit
        *

LibreOffice Version: 25.8.1.1 (X86_64) Build ID:
54047653041915e595ad4e45cccea684809c77b5
        *

Database Engine: Firebird embedded
        *

Python: The interpreter bundled with the LibreOffice installation
(program/python.exe)
        *

Connection Method: Connecting to a headless LibreOffice instance
listening on a socket
(--accept="socket,host=localhost,port=2002;urp;").

The Core Problem:
All attempted methods to create a new valid Form object and insert it
into the FormDocuments container of a loaded .odb document have
failed. The process of opening and modifying an existing,
manually-created Form works perfectly, but creating one from scratch
via the API seems to be broken or requires a non-obvious procedure.

Summary of Failed Methods and Errors:
I have systematically tested several approaches, all of which failed
in a clean environment (ensuring no lingering soffice processes were
running).

        *

Method 1: Creating a FormDefinition object

        *

Logic: Get the FormContainer, use
form_container.createInstance("com.sun.star.sdb.FormDefinition"), set
its name, and then try to either insertByName or use it in
loadComponentFromURL.
        *

Errors Encountered:

        *

com.sun.star.lang.IllegalArgumentException: incorrect number of
parameters (when createInstance is called without parameters).
        *

com.sun.star.script.CannotConvertException: value is not of same or
derived type! (when passing the created FormDefinition object to
loadComponentFromURL).

        *

Method 2: Loading a private:factory/sform document

        *

Logic: Create an independent, in-memory form document using
desktop.loadComponentFromURL("private:factory/sform", ...) and then
insert this valid object into the database's FormContainer.
        *

Error Encountered: com.sun.star.lang.IllegalArgumentException:
Unsupported URL <private:factory/sform>: "type detection failed". This
error suggests a context conflict when a database document is already
loaded.

        *

Method 3: Copying an internal template Form (ElementExistException)

        *

Logic: If a template form exists within the .odb, get it by name and
try to insertByName with a new name.
        *

Error Encountered: com.sun.star.container.ElementExistException: The
object is already, with a different name, part of the container. This
indicates that the object reference cannot be simply re-inserted; a
deep clone would be needed, for which there is no straightforward API
method.

        *

Obsolete Methods (leading to AttributeError)

        *

Attempts using db_doc.getContext() or form_docs.createNew() resulted
in AttributeError, confirming these methods are deprecated or invalid
for this object type.

The Key Question for the Community:

What is the officially supported, reliable sequence of API calls in
Python to programmatically achieve the equivalent of the manual user
action: "Go to the Forms section -> Click 'Create Form in Design
View...' -> Save the new empty form within the .odb file"?

Minimal Reproducible Example (Demonstrating Failure of Method 2):

Here is a self-contained script that reliably reproduces the type
detection failed error. It successfully connects, creates an in-memory
form, opens the database, but fails on the final insertion step.

codePython

#
# Minimal script to reproduce the form creation issue.
# PREREQUISITE: An empty, initialized Firebird .odb file named
"TestDB.odb" must exist.
#

import uno
import os
import sys
import subprocess
import time
from com.sun.star.beans import PropertyValue

def main():
    print("--- Starting Form Creation Test ---")

    # Define paths
    soffice_path = "C:\\Program
Files\\LibreOffice\\program\\soffice.exe"
    db_path = os.path.abspath("TestDB.odb")
    port = 2002

    # Launch LibreOffice in listening mode
    headless_cmd = [soffice_path, "--headless",
f"--accept=socket,host=localhost,port={port};urp;", "--norestore"]
    loffice_process = subprocess.Popen(headless_cmd)
    time.sleep(10)

    form_doc = None
    db_doc = None
    try:
        # Connect to LibreOffice
        local_context = uno.getComponentContext()
        resolver =
local_context.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver",
local_context)
        context =
resolver.resolve(f"uno:socket,host=localhost,port={port};urp;StarOffice.ComponentContext")
        desktop =
context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop",
context)

        # 1. Create a valid, in-memory sform document (This part
works)
        print("1. Creating a blank sform document in memory...")
        form_doc =
desktop.loadComponentFromURL("private:factory/sform", "_blank", 0, ())
        if not form_doc: raise Exception("Failed to create a blank
sform document.")
        print("   -> OK: In-memory form document created.")

        # 2. Open the target database document (This part works)
        print("2. Opening the target .odb database document...")
        db_url = uno.systemPathToFileUrl(db_path)
        db_doc = desktop.loadComponentFromURL(db_url, "_blank", 0, ())
        if not db_doc: raise Exception("Failed to open the database
document.")
        print("   -> OK: Database document opened.")

        # 3. Attempt to insert the form into the database container
(This is where it fails)
        print("3. Attempting to insert the sform document into the
database's FormContainer...")
        form_container = db_doc.getFormDocuments()
        form_name = "My_Auto_Generated_Form"
        if form_container.hasByName(form_name):
            form_container.dropByName(form_name)

        form_container.insertByName(form_name, form_doc) # This line
throws the exception
        print("   -> SUCCESS: Form inserted!")

        # 4. Save the database
        db_doc.store()
        print("Database saved successfully.")

    except Exception as e:
        print(f"\n--- TEST FAILED ---")
        print(f"ERROR: {e}")
        import traceback
        traceback.print_exc()
    finally:
        # Cleanup
        if form_doc: form_doc.close(True)
        if db_doc: db_doc.close(True)
        loffice_process.terminate()
        print("LibreOffice process terminated.")

if __name__ == "__main__":
    main()

Any guidance, pointers to correct documentation, or working code
snippets would be immensely appreciated. We believe solving this is
key to unlocking powerful automation capabilities in LibreOffice Base
for the entire community.

Thank you for your time and your work on this fantastic open-source
suite.

Best regards,

Alfredo

--
Hossein Nourikhah, Ph.D., Developer Community Architect
Tel: +49 30 5557992-65 | Email: [email protected]
The Document Foundation, Winterfeldtstraße 52, 10781 Berlin, DE
Gemeinnützige rechtsfähige Stiftung des bürgerlichen Rechts
Legal details: https://www.documentfoundation.org/imprint
# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#

import officehelper
import sys
import traceback

def main():
    try:
        remote_context = officehelper.bootstrap()
        if remote_context is None:
            print("ERROR: Could not bootstrap default Office.")
            sys.exit(1)
        srv_mgr = remote_context.getServiceManager()
        desktop = srv_mgr.createInstanceWithContext("com.sun.star.frame.Desktop", remote_context)
        base_component = desktop.loadComponentFromURL("file:///~/Downloads/TestDB.odb", "_blank", 0, tuple())
        base_frame = base_component.CurrentController.Frame
        dispatcher = srv_mgr.createInstanceWithContext('com.sun.star.frame.DispatchHelper', remote_context)
        dispatcher.executeDispatch(base_frame, '.uno:DBNewForm', '', 0, ())


    except Exception as e:
        print(e)
        traceback.print_exc()
        sys.exit(1)


if __name__ == "__main__":
    main()

# vim: set shiftwidth=4 softtabstop=4 expandtab:

Reply via email to