[JSR223][Jython]How to reload / refresh / recompile a personal python library as you're developing it

This may be a simple question, but I’ve spent a few minutes searching the forum without finding the answer. I may have searched for the wrong keywords, so I added multiple keywords to my topic to aid future visitors.

I’m trying to make a little python library with a reusable function.

So, I created

/etc/openhab2/automation/lib/python/personal/mylib.py

…and in my script file I reference it like so:

from personal.mylib import myfunction

So far so good. As soon as I call myfunction, mylib.py gets compiled to mylib$py.class in the same directory, and myfunction executes.

Now, here’s the question.

What should I do when I want to make changes to myfunction, just in case my code doesn’t work perfectly the first time? I know, it’s unlikely, but it could happen. :wink:

No matter what I do, the library is never recompiled. In fact, even deleting mylib$py.class has no effect!
The only way I was able to do it right now was to rename mylib.py to mylib2.py and then change the import reference, which is obviously as unmaintainable as restarting openHAB would be.

What is the intended workflow here?

https://openhab-scripters.github.io/openhab-helper-libraries/Python/Reference.html#modifying-and-reloading-modules

1 Like

THANK YOU!
Took me getting to toggle4.py before I got this stupid little function right:

from core.jsr223.scope import itemRegistry, OnOffType 

def toggle(strItem):
	item=itemRegistry.getItem(strItem)
	item.send(OnOffType.OFF if item.getState()==OnOffType.ON else OnOffType.ON)

Without the helper libraries ON doesn’t exist, “ON” is not the right type, and it doesn’t magically know you’re referring to OnOffType even after you’ve imported them…

Three follow-up questions:

  1. is this optimum?
import personal.toggle
reload(personal.toggle)
from personal.toggle import toggle
  1. is there a standard library function for “toggle” that I missed? I’ve been missing this since starting with openhab, just never thought to ask.

  2. If I have more than one function in a module, what’s the easiest way to access them?

For example:

import personal.libModeToggler
reload (personal.libModeToggler)
import personal.libModeToggler
libModeToggler=personal.libModeToggler

# I can now access functions like so:
libModeToggler.InnerWallLights()
libModeToggler.OuterWallLights()

That’s four lines at the header though, with a lot of repetition. Any way of optimizing that?
How I miss the C preprocessor at times like these, with its #include statement :slight_smile:

The alternative is restarting OH, so yeah :wink:.

No, not sure there’s a need…

events.sendCommand("My_Item", str(ON if items["My_Item"] == OFF else OFF))

… or if you have an Item already then you don’t need to convert to string…

events.sendCommand(item_object, ON if items["My_Item"] == OFF else OFF)

IME, this varies is on case-by-case need, but mostly it’s persoinal preference. I mostly use…

from personal.libModeToggler import InnerWallLights, OuterWallLights

You could do a star import, but it’s usually not recommended. If you do, it’s best to set all in the module.

from personal.libModeToggler import *

I’m not sure what you mean. In a module, use core.jsr223.scope to get access to the ScriptExtensions, including the default script scope. I recommend rereading the helper library docs, and reread them often as they are continuously evolving!

1 Like

:scream:

toggle("My_Item")

:grin:

Could you explain what you mean by “set all in the module”?

This was just a revision history of the four erroneous assumptions I made that resulted in having to bump the file name of such a simple function four times before getting it to work, since I didn’t know about reload() at the time.

I don’t quite understand what you mean by “use” though since it isn’t a python statement. Do you mean

from core.jsr223.scope import *

To make the question crystal clear, what exactly do I write in top of a module .py file to let me define a function exactly as follows, just as I could in a script? (the possibility of which was, in my humble opinion, implied by you when you didn’t understand the problem I “detailed” in my revision history)

def toggle(strItem):
	item=ir.getItem(strItem)
	item.send(OFF if item.getState()==ON else ON)

https://docs.python.org/2/tutorial/modules.html?highlight=all#importing-from-a-package

from core.jsr223 import scope
def toggle(strItem):
	scope.events.sendCommand(strItem, "OFF" if scope.items[strItem] == scope.ON else "ON")
1 Like

Clear. Exactly what I needed.

Ah, so it’s not in fact possible to do that. I misunderstood. Clear as well, thank you!

Not saying that :slightly_smiling_face:… the star import should work so that you could use the function as you had written it, but that’s going to import a lot of stuff you wont need. Check… log dir() before and after the import.

You could also just import ON and OFF.

1 Like

Ah okay. That’s probably not worth it indeed for such a small function.

But, dir() seems like a useful function! I hadn’t heard of that either. I really am a beginner at python. :slight_smile:

It’s VERY useful! https://openhab-scripters.github.io/openhab-helper-libraries/Guides/But%20How%20Do%20I.html#view-all-symbols-in-a-context (look at the one above this one too).

1 Like

I wish I could like a post more than once!

Seriously, holy crap. At least 90% of my python-based frustration comes from not knowing about this until now. I managed to use repr() to do something similar but this is a million times easier to use, not to mention better formatted.

2 Likes

How can I use this reload function for JS233 rules when I do use only ECMA (*.js) scripts?

Typing in blanks and Save again or even restart OH is driving me crazy…