Recursive Item Data: New boots reference a reference.
I found this issue running py -m lolstaticdata.items upon reaching the new boot upgrade "Forever Forward".
This item is the boots upgrade to Synchronized Souls which is a transformation of the tier 2 boots Symbiotic Soles.
They all share the passive "Voidborn" which gives empowered recall.
In the wiki data, a value containing "=>" followed by an item name indicates a reference to some shared value.
So these boots "Forever Forward" have as their first passive "=>Synchronized Souls", which in turn have as their first passive "=>Symbiotic Soles".
lolstaticdata already handles 1 reference but it does not handle when that result is another reference, atleast not for passives.
The error I found occurs in the file "pull_items_wiki.py" in the function "_parse_passive_info" in the code:
return unique, mythic, name, passive["description"], item_range, cd
The passive["description"] part is meant to be a dictionary with a "description" key but it crashes on "Forever Forward" because the passive is a string "=>Symbiotic Soles" (the value taken from Synchronized Souls) and thus it expects an integer index for a string instead of a string index for a dictionary and crashes.
To be clear the original value of this passive was "=>Synchronized Souls" which then was replaced with "=>Symbiotic Soles" and it just needs one more step to get to the actual voidborn passive object inside Symbiotic Soles.
I fixed this by defining a recursive function that will keep following the "=>" references until it reaches a non-string non-reference then return that, while also trying to track the failed keys to pop them later. This item might be a special case but heres the recursive method I wrote (I don't normally use python so not sure about pull requesting it).
@classmethod
def _parse_item_data(cls, item_data: dict, item_name:str,wiki_data:dict) -> Item:
not_unique = re.compile("[A-z]")
clear_keys = []
builds_from = []
nicknames = []
clear_keys_2 = []
def resolve_entry(current_item_name:str, key1: str, key2: Optional[str])->Optional[str]:
candidate_entry = wiki_data[current_item_name][key1]
if key2:
candidate_entry = candidate_entry[key2]
if type(candidate_entry) == str:
if "=>" in candidate_entry:
try:
resolve_item_name = candidate_entry.replace("=>", "")
if key2:
print(F"Replace value of ['{key1}']['{key2}'] in item '{item_name}' with item '{resolve_item_name}'.")
else:
print(F"Replace value of ['{key1}'] in item '{item_name}' with item '{resolve_item_name}'.")
return resolve_entry(resolve_item_name, key1, key2)
except KeyError as e:
print(F"Replacement failed... {e}")
if key2:
clear_keys_2.append(key1,key2)
return item_data[key1][key2]
clear_keys.append(key1)
return item_data[key1]
return candidate_entry
for x in item_data:
item_data[x] = resolve_entry(item_name, x, None)
if x in "effects":
for l in item_data[x]:
item_data[x][l] = resolve_entry(item_name, x, l)
if x in "stats":
for l in item_data[x]:
item_data[x][l] = resolve_entry(item_name, x, l)
for key in clear_keys:
item_data.pop(key)
index2 = 0
stored_clear_key = None
for key in clear_keys_2:
if index2 == 0:
stored_clear_key = key
index2 = 1
else:
item_data[stored_clear_key].pop(key)
index2 = 0
I created a PR that should fix this https://github.com/meraki-analytics/lolstaticdata/pull/108 It's not recursive like this solution, but it handles 2 redirects fine (essentially manually checking for a second redirect)