Using dictionaries

Asked by Calle Rundgren

This is acctually a additional question for this: https://answers.launchpad.net/sikuli/+question/144772

But since that question is closed I am starting a new question.

When using a dictionary in my imagelibrary, do I still need to declare all images? I think I got the wrapper working but sikuli keeps telling me I have to declare the images in the dictionary.

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Solved by:
RaiMan
Solved:
Last query:
Last reply:

This question was reopened

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

I just added the example dictionary based class to the question
https://answers.launchpad.net/sikuli/+question/144772.
and I marked it solved so it is present for standard searches.

--- When using a dictionary in my imagelibrary, do I still need to declare all images?
I am not really sure what you mean with "declare".

Please give an example code snippet.

Paste the original error message.

Revision history for this message
Calle Rundgren (c-rundgren) said :
#2

Here is the code which I would like to make imports from my module imageDictWrapper

import os
sikuliPath = r"c:\\sikuli\\imageshiRes.sikuli"
fullPath = r"c:\\sikuli\\imageDictWrapper.sikuli\\imageDictWrapper.py"
execfile(fullPath)
setBundlePath(sikuliPath)

from imageDictWrapper import*
click(imgSet.getImage(openButton)) #just so i can se if everything is working as planned

The error message tells me there is no module called imageDictWrapper:
ImportError: No module named imageDictWrapper

Even though there is a module with that name. The file which contains the module is called imageDictWrapper.py which is correct?

Revision history for this message
Calle Rundgren (c-rundgren) said :
#3

Almost forgot, In the file which contains the images in the dictionary. Should I

image1 = "2123904.png"
image2 = "2318371.png" #If i don't have this declaration of images I got error that I got
image3 = "7390302.png" to define them. Is this necessary? I thought it would be enough to
                               give the images keys in the dictionary
myDict = {}
myDict[image1] = "2123904.png"
mydict[image2] = "2318371.png"
myDict[image3] = "7390302.png"

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

--- the dictionary

myDict = {}
myDict["image1"] = "2123904.png"
mydict["image2"] = "2318371.png"
myDict["image3"] = "7390302.png"

the keys of the dictionary have to be known objects. In this case, it makes sense, to use strings.

--- the "import" problem

import os
sikuliPath = r"c:\\sikuli\\imageshiRes.sikuli"
fullPath = r"c:\\sikuli\\imageDictWrapper.sikuli\\imageDictWrapper.py"
execfile(fullPath)
setBundlePath(sikuliPath)

since you are using execfile(), the definitions contained in imageDictWrapper.py are already "imported".

I would prefer to use imports instead of your sequence

sikuliPath = r"c:\sikuli" # with raw strings ( r" " ) only one backslash is needed
if not sikuliPath in sys.path: sys.path.append(sikuliPath)
import imageshiRes
import imageDictWrapper

image files in both .sikuli will be found.

Revision history for this message
Calle Rundgren (c-rundgren) said :
#5

This is my wrapper:

And this is supposed to execute the wrapper:

from imagesHiRes import*

class imageDictWrapper():
    def __init__(self, images, imageSet = "HiRes"):
        self.images = theImageDict
    def getImage(self, imageName):
        return images[imageName]

sikuliPath = r"c:\sikuli"
if not sikuliPath in sys.path: sys.path.append(sikuliPath)
import imagesHiRes
import imageDictWrapper

imgSet = imageDictWrapper.imageDictWrapper("HiRes")

click(imgSet.getImage("openButton"))

I have got some different errors, the error I got now is: NameError: global name 'images' is not defined

Where am I supposed to define 'images'?

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

- inside a class definition the instance variables (in your case images) have to be qualified with self.
- the parameter images does not make sense with __init__()

class imageDictWrapper():
    def __init__(self, imageSet = "HiRes"):
        self.images = theImageDict
    def getImage(self, imageName):
        return self.images[imageName]

--- I would do your approach this way:

-- content of imageDictWrapper.sikuli

from sikuli.Sikuli import *
class imageDict():
    def __init__(self, imageSet):
        self.images = imageSet
    def getImage(self, imageName):
        return self.images[imageName]

-- main script:

sikuliPath = r"c:\sikuli"
if not sikuliPath in sys.path: sys.path.append(sikuliPath)
import imagesAllRes
import imageDictWrapper

imgSet = imageDictWrapper.imageDict(theImageDictHiRes)

click(imgSet.getImage("openButton"))

imagesAllRes.sikuli contains images for all resolutions AND the respective dictionaries containing the references to the images of a specific resolution.

So you have full control in your workflow, which of the dict's you want to use (theImageDictHiRes in this case).

Revision history for this message
Calle Rundgren (c-rundgren) said :
#7

I made these changes but I still got a NameError. Thias time it says that theImageDictHiRes is not defined. The error occurs on this line: imgSet = imageDictWrapper.imageDict(theImageDictHiRes)

Am I supposed to define the string 'theImageDictWrapper' somewhere?

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

--- mind this:
imagesAllRes.sikuli contains images for all resolutions AND the respective dictionaries containing the references to the images of a specific resolution.

This was the change to your code.

If you want to stick with your current imagesHiRes.sikuli:

import imagesHiRes
import imageDictWrapper

imgSet = imageDictWrapper.imageDict(theImageDict)

My suggestion was to change imagesHiRes.sikuli to imagesAllRes.sikuli and theImageDict to imageDictHiRes in this module. So you could pack other dictionaries like imageDictLowRes into imagesAllRes.sikuli, that would reference the low resolution images for the same set of image name indexes like "openButton". But it is totally up to you, how to make this solution more generic and felexible.

Revision history for this message
Calle Rundgren (c-rundgren) said :
#9

Yes I understand, and I have done the changes in order to stick to your suggestion. The changes I did was: change name of imagesHiRes.sikuli ----> imagesAllRes.sikuli, and I changed the name of the dictionary theImageDict ----> theImageDictHiRes.

But the main script does not seem to find the dictionary theImageDictHiRes in the module imagesAllRes.sikuli. Maybe I am defining my dictionary wrong? it is done like this now:

theImageDictHiRes {}
theImageDictHiRes["openButton"] = "1234455.png"
and on and on...

The 1234455.png is displayed as a image in the dictionary, shall I add it to the dict as a string instead? Or does it matter?

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

sorry for my blindness :-(

you either have to use
from imagesAllRes import *

or qualify the dict with imagesAllRes
imgSet = imageDictWrapper.imageDict(imagesAllRes.theImageDictHiRes)

I suggest the second solution, to not have any naming conflicts in the future. The first solution copies all names defined in imagesAllRes.sikuli in your main namespace (which is not really needed in your case).

*** one more things:
-- theImageDictHiRes {} should read theImageDictHiRes = {} (makes it an empty dictionary)

Revision history for this message
Calle Rundgren (c-rundgren) said :
#11

Thanks RaiMan, that solved my question.

Revision history for this message
Calle Rundgren (c-rundgren) said :
#12

Yes. Now the naming conflict is gone. ouch! I forgot the = with the dictionary.

Thank you for all the help. :-)

Revision history for this message
Calle Rundgren (c-rundgren) said :
#13

Yes. Now the naming conflict is gone. ouch! I forgot the = with the dictionary.

Thank you for all the help. :-)

Revision history for this message
Calle Rundgren (c-rundgren) said :
#14

Thanks RaiMan, that solved my question.

Revision history for this message
Calle Rundgren (c-rundgren) said :
#15

blah! I got another error now. TypeError: 'dict' object is not callable.

I found out that the solution to this is to make the dictionary look up with square brackets [].

But I ca not find out which () to replace with the [].

The error seems to occur at this line:

def getImage(self, imageName):
    return self.images[imageName]

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

No, an empty dictionary is defined with {} or dict().
The elements are set/retrieved using
aDict[someKey] = someValue
x = aDict[someKey]

Your error usually comes up, if you have written aDict() instead of aDict[].

The Error is in the line mentioned with the error or just scan your code for aDict().

Revision history for this message
Calle Rundgren (c-rundgren) said :
#17

I found the Error. The solution now looks like:

he wrapper:

from sikuli.Sikuli import *

class imageDict():
    def __init__(self, imageSet):
        self.images = imageSet
    def getImage(self, imageName):
        return self.images[imageName]

To execute the wrapper:

sikuliPath = r"c:\sikuli"
if not sikuliPath in sys.path: sys.path.append(sikuliPath)
import imagesAllRes
import imageDictWrapper

imgSet = imageDictWrapper.imageDict(imagesAllRes.theImageDictHiRes)
click(imgSet.getImage("openButton"))

Thanks for additional help! :-)

Revision history for this message
Calle Rundgren (c-rundgren) said :
#18

Thanks RaiMan, that solved my question.