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.odbcontainer.
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 theFormDocumentscontainer of a loaded.odbdocument 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 lingeringsofficeprocesses were running).
1.
*Method 1: Creating aFormDefinitionobject*
*
*Logic:*Get theFormContainer,
useform_container.createInstance("com.sun.star.sdb.FormDefinition"),
set its name, and then try to eitherinsertByNameor use it
inloadComponentFromURL.
*
*Errors Encountered:*
o
com.sun.star.lang.IllegalArgumentException: incorrect number
of parameters(whencreateInstanceis called without parameters).
o
com.sun.star.script.CannotConvertException: value is not of
same or derived type!(when passing the
createdFormDefinitionobject toloadComponentFromURL).
2.
*Method 2: Loading aprivate:factory/sformdocument*
*
*Logic:*Create an independent, in-memory form document
usingdesktop.loadComponentFromURL("private:factory/sform",
...)and then insert this valid object into the
database'sFormContainer.
*
*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.
3.
*Method 3: Copying an internal template Form (ElementExistException)*
*
*Logic:*If a template form exists within the.odb, get it by name
and try toinsertByNamewith 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.
4.
*Obsolete Methods (leading toAttributeError)*
*
Attempts usingdb_doc.getContext()orform_docs.createNew()resulted
inAttributeError, 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.odbfile"?
*Minimal Reproducible Example (Demonstrating Failure of Method 2):*
Here is a self-contained script that reliably reproduces thetype
detection failederror. 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