def load(self): """Load all possible cache details. Use full cache details page. Therefore all possible properties are filled in, but the loading is a bit slow. If you want to load basic details about a PM only cache, the :class:`.PMOnlyException` is still thrown, but avaliable details are filled in. If you know, that the cache you are loading is PM only, please consider using :meth:`load_quick` as it will load the same details, but quicker. .. note:: This method is called automatically when you access a property which isn't yet filled in (so-called "lazy loading"). You don't have to call it explicitly. :raise .PMOnlyException: If cache is PM only and current user is basic member. :raise .LoadError: If cache loading fails (probably because of not existing cache). """ try: # pick url based on what info we have right now if hasattr(self, "url"): root = self.geocaching._request(self.url) elif hasattr(self, "_wp"): root = self.geocaching._request("seek/cache_details.aspx", params={"wp": self._wp}) else: raise errors.LoadError("Cache lacks info for loading") except errors.Error as e: # probably 404 during cache loading - cache not exists raise errors.LoadError("Error in loading cache") from e # check for PM only caches if using free account self.pm_only = root.find("section", "pmo-banner") is not None cache_details = root.find(id="ctl00_divContentMain") if self.pm_only else root.find(id="cacheDetails") # details also avaliable for basic members for PM only caches ----------------------------- if self.pm_only: self.wp = cache_details.find("li", "li__gccode").text.strip() self.name = cache_details.find("h1").text.strip() author = cache_details.find(id="ctl00_ContentBody_uxCacheBy").text self.author = author[len("A cache by "):] # parse cache detail list into a python list details = cache_details.find("ul", "ul__hide-details").text.split("\n") self.difficulty = float(details[2]) self.terrain = float(details[5]) self.size = Size.from_string(details[8]) self.favorites = int(details[11]) else: # parse from <title> - get first word try: self.wp = root.title.string.split(" ")[0] except: raise errors.LoadError self.name = cache_details.find("h2").text self.author = cache_details("a")[1].text size = root.find("div", "CacheSize") D_and_T_img = root.find("div", "CacheStarLabels").find_all("img") size = size.find("img").get("src") # size img src size = size.split("/")[-1].rsplit(".", 1)[0] # filename w/o extension self.size = Size.from_filename(size) self.difficulty, self.terrain = [float(img.get("alt").split()[0]) for img in D_and_T_img] type = cache_details.find("img").get("src") # type img src type = type.split("/")[-1].rsplit(".", 1)[0] # filename w/o extension self.type = Type.from_filename(type) if self.pm_only: raise errors.PMOnlyException() # details not avaliable for basic members for PM only caches ------------------------------ pm_only_warning = root.find("p", "Warning NoBottomSpacing") self.pm_only = pm_only_warning and ("Premium Member Only" in pm_only_warning.text) or False attributes_widget, inventory_widget, *_ = root.find_all("div", "CacheDetailNavigationWidget") hidden = cache_details.find("div", "minorCacheDetails").find_all("div")[1].text self.hidden = parse_date(hidden.split(":")[-1]) self.location = Point.from_string(root.find(id="uxLatLon").text) self.state = root.find("ul", "OldWarning") is None found = root.find("div", "FoundStatus") self.found = found and ("Found It!" or "Attended" in found.text) or False attributes_raw = attributes_widget.find_all("img") attributes_raw = [_.get("src").split("/")[-1].rsplit("-", 1) for _ in attributes_raw] self.attributes = {attribute_name: appendix.startswith("yes") for attribute_name, appendix in attributes_raw if not appendix.startswith("blank")} user_content = root.find_all("div", "UserSuppliedContent") self.summary = user_content[0].text self.description = str(user_content[1]) self.hint = rot13(root.find(id="div_hint").text.strip()) favorites = root.find("span", "favorite-value") self.favorites = 0 if favorites is None else int(favorites.text) self._log_page_url = root.find(id="ctl00_ContentBody_GeoNav_logButton")["href"] js_content = "\n".join(map(lambda i: i.text, root.find_all("script"))) self._logbook_token = re.findall("userToken\\s*=\\s*'([^']+)'", js_content)[0] # find original location if any if "oldLatLng\":" in js_content: old_lat_long = js_content.split("oldLatLng\":")[1].split(']')[0].split('[')[1] self.original_location = Point(old_lat_long) else: self.original_location = None # if there are some trackables if len(inventory_widget.find_all("a")) >= 3: trackable_page_url = inventory_widget.find(id="ctl00_ContentBody_uxTravelBugList_uxViewAllTrackableItems") self._trackable_page_url = trackable_page_url.get("href")[3:] # has "../" on start else: self._trackable_page_url = None logging.debug("Cache loaded: {}".format(self))
def test_rot13(self): self.assertEqual(rot13("Text"), "Grkg") self.assertEqual(rot13("abc'ř"), "nop'ř")