예제 #1
0
 def test_contains(self):
     inside_points = [Point(*i) for i in [(10.0, 20.0), (30.0, -5.0), (18.0, 15.0), (29.0, -1), (10.0, -3)]]
     outside_points = [Point(*i) for i in [(-10.0, -170.0), (-70.0, 0.0), (0.0, 40), (20.0, -10.0), (50.0, 0.0)]]
     for p in inside_points:
         self.assertTrue(p in self.rect)
     for p in outside_points:
         self.assertFalse(p in self.rect)
예제 #2
0
 def setUp(self):
     self.gc = Geocaching()
     self.c = Cache(self.gc,
                    "GC12345",
                    name="Testing",
                    type=Type.traditional,
                    location=Point(),
                    state=True,
                    found=False,
                    size=Size.micro,
                    difficulty=1.5,
                    terrain=5,
                    author="human",
                    hidden=date(2000, 1, 1),
                    attributes={
                        "onehour": True,
                        "kids": False,
                        "available": True
                    },
                    summary="text",
                    description="long text",
                    hint="rot13",
                    favorites=0,
                    pm_only=False,
                    original_location=Point(),
                    waypoints={},
                    guid="53d34c4d-12b5-4771-86d3-89318f71efb1")
     self.c._log_page_url = "/seek/log.aspx?ID=1234567&lcn=1"
예제 #3
0
 def test_format_gc(self):
     """Test Geocaching point formatting."""
     self.assertEqual(
         Point(49.73012, 13.40102).format_gc(),
         "N 49° 43.807, E 13° 24.061")
     self.assertEqual(
         Point(-49.73012, -13.40102).format_gc(),
         "S 49° 43.807, W 13° 24.061")
예제 #4
0
    def test_from_tile(self):
        """Test coordinate creation from tile"""
        p = Point.from_tile(*make_tile(8800, 5574, 14, 0, 0, 256))
        p_pos = Point(49.752879934150215, 13.359375, 0.0)

        p2 = Point.from_tile(*make_tile(8801, 5575, 14, 0, 0, 256))
        p_half = Point.from_tile(*make_tile(8800, 5574, 14, 1, 1, 2))

        # Check creation
        for att in ['latitude', 'longitude']:
            with self.subTest("assumed location: {}".format(att)):
                self.assertAlmostEqual(getattr(p, att), getattr(p_pos, att))

        with self.subTest("fractional tiles: y-axis addition"):
            self.assertEqual(
                Point.from_tile(*make_tile(8800, 5574, 14, 0, 32, 32)),
                Point.from_tile(*make_tile(x=8800, y=5575, z=14)))
        with self.subTest("fractional tiles: x-axis addition"):
            self.assertAlmostEqual(
                Point.from_tile(*make_tile(8800, 5574, 14, 32, 0, 32)),
                Point.from_tile(*make_tile(x=8801, y=5574, z=14)))
        with self.subTest("fractional tiles: addition on both axes"):
            self.assertEqual(
                Point.from_tile(*make_tile(8800, 5574, 14, 32, 32, 32)), p2)

        with self.subTest("y increases -> latitude decreases"):
            self.assertGreater(p.latitude, p_half.latitude)
        with self.subTest("x increases -> latitude increases"):
            self.assertLess(p.longitude, p_half.longitude)
예제 #5
0
    def test_from_tile(self):
        """Test coordinate creation from tile"""
        p = Point.from_tile(*make_tile(8800, 5574, 14, 0, 0, 256))
        p_pos = Point(49.752879934150215, 13.359375, 0.0)

        p2 = Point.from_tile(*make_tile(8801, 5575, 14, 0, 0, 256))
        p_half = Point.from_tile(*make_tile(8800, 5574, 14, 1, 1, 2))

        # Check creation
        for att in ['latitude', 'longitude']:
            with self.subTest("assumed location: {}".format(att)):
                self.assertAlmostEqual(getattr(p, att), getattr(p_pos, att))

        with self.subTest("fractional tiles: y-axis addition"):
            self.assertEqual(Point.from_tile(*make_tile(8800, 5574, 14, 0, 32, 32)),
                             Point.from_tile(*make_tile(x=8800, y=5575, z=14)))
        with self.subTest("fractional tiles: x-axis addition"):
            self.assertAlmostEqual(Point.from_tile(*make_tile(8800, 5574, 14, 32, 0, 32)),
                                   Point.from_tile(*make_tile(x=8801, y=5574, z=14)))
        with self.subTest("fractional tiles: addition on both axes"):
            self.assertEqual(Point.from_tile(*make_tile(8800, 5574, 14, 32, 32, 32)), p2)

        with self.subTest("y increases -> latitude decreases"):
            self.assertGreater(p.latitude, p_half.latitude)
        with self.subTest("x increases -> latitude increases"):
            self.assertLess(p.longitude, p_half.longitude)
예제 #6
0
    def test_location(self):
        self.assertEqual(self.c.location, Point())

        with self.subTest("automatic str conversion"):
            self.c.location = "S 36 51.918 E 174 46.725"
            self.assertEqual(self.c.location, Point.from_string("S 36 51.918 E 174 46.725"))

        with self.subTest("filter invalid string"):
            with self.assertRaises(PycachingValueError):
                self.c.location = "somewhere"

        with self.subTest("filter invalid types"):
            with self.assertRaises(PycachingValueError):
                self.c.location = None
예제 #7
0
    def test_to_tile(self):
        t = make_tile(8800, 5574, 14)[0]
        point_in_t = Point(49.75, 13.36)

        with self.subTest("from tile and back"):
            self.assertEqual(Point.from_tile(t).to_tile(None, t.z), t)

        with self.subTest("random point"):
            self.assertEqual(point_in_t.to_tile(None, 14), t)

        with self.subTest("increase in latitude: decrease in y value"):
            self.assertLess(Point(50., 13.36).to_tile(None, 14).y, t.y)

        with self.subTest("increase in longitude: increase in x value"):
            self.assertGreater(Point(49.75, 14.).to_tile(None, 14).x, t.x)
예제 #8
0
    def _from_api_record(cls, geocaching, record):
        """Create a cache instance from a JSON record returned by API."""
        cache = Cache(
            geocaching,
            wp=record['code'],
            name=record['name'],
            type=Type.from_number(record['geocacheType']),
            state=Status(record['cacheStatus']) == Status.enabled,
            found=record['userFound'],
            size=Size.from_number(record['containerType']),
            difficulty=record['difficulty'],
            terrain=record['terrain'],
            author=record['owner']['username'],
            hidden=record['placedDate'].split('T')[0],
            favorites=record['favoritePoints'],
            pm_only=record['premiumOnly'],

            # Not consumed attributes:
            # detailsUrl
            # hasGeotour
            # hasLogDraft
            # id
            # lastFoundDate
            # owner.code
            # userDidNotFind
        )

        # NOTE: Basic Members have no access to postedCoordinates of Premium-only caches
        if 'postedCoordinates' in record:
            cache.location = Point(record['postedCoordinates']['latitude'],
                                   record['postedCoordinates']['longitude'])

        return cache
예제 #9
0
파일: cache.py 프로젝트: forslund/pycaching
 def location(self, location):
     if _type(location) is str:
         location = Point.from_string(location)
     elif _type(location) is not Point:
         raise errors.ValueError(
             "Passed object is not Point instance nor string containing coordinates.")
     self._location = location
예제 #10
0
파일: cache.py 프로젝트: forslund/pycaching
 def original_location(self, original_location):
     if _type(original_location) is str:
         original_location = Point.from_string(original_location)
     elif _type(original_location) is not Point and original_location is not None:
         raise errors.ValueError(
             "Passed object is not Point instance nor string containing coordinates.")
     self._original_location = original_location
예제 #11
0
 def location(self, location):
     if isinstance(location, str):
         location = Point.from_string(location)
     elif not isinstance(location, Point):
         raise errors.ValueError(
             "Passed object is not Point instance nor string containing coordinates.")
     self._location = location
예제 #12
0
    def test_load_by_guid(self, mock_load_quick, mock_load):
        with self.subTest("normal"):
            cache = Cache(self.gc,
                          "GC2WXPN",
                          guid="5f45114d-1d79-4fdb-93ae-8f49f1d27188")
            with self.recorder.use_cassette('cache_guidload_normal'):
                cache.load_by_guid()
            self.assertEqual(cache.name, "Der Schatz vom Luftschloss")
            self.assertEqual(cache.location,
                             Point("N 49° 57.895' E 008° 12.988'"))
            self.assertEqual(cache.type, Type.mystery)
            self.assertEqual(cache.size, Size.large)
            self.assertEqual(cache.difficulty, 2.5)
            self.assertEqual(cache.terrain, 1.5)
            self.assertEqual(cache.author, "engelmz & Punxsutawney Phil")
            self.assertEqual(cache.hidden, parse_date("23/06/2011"))
            self.assertDictEqual(
                cache.attributes, {
                    "bicycles": True,
                    "available": True,
                    "parking": True,
                    "onehour": True,
                    "kids": True,
                    "s-tool": True,
                })
            self.assertEqual(cache.summary,
                             "Gibt es das Luftschloss wirklich?")
            self.assertIn("Seit dem 16.", cache.description)
            self.assertEqual(cache.hint, "Das ist nicht nötig")
            self.assertGreater(cache.favorites, 350)
            self.assertEqual(len(cache.waypoints), 2)
            self.assertDictEqual(
                cache.log_counts, {
                    LogType.found_it: 800,
                    LogType.note: 35,
                    LogType.archive: 1,
                    LogType.needs_archive: 1,
                    LogType.temp_disable_listing: 5,
                    LogType.enable_listing: 4,
                    LogType.publish_listing: 1,
                    LogType.needs_maintenance: 5,
                    LogType.owner_maintenance: 3,
                    LogType.post_reviewer_note: 2,
                })

        with self.subTest("PM-only"):
            cache = Cache(self.gc,
                          "GC6MKEF",
                          guid="53d34c4d-12b5-4771-86d3-89318f71efb1")
            with self.recorder.use_cassette('cache_guidload_PMO'):
                with self.assertRaises(PMOnlyException):
                    cache.load_by_guid()

        with self.subTest("calls load_quick if no guid"):
            cache = Cache(self.gc, "GC2WXPN")
            with self.recorder.use_cassette('cache_guidload_fallback'):
                with self.assertRaises(Exception):
                    cache.load_by_guid(
                    )  # Raises error since we mocked load_quick()
            self.assertTrue(mock_load_quick.called)
예제 #13
0
    def from_html(cls, soup, table_id):
        """Return a dictionary of all waypoints found in the page
        representation

        :param bs4.BeautifulSoup soup: parsed html document containing the
            waypoints table
        :param str table_id: html id of the waypoints table
        """
        waypoints_dict = {}
        waypoints_table = soup.find('table', id=table_id)
        if waypoints_table:
            waypoints_table = waypoints_table.find_all("tr")
            for r1, r2 in zip(waypoints_table[1::2], waypoints_table[2::2]):
                columns = r1.find_all("td") + r2.find_all("td")
                identifier = columns[3].text.strip()
                type = columns[1].find("img").get("title")
                location_string = columns[5].text.strip()
                try:
                    loc = Point(location_string)
                except ValueError:
                    loc = None
                    logging.debug(
                        "No valid location format in waypoint {}: {}".format(
                            identifier, location_string))
                note = columns[8].text.strip()
                waypoints_dict[identifier] = cls(identifier, type, loc, note)
        return waypoints_dict
예제 #14
0
 def location(self, location):
     if isinstance(location, str):
         location = Point.from_string(location)
     elif not isinstance(location, Point):
         raise errors.ValueError(
             "Passed object is not Point instance nor string containing coordinates.")
     self._location = location
예제 #15
0
    def _from_print_page(cls, geocaching, guid, soup):
        """Create a cache instance from a souped print-page and a GUID."""
        if soup.find("p", "Warning") is not None:
            raise errors.PMOnlyException()

        cache_info = dict()
        cache_info["guid"] = guid
        cache_info["wp"] = soup.find(
            class_="HalfRight").find("h1").text.strip()
        content = soup.find(id="Content")
        cache_info["name"] = content.find("h2").text.strip()
        cache_info["type"] = Type.from_filename(
            content.h2.img["src"].split("/")[-1].partition(".")[0])
        cache_info["author"] = content.find(
            class_="Meta").text.partition(":")[2].strip()
        diff_terr = content.find(class_="DiffTerr").find_all("img")
        assert len(diff_terr) == 2
        cache_info["difficulty"] = float(diff_terr[0]["alt"].split()[0])
        cache_info["terrain"] = float(diff_terr[1]["alt"].split()[0])
        cache_info["size"] = Size.from_string(
            content.find(
                class_="Third AlignCenter").p.img["alt"].partition(":")[2])
        fav_text = content.find(class_="Third AlignRight").p.contents[2]
        try:
            cache_info["favorites"] = int(fav_text)
        except ValueError:  # element not present when 0 favorites
            cache_info["favorites"] = 0
        cache_info["hidden"] = parse_date(
            content.find(class_="HalfRight AlignRight").p.text.strip().
            partition(":")[2].strip())
        cache_info["location"] = Point.from_string(
            content.find(class_="LatLong").text.strip())
        cache_info["state"] = None  # not on the page
        attributes = [
            img["src"].split("/")[-1].partition(".")[0].rpartition("-")
            for img in content.find(class_="sortables").find_all("img")
            if img.get("src") and img["src"].startswith("/images/attributes/")
        ]
        cache_info["attributes"] = {
            attr_name: attr_setting == "yes"
            for attr_name, _, attr_setting in attributes
        }
        if "attribute" in cache_info["attributes"]:  # 'blank' attribute
            del cache_info["attributes"]["attribute"]
        cache_info["summary"] = content.find(
            "h2", text="Short Description").find_next("div").text
        cache_info["description"] = content.find(
            "h2", text="Long Description").find_next("div").text
        hint = content.find(id="uxEncryptedHint")
        cache_info["hint"] = hint.text.strip() if hint else None
        cache_info["waypoints"] = Waypoint.from_html(content,
                                                     table_id="Waypoints")
        cache_info["log_counts"] = Cache._get_log_counts_from_print_page(soup)
        return Cache(geocaching, **cache_info)
예제 #16
0
파일: cache.py 프로젝트: forslund/pycaching
    def from_block(cls, block):
        """Return :class:`.Cache` instance from :class:`.Block`.

        Used during quick search. The Cache will have only waypoint, name and approximate location
        filled in.

        :param .Block block: Source block
        """
        c = cls(block.tile.geocaching, block.cache_wp, name=block.cache_name)
        c.location = Point.from_block(block)
        return c
예제 #17
0
    def _from_print_page(cls, geocaching, guid, soup):
        """Create a cache instance from a souped print-page and a GUID"""
        if soup.find("p", "Warning") is not None:
            raise errors.PMOnlyException()

        cache_info = dict()
        cache_info['guid'] = guid
        cache_info['wp'] = soup.find(
            class_='HalfRight').find('h1').text.strip()
        content = soup.find(id="Content")
        cache_info['name'] = content.find("h2").text.strip()
        cache_info['type'] = Type.from_filename(
            content.h2.img['src'].split('/')[-1].partition('.')[0])
        cache_info['author'] = content.find(
            class_='Meta').text.partition(':')[2].strip()
        diff_terr = content.find(class_='DiffTerr').find_all('img')
        assert len(diff_terr) == 2
        cache_info['difficulty'] = float(diff_terr[0]['alt'].split()[0])
        cache_info['terrain'] = float(diff_terr[1]['alt'].split()[0])
        cache_info['size'] = Size.from_string(
            content.find(
                class_='Third AlignCenter').p.img['alt'].partition(':')[2])
        fav_text = content.find(class_='Third AlignRight').p.contents[2]
        try:
            cache_info['favorites'] = int(fav_text)
        except ValueError:  # element not present when 0 favorites
            cache_info['favorites'] = 0
        cache_info['hidden'] = parse_date(
            content.find(class_='HalfRight AlignRight').p.text.strip().
            partition(':')[2].strip())
        cache_info['location'] = Point.from_string(
            content.find(class_='LatLong').text.strip())
        cache_info['state'] = None  # not on the page
        attributes = [
            img['src'].split('/')[-1].partition('.')[0].rpartition('-')
            for img in content.find(class_='sortables').find_all('img')
            if img.get('src') and img['src'].startswith('/images/attributes/')
        ]
        cache_info['attributes'] = {
            attr_name: attr_setting == 'yes'
            for attr_name, _, attr_setting in attributes
        }
        if 'attribute' in cache_info['attributes']:  # 'blank' attribute
            del cache_info['attributes']['attribute']
        cache_info['summary'] = content.find(
            "h2", text="Short Description").find_next("div").text
        cache_info['description'] = content.find(
            "h2", text="Long Description").find_next("div").text
        hint = content.find(id='uxEncryptedHint')
        cache_info['hint'] = hint.text.strip() if hint else None
        cache_info['waypoints'] = Waypoint.from_html(content,
                                                     table_id="Waypoints")
        return Cache(geocaching, **cache_info)
예제 #18
0
    def test_location(self):
        self.assertEqual(self.c.location, Point())

        with self.subTest("automatic str conversion"):
            self.c.location = "S 36 51.918 E 174 46.725"
            self.assertEqual(self.c.location, Point.from_string("S 36 51.918 E 174 46.725"))

        with self.subTest("filter invalid string"):
            with self.assertRaises(PycachingValueError):
                self.c.location = "somewhere"

        with self.subTest("filter invalid types"):
            with self.assertRaises(PycachingValueError):
                self.c.location = None
예제 #19
0
    def test_from_location(self):
        ref_point = Point(50.08746, 14.42125)

        with self.subTest("existing location"):
            with self.recorder.use_cassette('geo_location_existing'):
                self.assertLess(great_circle(Point.from_location(self.gc, "Prague"), ref_point).miles, 10)
                self.assertLess(great_circle(Point.from_location(self.gc, "Praha"), ref_point).miles, 10)
                self.assertLess(great_circle(Point.from_location(self.gc, "praha"), ref_point).miles, 10)

        with self.subTest("non-existing location"):
            with self.recorder.use_cassette('geo_location_nonexisting'):
                with self.assertRaises(GeocodeError):
                    Point.from_location(self.gc, "qwertzuiop")

        with self.subTest("empty request"):
            with self.recorder.use_cassette('geo_location_empty'):
                with self.assertRaises(GeocodeError):
                    Point.from_location(self.gc, "")
예제 #20
0
    def test_precision(self):
        with self.subTest("with point coorection"):
            t1 = make_tile(0, 0, 14)[0]
            p = Point(49.75, 13.36)
            self.assertAlmostEqual(t1.precision(p), 6.173474613462484)

        with self.subTest("precision is larger on greater z values"):
            t1 = make_tile(0, 0, 13)[0]
            t2 = make_tile(0, 0, 14)[0]
            self.assertGreater(t1.precision(), t2.precision())

        with self.subTest("precision is larger when tile is divided to smaller pieces"):
            t1 = make_tile(0, 0, 14)[0]
            t1.size = 10
            t2 = make_tile(0, 0, 14)[0]
            t2.size = 100
            self.assertGreater(t1.precision(), t2.precision())
예제 #21
0
    def test_load_by_guid(self, mock_load_quick, mock_load):
        with self.subTest("normal"):
            cache = Cache(self.gc,
                          "GC2WXPN",
                          guid="5f45114d-1d79-4fdb-93ae-8f49f1d27188")
            cache.load_by_guid()
            self.assertEqual(cache.name, "Der Schatz vom Luftschloss")
            self.assertEqual(cache.location,
                             Point("N 49° 57.895' E 008° 12.988'"))
            self.assertEqual(cache.type, Type.mystery)
            self.assertEqual(cache.size, Size.large)
            self.assertEqual(cache.difficulty, 2.5)
            self.assertEqual(cache.terrain, 1.5)
            self.assertEqual(cache.author, "engelmz & Punxsutawney Phil")
            self.assertEqual(cache.hidden, parse_date("23/06/2011"))
            self.assertDictEqual(
                cache.attributes, {
                    "bicycles": True,
                    "available": True,
                    "firstaid": True,
                    "parking": True,
                    "onehour": True,
                    "kids": True,
                    "s-tool": True,
                })
            self.assertEqual(cache.summary,
                             "Gibt es das Luftschloss wirklich?")
            self.assertIn("Seit dem 16.", cache.description)
            self.assertEqual(cache.hint, "Das ist nicht nötig")
            self.assertGreater(cache.favorites, 380)
            self.assertEqual(len(cache.waypoints), 2)

        with self.subTest("PM-only"):
            cache = Cache(self.gc,
                          "GC6MKEF",
                          guid="53d34c4d-12b5-4771-86d3-89318f71efb1")
            with self.assertRaises(PMOnlyException):
                cache.load_by_guid()

        with self.subTest("calls load_quick if no guid"):
            cache = Cache(self.gc, "GC2WXPN")
            with self.assertRaises(Exception):
                cache.load_by_guid(
                )  # Raises error since we mocked load_quick()
            self.assertTrue(mock_load_quick.called)
예제 #22
0
    def test_from_location(self):
        gc = Geocaching()
        gc.login(_username, _password)

        ref_point = Point(49.74774, 13.37752)

        with self.subTest("existing location"):
            self.assertLess(great_circle(Point.from_location(gc, "Pilsen"), ref_point).miles, 10)
            self.assertLess(great_circle(Point.from_location(gc, "Plzeň"), ref_point).miles, 10)
            self.assertLess(great_circle(Point.from_location(gc, "plzen"), ref_point).miles, 10)

        with self.subTest("non-existing location"):
            with self.assertRaises(GeocodeError):
                Point.from_location(gc, "qwertzuiop")

        with self.subTest("empty request"):
            with self.assertRaises(GeocodeError):
                Point.from_location(gc, "")
예제 #23
0
    def test_from_location(self):
        ref_point = Point(50.08746, 14.42125)

        with self.subTest("existing location"):
            with self.recorder.use_cassette('geo_location_existing'):
                self.assertLess(great_circle(Point.from_location(self.gc, "Prague"), ref_point).miles, 10)
                self.assertLess(great_circle(Point.from_location(self.gc, "Praha"), ref_point).miles, 10)
                self.assertLess(great_circle(Point.from_location(self.gc, "praha"), ref_point).miles, 10)

        with self.subTest("non-existing location"):
            with self.recorder.use_cassette('geo_location_nonexisting'):
                with self.assertRaises(GeocodeError):
                    Point.from_location(self.gc, "qwertzuiop")

        with self.subTest("empty request"):
            with self.recorder.use_cassette('geo_location_empty'):
                with self.assertRaises(GeocodeError):
                    Point.from_location(self.gc, "")
예제 #24
0
    def test_to_tile(self):
        t = make_tile(8800, 5574, 14)[0]
        point_in_t = Point(49.75, 13.36)

        with self.subTest("from tile and back"):
            self.assertEqual(Point.from_tile(t).to_tile(None, t.z), t)

        with self.subTest("random point"):
            self.assertEqual(point_in_t.to_tile(None, 14), t)

        with self.subTest("increase in latitude: decrease in y value"):
            self.assertLess(Point(50., 13.36).to_tile(None, 14).y, t.y)

        with self.subTest("increase in longitude: increase in x value"):
            self.assertGreater(Point(49.75, 14.).to_tile(None, 14).x, t.x)
예제 #25
0
    def _from_print_page(cls, geocaching, guid, soup):
        """Create a cache instance from a souped print-page and a GUID"""
        if soup.find("p", "Warning") is not None:
            raise errors.PMOnlyException()

        cache_info = dict()
        cache_info['guid'] = guid
        cache_info['wp'] = soup.find(class_='HalfRight').find('h1').text.strip()
        content = soup.find(id="Content")
        cache_info['name'] = content.find("h2").text.strip()
        cache_info['type'] = Type.from_filename(content.h2.img['src'].split('/')[-1].partition('.')[0])
        cache_info['author'] = content.find(class_='Meta').text.partition(':')[2].strip()
        diff_terr = content.find(class_='DiffTerr').find_all('img')
        assert len(diff_terr) == 2
        cache_info['difficulty'] = float(diff_terr[0]['alt'].split()[0])
        cache_info['terrain'] = float(diff_terr[1]['alt'].split()[0])
        cache_info['size'] = Size.from_string(content.find(class_='Third AlignCenter').p.img['alt'].partition(':')[2])
        fav_text = content.find(class_='Third AlignRight').p.contents[2]
        try:
            cache_info['favorites'] = int(fav_text)
        except ValueError:  # element not present when 0 favorites
            cache_info['favorites'] = 0
        cache_info['hidden'] = parse_date(
            content.find(class_='HalfRight AlignRight').p.text.strip().partition(':')[2].strip())
        cache_info['location'] = Point.from_string(content.find(class_='LatLong').text.strip())
        cache_info['state'] = None  # not on the page
        attributes = [img['src'].split('/')[-1].partition('.')[0].rpartition('-')
                      for img in content.find(class_='sortables').find_all('img')
                      if img.get('src') and img['src'].startswith('/images/attributes/')]
        cache_info['attributes'] = {attr_name: attr_setting == 'yes'
                                    for attr_name, _, attr_setting in attributes}
        if 'attribute' in cache_info['attributes']:  # 'blank' attribute
            del cache_info['attributes']['attribute']
        cache_info['summary'] = content.find("h2", text="Short Description").find_next("div").text
        cache_info['description'] = content.find("h2", text="Long Description").find_next("div").text
        hint = content.find(id='uxEncryptedHint')
        cache_info['hint'] = hint.text.strip() if hint else None
        cache_info['waypoints'] = Waypoint.from_html(content, table_id="Waypoints")
        return Cache(geocaching, **cache_info)
예제 #26
0
    def test_from_location(self):
        gc = Geocaching()
        gc.login(_username, _password)

        ref_point = Point(49.74774, 13.37752)

        with self.subTest("existing location"):
            self.assertLess(
                great_circle(Point.from_location(gc, "Pilsen"),
                             ref_point).miles, 10)
            self.assertLess(
                great_circle(Point.from_location(gc, "Plzeň"),
                             ref_point).miles, 10)
            self.assertLess(
                great_circle(Point.from_location(gc, "plzen"),
                             ref_point).miles, 10)

        with self.subTest("non-existing location"):
            with self.assertRaises(GeocodeError):
                Point.from_location(gc, "qwertzuiop")

        with self.subTest("empty request"):
            with self.assertRaises(GeocodeError):
                Point.from_location(gc, "")
예제 #27
0
파일: cache.py 프로젝트: forslund/pycaching
    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))
예제 #28
0
    def test_from_string(self):
        with self.subTest("normal"):
            self.assertEqual(Point.from_string("N 49 45.123 E 013 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("south and west"):
            self.assertEqual(Point.from_string("S 49 45.123 W 013 22.123"),
                             Point(-49.75205, -13.36872))

        with self.subTest("letter together"):
            self.assertEqual(Point.from_string("N49 45.123 E013 22.123"), Point(49.75205, 13.36872))

        with self.subTest("letter after"):
            self.assertEqual(Point.from_string("49N 45.123 013E 22.123"), Point(49.75205, 13.36872))

        with self.subTest("south and west letter after"):
            self.assertEqual(Point.from_string("49S 45.123 013W 22.123"),
                             Point(-49.75205, -13.36872))

        with self.subTest("decimal separator: comma"):
            self.assertEqual(Point.from_string("N 49 45,123 E 013 22,123"),
                             Point(49.75205, 13.36872))

        with self.subTest("degree symbol"):
            self.assertEqual(Point.from_string("N 49° 45.123 E 013° 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("coma between lat and lon"):
            self.assertEqual(Point.from_string("N 49 45.123, E 013 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("marginal values: zeroes"):
            self.assertEqual(Point.from_string("N 49 45.000 E 13 0.0"), Point(49.75, 13.0))

        with self.subTest("include precision"):
            self.assertIn("precision", Point(49.75, 13.0).__dict__)

        with self.assertRaises(ValueError):
            Point.from_string("123")
예제 #29
0
 def setUp(self):
     self.rect = Rectangle(Point(10.0, 20.0), Point(30.0, -5.0))
예제 #30
0
    def geocode(self, location):
        """Return a :class:`.Point` object from geocoded location.

        :param str location: Location to geocode.
        """
        return Point.from_location(self, location)
예제 #31
0
    def load_by_guid(self):
        """Load cache details using the GUID to request and parse the caches
        'print-page'. Loading as many properties as possible except the
        following ones, since they are not present on the 'print-page':

          + original_location
          + state
          + found
          + pm_only

        :raise .PMOnlyException: If the PM only warning is shown on the page
        """
        # If GUID has not yet been set, load it using the "tiles_server"
        # utilizing `load_quick()`
        if not self.guid:
            self.load_quick()

        res = self.geocaching._request(self._urls["print_page"],
                                       params={"guid": self.guid})
        if res.find("p", "Warning") is not None:
            raise errors.PMOnlyException()
        content = res.find(id="Content")

        self.name = content.find("h2").text

        self.location = Point.from_string(
            content.find("p", "LatLong Meta").text)

        type_img = os.path.basename(content.find("img").get("src"))
        self.type = Type.from_filename(os.path.splitext(type_img)[0])

        size_img = content.find("img", src=re.compile("\/icons\/container\/"))
        self.size = Size.from_string(size_img.get("alt").split(": ")[1])

        D_and_T_img = content.find("p", "Meta DiffTerr").find_all("img")
        self.difficulty, self.terrain = [
            float(img.get("alt").split()[0]) for img in D_and_T_img
        ]

        # TODO do NOT use English phrases like "Placed by" to search for attributes

        self.author = content.find(
            "p", text=re.compile("Placed by:")).text.split("\r\n")[2].strip()

        hidden_p = content.find("p", text=re.compile("Placed Date:"))
        self.hidden = hidden_p.text.replace("Placed Date:", "").strip()

        attr_img = content.find_all("img", src=re.compile("\/attributes\/"))
        attributes_raw = [
            os.path.basename(_.get("src")).rsplit("-", 1) for _ in attr_img
        ]
        self.attributes = {
            name: appendix.startswith("yes")
            for name, appendix in attributes_raw
            if not appendix.startswith("blank")
        }

        self.summary = content.find(
            "h2", text="Short Description").find_next("div").text

        self.description = content.find(
            "h2", text="Long Description").find_next("div").text

        self.hint = content.find(id="uxEncryptedHint").text

        self.favorites = content.find(
            "strong", text=re.compile("Favorites:")).parent.text.split()[-1]

        self.waypoints = Waypoint.from_html(content, "Waypoints")
예제 #32
0
    def geocode(self, location):
        """Return a :class:`.Point` object from geocoded location.

        :param str location: Location to geocode.
        """
        return Point.from_location(self, location)
예제 #33
0
    def load_by_guid(self):
        """Load cache details using the GUID to request and parse the caches
        'print-page'. Loading as many properties as possible except the
        following ones, since they are not present on the 'print-page':

          + original_location
          + state
          + found
          + pm_only

        :raise .PMOnlyException: If the PM only warning is shown on the page
        """
        # If GUID has not yet been set, load it using the "tiles_server"
        # utilizing `load_quick()`
        if not self.guid:
            self.load_quick()

        res = self.geocaching._request(self._urls["print_page"],
                                       params={"guid": self.guid})
        if res.find("p", "Warning") is not None:
            raise errors.PMOnlyException()
        content = res.find(id="Content")

        self.name = content.find("h2").text

        self.location = Point.from_string(
            content.find("p", "LatLong Meta").text)

        type_img = os.path.basename(content.find("img").get("src"))
        self.type = Type.from_filename(os.path.splitext(type_img)[0])

        size_img = content.find("img", src=re.compile("\/icons\/container\/"))
        self.size = Size.from_string(size_img.get("alt").split(": ")[1])

        D_and_T_img = content.find("p", "Meta DiffTerr").find_all("img")
        self.difficulty, self.terrain = [
            float(img.get("alt").split()[0]) for img in D_and_T_img
        ]

        # TODO do NOT use English phrases like "Placed by" to search for attributes

        self.author = content.find(
            "p", text=re.compile("Placed by:")).text.split("\r\n")[2].strip()

        hidden_p = content.find("p", text=re.compile("Placed Date:"))
        self.hidden = hidden_p.text.replace("Placed Date:", "").strip()

        attr_img = content.find_all("img", src=re.compile("\/attributes\/"))
        attributes_raw = [
            os.path.basename(_.get("src")).rsplit("-", 1) for _ in attr_img
        ]
        self.attributes = {
            name: appendix.startswith("yes") for name, appendix
            in attributes_raw if not appendix.startswith("blank")
        }

        self.summary = content.find(
            "h2", text="Short Description").find_next("div").text

        self.description = content.find(
            "h2", text="Long Description").find_next("div").text

        self.hint = content.find(id="uxEncryptedHint").text

        self.favorites = content.find(
            "strong", text=re.compile("Favorites:")).parent.text.split()[-1]

        self.waypoints = Waypoint.from_html(content, "Waypoints")
예제 #34
0
 def setUp(self):
     self.p = Polygon(*[
         Point(*i)
         for i in [(10., 20.), (30., -5.), (-10., -170.), (-70.,
                                                           0.), (0., 40)]
     ])
예제 #35
0
 def setUp(self):
     self.w = Waypoint("id", "Parking",
                       Point("N 56° 50.006′ E 13° 56.423′"),
                       "This is a test")
예제 #36
0
 def setUp(self):
     self.rect = Rectangle(Point(10., 20.), Point(30., -5.))
예제 #37
0
    def test_from_string(self):
        with self.subTest("normal"):
            self.assertEqual(Point.from_string("N 49 45.123 E 013 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("south and west"):
            self.assertEqual(Point.from_string("S 49 45.123 W 013 22.123"),
                             Point(-48.24795, -12.63128))

        with self.subTest("letter together"):
            self.assertEqual(Point.from_string("N49 45.123 E013 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("letter after"):
            self.assertEqual(Point.from_string("49N 45.123 013E 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("south and west letter after"):
            self.assertEqual(Point.from_string("49S 45.123 013W 22.123"),
                             Point(-48.24795, -12.63128))

        with self.subTest("decimal separator: coma"):
            self.assertEqual(Point.from_string("N 49 45,123 E 013 22,123"),
                             Point(49.75205, 13.36872))

        with self.subTest("degree symbol"):
            self.assertEqual(Point.from_string("N 49° 45.123 E 013° 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("coma between lat and lon"):
            self.assertEqual(Point.from_string("N 49 45.123, E 013 22.123"),
                             Point(49.75205, 13.36872))

        with self.subTest("marginal values: zeroes"):
            self.assertEqual(Point.from_string("N 49 45.000 E 13 0.0"),
                             Point(49.75, 13.0))

        with self.subTest("include precision"):
            self.assertIn("precision", Point(49.75, 13.0).__dict__)

        with self.assertRaises(ValueError):
            Point.from_string("123")