How to import modules in jython scripts using helper libraries?

Hi

I’m in the process of migrating my old DSL rules to the JSR233 Jython engine. I’m using the Helper Libraries for that.

One of the advantages of Jython should be, that you can use modules and imports. For example in my current DSL rules I defined multiple constants, that I use across the rule files. In DSL I have to duplicate all these definitions in all files. As Jython supports imports I want to import these definitions from a central place instead of duplicating them. However, I’m not able to import any of my files.

That’s what I try to do:

Two files Test.py and Test2.py are located in directory …\automation\jsr223\python\personal

Test.py:

from core.rules import rule
from core.triggers import when
from core.actions import LogAction 

import personal.Test2

@rule("test")
@when("Time cron 0 * * * * ?")  
def test(event):
    LogAction.logError("Test", "MY_CONST=" + str(MY_CONST))

Test2.py:

from core.rules import rule
from core.triggers import when

MY_CONST = 10

When I save both files I get the following error message in the logfile:

[ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/etc/openhab2/automation/jsr223/python/personal/Test.py': ImportError: No module named Test2 in <script> at line number 5´

What am I doing wrong?

Please excuse, if this is a stupid question. But I’m stlll learning JSR223/Jython and I wasn’t able to find a solution by Google.

1 Like

This directory is for personal scripts. Use /automation/lib/python/personal\ for personal packages and modules. The /automation/lib/python/ directory is special, since it has been added to the python.path so that it is included in searches when importing. Take another read through this…

1 Like

Thanks for your reply. I moved Test2.py to …\automation\lib\python\personal and modified the import statement in Test.py like this

from core.rules import rule
from core.triggers import when
from core.actions import LogAction 

from personal.Test2 import MY_CONST

@rule("test")
@when("Time cron 0 * * * * ?")  
def test(event):
    LogAction.logError("Test", "MY_CONST=" + str(MY_CONST))'

This works, but it has a serious drawback: updates in Test2.py are no longer reflected in Test1.py. If for example I change Test2.py to MY_CONST = 20, Test1.py still prints MY_CONST=10 to the log file. Simply touching and reloading Test1.py does not help.

In know there is a reload() statement. But I was not able to figure out how I can use it to pickup changes in Test2. I tried:
reload(personal.Test2)
reload(Test2)
reload(personal)
reload(personal.Test2.MY_CONST)
reload(MY_CONST)
The all cause different but similar errors about not finding a module in the log file.

What is the best way to reload changes in Modules without having to restart openhab services every change?

This is what it looks like from one of my files.


import personal.occupancy.areas.area_occupancy_event_metadata
reload (personal.occupancy.areas.area_occupancy_event_metadata)
from personal.occupancy.areas.area_occupancy_event_metadata import Area_Occupancy_Event_Metadata

OK. I found the solution myself. You need a somewhat awkward construct for importing the Modul:

import personal.Test2
reload(personal.Test2) 
from personal.Test2 import MY_CONST

This is not KISS. And definitely does not follow the best practice: “don’t repeat yourself” :thinking:

This is documented right above the section that I linked to earlier… https://openhab-scripters.github.io/openhab-helper-libraries/Python/Reference.html#modifying-and-reloading-packages-or-modules

It would probably help if you would read through all of the helper library documentation. :wink:

You had said constants, which do not change and work great when stored in modules. If you want to share a variable across scripts, you could use a ScriptExtension…

You could also create a class with a getter and setter to store/return the data. None of these will persist the data between OH restarts though, so if you want it to be around after a restart, Item metadata may be the best place for it. Although, there are other ways to add things to persistent storage and this is functionality that I plan to add to the core libraries.