← Back to team overview

sikuli-driver team mailing list archive

[Bug 627986] Re: [request] support Python import for reusable scripts

 

Hi all,

Im trying to import a "common" sikuli script using the following Python
code.

common =  os.path.join(os.path.dirname(getBundlePath()), 'common.sikuli')
if not common in sys.path: sys.path.append(common)
from common import *

The import is successful but my functions in the common module use
methods like click, find, wait etc... which is available to the script
that is importing the common module but I get the following error when I
call a function from it

NameError: global name 'click' is not defined

I understand that the click function is not available to the common
module that I've imported, but my question is where are these methods
coming from, they are just there implicitly.

Any help appreciated.

Cheers

-- 
You received this bug notification because you are a member of Sikuli
Drivers, which is subscribed to Sikuli.
https://bugs.launchpad.net/bugs/627986

Title:
  [request] support Python import for reusable scripts

Status in Sikuli:
  Fix Committed

Bug description:
  This report is related to different questions and requests that ask for a feature to import reusable code in a manner like using the Python import feature. a summary is reported in FAQ 1114 (https://answers.launchpad.net/sikuli/+faq/1114), but it is not possible to comment there.

MY REQUEST is, to implement the following somehow into Sikuli, so that it can be controlled by setting a preference "library path" or giving an arg like "lib=a-path" to a .skl. when the script is running, this path should be availble (e.g. Env.getLibraryPath()) and sys.path should be set accordingly. So a simple "from myLib import *" should work as expected.

Following is based on Sikuli 10.2 and works on both Mac 10.6 (my primary system) and Win7. Just using the Sikuli IDE, no handling of any .py files.

(tip: no need for import sys or import time, since this is already done during the initialization of Sikuli, just use it)

--- create a script that contains some functions, that you want to reuse and save it somewhere (e.g. myLib.sikuli)
example content:
def myFunction()
    print "Hello from myLib"

--- to use your reusable script try in the IDE
sys.path.append("absolute-path-to-myLib.sikuli")
# Mac e.g. "/Users/myName/myLib.sikuli"
# Windows e.g. "c:\\myStuff\\myLib.sikuli"
from myLib import * # your functions are available in the local namespace now
myFunction() # Hello ... shows up in the message area

If you want to use Sikuli functions in your reusable code, your myLib needs an additional import:
from sikuli.Sikuli import * # should be the first line in myLib.sikuli

--- If you are using images in your myLib script, these will be stored in myLib.sikuli. But at runtime they will not be available, since the path of your main script is where Sikuli looks for the image files.

Solution:
the image references have to be qualified to point to myLib.Sikuli:
example content of myLib.sikuli:
from sikuli.Sikuli import * 
imagePath = sys.path[-1] + "/" # (Windows: "\\")
# obviously the path to myLib.Sikuli ;-)
def myFunction()
    return find(imagePath + "1283333068882.png")

1283333068882.png would be replaced by its thumbnail, when editing myLib.sikuli in the IDE.

--- If you want to import more than on .sikuli, you have to append each one to sys.path and give different imagePath's.
e.g.
sys.path.append("absolute-path-to-myLib1.sikuli")
from myLib1 import * # your functions are available in the local namespace now
sys.path.append("absolute-path-to-myLib2.sikuli")
from myLib2 import * # your functions are available in the local namespace now

and in myLib1:
myLib1Path = sys.path[-1] + "/" # (Windows: "\\")
and in myLib2:
myLib2Path = sys.path[-1] + "/" # (Windows: "\\")

Tip: setup a naming convention for your reusables.

+++ CAUTION +++ when testing in the IDE: Due to the fact, that sys.path is bound to the life of the IDE, it is not reset when running the same script again (your path is appended again). Same goes for the import: no reload on rerun. So if you make changes to your myLib, you have to stop and restart the IDE.
If you want to avoid the sys.path problem, code instead:
myLib = "absolute-path-to-myLib.sikuli"
if not myLib in sys.path: sys.path.append(myLib)

All this is no problem, when running your script as .skl, since in this case everything starts from scratch at every rerun.

--- Additional info, if you want to deal with .py files directly:
sys.path contains a path, that points to a directory of the sikuli installation, that does not exist (don't know why, where and how, but I guess it is some standard that is set when initializing a PythonInterpreter based on the actual Java classpath):
Mac: /Applications/Sikuli-IDE.app/Contents/Resources/Java/Lib
Windows: C:\\Program Files\\Sikuli\\Lib
if you have a standard installation of Sikuli.
If you now move .py-files (e.g. myLib.py from our myLib.sikuli above) into this directory (after creating it ;-), you can use "from myLib import *" without any manipulation of sys.path.
This can be used, when you want to add some basic additions to Sikuli or helpers (e.g. a function, that supports the handling of sys.path) that you use in many of your scripts. 

--- next step
test this with python modules, that are not available in the Jython environment (PIL, pyTesser, ...)