Skip to content

Commit eb000ff

Browse files
Merge pull request #207 from BelKed/quick-search
Deprecate the `Geocaching.search_quick()` method
2 parents ca5fb04 + 5fbe7a7 commit eb000ff

File tree

6 files changed

+105
-95
lines changed

6 files changed

+105
-95
lines changed

README.rst

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,24 +188,19 @@ Geocode address and search around
188188
for cache in geocaching.search(point, limit=10):
189189
print(cache.name)
190190
191-
Find caches with their approximate locations in some area
191+
Find caches in some area
192192
---------------------------------------------------------------------------------------------------
193193

194-
.. warning::
195-
196-
This is currently not working because of
197-
`this issue <https://github.com/tomasbedrich/pycaching/issues/75>`__. Contributions are
198-
very welcome!
199-
200194
.. code-block:: python
201195
202196
from pycaching import Point, Rectangle
203197
204198
rect = Rectangle(Point(60.15, 24.95), Point(60.17, 25.00))
205199
206-
for cache in geocaching.search_quick(rect, strict=True):
207-
print(cache.name, cache.location.precision)
200+
for cache in geocaching.search_rect(rect):
201+
print(cache.name)
208202
203+
If you want to search in a larger area, you could use the ``limit`` parameter as described above.
209204

210205
Load trackable details
211206
---------------------------------------------------------------------------------------------------

pycaching/geocaching.py

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import logging
77
import re
88
import subprocess
9-
import warnings
109
from os import path
1110
from typing import Optional, Union
1211
from urllib.parse import parse_qs, urljoin, urlparse
@@ -21,6 +20,7 @@
2120
from pycaching.log import Log
2221
from pycaching.log import Type as LogType
2322
from pycaching.trackable import Trackable
23+
from pycaching.util import deprecated
2424

2525

2626
class SortOrder(enum.Enum):
@@ -354,38 +354,17 @@ def _search_get_page(self, point, start_index):
354354

355355
return bs4.BeautifulSoup(res["HtmlString"].strip(), "html.parser"), None
356356

357-
def search_quick(self, area, *, strict=False, zoom=None):
358-
"""Return a generator of caches in some area.
357+
@deprecated
358+
def search_quick(self, area):
359+
"""Search for caches in a specified :class:`.Rectangle` area.
359360
360-
Area is converted to map tiles, each tile is then loaded and :class:`.Cache` objects are then
361-
created from its blocks.
362-
363-
:param bool strict: Whether to return caches strictly in the `area` and discard others.
364-
:param int zoom: Zoom level of tiles. You can also specify it manually, otherwise it is
365-
automatically determined for whole :class:`.Area` to fit into one :class:`.Tile`. Higher
366-
zoom level is more precise, but requires more tiles to be loaded.
361+
:param rect: The :class:`.Rectangle` object representing the search area.
362+
:type rect: geo.Rectangle
363+
:return: A generator that yields :class:`.Cache` objects.
364+
:rtype: Generator[Optional[Cache], None, None]
367365
"""
368-
# FIXME
369-
warnings.warn(
370-
"Quick search is temporary disabled because of Groundspeak breaking change. "
371-
"If you would like to use it, please consider helping with this issue: "
372-
"https://github.com/tomasbedrich/pycaching/issues/75"
373-
)
374-
raise NotImplementedError()
375-
376-
# logging.info("Searching quick in {}".format(area))
377-
#
378-
# tiles = area.to_tiles(self, zoom)
379-
# # TODO process tiles by multiple workers
380-
# for tile in tiles:
381-
# for block in tile.blocks:
382-
# cache = Cache.from_block(block)
383-
# if strict and cache.location not in area:
384-
# # if strict mode is on and cache is not in area
385-
# continue
386-
# else:
387-
# # can yield more caches (which are not exactly in desired area)
388-
# yield cache
366+
367+
return self.search_rect(area)
389368

390369
# add some shortcuts ------------------------------------------------------
391370

test/cassettes/geocaching_matchload.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

test/cassettes/geocaching_quick_normal.json

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"http_interactions": [
3+
{
4+
"recorded_at": "2023-03-25T19:01:14",
5+
"request": {
6+
"body": {
7+
"encoding": "utf-8",
8+
"string": ""
9+
},
10+
"headers": {
11+
"Accept": [
12+
"*/*"
13+
],
14+
"Accept-Encoding": [
15+
"gzip, deflate"
16+
],
17+
"Connection": [
18+
"keep-alive"
19+
],
20+
"Cookie": [
21+
"gspkauth=<AUTH COOKIE>; Culture=en-US; __RequestVerificationToken=<AUTH COOKIE>"
22+
],
23+
"User-Agent": [
24+
"python-requests/2.28.1"
25+
]
26+
},
27+
"method": "GET",
28+
"uri": "https://www.geocaching.com/api/proxy/web/search?box=49.74%2C13.38%2C49.73%2C13.4&take=200&asc=true&skip=0&sort=datelastvisited"
29+
},
30+
"response": {
31+
"body": {
32+
"base64_string": "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",
33+
"encoding": "utf-8",
34+
"string": ""
35+
},
36+
"headers": {
37+
"Cache-Control": [
38+
"max-age=60, private"
39+
],
40+
"Connection": [
41+
"Keep-Alive"
42+
],
43+
"Content-Encoding": [
44+
"gzip"
45+
],
46+
"Content-Length": [
47+
"2647"
48+
],
49+
"Content-Type": [
50+
"application/json; charset=utf-8"
51+
],
52+
"CorrelationGuid": [
53+
"05719242-28d1-41f4-a71f-29f36eed56df"
54+
],
55+
"Date": [
56+
"Sat, 25 Mar 2023 19:01:13 GMT"
57+
],
58+
"Set-Cookie": [
59+
"jwt=<AUTH COOKIE>; expires=Sat, 25 Mar 2023 20:00:13 GMT; domain=.geocaching.com; path=/; secure; httponly"
60+
],
61+
"Strict-Transport-Security": [
62+
"max-age=31536000; includeSubDomains"
63+
],
64+
"Vary": [
65+
"Accept-Encoding"
66+
],
67+
"X-Content-Type-Options": [
68+
"nosniff"
69+
],
70+
"X-Frame-Options": [
71+
"SAMEORIGIN"
72+
],
73+
"X-XSS-Protection": [
74+
"1"
75+
]
76+
},
77+
"status": {
78+
"code": 200,
79+
"message": "OK"
80+
},
81+
"url": "https://www.geocaching.com/api/proxy/web/search?box=49.74%2C13.38%2C49.73%2C13.4&take=200&asc=true&skip=0&sort=datelastvisited"
82+
}
83+
}
84+
],
85+
"recorded_with": "betamax/0.8.1"
86+
}

test/test_geocaching.py

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import itertools
2-
import unittest
31
from unittest.mock import patch
42

53
from geopy.distance import great_circle
@@ -39,55 +37,15 @@ def test_search(self):
3937
caches = list(self.gc.search(Point(49.733867, 13.397091), 100))
4038
self.assertNotEqual(caches[0], caches[50])
4139

42-
@unittest.expectedFailure
4340
def test_search_quick(self):
4441
"""Perform quick search and check found caches"""
45-
# at time of writing, there were exactly 16 caches in this area + one PM only
46-
expected_cache_num = 16
47-
tolerance = 7
4842
rect = Rectangle(Point(49.73, 13.38), Point(49.74, 13.40))
4943

50-
with self.subTest("normal"):
51-
with self.recorder.use_cassette("geocaching_quick_normal"):
52-
# Once this feature is fixed, the corresponding cassette will have to be deleted
53-
# and re-recorded.
54-
res = [c.wp for c in self.gc.search_quick(rect)]
55-
for wp in ["GC41FJC", "GC17E8Y", "GC383XN"]:
56-
self.assertIn(wp, res)
57-
# but 108 caches larger tile
58-
self.assertLess(len(res), 130)
59-
self.assertGreater(len(res), 90)
60-
61-
with self.subTest("strict handling of cache coordinates"):
62-
with self.recorder.use_cassette("geocaching_quick_strictness"):
63-
res = list(self.gc.search_quick(rect, strict=True))
64-
self.assertLess(len(res), expected_cache_num + tolerance)
65-
self.assertGreater(len(res), expected_cache_num - tolerance)
66-
67-
with self.subTest("larger zoom - more precise"):
68-
with self.recorder.use_cassette("geocaching_quick_zoom"):
69-
res1 = list(self.gc.search_quick(rect, strict=True, zoom=15))
70-
res2 = list(self.gc.search_quick(rect, strict=True, zoom=14))
71-
for res in res1, res2:
72-
self.assertLess(len(res), expected_cache_num + tolerance)
73-
self.assertGreater(len(res), expected_cache_num - tolerance)
74-
for c1, c2 in itertools.product(res1, res2):
75-
self.assertLess(c1.location.precision, c2.location.precision)
76-
77-
@unittest.expectedFailure
78-
def test_search_quick_match_load(self):
79-
"""Test if quick search results matches exact cache locations."""
80-
rect = Rectangle(Point(49.73, 13.38), Point(49.74, 13.39))
81-
with self.recorder.use_cassette("geocaching_matchload"):
82-
# at commit time, this test is an allowed failure. Once this feature is fixed, the
83-
# corresponding cassette will have to be deleted and re-recorded.
84-
caches = list(self.gc.search_quick(rect, strict=True, zoom=15))
85-
for cache in caches:
86-
try:
87-
cache.load()
88-
self.assertIn(cache.location, rect)
89-
except PMOnlyException:
90-
pass
44+
with self.recorder.use_cassette("geocaching_quick_search"):
45+
res = [c.wp for c in self.gc.search_quick(rect)]
46+
for wp in ["GC11PRW", "GC161KR", "GC167Y7"]:
47+
self.assertIn(wp, res)
48+
self.assertEqual(len(res), 11)
9149

9250
def test__try_getting_cache_from_guid(self):
9351
# get "normal" cache from guidpage

0 commit comments

Comments
 (0)