ebird-api-requests 4.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,239 @@
1
+ """Functions for fetching information about hotspots."""
2
+
3
+ from urllib.error import HTTPError
4
+
5
+ from ebird.api.requests.utils import call
6
+ from ebird.api.requests.validation import (
7
+ clean_back,
8
+ clean_dist,
9
+ clean_lat,
10
+ clean_lng,
11
+ clean_location,
12
+ clean_region,
13
+ )
14
+
15
+ REGION_HOTSPOTS_URL = "https://api.ebird.org/v2/ref/hotspot/%s"
16
+ NEARBY_HOTSPOTS_URL = "https://api.ebird.org/v2/ref/hotspot/geo"
17
+ HOTSPOT_INFO_URL = "https://api.ebird.org/v2/ref/hotspot/info/%s"
18
+ LOCATION_INFO_URL = "https://api.ebird.org/v2/ref/region/info/%s"
19
+
20
+
21
+ def get_hotspots(token, region, back=None):
22
+ """List all hotspots within a region.
23
+
24
+ If back is specified then only the hotspots visited in the given number
25
+ of days are returned.
26
+
27
+ Fetch all the hotspots visited in a country, subnational1 or subnational2
28
+ area recently (up to 30 days ago).
29
+
30
+ This maps to the end point in the eBird API 2.0,
31
+ https://documenter.getpostman.com/view/664302/S1ENwy59?version=latest#f4f59f90-854e-4ba6-8207-323a8cf0bfe0
32
+
33
+ The API supports the option of returning records either in JSON or
34
+ CSV format. Currently results are always returned in JSON format
35
+ since that is consistent with the other functions.
36
+
37
+ :param token: the token needed to access the API.
38
+
39
+ :param region: the code for a country, subnational1 or subnational2 region.
40
+
41
+ :param back: the past number of days to check, default is 14.
42
+
43
+ :return: the list of hotspots.
44
+
45
+ :raises ValueError: if an invalid region code is given or if the value for
46
+ 'back', if given, is not in the range 1..30.
47
+
48
+ :raises URLError if there is an error with the connection to the
49
+ eBird site.
50
+
51
+ :raises HTTPError if the eBird API returns an error.
52
+
53
+ """
54
+ url = REGION_HOTSPOTS_URL % clean_region(region)
55
+
56
+ params = {"fmt": "json"}
57
+
58
+ if back is not None:
59
+ params["back"] = clean_back(back)
60
+
61
+ headers = {
62
+ "X-eBirdApiToken": token,
63
+ }
64
+
65
+ return call(url, params, headers)
66
+
67
+
68
+ def get_nearby_hotspots(token, lat, lng, dist=25, back=None):
69
+ """Get the list of nearby hotspots.
70
+
71
+ Get the list of hotspots closest to a set of coordinates (latitude,
72
+ longitude) up to a distance of 50km. If back is specified then only
73
+ the hotspots visited in the given number of days are returned.
74
+
75
+ The maps to the end point in the eBird API 2.0,
76
+ https://documenter.getpostman.com/view/664302/S1ENwy59?version=latest#674e81c1-6a0c-4836-8a7e-6ea1fe8e6677
77
+
78
+ The API supports the option of returning records either in JSON or
79
+ CSV format. Currently results are always returned in JSON format
80
+ since that is consistent with the other functions.
81
+
82
+ :param token: the token needed to access the API.
83
+
84
+ :param lat: the latitude, which will be rounded to 2 decimal places.
85
+
86
+ :param lng: the longitude, which will be rounded to 2 decimal places.
87
+
88
+ :param dist: include all sites within this distance, from 0 to 50km
89
+ with a default of 25km.
90
+
91
+ :param back: include only visits to the hotspots from 1 to 30 days.
92
+ The default value of None will include all hotspots.
93
+
94
+ :return: the list of hotspots nearest to the given set of coordinates.
95
+
96
+ :raises ValueError: if the coordinates are out of range, if the value
97
+ for 'dist' is not in the range 1..50 or if the value for 'back', if
98
+ specified, is not in the range 1..30.
99
+
100
+ :raises URLError if there is an error with the connection to the
101
+ eBird site.
102
+
103
+ :raises HTTPError if the eBird API returns an error.
104
+
105
+ """
106
+ params = {
107
+ "lat": clean_lat(lat),
108
+ "lng": clean_lng(lng),
109
+ "dist": clean_dist(dist),
110
+ "fmt": "json",
111
+ }
112
+
113
+ if back is not None:
114
+ params["back"] = clean_back(back)
115
+
116
+ headers = {
117
+ "X-eBirdApiToken": token,
118
+ }
119
+
120
+ return call(NEARBY_HOTSPOTS_URL, params, headers)
121
+
122
+
123
+ def get_hotspot(token, loc_id):
124
+ """Get the geographical details of a hotspot.
125
+
126
+ The call only work for hotspots. If you use the identifier for a private
127
+ location the eBird API will return HTTP 410 Gone and an HttpError will be
128
+ raised.
129
+
130
+ This maps to the end point in the eBird API 2.0,
131
+ https://documenter.getpostman.com/view/664302/S1ENwy59?version=latest#e25218db-566b-4d8b-81ca-e79a8f68c599
132
+
133
+ :param token: the token needed to access the API.
134
+
135
+ :param loc_id: the location code for a hotspot, eg. L374326.
136
+
137
+ :return: the latitude, longitude, name, region, etc. for the hotspot.
138
+
139
+ :raises ValueError: if an invalid location code is given.
140
+
141
+ :raises URLError if there is an error with the connection to the
142
+ eBird site.
143
+
144
+ :raises HTTPError if the eBird API returns an error.
145
+
146
+ """
147
+ url = HOTSPOT_INFO_URL % clean_location(loc_id)
148
+
149
+ headers = {
150
+ "X-eBirdApiToken": token,
151
+ }
152
+
153
+ return call(url, {}, headers)
154
+
155
+
156
+ def get_location(token, loc_id):
157
+ """Get the geographical details of a location (hotspot or private).
158
+
159
+ This maps to the end point in the eBird API 2.0,
160
+ https://documenter.getpostman.com/view/664302/S1ENwy59?version=latest#e25218db-566b-4d8b-81ca-e79a8f68c599
161
+
162
+ This uses the same API call for get_region, however the data is flattened
163
+ so it matches the format returned by get_hotspot(). As result you can use
164
+ this as a drop-in replacement for get_hotspot() which will work with any
165
+ location.
166
+
167
+ NOTE: There is one difference between get_hotspot(). The 'hierarchicalName'
168
+ attribute ends with the name of the country. In get_hotspot() is ends with
169
+ the country code.
170
+
171
+ :param token: the token needed to access the API.
172
+
173
+ :param loc_id: the code for the location, eg. L34742596.
174
+
175
+ :return: the latitude, longitude, name, region, etc. for the location.
176
+
177
+ :raises ValueError: if an invalid region code is given.
178
+
179
+ :raises URLError if there is an error with the connection to the
180
+ eBird site.
181
+
182
+ :raises HTTPError if the eBird API returns an error.
183
+
184
+ """
185
+
186
+ # get_region() does not return "isHotspot" in the results, so we
187
+ # try get_hotspot() first and if the call fails with HTTP 410 Gone,
188
+ # indicating it's a private location, we call get_region and
189
+ # massage the result.
190
+
191
+ try:
192
+ return get_hotspot(token, loc_id)
193
+ except HTTPError as err:
194
+ if err.code != 410:
195
+ raise
196
+
197
+ url = LOCATION_INFO_URL % clean_location(loc_id)
198
+
199
+ headers = {
200
+ "X-eBirdApiToken": token,
201
+ }
202
+
203
+ data: dict = call(url, {}, headers)
204
+
205
+ result = {
206
+ "locId": data["code"],
207
+ "name": data["result"],
208
+ "latitude": data["latitude"],
209
+ "longitude": data["longitude"],
210
+ "isHotspot": False,
211
+ "locName": data["result"],
212
+ "lat": data["latitude"],
213
+ "lng": data["longitude"],
214
+ "locID": data["code"],
215
+ }
216
+
217
+ # Get all the parent regions in reverse order
218
+ items = [data["parent"]]
219
+ while "parent" in items[-1]:
220
+ items.append(items[-1].pop("parent"))
221
+ parents = items[::-1]
222
+
223
+ # if the name contains the parent, remove it
224
+ full_name = ", " + parents[0]["result"]
225
+ for parent in parents[1:]:
226
+ if parent["result"].endswith(full_name):
227
+ parent["result"] = parent["result"][: -len(full_name)]
228
+ full_name = ", " + parent["result"] + full_name
229
+
230
+ # Add the processed regions to the record
231
+ for parent in parents:
232
+ kind = parent["type"]
233
+ name = parent["result"]
234
+ result["%sName" % kind] = name
235
+ result["%sCode" % kind] = parent["code"]
236
+
237
+ result["hierarchicalName"] = result["name"] + full_name
238
+
239
+ return result