-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeocoder.py
More file actions
82 lines (72 loc) · 3.16 KB
/
geocoder.py
File metadata and controls
82 lines (72 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
from geopy.geocoders import Nominatim
from geopy.exc import GeocoderUnavailable, GeocoderTimedOut
from time import sleep
from typing import Dict
from cache import AddressCache
from constants import DEFAULT_DB_PATH
class Geocoder:
def __init__(self, db_path: str = DEFAULT_DB_PATH):
self.cache = AddressCache(db_path)
self.geolocator = Nominatim(user_agent="rus_geocoder")
def geocode(self, query: str, max_retries: int = 3) -> Dict:
if cached := self.cache.get_address(query):
return self._format_result(query, *cached, "cache")
for attempt in range(max_retries):
try:
location = self.geolocator.geocode(query,
exactly_one=True,
language="ru")
sleep(1)
if location:
self.cache.save_address(query,
location.address,
location.latitude,
location.longitude)
return self._format_result(
query,
location.address,
location.latitude,
location.longitude,
"nominatim"
)
except (GeocoderUnavailable, GeocoderTimedOut) as e:
if attempt == max_retries - 1:
return {"error": f"Адрес не найден. Ошибка сервиса: "
f"{str(e)}"}
sleep(2)
return {"error": "Адрес не найден после нескольких попыток"}
def reverse_geocode(self, lat: float, lon: float) -> Dict:
if cached := self.cache.get_reverse_address(lat, lon):
return self._format_reverse_result(lat, lon, cached, "cache")
try:
location = self.geolocator.reverse((lat, lon),
exactly_one=True,
language="ru")
sleep(1)
if location:
self.cache.save_reverse_address(lat, lon, location.address)
return self._format_reverse_result(lat, lon,
location.address,
"nominatim")
except (GeocoderUnavailable, GeocoderTimedOut):
pass
return {"error": "Адрес не найден по координатам"}
@staticmethod
def _format_result(query: str, address: str, lat: float, lon: float,
source: str) -> Dict:
return {
"query": query,
"address": address,
"lat": lat,
"lon": lon,
"source": source
}
@staticmethod
def _format_reverse_result(lat: float, lon: float,
address: str, source: str) -> Dict:
return {
"lat": lat,
"lon": lon,
"address": address,
"source": source
}