SctiptForge Python scripts and default pipe

Python scripts may run either
(1) inside the LO process, the usual mode
(2) as a client of a LO server
    using a pipe or a socket.
    The LO command is started with
    an "--accept" argument.

The benefit of (2) is the freedom to
choose his/her preferred IDE to edit
and debug the script. The drawback is the
reference to the pipe/socket in the
script source code.

APSO is the best (only ?) choice for debugging (1).

With this commit, when no reference is given
to a pipe or a socket in the user script,
ScriptForge tries a connection through the
default pipe 'PIPE2LIBREOFFICE'.
If the connection fails, mode (1) is assumed.

The benefit is that the same source code
can run without change in both (1) and (2)
modes.
The command to run LO must refer explicitly
to the default pipe when (2) is wanted.

The change has no effect on existing Python
scripts.

Change-Id: I3176f4744ffea5b387280e9364b3563483fd14f0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205228
Reviewed-by: Jean-Pierre Ledure <jp@ledure.be>
Tested-by: Jenkins
This commit is contained in:
Jean-Pierre Ledure
2026-05-16 11:12:33 +02:00
parent b19cc5a5d1
commit d8f94b5a26
2 changed files with 46 additions and 16 deletions
@@ -49,14 +49,23 @@
from scriptforge import CreateScriptService
When Python and LibreOffice are started in separate processes,
LibreOffice being started from console ... (example for Linux with port = 2024)
./soffice --accept='socket,host=localhost,port=2024;urp;'
then use next statements:
LibreOffice being started from console ... (examples for Linux with port = 2026 or pipe = 'MYPIPE')
Either:
./soffice --accept='socket,host=localhost,port=2026;urp;'
or:
./soffice --accept='pipe,name=MYPIPE;urp;'
then use next statements: either
from scriptforge import CreateScriptService, ScriptForge
ScriptForge(hostname = 'localhost', port = 2024)
ScriptForge(hostname = 'localhost', port = 2026)
or
from scriptforge import CreateScriptService, ScriptForge
ScriptForge(pipe = 'MYPIPE')
When the user uses an IDE like PyCharm or VSCode, (s)he might benefit from the typing
hints provided by them thanks to the twin scriptforge.pyi module.
To edit and debug a user script in a specialized Python IDE, and afterwards, when ready,
run it in the usual interactive mode without code change, write:
from scriptforge import CreateScriptService
and start LibreOffice with a dedicated pipe:
./soffice --accept='pipe,name=PIPE2LIBREOFFICE;urp;'
Specific documentation about the use of ScriptForge from Python scripts:
https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_intro.html?DbPAR=BASIC
@@ -96,9 +105,10 @@ class ScriptForge(object, metaclass = _Singleton):
- Dispatching of services
- Coexistence with UNO
The class may be instantiated several times. Only the first instance will be retained ("Singleton").
The class has the singleton pattern. It creates an instance only if it does not exist.
Otherwise, it returns the already created instance.
All its properties and methods are for INTERNAL / DEBUGGING use only.
All the properties and methods of the actual class are for INTERNAL / DEBUGGING use only.
"""
# #########################################################################
@@ -148,6 +158,8 @@ class ScriptForge(object, metaclass = _Singleton):
('ScriptForge.SharedMemory', 7),
('ScriptForge.String', 8),
('ScriptForge.UI', 9)])
# The default pipe name to connect to when debugging user scripts from external IDE's
defaultpipe = 'PIPE2LIBREOFFICE'
def __init__(self, hostname = '', port = 0, pipe = ''):
"""
@@ -189,11 +201,12 @@ class ScriptForge(object, metaclass = _Singleton):
:param pipe: pipe name or ''
:return: the derived component context
"""
ctx = uno.getComponentContext() # com.sun.star.uno.XComponentContext
resolver = ctx.ServiceManager.createInstanceWithContext(
'com.sun.star.bridge.UnoUrlResolver', ctx) # com.sun.star.comp.bridge.UnoUrlResolver
if (len(hostname) > 0 and port > 0 and len(pipe) == 0) \
or (len(hostname) == 0 and port == 0 and len(pipe) > 0): # Explicit connection via socket or pipe
ctx = uno.getComponentContext() # com.sun.star.uno.XComponentContext
resolver = ctx.ServiceManager.createInstanceWithContext(
'com.sun.star.bridge.UnoUrlResolver', ctx) # com.sun.star.comp.bridge.UnoUrlResolver
try:
if len(pipe) == 0:
conn = 'socket,host=%s,port=%d' % (hostname, port)
@@ -206,7 +219,15 @@ class ScriptForge(object, metaclass = _Singleton):
"Connection to LibreOffice failed (%s)" % conn)
return ctx
elif len(hostname) == 0 and port == 0 and len(pipe) == 0: # Usual interactive mode
return uno.getComponentContext()
# Try a connection through the default pipe first
try:
conn = 'pipe,name=%s' % ScriptForge.defaultpipe
url = 'uno:%s;urp;StarOffice.ComponentContext' % conn
ctx = resolver.resolve(url)
except Exception: # thrown when LibreOffice specified instance isn't started
print("Connection to LibreOffice failed (%s). Assuming interactive mode." % conn)
finally: # Ignore exception
return ctx
else:
raise SystemExit('The creation of the ScriptForge() instance got invalid arguments: '
+ "(host = '" + hostname + "', port = " + str(port) + ", pipe = '" + pipe + "')")
@@ -236,7 +236,14 @@ class ScriptForge(object, metaclass = ...):
- Dispatching of services
- Coexistence with UNO
The class may be instantiated several times. Only the first instance will be retained ("Singleton").
The class has the singleton pattern. It creates an instance only if it does not exist.
Otherwise, it returns the already created instance.
The instance may be created explicitly in a user script. This must be done before any
invocation of CreateScriptService().
If not done yet, the CreateScriptService() will create it with the default arguments.
However, a connection with the default pipe will be tried in the first place. If successful,
the default pipe will be used. If failed, the usual interactive mode is selected.
"""
def __init__(self, hostname: str = ..., port: int = ..., pipe: str = ...):
@@ -248,10 +255,12 @@ class ScriptForge(object, metaclass = ...):
- Dispatching of services
- Coexistence with UNO
The class may be instantiated several times. Only the first instance will be retained ("Singleton").
he class has the singleton pattern. It creates an instance only if it does not exist.
Otherwise, it returns the already created instance.
Both arguments are mandatory when Python and LibreOffice run in separate processes.
Otherwise, do not call this routine or leave both arguments out.
Either the first two arguments are mandatory when Python and LibreOffice run in separate processes,
or the the third one is required.
Otherwise, do not call this routine or leave all arguments out.
To execute at most once by LibreOffice session.
Args
``hostname``: probably 'localhost'