Python3 Binding (Discussion)

no, it is just the next pythonscripting version, compared with the official one.

Calling it beta would discourage too many people from testing it. And it’s not a beta. It is the “next” stable version :slight_smile:

Thats why I named the markedplace version “pythonscripting next”

1 Like

Is there is a way to use this newer binding while creating importable python modules? I wanted to port over my previous work from the Jython bindings to this binding to get my home automation functional again. As far as I can tell, however, the new binding just recursively loads every .py file it sees, which is unfriendly to modules.

Just put your modules into the lib folder

1 Like

This did help it load as a module correctly. Unfortunately, relative module imports are non-functional for me. I have to fully qualify all module imports even for other files in the same module.

for me this works. I tested it with openhab 5.0.3 and the latest marketplace version of this addon. Additionally I tested it with openhab 5.1 snapshot (upcoming milestone3)

Here is my scenario

conf/automation/python/test.py

from test import TEST_VAR1

print(TEST_VAR1)

conf/automation/python/lib/test/__init__.py

from .subtest import TEST_VAR2

TEST_VAR1 = TEST_VAR2

conf/automation/python/lib/test/subtest/__init__.py

TEST_VAR2 = "ABC"

Oh interesting. That works for me as well, but the relative module imports I was using were broken.

If I do

from itemmanager import add_item

it doesn’t work. It complains it can’t find itemmanager despite being a direct submodule.

If I do

from .itemmanager import add_item

it works perfectly fine. My existing python code all used the former form. There might be something funky going on with the module loader, I wouldn’t expect any behavior difference from the above, they should be semantically equivalent.

Not a big deal, I already switched my module imports to absolute, but I think there might be a bug hiding there.

[b.automation.pythonscripting.home.py] - File “/openhab/conf/automation/python/lib/mmdev/manager.py”, line 6, in from itemmanager import add_item

2025-11-20 11:01:22.859 [ERROR] [b.automation.pythonscripting.home.py] - ModuleNotFoundError, No module named ‘itemmanager’

I guess it is related to python3 in graalpy vs python2 in jython. Python 3 is more strict with imports and requires the dot notation with relative imports. In addition to one dot, you can also use two dots to access the parent module.

Yeah, I think you are correct, sorry for that. I write python3 code all the time, but looking through the older Jython stuff I’ve written for openhab put me into a funky headspace.

I’m excited to get this all on python3! Writing it all in python2 was rather annoying.

1 Like

Hi. I am struggling to get this binding to work. I was using jython in 4.3.3. Now I can’t get this to work in either 5.0 and 5.1.

I am now running openhab 5.1.0~M2 on openSUSE Leap 15.6 installed from the official openhab.jfrog.io repository.

Here is what I get in openhab-cli console:

openhab> pythonscripting info
Python Scripting Environment:
======================================
  Runtime:
    Bundle version: 5.1.0.M2
    GraalVM version: 24.2.1
    Python version: 3.11.7
    Helper lib version: 1.0.13
    VEnv state: disabled
    Type hints: available

  Directories:
    Scripts: /etc/openhab/automation/python
    Libraries: /etc/openhab/automation/python/lib
    Typing: /etc/openhab/automation/python/typings
    Temp: /var/lib/openhab/tmp
    VEnv: /var/lib/openhab/cache/org.openhab.automation.pythonscripting/venv

Python Scripting Add-on Configuration:
======================================
  Python Environment
    scopeEnabled: true
    helperEnabled: true
    injectionEnabled: 2

  System Behavior
    pipModules: 
    nativeModules: true
    dependencyTrackingEnabled: true
    cachingEnabled: true
    jythonEmulation: false

openhab> pythonscripting update check
Latest version '1.0.13' already installed.

openhab> pythonscripting console
Loading Python script engine...[python::PythonContext] WARNING: could not determine Graal.Python's core path - you may need to pass --python.CoreHome.
[python::PythonContext] WARNING: could not determine Graal.Python's sys prefix path - you may need to pass --python.SysPrefix.
[python::PythonContext] WARNING: could not determine Graal.Python's standard library path. You need to pass --python.StdLibHome if you want to use the standard library.
[python::PythonContext] WARNING: could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
[python::PythonContext] WARNING: could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
[python::PythonContext] WARNING: could not determine Graal.Python's JNI library. You need to pass --python.JNILibrary if you want to run, for example, binary HPy extension modules.
[python::PythonContext] WARNING: could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
[python::PythonContext] WARNING: could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
[python::PythonContext] WARNING: could not determine Graal.Python's JNI library. You need to pass --python.JNILibrary if you want to run, for example, binary HPy extension modules.
Error: null in /etc/openhab/automation/python/lib/openhab/__wrapper__.py at line number 1 at column number 1

This is what appears in log whenever I try pythonscript console or when it tries to load any python script:

2025-11-24 16:15:09.256 [DEBUG] [cripting.internal.PythonScriptEngine] - Lock acquired before invocation for engine '<uninitialized>'
2025-11-24 16:15:09.256 [DEBUG] [cripting.internal.PythonScriptEngine] - Initializing GraalPython script engine 'python-console-6487106e-66bd-4abd-8c3a-7e30d34d1664' ...
2025-11-24 16:15:09.268 [ERROR] [cripting.internal.PythonScriptEngine] - Traceback (most recent call last):
2025-11-24 16:15:09.268 [ERROR] [cripting.internal.PythonScriptEngine] -   File "/etc/openhab/automation/python/lib/openhab/__wrapper__.py", line 96, in <module>
2025-11-24 16:15:09.269 [ERROR] [cripting.internal.PythonScriptEngine] -     __import_wrapper__()
2025-11-24 16:15:09.269 [ERROR] [cripting.internal.PythonScriptEngine] -   File "/etc/openhab/automation/python/lib/openhab/__wrapper__.py", line 11, in __import_wrapper__
2025-11-24 16:15:09.269 [ERROR] [cripting.internal.PythonScriptEngine] -     import traceback
2025-11-24 16:15:09.269 [ERROR] [cripting.internal.PythonScriptEngine] - ModuleNotFoundError: No module named 'traceback'
2025-11-24 16:15:09.270 [DEBUG] [cripting.internal.PythonScriptEngine] - Failed to execute script (PolyglotException) for engine 'python-console-6487106e-66bd-4abd-8c3a-7e30d34d1664':         at org.graalvm.polyglot.Context.eval(Context.java:416)
        at org.openhab.automation.pythonscripting.internal.PythonScriptEngine.beforeInvocation(PythonScriptEngine.java:319)
        at org.openhab.automation.pythonscripting.internal.scriptengine.InvocationInterceptingPythonScriptEngine.eval(InvocationInterceptingPythonScriptEngine.java:43)
        at java.scripting/javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:262)
        at org.openhab.automation.pythonscripting.internal.console.PythonConsoleCommandExtension.lambda$0(PythonConsoleCommandExtension.java:195)
        ... 22 more

The system has python3.11 installed and the traceback module is there (not sure if that is relevant):

# python3.11 
Python 3.11.13 (main, Jun 09 2025, 21:55:43) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import traceback
>>>

Do I need any additional dependencies installed on the system?

@michalsrb that’s strange

I checked M2 and latest snapshot as a docker container and it works.

The logs you are showing, are just the symptoms. Means it’s the result of a not fully available/initialized python script engine.

The installed python version on the host/server itself, does not matter. Openhab provides its own python as part of graalpy.

How have you installed openhab?

Can you also show the startup logs. just to check if there are some additional errors.

And please show the result of

openhab> bundle:list | grep "Graal"
openhab> bundle:list | grep "Python"

How have you installed openhab?

Following the Yum or Dnf Based Systems instructions I added the repository and installed openhab and openhab-addons packages. This worked well for me in the past. The issue happens to be with both 5.0 from the stable repository and 5.1 from the testing repository.

I believe the pythonscripting addon comes from a /usr/share/openhab/addons/openhab-addons-5.1.0.M2.kar file that is in the openhab-addons package.

Can you also show the startup logs. just to check if there are some additional errors.

openhab.log (407.1 KB) Attached here.

And please show the result of.

openhab> bundle:list | grep "Graal"                                                                                                                                                                                                                                                                                         
274 │ Active  │  78 │ 24.2.1                │ GraalVM :: JS :: Language
275 │ Active  │  80 │ 24.2.1                │ GraalVM :: JS :: Script Engine
276 │ Active  │  80 │ 24.2.1                │ GraalVM :: LLVM :: API
277 │ Active  │  80 │ 24.2.1                │ GraalVM :: Polyglot :: Polyglot
278 │ Active  │  80 │ 24.2.1                │ GraalVM :: Python :: Embedding
279 │ Active  │  78 │ 24.2.1                │ GraalVM :: Python :: Language
280 │ Active  │  78 │ 24.2.1                │ GraalVM :: Python :: Resources
281 │ Active  │  78 │ 24.2.1                │ GraalVM :: Regex :: TRegex
282 │ Active  │  80 │ 24.2.1                │ GraalVM :: SDK :: Collections
283 │ Active  │  80 │ 24.2.1                │ GraalVM :: SDK :: Native Image
284 │ Active  │  80 │ 24.2.1                │ GraalVM :: SDK :: Word
285 │ Active  │  80 │ 24.2.1                │ GraalVM :: Truffle :: ICU4J
286 │ Active  │  80 │ 24.2.1                │ GraalVM :: Truffle :: JSON
287 │ Active  │  80 │ 24.2.1                │ GraalVM :: Truffle :: XZ
288 │ Active  │  80 │ 24.2.1                │ GraalVM :: Tools :: Profiler
289 │ Active  │  79 │ 24.2.1                │ GraalVM :: Truffle :: API
290 │ Active  │  80 │ 24.2.1                │ GraalVM :: Truffle :: Compiler
291 │ Active  │  78 │ 24.2.1                │ GraalVM :: Truffle :: NFI
293 │ Active  │  80 │ 24.2.1                │ GraalVM :: Truffle :: Runtime
352 │ Active  │  78 │ 24.2.1                │ GraalVM :: Truffle :: NFI :: LibFFI

openhab> bundle:list | grep "Python"                                                                                                                                                                                                                                                                                        
278 │ Active  │  80 │ 24.2.1                │ GraalVM :: Python :: Embedding
279 │ Active  │  78 │ 24.2.1                │ GraalVM :: Python :: Language
280 │ Active  │  78 │ 24.2.1                │ GraalVM :: Python :: Resources
353 │ Active  │  80 │ 5.1.0.M2              │ openHAB Add-ons :: Bundles :: Automation :: Python Scripting

Somehow, at one moment it was suddenly working, until I restarted openhab and it stopped again. I don’t know how it happened. I wonder if there is some timing / order of initialization issue.

I will try to reproduce with a VM running opensuse leap 15.6

But a first check showed me that homeassistent has the same problem.

2025-11-24 20:21:54.810 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's sys prefix path - you may need to pass --python.SysPrefix.
2025-11-24 20:21:54.810 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's standard library path. You need to pass --python.StdLibHome if you want to use the standard library.
2025-11-24 20:21:54.811 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
2025-11-24 20:21:55.092 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
2025-11-24 20:21:55.093 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's JNI library. You need to pass --python.JNILibrary if you want to run, for example, binary HPy extension modules.
2025-11-24 20:21:55.320 [INFO ] [e.automation.internal.RuleEngineImpl] - Rule engine started.
2025-11-24 20:21:56.358 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
2025-11-24 20:21:56.488 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's C API library path. You need to pass --python.CAPI if you want to use the C extension modules.
2025-11-24 20:21:56.488 [WARN ] [t.internal.HomeAssistantPythonBridge] - could not determine Graal.Python's JNI library. You need to pass --python.JNILibrary if you want to run, for example, binary HPy extension modules.
2025-11-24 20:21:57.984 [ERROR] [t.internal.HomeAssistantPythonBridge] - bundle org.openhab.binding.mqtt.homeassistant:5.1.0.M2 (317)[org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantPythonBridge(483)] : Error during instantiation of the implementation object

This is a strong sign that something with your installation is wrong.

@michalsrb I can’t reproduce. I was trying the following steps.

  1. I installed a clean opensuse leap 15.6 in a VirtualBox VM
  2. I installed java 21
  3. I added the jfrog testing repository
  4. I installed openhab and openhab addons
  5. I started openhab with systemctl start openhab
  6. I opened the webui and activated pythonscripting by clicking on “Install”
  7. I opened the openhab cli with openhab-cli console
  8. And below you see the result

Thank you for going such lengths to try to reproduce it. I also tried to install it in fresh VM and it works. I’ll try to get the configuration in the VM to match my system’s configuration and see if it breaks at some point or if I can spot a difference…

1 Like

I figured out what the problem was. This github comment gave me a hint that the .cache directory in the home directory of the openhab user is important for the pythonscripting plugin.

The openhab user on my system was created long time ago and had a non-existing directory set as its home. In contrast the new installation in VM had openhab user with the /var/lib/openhab directory set as its home. When I changed the home on my system, the pythonscripting started working again.

1 Like

Is there any update regarding graalyp? I still think that having an individual VEnv for a specific rule and also setting it up via rule might be usefull.

Openhab 5.1 contains grallvm 25.0.1

I’ve had trouble locating any documentation or examples of using the cache in a 1:1 way like JS scripting, but I think I have figured out the main functions. What does the compute object do?

from scope import cache

cache.privateCache.put('private_key', 'value')
cache.sharedCache.put('shared_key', 'value')

val1 = cache.privateCache.get('private_key')
val2 = cache.sharedCache.get('shared_key')

cache.privateCache.remove('private_key')
cache.sharedCache.remove('shared_key')

#Not sure what these are for:
#cache.privateCache.compute
#cache.sharedCache.compute

Here is the JavaDoc for the function:

    /**
     * Attempts to compute a mapping for the specified key and its current mapped value
     * (or null if there is no current mapping).
     * 
     * See {@code java.util.Map.compute()} for details.
     * 
     * @param key the key of the requested value.
     * @param remappingFunction the remapping function to compute a value.
     * @return the new value associated with the specified key, or null if none
     */

The Java Map JavaDoc is:

    /**
     * Attempts to compute a mapping for the specified key and its current
     * mapped value (or {@code null} if there is no current mapping). For
     * example, to either create or append a {@code String} msg to a value
     * mapping:
     *
     * <pre> {@code
     * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
     * (Method {@link #merge merge()} is often simpler to use for such purposes.)
     *
     * <p>If the remapping function returns {@code null}, the mapping is removed
     * (or remains absent if initially absent).  If the remapping function
     * itself throws an (unchecked) exception, the exception is rethrown, and
     * the current mapping is left unchanged.
     *
     * <p>The remapping function should not modify this map during computation.
     *
     * @implSpec
     * The default implementation is equivalent to performing the following
     * steps for this {@code map}:
     *
     * <pre> {@code
     * V oldValue = map.get(key);
     * V newValue = remappingFunction.apply(key, oldValue);
     * if (newValue != null) {
     *     map.put(key, newValue);
     * } else if (oldValue != null || map.containsKey(key)) {
     *     map.remove(key);
     * }
     * return newValue;
     * }</pre>
     *
     * <p>The default implementation makes no guarantees about detecting if the
     * remapping function modifies this map during computation and, if
     * appropriate, reporting an error. Non-concurrent implementations should
     * override this method and, on a best-effort basis, throw a
     * {@code ConcurrentModificationException} if it is detected that the
     * remapping function modifies this map during computation. Concurrent
     * implementations should override this method and, on a best-effort basis,
     * throw an {@code IllegalStateException} if it is detected that the
     * remapping function modifies this map during computation and as a result
     * computation would never complete.
     *
     * <p>The default implementation makes no guarantees about synchronization
     * or atomicity properties of this method. Any implementation providing
     * atomicity guarantees must override this method and document its
     * concurrency properties. In particular, all implementations of
     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
     * whether the remapping function is applied once atomically only if the
     * value is not present.
     *
     * @param key key with which the specified value is to be associated
     * @param remappingFunction the remapping function to compute a value
     * @return the new value associated with the specified key, or null if none
     * @throws NullPointerException if the specified key is null and
     *         this map does not support null keys, or the
     *         remappingFunction is null
     * @throws UnsupportedOperationException if the {@code put} operation
     *         is not supported by this map
               ({@linkplain Collection##optional-restrictions optional})
     * @throws ClassCastException if the class of the specified key or value
     *         prevents it from being stored in this map
     *         ({@linkplain Collection##optional-restrictions optional})
     * @throws IllegalArgumentException if some property of the specified key
     *         or value prevents it from being stored in this map
     *         ({@linkplain Collection##optional-restrictions optional})
     * @since 1.8
     */

Exactly how such an operation looks in Python I don’t know, but basically it lets you update the cached value using a function where the key and the old value are inputs.

2 Likes

Ah ok, probably not too much use in my scripts. I notice there is no python equivalent to the JS function:

cache.private.exists()

However, the python functions:

cache.privateCache.get('private_key')
cache.sharedCache.get('shared_key')

will return None if the key doesn’t exist, so a simple “if val is not None:” conditional statement should act as a replacement.