How To import a .skl file --- workaround

Asked by Test

--- a workaround for Sikuli 1.0.1

Here a useable function, to make a .skl ready to be imported:

def loadSKL(name, dir = None):
    import org.sikuli.basics.FileManager as SFm
    import os
    if not dir:
        dir = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
    sub = os.path.join(dir, name + ".skl")
    spath = os.path.dirname(SFm.unzipSKL(sub))
    if sPath:
        sys.path.append(spath)
        return true
    return false

*** usage for a mymodule.skl in same directory:

loadSKL("mymodule")
import mymodule

usage for a mymodule.skl in same directory:

loadSKL("mymodule", "some-absolute-path-to-folder-containing-the-skl")
import mymodule

------------------------------------------------

Hey there,

Is it possible to import a .skl file? I understand that the .skl file is a compressed version of the .sikuli file.

I have a requirement to mask the code found in the .sikuli file as well as the images, hence bringing a .skl file into the picture. However, the main script I'm running needs to IMPORT the .skl file. Is that possible?

If it is - how do I go about doing it?

If it isn't - what is a workaround I can employ to achieve this?

At present, what I'm thinking of is to password-protect a zip file, then unzip it with python, import the script and delete the unzipped file.

P.S. I'm pretty sure you can reverse engineer the .skl file and even break through the workaround I'm thinking of right now, but if the user wishes to go to that length to get the script, they can have it. This is just a precautionary measure to discourage the average user.

Thanks.

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
RaiMan Edit question
Solved by:
RaiMan
Solved:
Last query:
Last reply:
Revision history for this message
Best RaiMan (raimund-hocke) said :
#1

yes, .skl cannot be imported currently.

The workflow you mentioned to get a "secured" script is ok on the surface.

... but since at runtime at some time everything is readable, one that wants to get the code, simply has to abort the script and start with the main script that is in the temp folder at that time.

Generally: Scripting means interpreting a given text and hence trying to secure will never be finally work as expected.
... and with the current approach, the images will be freely available at any time during run.

If you want to have more options to secure your code and images, you have to program in Java against sikuli-java.jar.

Revision history for this message
Rubynator (datagatepdx) said :
#2

Hi RaiMan, Do you know when they are going to implement this feature? (Importing of .skl)
I think It's a very high priority.

Thank you!

Revision history for this message
RaiMan (raimund-hocke) said :
#3

LOL - Do you know when they are going to implement this feature?

... they ... in the moment is just RaiMan ;-)

... I think It's a very high priority.
might be from your point of view, but I will not add any further support for .skl

In version 1.1.0+, there will be an option to pack script stuff into a jar, that can even be made self-starting on double click.
With a jar container it is much easier to hide the stuff contained in the jar even with some basic "encryption".
And they are importable/loadable.

So for now, you have to find your own solution for that. Sorry, but I have other priorities with Sikuli.

Revision history for this message
Test (c4456517) said :
#4

Thanks RaiMan, that solved my question.

Revision history for this message
RaiMan (raimund-hocke) said :
#5

In a private communicationIi suggested the following workaround to import a .skl:

# get Sikuli’s Filemanager class
import org.sikuli.basics.FileManager as SFm
import os
# get the folderpath the main script is stored
scriptPath = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
# get the folder path of a ….skl stored in the same folder (here sub.skl)
sub = os.path.join(scriptPath, "sub.skl“)
# unzip to temp folder (the only option here ;-)
subPath = SFm.unzipSKL(sub)
# put it on sys.path
sys.path.append(os.path.dirname(subPath))
# import it
import sub
# use it
….
# before exit delete it
SFm.deleteFileOrFolder(subPath)

This is necessary, since with the current Sikuli 1.0.1 the Jython 2.5 is bundled and the Python zip features are introduced with Python 2.6, so they are not available (so eventually they will be available with version 1.1.0 which comes with Jython 2.7beta1, that says to be on Python language level 2.7 - not checked yet)

Revision history for this message
Rubynator (datagatepdx) said :
#6

So when I try to use "Import sub" There's no library called sub, Is it all called something else? And why do I need that for?

It's throwing out this error :

[error] script [ Assignment1 ] stopped with error in line 12
[error] ImportError ( No module named sub )

@Raiman I'm so glad to hear that In version 1.1.0+, there will be an option to pack script stuff into a jar, that can even be made self-starting on double click. So I don't have to deal with all these workarounds;)

Thanks!

Revision history for this message
RaiMan (raimund-hocke) said :
#7

@Rubinator
your question???

might be a good idea to start a new one.

Revision history for this message
Rubynator (datagatepdx) said :
#8

@RaiMan It's related to this topic,
I can't get this example working. It throws multiple errors, Can you double check the code?

In this example of:

# get Sikuli’s Filemanager class
import org.sikuli.basics.FileManager as SFm
import os
# get the folderpath the main script is stored
scriptPath = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
# get the folder path of a ….skl stored in the same folder (here sub.skl)
sub = os.path.join(scriptPath, "sub.skl“)
# unzip to temp folder (the only option here ;-)
subPath = SFm.unzipSKL(sub)
# put it on sys.path
sys.path.append(os.path.dirname(subPath))
# import it
import sub
# use it
….
# before exit delete it
SFm.deleteFileOrFolder(subPath)

So I'm wondering:

1. What is "import sub". Since there's no library called sub, I keep getting this error:
[error] script [ Assignment1 ] stopped with error in line 12
[error] ImportError ( No module named sub )

2. I commented out the import sub , and then this time this line gives an error:
"scriptPath = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))"
Can you check to see if the usage is correct?

Here's the error message I get from this line:
C:/Users/Rubynator/Desktop/SikuLiSource\assignment1.skl: No such file
[error] script [ Playdom2 ] stopped with error in line 11
[error] TypeError ( 'NoneType' object is unsubscriptable )

So with the import sub commented out I used this instead:
scriptPath = os.path.dirname(os.path.dirname(os.path.dirname(getBundlePath())))

With this slight modification the script works on my local fine, then I exported it into a .skl file. Send it to another Win64Bit machine with a fresh install of Sikuli (1.0.1) and java on.
Ran it with: runide -r C:\Users\Rubynator\Desktop\assignment1.skl -d 3 -c
Again this is with no import sub, and a slight modification to the scriptPath= line.
It fails with a long log file, below is the output:

C:\Sikuli>runide -r c:\users\Rubynator\desktop\assignment1.skl -d 3 -c
'Files' is not recognized as an internal or external command,
operable program or batch file.
+++ running this Java
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) Client VM (build 24.51-b03, mixed mode, sharing)
+++ trying to start Sikuli IDE
+++ using: -Xms64M -Xmx512M -Dfile.encoding=UTF-8 -Dsikuli.FromCommandLine -jar
C:\Sikuli\sikuli-ide.jar -r c:\users\Rubynator\desktop\assignment1.skl -d 3 -c
[debug] SikuliIDE: Switching to SikuliScript with option -r, -t or -i
[debug] SikuliScript: CmdOrg: -r c:\users\Rubynator\desktop\assignment1.skl -d 3 -
c
[debug] Running on Java 7 (1.7.0_51-b13)
[debug] --- Sikuli parameters ---
[debug] 1: -r
[debug] 2: c:\users\Rubynator\desktop\assignment1.skl
[debug] 3: -d
[debug] 4: 3
[debug] 5: -c
[debug] FileManager: tempdir create: C:\Users\Rubynator\AppData\Local\Temp\Rubynator
\tmp-1400964603.sikuli
[debug] SikuliScript: givenScriptName: C:\Users\Rubynator\AppData\Local\Temp\Rubynator\tmp-1400964603.sikuli\assignment1.sikuli
[debug] SikuliX Jython Support Build: 1.0.1 12SEP2013160248
[debug] Trying to run script: C:\Users\Rubynator\AppData\Local\Temp\Rubynator\tmp-14
00964603.sikuli\assignment1.sikuli\assignment1.py
[debug] JythonScriptRunner: : executeScriptHeader: adding SikuliX Lib path to sy
s.path
C:\Sikuli\sikuli-ide.jar\Lib
[debug] Jython: sikuli: __init__: entering
[debug] Jython: sikuli: Sikuli: entering
[debug] Jython: sikuli: Sikuli: constants
[debug] Jython: sikuli: Sikuli: import Region
[debug] Jython: sikuli: Sikuli: import Screen
[debug] Jython: sikuli: Sikuli: Env.addHotkey
[debug] Jython: sikuli: Sikuli: import Match
[debug] Jython: sikuli: Sikuli: import Pattern
[debug] Jython: sikuli: Sikuli: import Location
[debug] Jython: sikuli: Sikuli: import ScreenUnion
[debug] Jython: sikuli: Sikuli: import Finder
[debug] ResourceLoaderBasic: SikuliX Package Build: 1.0.1 12SEP2013160242
[debug] ResourceLoaderBasic: check: we are running on arch: x86
[debug] ResourceLoaderBasic: check: using Java at: C:/Program Files (x86)/Java/j
re7/
[debug] ResourceLoaderBasic: check: Exists Environment.SIKULIX_HOME? YES: C:/Sik
uli/libs
[debug] ResourceLoaderBasic: checkLibsDir: C:/Sikuli/libs
[debug] ResourceLoaderBasic: loadLib: WinUtil
[debug] ResourceLoaderBasic: loadLib: Found: WinUtil
[debug] ResourceLoaderBasic: loadLib: Now loaded: WinUtil
[debug] ResourceLoaderBasic: checkLibsDir: Using libs at: C:\Sikuli\libs
[debug] ResourceLoaderBasic: check: Using this as OCR directory (tessdata) too
[debug] ResourceLoaderBasic: loadLib: VisionProxy
[debug] ResourceLoaderBasic: loadLib: Found: VisionProxy
[debug] ResourceLoaderBasic: loadLib: Now loaded: VisionProxy
[debug] Jython: sikuli: Sikuli: import App
[debug] ResourceLoaderBasic: loadLib: Is already loaded: WinUtil
[debug] Screen: initScreens: basic initialization (1 Screen(s) found)
[debug] *** monitor configuration (primary: 0) ***
[debug] Screen 0: S(0)[0,0 1440x900]
[debug] *** end monitor configuration ***
[debug] Jython: sikuli: Sikuli: import Key
[debug] Jython: sikuli: Sikuli: import from Basics
[debug] Jython: sikuli: Sikuli: import from compare
[debug] Jython: sikuli: Sikuli: init SikuliImporter
[debug] Jython: sikuli: Sikuli: import SikuliScript
[debug] Jython: init SCREEN as ()
[debug] Sikuli-IDE environment setup: 7438
C:/Users/Rubynator/AppData/Local/Temp/Rubynator\assignment1.skl: No such file
[error] script stopped with error in line 10
[error] TypeError ( 'NoneType' object is unsubscriptable )
Exception in thread "main" java.lang.IllegalStateException: No match found
        at java.util.regex.Matcher.group(Unknown Source)
        at org.sikuli.scriptrunner.JythonScriptRunner.findErrorSourceWalkTrace(J
ythonScriptRunner.java:326)
        at org.sikuli.scriptrunner.JythonScriptRunner.findErrorSource(JythonScri
ptRunner.java:290)
        at org.sikuli.scriptrunner.JythonScriptRunner.runPython(JythonScriptRunn
er.java:200)
        at org.sikuli.scriptrunner.JythonScriptRunner.runScript(JythonScriptRunn
er.java:162)
        at org.sikuli.basics.SikuliScript.main(SikuliScript.java:181)
        at org.sikuli.ide.SikuliIDE.main(SikuliIDE.java:212)

C:\Sikuli>

Any thoughts will be highly appreciated!
Thank you!

Revision history for this message
RaiMan (raimund-hocke) said :
#9

ok, a bug in the code ;-) sorry

# get Sikuli’s Filemanager class
import org.sikuli.basics.FileManager as SFm
import os
# get the folderpath the main script is stored
scriptPath = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
# get the folder path of a ….skl stored in the same folder (here sub.skl)
sub = os.path.join(scriptPath, "sub.skl“)
# unzip to temp folder (the only option here ;-)
subPath = SFm.unzipSKL(sub)
# put it on sys.path
sys.path.append(os.path.dirname(subPath))
# import it
import <submodule name>
# use it
….
# before exit delete it
SFm.deleteFileOrFolder(subPath)

There are 2 "variables" that have to be adapted to your situation:
- "sub.skl" has to be the file name os your .skl to be imported.
- <submodule name> has to be the name of the module to be imported

example:
- you had a mystuff.sikuli, that you exported as mystuff.skl

the instead of "sub.skl" you have to use
"mystuff.skl"

and instead of <submodule name> you have to use
mystuff

again the relevant part:
...
sub = os.path.join(scriptPath, "mystuff.skl“)
# unzip to temp folder (the only option here ;-)
subPath = SFm.unzipSKL(sub)
# put it on sys.path
sys.path.append(os.path.dirname(subPath))
# import it
import mystuff
...

Revision history for this message
Rubynator (datagatepdx) said :
#10

Raiman, thanks but this isn't working either.

Here's my code

import org.sikuli.basics.FileManager as SFm
import os
scriptPath = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
sub = os.path.join(scriptPath, "assignment1.skl")
subPath = SFm.unzipSKL(sub)
sys.path.append(os.path.dirname(subPath))
import assignment1

And here's what I get:

[error] script [ Xcode2 ] stopped with error in line 10
[error] NameError ( !!WHILE IMPORTING!! name 'getBundlePath' is not defined )

Please advise , thank you!

Revision history for this message
RaiMan (raimund-hocke) said :
#11

imported scripts need a
from sikuli import *
at the beginning

Revision history for this message
Rubynator (datagatepdx) said :
#13

RE- Edited. Please disregard the previous one and review this one.

Thank you for that.

now I have this:
import org.sikuli.basics.FileManager as SFm
import os
scriptPath = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
sub = os.path.join(scriptPath, "assignment1.skl")
subPath = SFm.unzipSKL(sub)
# put it on sys.path
sys.path.append(os.path.dirname(subPath))
# import it
from sikuli import assignment1

And I get this error message:
[error] script [ Xcode2 ] stopped with error in line 10
[error] ImportError ( cannot import name assignment1 )

What am I doing wrong?

Revision history for this message
RaiMan (raimund-hocke) said :
#14

yeah, not that easy to look through ;-)

but now you are nearly there.

a little know how boost:

from sikuli import assignment1

what you are saying to Sikuli:

look for a module sikuli and inside this module look for something named assignment1

This cannot work, since the module sikuli comes with the package (therefor the from sikuli import *, so all names contained in sikuli module and submodules are known in your script - for the main script this is done automatically at runtime), because it does not have anything named assignment1 (and if it had, it would not be what you want ;-)

modules are found by their name in the folders listed in sys.path.
with <sys.path.append(os.path.dirname(subPath))> we have put the parent folder of the unzipped assignment1.sikuli on sys.path.
now assignment1.sikuli is locatable.

so simply
import assignment1

will import your stuff according to the rules that apply to importing a .sikuli script this way:
- the contained .py script is imported according to the Python-rules
- the path to the .sikuli folder is put on ImagePath (so images referenced in the imported module are found.)

now you can use names defined in assignment1 like this:
assignment1.some_name (variable)
assignment1.some_name() (function or class)

If you have taken care, that you will not get any name clashes (naming convention) you might use as well
from assignment1 import *
some_name (variable)
some_name() (function or class)

hope this helps

Revision history for this message
Rubynator (datagatepdx) said :
#15

Okay, thanks for explaining, but this is getting complicated for a too simple of an issue.
Hopefully in the next version, when you add the option to pack script stuff into a jar file, It'll be very simple to share them with coworkers and have them run it on their machines without having to deal with this import problems
Btw, When are you planning to release the next versison 1.1.0 ??

Revision history for this message
RaiMan (raimund-hocke) said :
#16

Uuups, I do not understand your "but this is getting complicated for a too simple of an issue"

The issue is 2-fold:
1. importing skl
2. organizing modules and using the import feature of Python correctly and efficiently

2. has nothing to do with Sikuli or the fact, that .skl cannot be imported currently.

1. is solved easily with the proposed solution: (comment #9)

Here a useable function, to make a .skl ready to be imported:

def loadSKL(name, dir = None):
    import org.sikuli.basics.FileManager as SFm
    import os
    if not dir:
        dir = os.path.join(os.path.dirname(os.path.dirname(getBundlePath())))
    sub = os.path.join(dir, name + ".skl")
    spath = os.path.dirname(SFm.unzipSKL(sub))
    if sPath:
        sys.path.append(spath)
        return true
    return false

*** usage for a mymodule.skl in same directory:

loadSKL("mymodule")
import mymodule

usage for a mymodule.skl in same directory:

loadSKL("mymodule", "some-absolute-path-to-folder-containing-the-skl")
import mymodule

as already mentioned
from my module import *
can be used as well

So besides the fact, that currently you have to implement your own function, to make a .skl importable, there is no difference to the situation, when Sikuli will allow other forms of packaging scripts, images and other resources, since the usage will be:

load <script-container>
import some-module-from-container

So the valuation in comment #15 to some extent underestimates your current possibilities and overestimates the role of Sikuli in this case.