Skip to content
This repository was archived by the owner on Jan 18, 2023. It is now read-only.

Commit 154a57b

Browse files
committed
Add AAL and AVM products
1 parent 4d39b9f commit 154a57b

File tree

20 files changed

+909
-78
lines changed

20 files changed

+909
-78
lines changed

firststreet/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from firststreet.api.location import Location
1414
from firststreet.api.probability import Probability
1515
from firststreet.api.tile import Tile
16+
from firststreet.api.aal import AAL
17+
from firststreet.api.avm import AVM
1618
from firststreet.errors import MissingAPIKeyError
1719
from firststreet.http_util import Http
1820

@@ -57,3 +59,5 @@ def __init__(self, api_key=None, connection_limit=100, rate_limit=20000, rate_pe
5759
self.environmental = Environmental(self.http)
5860
self.fema = Fema(self.http)
5961
self.tile = Tile(self.http)
62+
self.aal = AAL(self.http)
63+
self.avm = AVM(self.http)

firststreet/__main__.py

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,107 +74,117 @@
7474
rate_limit = int(argument.rate_limit)
7575
rate_period = int(argument.rate_period)
7676

77-
fs = firststreet.FirstStreet(api_key, version=argument.version, connection_limit=limit,
78-
rate_limit=rate_limit, rate_period=rate_period,
77+
formatted_params = {}
78+
79+
if argument.extra_param:
80+
for element in argument.extra_param.split(";"):
81+
key, value = element.split(":")
82+
formatted_params[key] = ast.literal_eval(value)
83+
84+
fs = firststreet.FirstStreet(api_key,
85+
version=argument.version,
86+
connection_limit=limit,
87+
rate_limit=rate_limit,
88+
rate_period=rate_period,
7989
log=bool(strtobool(argument.log)))
8090

8191
if argument.product == 'adaptation.get_detail':
8292
fs.adaptation.get_detail(search_items,
8393
csv=True,
8494
output_dir=argument.output_dir,
85-
extra_param=argument.extra_param)
95+
extra_param=formatted_params)
8696

8797
elif argument.product == 'adaptation.get_summary':
8898
fs.adaptation.get_summary(search_items,
8999
argument.location_type,
90100
csv=True,
91101
output_dir=argument.output_dir,
92-
extra_param=argument.extra_param)
102+
extra_param=formatted_params)
93103

94104
elif argument.product == 'adaptation.get_detail_by_location':
95105
fs.adaptation.get_detail_by_location(search_items,
96106
argument.location_type,
97107
csv=True,
98108
output_dir=argument.output_dir,
99-
extra_param=argument.extra_param)
109+
extra_param=formatted_params)
100110

101111
elif argument.product == 'probability.get_depth':
102112
fs.probability.get_depth(search_items,
103113
csv=True,
104114
output_dir=argument.output_dir,
105-
extra_param=argument.extra_param)
115+
extra_param=formatted_params)
106116

107117
elif argument.product == 'probability.get_chance':
108118
fs.probability.get_chance(search_items,
109119
csv=True,
110120
output_dir=argument.output_dir,
111-
extra_param=argument.extra_param)
121+
extra_param=formatted_params)
112122

113123
elif argument.product == 'probability.get_count_summary':
114124
fs.probability.get_count_summary(search_items,
115125
csv=True,
116126
output_dir=argument.output_dir,
117-
extra_param=argument.extra_param)
127+
extra_param=formatted_params)
118128

119129
elif argument.product == 'probability.get_cumulative':
120130
fs.probability.get_cumulative(search_items,
121131
csv=True,
122132
output_dir=argument.output_dir,
123-
extra_param=argument.extra_param)
133+
extra_param=formatted_params)
124134

125135
elif argument.product == 'probability.get_count':
126136
fs.probability.get_count(search_items,
127137
argument.location_type,
128138
csv=True,
129139
output_dir=argument.output_dir,
130-
extra_param=argument.extra_param)
140+
extra_param=formatted_params)
131141

132142
elif argument.product == 'historic.get_event':
133143
fs.historic.get_event(search_items,
134144
csv=True,
135145
output_dir=argument.output_dir,
136-
extra_param=argument.extra_param)
146+
extra_param=formatted_params)
137147

138148
elif argument.product == 'historic.get_summary':
139149
fs.historic.get_summary(search_items,
140150
argument.location_type,
141151
csv=True,
142152
output_dir=argument.output_dir,
143-
extra_param=argument.extra_param)
153+
extra_param=formatted_params)
144154

145155
elif argument.product == 'historic.get_events_by_location':
146156
fs.historic.get_events_by_location(search_items,
147157
argument.location_type,
148158
csv=True,
149159
output_dir=argument.output_dir,
150-
extra_param=argument.extra_param)
160+
extra_param=formatted_params)
151161

152162
elif argument.product == 'location.get_detail':
153163
fs.location.get_detail(search_items,
154164
argument.location_type,
155165
csv=True,
156166
output_dir=argument.output_dir,
157-
extra_param=argument.extra_param)
167+
extra_param=formatted_params)
158168

159169
elif argument.product == 'location.get_summary':
160170
fs.location.get_summary(search_items,
161171
argument.location_type,
162172
csv=True,
163173
output_dir=argument.output_dir,
164-
extra_param=argument.extra_param)
174+
extra_param=formatted_params)
165175

166176
elif argument.product == 'fema.get_nfip':
167177
fs.fema.get_nfip(search_items,
168178
argument.location_type,
169179
csv=True,
170180
output_dir=argument.output_dir,
171-
extra_param=argument.extra_param)
181+
extra_param=formatted_params)
172182

173183
elif argument.product == 'environmental.get_precipitation':
174184
fs.environmental.get_precipitation(search_items,
175185
csv=True,
176186
output_dir=argument.output_dir,
177-
extra_param=argument.extra_param)
187+
extra_param=formatted_params)
178188

179189
elif argument.product == 'tile.get_probability_depth':
180190
if not argument.year:
@@ -223,6 +233,25 @@
223233
output_dir=argument.output_dir,
224234
image=True)
225235

236+
elif argument.product == 'aal.get_summary':
237+
fs.aal.get_summary(search_items,
238+
argument.location_type,
239+
csv=True,
240+
output_dir=argument.output_dir,
241+
extra_param=formatted_params)
242+
243+
elif argument.product == 'avm.get_avm':
244+
fs.avm.get_avm(search_items,
245+
csv=True,
246+
output_dir=argument.output_dir,
247+
extra_param=formatted_params)
248+
249+
elif argument.product == 'avm.get_provider':
250+
fs.avm.get_provider(search_items,
251+
csv=True,
252+
output_dir=argument.output_dir,
253+
extra_param=formatted_params)
254+
226255
else:
227256
logging.error("Product not found. Please check that the argument"
228257
" provided is correct: {}".format(argument.product))

firststreet/api/aal.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Author: Kelvin Lai <kelvin@firststreet.org>
2+
# Copyright: This module is owned by First Street Foundation
3+
4+
# Standard Imports
5+
import logging
6+
7+
# Internal Imports
8+
from firststreet.api import csv_format
9+
from firststreet.api.api import Api
10+
from firststreet.errors import InvalidArgument
11+
from firststreet.models.aal import AALSummaryProperty, AALSummaryOther
12+
13+
14+
class AAL(Api):
15+
"""This class receives a list of search_items and handles the creation of an aal product from the request.
16+
17+
Methods:
18+
get_summary: Retrieves a list of AAL Summary for the given list of IDs
19+
"""
20+
21+
def get_summary(self, search_items, location_type, csv=False, output_dir=None, extra_param=None):
22+
"""Retrieves AAL summary product data from the First Street Foundation API given a list of search_items and
23+
returns a list of AAL Summary objects.
24+
25+
Args:
26+
search_items (list/file): A First Street Foundation IDs, lat/lng pair, address, or a
27+
file of First Street Foundation IDs
28+
location_type (str): The location lookup type
29+
csv (bool): To output extracted data to a csv or not
30+
output_dir (str): The output directory to save the generated csvs
31+
extra_param (dict): Extra parameter to be added to the url
32+
33+
Returns:
34+
A list of AAL Summary
35+
Raises:
36+
InvalidArgument: The location provided is empty
37+
TypeError: The location provided is not a string
38+
"""
39+
40+
if not location_type:
41+
raise InvalidArgument(location_type)
42+
elif not isinstance(location_type, str):
43+
raise TypeError("location is not a string")
44+
45+
# Get data from api and create objects
46+
if extra_param and "depths" in extra_param:
47+
extra_param["depths"] = ','.join(map(str, extra_param["depths"]))
48+
49+
api_datas = self.call_api(search_items, "economic/aal", "summary", location_type, extra_param=extra_param)
50+
51+
if location_type == "property":
52+
product = []
53+
for api_data, fsid in zip(api_datas, search_items):
54+
api_data["fsid"] = fsid
55+
product.append(AALSummaryProperty(api_data))
56+
57+
else:
58+
product = []
59+
for api_data, fsid in zip(api_datas, search_items):
60+
api_data["fsid"] = fsid
61+
product.append(AALSummaryOther(api_data))
62+
63+
if csv:
64+
csv_format.to_csv(product, "economic_aal", "summary", location_type, output_dir=output_dir)
65+
66+
logging.info("AAL Summary Data Ready.")
67+
68+
return product

firststreet/api/adaptation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_detail(self, search_items, csv=False, output_dir=None, extra_param=None)
2828
file of First Street Foundation IDs
2929
csv (bool): To output extracted data to a csv or not
3030
output_dir (str): The output directory to save the generated csvs
31-
extra_param (str): Extra parameter to be added to the url
31+
extra_param (dict): Extra parameter to be added to the url
3232
3333
Returns:
3434
A list of Adaptation Detail
@@ -54,7 +54,7 @@ def get_detail_by_location(self, search_items, location_type, csv=False, output_
5454
location_type (str): The location lookup type
5555
csv (bool): To output extracted data to a csv or not
5656
output_dir (str): The output directory to save the generated csvs
57-
extra_param (str): Extra parameter to be added to the url
57+
extra_param (dict): Extra parameter to be added to the url
5858
5959
Returns:
6060
A list of list of Adaptation Summary and Adaptation Detail
@@ -101,7 +101,7 @@ def get_summary(self, search_items, location_type, csv=False, output_dir=None, e
101101
location_type (str): The location lookup type
102102
csv (bool): To output extracted data to a csv or not
103103
output_dir (str): The output directory to save the generated csvs
104-
extra_param (str): Extra parameter to be added to the url
104+
extra_param (dict): Extra parameter to be added to the url
105105
106106
Returns:
107107
A list of Adaptation Summary

firststreet/api/api.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
# Standard Imports
55
import asyncio
6+
import urllib.parse
67

78
# Internal Imports
89
import os
@@ -39,7 +40,7 @@ def call_api(self, search_item, product, product_subtype, location=None, tile_pr
3940
year (int/None): The year for probability depth tiles (if suitable)
4041
return_period (int/None): The return period for probability depth tiles (if suitable)
4142
event_id (int/None): The event_id for historic tiles (if suitable)
42-
extra_param (str): Extra parameter to be added to the url
43+
extra_param (dict): Extra parameter to be added to the url
4344
Returns:
4445
A list of JSON responses
4546
"""
@@ -66,7 +67,8 @@ def call_api(self, search_item, product, product_subtype, location=None, tile_pr
6667
"Provided Arg: {}".format(search_item))
6768

6869
if not all(isinstance(coord, int) for t in search_item for coord in t):
69-
raise TypeError("Each coordinate in the tuple must be an integer. Provided Arg: {}".format(search_item))
70+
raise TypeError("Each coordinate in the tuple must be an integer. Provided Arg: {}"
71+
.format(search_item))
7072

7173
if not all(0 < t[0] <= 18 for t in search_item):
7274
raise TypeError("Max zoom is 18. Provided Arg: {}".format(search_item))
@@ -75,8 +77,9 @@ def call_api(self, search_item, product, product_subtype, location=None, tile_pr
7577

7678
# Ensure for historic and adaptation the search items are EventIDs or AdaptationIDs
7779
if ((product == "adaptation" and product_subtype == "detail") or
78-
(product == "historic" and product_subtype == "event")) and \
79-
not all(isinstance(t, int) for t in search_item):
80+
(product == "historic" and product_subtype == "event") or
81+
(product == "economic/avm" and product_subtype == "provider")) and \
82+
not all(isinstance(t, int) for t in search_item):
8083
raise TypeError("Input must be an integer for this product. "
8184
"Provided Arg: {}".format(search_item))
8285

@@ -104,17 +107,22 @@ def call_api(self, search_item, product, product_subtype, location=None, tile_pr
104107

105108
if not tile_product:
106109

110+
if not extra_param:
111+
formatted_params = ""
112+
else:
113+
formatted_params = urllib.parse.urlencode(extra_param)
114+
107115
# fsid
108116
if isinstance(item, int):
109-
endpoint = endpoint + "/{}".format(item) + "?{}".format(extra_param)
117+
endpoint = endpoint + "/{}".format(item) + "?{}".format(formatted_params)
110118

111119
# lat/lng
112120
elif isinstance(item, tuple):
113-
endpoint = endpoint + "?lat={}&lng={}&{}".format(item[0], item[1], extra_param)
121+
endpoint = endpoint + "?lat={}&lng={}&{}".format(item[0], item[1], formatted_params)
114122

115123
# address
116124
elif isinstance(item, str):
117-
endpoint = endpoint + "?address={}&{}".format(item, extra_param)
125+
endpoint = endpoint + "?address={}&{}".format(item, formatted_params)
118126

119127
endpoints.append((endpoint, item, product, product_subtype))
120128

0 commit comments

Comments
 (0)