Source code for src.activemods

from src.trie import Trie
from src.utils import edit_distance

ACTIVEMODS_KEY = "activemods:active_mods"

[docs] class ActiveMods(): def __init__(self, data): self._activemods = {} self._trie = Trie() if ACTIVEMODS_KEY in data: for x in data[ACTIVEMODS_KEY]: m = ActiveMod(x) self._activemods[m.normalized_name] = m self._trie.insert(m.normalized_name) @property def all_mods(self): return self._activemods.values()
[docs] def normalize(self, string): return string.lower().replace(" ", "")
[docs] def edit_distance_ratio(self, distance, word): return (len(word)-distance)/len(word)
[docs] def find_mod(self, mod_name): mod_name = self.normalize(mod_name) # it's pointless... if len(mod_name) == 0: return None # easy, they entered the name correctly if mod_name in self._activemods: return self._activemods[mod_name] names = self._trie.search(mod_name) # still pretty easy... if len(names) == 1: return self._activemods[names[0]] # getting annoying... if len(names) < 3: # sort by edit distance distances = sorted([(name, edit_distance(name, mod_name)) for name in names], key=lambda x: x[1]) # and check the first one name, distance = distances[0] # close enough, i guess if self.edit_distance_ratio(distance, name) > 0.9: return self._activemods[potential[0]] # nope, we give up return None
[docs] class ActiveMod(): def __init__(self, data: dict): """ See https://github.com/drummeur/activemods/blob/master/schema.json for the dict schema. A few of the fields are renamed to avoid python keywords """ if "id" in data: self.modid = data["id"] else: self.modid = "" if "name" in data: self.name = data["name"].strip() else: self.name = "" if "description" in data: self.description = data["description"] else: self.description = "" if "authors" in data: self.authors = data["authors"] else: self.authors = [] if "credits" in data: self.mod_credits = data["credits"] else: self.mod_credits = "" if "mod_version" in data: self.mod_version = data["mod_version"] else: self.mod_version = { "version": "unknown", "major": 0, "minor": 0, "patch": 0 } if "dependencies" in data: self.dependencies = data["dependencies"] else: self.dependencies = [] if "optional_dependencies" in data: self.optional_dependencies = data["optional_dependencies"] else: self.optional_dependencies = [] if "mod_url" in data: self._mod_url = data["mod_url"] else: self._mod_url = "" if "is_steam_workshop_mod" in data: self.is_steam_workshop_mod = data["is_steam_workshop_mod"] else: self.is_steam_workshop_mod = None def __str__(self): return self.name @property def mod_url(self) -> str: # infomod and mapmarks are hardcoded until custom URLs are implemented into ActiveMods if self.modid == "ojb_infomod2": return "https://casey-c.github.io/slaythespire/infomod.html" elif self.modid == "ojb_mapmarks": return "https://github.com/casey-c/mapmarks" else: return self._mod_url @property def version(self) -> str: return self.mod_version["version"] def _try_get_int_version(self, field: str) -> int: result = 0 try: result = int(self.mod_version["version"]) except (ValueError, KeyError): pass return result @property def major_version(self) -> int: return self._try_get_int_version("major") @property def minor_version(self): return self._try_get_int_version("minor") @property def patch_version(self): return self._try_get_int_version("patch") @property def authors_formatted(self): if len(self.authors) == 0: authors = "An unknown STS modder" elif len(self.authors) == 1: authors = self.authors[0] else: authors = ", ".join(self.authors[:-1]) authors += f", and {self.authors[-1]}" return authors @property def description_formatted(self): if len(self.description) == 0: desc = "This mod is indescribable (because it has no description...)" else: desc = self.description return desc @property def normalized_name(self): return self.name.lower().replace(" ", "")