Skip to content

Commit 05d9713

Browse files
authored
TYPE: Add type hints (#8)
1 parent 2d0fca1 commit 05d9713

File tree

7 files changed

+136
-90
lines changed

7 files changed

+136
-90
lines changed

gars_field/edgarsgrid.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"""
6363
import math
6464
import re
65+
from typing import Optional
6566

6667
import shapely.geometry
6768

@@ -84,7 +85,7 @@ class EDGARSGrid(GARSGridBase):
8485
r"(?P<quadrant_1deg>[1-9])?)?$"
8586
)
8687

87-
def __init__(self, gars_id, max_resolution=None):
88+
def __init__(self, gars_id: str, max_resolution: Optional[int] = None) -> None:
8889
"""
8990
Parameters
9091
----------
@@ -111,13 +112,13 @@ def __init__(self, gars_id, max_resolution=None):
111112
gars_match = self.RE_PATTERN.match(gars_id)
112113
if not gars_match:
113114
raise ValueError(f'"{gars_id}" is not a valid ED-GARS grid ID.')
114-
self.gars_id = gars_id
115+
self.gars_id: str = gars_id
115116

116117
gars_dict = gars_match.groupdict()
117118

118-
self.quadrant_1deg = gars_dict["quadrant_1deg"]
119-
self.quadrant_3deg = gars_dict["quadrant_3deg"]
120-
self.quadrant_6deg = gars_dict["quadrant_6deg"]
119+
self.quadrant_1deg: str = gars_dict["quadrant_1deg"]
120+
self.quadrant_3deg: str = gars_dict["quadrant_3deg"]
121+
self.quadrant_6deg: str = gars_dict["quadrant_6deg"]
121122

122123
lon_num = int(self.quadrant_6deg[:2])
123124
if (lon_num < 1) or (lon_num > 60):
@@ -133,20 +134,22 @@ def __init__(self, gars_id, max_resolution=None):
133134
)
134135

135136
# determine resolution from ED-GARS ID
136-
self.resolution = 6
137+
self.resolution: int = 6
137138
if self.quadrant_1deg:
138139
self.resolution = 1
139140
elif self.quadrant_3deg:
140141
self.resolution = 3
141142

142143
# properties
143-
self._polygon = None
144+
self._polygon: Optional[shapely.geometry.Polygon] = None
144145

145-
def __repr__(self):
146+
def __repr__(self) -> str:
146147
return f"<ED-GARS(gars_id={self}, resolution={self.resolution})>"
147148

148149
@classmethod
149-
def from_latlon(cls, latitude, longitude, resolution):
150+
def from_latlon(
151+
cls, latitude: float, longitude: float, resolution: int
152+
) -> "EDGARSGrid":
150153
"""Load ED-GARS grid from latitude and longitude.
151154
152155
Parameters
@@ -186,20 +189,20 @@ def from_latlon(cls, latitude, longitude, resolution):
186189
if resolution < 6:
187190
lon_3deg_idx = math.floor((longitude % 6) / 3.0) + 1
188191
lat_3deg_idx = 2 - math.floor((latitude % 6) / 3.0)
189-
quadrant_3deg = int((lat_3deg_idx - 1) * 2 + lon_3deg_idx)
192+
quadrant_3deg = str(int((lat_3deg_idx - 1) * 2 + lon_3deg_idx))
190193

191194
# 1 deg quadrant
192195
if resolution < 3:
193196
lon_1deg_idx = math.floor(longitude % 3) + 1
194197
lat_1deg_idx = 3 - math.floor(latitude % 3)
195-
quadrant_1deg = int((lat_1deg_idx - 1) * 3 + lon_1deg_idx)
198+
quadrant_1deg = str(int((lat_1deg_idx - 1) * 3 + lon_1deg_idx))
196199

197-
gars_id = "".join(["D", quadrant_6deg, str(quadrant_3deg), str(quadrant_1deg)])
200+
gars_id = "".join(["D", quadrant_6deg, quadrant_3deg, quadrant_1deg])
198201

199202
return cls(gars_id, max_resolution=resolution)
200203

201204
@property
202-
def polygon(self):
205+
def polygon(self) -> shapely.geometry.Polygon:
203206
"""Generates the GARS bounding polygon.
204207
205208
Returns
@@ -212,15 +215,15 @@ def polygon(self):
212215

213216
# CALCULATE 6 DEG DEGREES
214217
# get 6 DEG quadrant info
215-
longitude = ((int(self.quadrant_6deg[:2]) - 1) * 6) - 180
218+
longitude: float = ((int(self.quadrant_6deg[:2]) - 1) * 6) - 180
216219

217220
# first 6 deg north/south letter, A-B
218221
lat_6deg_letter1 = self.quadrant_6deg[2]
219222

220223
# second 6 deg north/south letter, A-V
221224
lat_6deg_letter2 = self.quadrant_6deg[3]
222225

223-
latitude = (-90.0 + (self.LETTERS.index(lat_6deg_letter1) * 120.0)) + (
226+
latitude: float = (-90.0 + (self.LETTERS.index(lat_6deg_letter1) * 120.0)) + (
224227
self.LETTERS.index(lat_6deg_letter2) * 6.0
225228
)
226229

gars_field/field.py

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
77
"""
88
import itertools
9+
from typing import List, Optional, Tuple, Type
10+
11+
import shapely
912

1013
from .edgarsgrid import EDGARSGrid
11-
from .garsgrid import GARSGrid
14+
from .garsgrid import GARSGrid, GARSGridBase
1215
from .gedgarsgrid import GEDGARSGrid
1316

1417

@@ -19,7 +22,7 @@ class GARSField:
1922
"""
2023

2124
# pylint: disable=too-many-instance-attributes
22-
def __init__(self, bounding_geom):
25+
def __init__(self, bounding_geom: shapely.geometry.base.BaseGeometry) -> None:
2326
"""
2427
Parameters
2528
----------
@@ -29,19 +32,19 @@ def __init__(self, bounding_geom):
2932
"""
3033
self.bounding_geom = bounding_geom
3134

32-
self._gars_60deg = None
33-
self._gars_30deg = None
35+
self._gars_60deg: Optional[List[GEDGARSGrid]] = None
36+
self._gars_30deg: Optional[List[GEDGARSGrid]] = None
3437

35-
self._gars_6deg = None
36-
self._gars_3deg = None
37-
self._gars_1deg = None
38+
self._gars_6deg: Optional[List[EDGARSGrid]] = None
39+
self._gars_3deg: Optional[List[EDGARSGrid]] = None
40+
self._gars_1deg: Optional[List[EDGARSGrid]] = None
3841

39-
self._gars_30min = None
40-
self._gars_15min = None
41-
self._gars_5min = None
42-
self._gars_1min = None
42+
self._gars_30min: Optional[List[GARSGrid]] = None
43+
self._gars_15min: Optional[List[GARSGrid]] = None
44+
self._gars_5min: Optional[List[GARSGrid]] = None
45+
self._gars_1min: Optional[List[GARSGrid]] = None
4346

44-
def _get_bounds(self):
47+
def _get_bounds(self) -> Tuple[float, float, float, float]:
4548
"""
4649
Retrieve the bounding coordinates of the input geometry
4750
@@ -60,34 +63,42 @@ def _get_bounds(self):
6063
return min_lon, min_lat, max_lon, max_lat
6164

6265
@staticmethod
63-
def _get_lat_letter_range(gars_grid, ll_lat1, ll_lat2, ur_lat1, ur_lat2):
66+
def _get_lat_letter_range(
67+
gars_grid: Type[GARSGridBase],
68+
ll_lat1: str,
69+
ll_lat2: str,
70+
ur_lat1: str,
71+
ur_lat2: str,
72+
) -> List[str]:
6473
"""
6574
Retrieve the latitude letter range for the bounding box.
6675
"""
76+
# ignoring types due to: https://github.com/python/mypy/issues/4125
77+
6778
# first north/south letter, GARSGrid (A-Q), EDGARSGRid (A-B)
68-
lat_letter1_range = gars_grid.LETTERS[
69-
gars_grid.LETTERS.index(ll_lat1) : gars_grid.LETTERS.index(ur_lat1) + 1
79+
lat_letter1_range: str = gars_grid.LETTERS[ # type: ignore
80+
gars_grid.LETTERS.index(ll_lat1) : gars_grid.LETTERS.index(ur_lat1) + 1 # type: ignore
7081
]
7182

7283
# second north/south letter, A-Z
73-
lat_letter2_range = gars_grid.LETTERS[
74-
gars_grid.LETTERS.index(ll_lat2) : gars_grid.LETTERS.index(ur_lat2) + 1
84+
lat_letter2_range: str = gars_grid.LETTERS[ # type: ignore
85+
gars_grid.LETTERS.index(ll_lat2) : gars_grid.LETTERS.index(ur_lat2) + 1 # type: ignore
7586
]
7687

77-
lat_letter_range = []
88+
lat_letter_range: List[str] = []
7889
if ll_lat1 != ur_lat1:
7990
# part 1: using first letter1 and all from first letter2 to end of all LETTERS
80-
for letter2 in gars_grid.LETTERS[gars_grid.LETTERS.index(ll_lat2) :]:
91+
for letter2 in gars_grid.LETTERS[gars_grid.LETTERS.index(ll_lat2) :]: # type: ignore
8192
lat_letter_range.append("".join([ll_lat1, letter2]))
8293

8394
# part 2: from second letter1 to next to last letter2 with all LETTERS
8495
for letter1, letter2 in itertools.product(
85-
lat_letter1_range[1:-1], gars_grid.LETTERS
96+
lat_letter1_range[1:-1], gars_grid.LETTERS # type: ignore
8697
):
8798
lat_letter_range.append("".join([letter1, letter2]))
8899

89100
# part 3: using last letter1 and all from beginning of all LETTERS to last last letter2
90-
for letter2 in gars_grid.LETTERS[: gars_grid.LETTERS.index(ur_lat2) + 1]:
101+
for letter2 in gars_grid.LETTERS[: gars_grid.LETTERS.index(ur_lat2) + 1]: # type: ignore
91102
lat_letter_range.append("".join([ur_lat1, letter2]))
92103

93104
else:
@@ -98,7 +109,7 @@ def _get_lat_letter_range(gars_grid, ll_lat1, ll_lat2, ur_lat1, ur_lat2):
98109
return lat_letter_range
99110

100111
@property
101-
def gars_60deg(self):
112+
def gars_60deg(self) -> List[GEDGARSGrid]:
102113
"""list: The 36deg GEDGARSGrid objects that intersect the bounding geometry."""
103114
if self._gars_60deg is not None:
104115
return self._gars_60deg
@@ -124,7 +135,7 @@ def gars_60deg(self):
124135
return self._gars_60deg
125136

126137
@property
127-
def gars_30deg(self):
138+
def gars_30deg(self) -> List[GEDGARSGrid]:
128139
"""list: The 30deg GEDGARSGrid objects that intersect the bounding geometry."""
129140
if self._gars_30deg is not None:
130141
return self._gars_30deg
@@ -148,7 +159,7 @@ def gars_30deg(self):
148159
self._gars_30deg.append(g30deg)
149160
return self._gars_30deg
150161

151-
def _get_6deg_ranges(self):
162+
def _get_6deg_ranges(self) -> Tuple[List[str], List[str]]:
152163
"""Retrieves the latitude numeric range and longitude letter range
153164
within the bounds.
154165
"""
@@ -169,7 +180,7 @@ def _get_6deg_ranges(self):
169180
return lon_num_range, lat_letter_range
170181

171182
@property
172-
def gars_6deg(self):
183+
def gars_6deg(self) -> List[EDGARSGrid]:
173184
"""list: The 6deg EDGARSGrid objects that intersect the bounding geometry."""
174185
if self._gars_6deg is not None:
175186
return self._gars_6deg
@@ -198,7 +209,7 @@ def gars_6deg(self):
198209
return self._gars_6deg
199210

200211
@property
201-
def gars_3deg(self):
212+
def gars_3deg(self) -> List[EDGARSGrid]:
202213
"""list: The 3deg EDGARSGrid objects that intersect the bounding geometry."""
203214
if self._gars_3deg is not None:
204215
return self._gars_3deg
@@ -221,7 +232,7 @@ def gars_3deg(self):
221232
return self._gars_3deg
222233

223234
@property
224-
def gars_1deg(self):
235+
def gars_1deg(self) -> List[EDGARSGrid]:
225236
"""list: The 1deg EDGARSGrid objects that intersect the bounding geometry."""
226237
if self._gars_1deg is not None:
227238
return self._gars_1deg
@@ -243,7 +254,7 @@ def gars_1deg(self):
243254
self._gars_1deg.append(g1deg)
244255
return self._gars_1deg
245256

246-
def _get_30min_ranges(self):
257+
def _get_30min_ranges(self) -> Tuple[List[str], List[str]]:
247258
"""Retrieves the latitude numeric range and longitude letter range
248259
within the bounds.
249260
"""
@@ -264,7 +275,7 @@ def _get_30min_ranges(self):
264275
return lon_num_range, lat_letter_range
265276

266277
@property
267-
def gars_30min(self):
278+
def gars_30min(self) -> List[GARSGrid]:
268279
"""list: The 30min GARSGrid objects that intersect the bounding geometry."""
269280
if self._gars_30min is not None:
270281
return self._gars_30min
@@ -293,7 +304,7 @@ def gars_30min(self):
293304
return self._gars_30min
294305

295306
@property
296-
def gars_15min(self):
307+
def gars_15min(self) -> List[GARSGrid]:
297308
"""list: The 15min GARSGrid objects that intersect the bounding geometry."""
298309
if self._gars_15min is not None:
299310
return self._gars_15min
@@ -318,7 +329,7 @@ def gars_15min(self):
318329
return self._gars_15min
319330

320331
@property
321-
def gars_5min(self):
332+
def gars_5min(self) -> List[GARSGrid]:
322333
"""list: The 5min GARSGrid objects that intersect the bounding geometry."""
323334
if self._gars_5min is not None:
324335
return self._gars_5min
@@ -343,7 +354,7 @@ def gars_5min(self):
343354
return self._gars_5min
344355

345356
@property
346-
def gars_1min(self):
357+
def gars_1min(self) -> List[GARSGrid]:
347358
"""list: The 1min GARSGrid objects that intersect the bounding geometry."""
348359
if self._gars_1min is not None:
349360
return self._gars_1min

0 commit comments

Comments
 (0)