lolstaticdata icon indicating copy to clipboard operation
lolstaticdata copied to clipboard

Recursive Item Data: New boots reference a reference.

Open tsworc opened this issue 1 year ago • 1 comments

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

tsworc avatar Jan 11 '25 19:01 tsworc

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)

Galvantua avatar Jan 26 '25 06:01 Galvantua