Skip to content

Commit 927ae7f

Browse files
committed
Fix #121 - defer loading of tzwhere until it's needed
1 parent d9fdf85 commit 927ae7f

File tree

2 files changed

+39
-26
lines changed

2 files changed

+39
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Fixed
66

77
- #120 - Improve handling of Zayo notifications.
8+
- #121 - Defer loading of `tzwhere` data until it's needed, to reduce memory overhead.
89

910
## v2.0.6 - 2021-11-30
1011

circuit_maintenance_parser/utils.py

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,46 @@
1616
dirname = os.path.dirname(__file__)
1717

1818

19+
class classproperty: # pylint: disable=invalid-name,too-few-public-methods
20+
"""Simple class-level equivalent of an @property."""
21+
22+
def __init__(self, method):
23+
"""Wrap a method."""
24+
self.getter = method
25+
26+
def __get__(self, _, cls):
27+
"""Call the wrapped method."""
28+
return self.getter(cls)
29+
30+
1931
class Geolocator:
2032
"""Class to obtain Geo Location coordinates."""
2133

2234
# Keeping caching of local DB and timezone in the class
23-
db_location: Dict[Union[Tuple[str, str], str], Tuple[float, float]] = {}
24-
timezone = None
35+
_db_location: Dict[Union[Tuple[str, str], str], Tuple[float, float]] = {}
36+
_timezone = None
2537

26-
def __init__(self):
27-
"""Initialize instance."""
28-
self.load_db_location()
29-
self.load_timezone()
30-
31-
@classmethod
32-
def load_timezone(cls):
38+
@classproperty
39+
def timezone(cls): # pylint: disable=no-self-argument
3340
"""Load the timezone resolver."""
34-
if cls.timezone is None:
35-
cls.timezone = tzwhere.tzwhere()
41+
if cls._timezone is None:
42+
cls._timezone = tzwhere.tzwhere()
3643
logger.info("Loaded local timezone resolver.")
37-
38-
@classmethod
39-
def load_db_location(cls):
40-
"""Load the localtions DB from CSV into a Dict."""
41-
with open(os.path.join(dirname, "data", "worldcities.csv")) as csvfile:
42-
reader = csv.DictReader(csvfile)
43-
for row in reader:
44-
# Index by city and country
45-
cls.db_location[(row["city_ascii"], row["country"])] = (float(row["lat"]), float(row["lng"]))
46-
# Index by city (first entry wins if duplicated names)
47-
if row["city_ascii"] not in cls.db_location:
48-
cls.db_location[row["city_ascii"]] = (float(row["lat"]), float(row["lng"]))
44+
return cls._timezone
45+
46+
@classproperty
47+
def db_location(cls): # pylint: disable=no-self-argument
48+
"""Load the locations DB from CSV into a Dict."""
49+
if not cls._db_location:
50+
with open(os.path.join(dirname, "data", "worldcities.csv")) as csvfile:
51+
reader = csv.DictReader(csvfile)
52+
for row in reader:
53+
# Index by city and country
54+
cls._db_location[(row["city_ascii"], row["country"])] = (float(row["lat"]), float(row["lng"]))
55+
# Index by city (first entry wins if duplicated names)
56+
if row["city_ascii"] not in cls._db_location:
57+
cls._db_location[row["city_ascii"]] = (float(row["lat"]), float(row["lng"]))
58+
return cls._db_location
4959

5060
def get_location(self, city: str) -> Tuple[float, float]:
5161
"""Get location."""
@@ -64,7 +74,9 @@ def get_location_from_local_file(self, city: str) -> Tuple[float, float]:
6474
city_name = city.split(", ")[0]
6575
country = city.split(", ")[-1]
6676

67-
lat, lng = self.db_location.get((city_name, country), self.db_location.get(city_name, (None, None)))
77+
lat, lng = self.db_location.get( # pylint: disable=no-member
78+
(city_name, country), self.db_location.get(city_name, (None, None)) # pylint: disable=no-member
79+
)
6880
if lat and lng:
6981
logger.debug("Resolved %s to lat %s, lon %sfrom local locations DB.", city, lat, lng)
7082
return (lat, lng)
@@ -92,12 +104,12 @@ def city_timezone(self, city: str) -> str:
92104
if self.timezone is not None:
93105
try:
94106
latitude, longitude = self.get_location(city)
95-
timezone = self.timezone.tzNameAt(latitude, longitude)
107+
timezone = self.timezone.tzNameAt(latitude, longitude) # pylint: disable=no-member
96108
if not timezone:
97109
# In some cases, given a latitued and longitued, the tzwhere library returns
98110
# an empty timezone, so we try with the coordinates from the API as an alternative
99111
latitude, longitude = self.get_location_from_api(city)
100-
timezone = self.timezone.tzNameAt(latitude, longitude)
112+
timezone = self.timezone.tzNameAt(latitude, longitude) # pylint: disable=no-member
101113

102114
if timezone:
103115
logger.debug("Matched city %s to timezone %s", city, timezone)

0 commit comments

Comments
 (0)