I stumbled across an issue in my plugin and trying to work out what’s going wrong. Here’s some example code:
<br />
<br />
userRatedCache = None<br />
<br />
def Example():<br />
global userRatedCache<br />
<br />
if userRatedCache is not None:<br />
Log("Found Cache")<br />
# Cache hit, use it!<br />
else:<br />
Log("Initializing")<br />
userRatedCache = {}<br />
<br />
...<br />
I'm using the global variable to cache results of an expensive HTTP request. However, what I was expecting is that the first time it is called, it would populate the variable. Then, subsequent calls would find that userRatedCache is no longer None and therefore simply use it. However, looking through the logs, all I see is that it "Initializes" every time. Is this what people would expect?
Yes, this is expected behaviour. Because plug-ins need to support multiple parallel requests, potentially from different users, writing to globals inside functions called from a user request isn’t supported. Globals can be used to define constants, but that’s all. Have you tried using the HTTP caching feature (by setting the cacheTime argument of HTTP.Request), or storing the data in the Dict (a persistent per-user dictionary object)?
I think that using the Dict (user dictionary object) might be better suited. I had a look through the SDK documentation and tried a few things out. However, i'm still not fully understanding it (sorry). I've changed the above example to the following:
<br />
def Example():<br />
userRatedCache = None<br />
if Dict.HasKey("userRatedCache"):<br />
userRatedCache = Dict.Get("userRatedCache")<br />
<br />
if userRatedCache is not None:<br />
Log("Found Cache")<br />
# Cache hit, use it!<br />
else:<br />
Log("Initializing")<br />
userRatedCache = {}<br />
<br />
...<br />
<br />
# Store the dictionary in the Dict so we can use it next time<br />
Dict.Set("userRatedCache", userRatedCache)<br />
I'm using the presence of this variable within the Dict to determine if it's been worked out. When I run this code, I get the following error:
<br />
2011-02-08 20:29:26,795 (-4faed000) : CRITICAL (core) - Exception when calling function 'UserListMenu' (most recent call last):<br />
File "/Users/IanDBird/Library/Application Support/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/code.py", line 552, in call_named_function<br />
result = f(*args, **kwargs)<br />
File "/Users/IanDBird/Library/Application Support/Plex Media Server/Plug-ins/LoveFilm.bundle/Contents/Code/__init__.py", line 274, in UserListMenu<br />
dir = ProcessQuery(sender, url, params)<br />
File "/Users/IanDBird/Library/Application Support/Plex Media Server/Plug-ins/LoveFilm.bundle/Contents/Code/__init__.py", line 329, in ProcessQuery<br />
dir = populateFromCatalog(items, dir)<br />
File "/Users/IanDBird/Library/Application Support/Plex Media Server/Plug-ins/LoveFilm.bundle/Contents/Code/__init__.py", line 573, in populateFromCatalog<br />
userRating = getRating(url = t['id'], defaultRating = t['user_rating']),<br />
File "/Users/IanDBird/Library/Application Support/Plex Media Server/Plug-ins/LoveFilm.bundle/Contents/Code/__init__.py", line 745, in getRating<br />
if Dict.HasKey("userRatedCache"):<br />
File "/Users/IanDBird/Library/Application Support/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions/2/Python/Framework/bases.py", line 85, in __getattribute__<br />
attr = object.__getattribute__(self, name)<br />
AttributeError: 'DictKit' object has no attribute 'HasKey'<br />
Also, I'm only wanting the dictionary not to be persistent. I'm guessing that I need to use the CreateDict method to call Dict.Reset()? I wrote a basic CreateDict method which just logs (Log("Creating Dict")) but i'm finding that it never gets called. When should I find that it's called?
No need to apologise If you’re using the v2 framework, the methods of interacting with the Dict have changed slightly to use more standard Python idioms for interacting with dictionary types.
To check if an item is in the dictionary, use “if X in Dict”. If this is all you’re using the Dict for, the easiest way to make it non-persistent would be to call Dict.Reset() in the Start() function.
Hey, thanks for this. I’ve got something looking like it’s working. One last question though, should I decorate all functions that can modify the Dict (including now my Start) with @modify_dict . Is this used for thread synchronisation?