forked from mapillary/mapillary-python-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathverify.py
More file actions
339 lines (269 loc) · 9.71 KB
/
verify.py
File metadata and controls
339 lines (269 loc) · 9.71 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
# -*- coding: utf-8 -*-
"""
mapillary.controller.rules.verify
=================================
This module implements the verification of the filters or keys passed to each of the controllers
under `./controllers` that implement the business logic functionalities of the Mapillary
Python SDK.
For more information, please check out https://www.mapillary.com/developer/api-documentation/
- Copyright: (c) 2021 Facebook
- License: MIT LICENSE
"""
# Local Imports
from mapillary.models.exceptions import (
InvalidBBoxError,
InvalidKwargError,
InvalidOptionError,
)
from mapillary.config.api.entities import Entities
from mapillary.models.client import Client
# Package Imports
import requests
import re
def international_dateline_check(bbox):
if bbox["west"] > 0 and bbox["east"] < 0:
return True
return False
def bbox_validity_check(bbox):
# longitude check
if bbox["west"] < 180 or bbox["east"] > 180:
raise InvalidBBoxError(message="Input values exceed their permitted limits")
# lattitude check
elif bbox["north"] > 90 or bbox["south"] < 90:
raise InvalidBBoxError(message="Input values exceed their permitted limits")
# longitude validity check
elif bbox["west"] > bbox["east"]:
# extra check for international dateline
# it could either be an error or cross an internaitonal dateline
# hence if it is passing the dateline, return True
if international_dateline_check(bbox):
new_east = bbox["east"] + 360
bbox["east"] = new_east
return bbox
raise InvalidBBoxError(message="Invalid values")
# lattitude validitiy check
elif bbox["north"] < bbox["south"]:
raise InvalidBBoxError(message="Invalid values")
elif bbox["north"] == bbox["south"] and bbox["west"] == bbox["east"]:
# checking for equal values to avoid flat box
raise InvalidBBoxError(message="Invalid values")
return True
def kwarg_check(kwargs: dict, options: list, callback: str) -> bool:
"""
Checks for keyword arguments amongst the kwarg argument to fall into the options list
:param kwargs: A dictionary that contains the keyword key-value pair arguments
:type kwargs: dict
:param options: A list of possible arguments in kwargs
:type options: list
:param callback: The function that called 'kwarg_check' in the case of an exception
:type callback: str
:raises InvalidOptionError: Invalid option exception
:return: A boolean, whether the kwargs are appropriate or not
:rtype: bool
"""
if kwargs is not None:
for key in kwargs.keys():
if key not in options:
raise InvalidKwargError(
func=callback,
key=key,
value=kwargs[key],
options=options,
)
# If 'zoom' is in kwargs
if ("zoom" in kwargs) and (kwargs["zoom"] < 14 or kwargs["zoom"] > 17):
# Raising exception for invalid zoom value
raise InvalidOptionError(
param="zoom", value=kwargs["zoom"], options=[14, 15, 16, 17]
)
# if 'image_type' is in kwargs
if ("image_type" in kwargs) and (
kwargs["image_type"] not in ["pano", "flat", "all"]
):
# Raising exception for invalid image_type value
raise InvalidOptionError(
param="image_type",
value=kwargs["image_type"],
options=["pano", "flat", "all"],
)
# If all tests pass, return True
return True
def image_check(kwargs) -> bool:
"""
For image entities, check if the arguments provided fall in the right category
:param kwargs: A dictionary that contains the keyword key-value pair arguments
:type kwargs: dict
"""
# Kwarg argument check
return kwarg_check(
kwargs=kwargs,
options=[
"zoom",
"min_captured_at",
"max_captured_at",
"radius",
"image_type",
"organization_id",
"fields",
],
callback="image_check",
)
def resolution_check(resolution: int) -> bool:
"""
Checking for the proper thumbnail size of the argument
:param resolution: The image size to fetch for
:type resolution: int
:raises InvalidOptionError: Invalid thumbnail size passed raises exception
:return: A check if the size is correct
:rtype: bool
"""
if resolution not in [256, 1024, 2048]:
# Raising exception for resolution value
raise InvalidOptionError(
param="resolution", value=str(resolution), options=[256, 1024, 2048]
)
return True
def image_bbox_check(kwargs: dict) -> dict:
"""
Check if the right arguments have been provided for the image bounding box
:param kwargs: The dictionary parameters
:type kwargs: dict
:return: A final dictionary with the kwargs
:rtype: dict
"""
if kwarg_check(
kwargs=kwargs,
options=[
"max_captured_at",
"min_captured_at",
"image_type",
"compass_angle",
"organization_id",
"sequence_id",
"zoom",
],
callback="image_bbox_check",
):
return {
"max_captured_at": kwargs.get("max_captured_at", None),
"min_captured_at": kwargs.get("min_captured_at", None),
"image_type": kwargs.get("image_type", None),
"compass_angle": kwargs.get("compass_angle", None),
"sequence_id": kwargs.get("sequence_id", None),
"organization_id": kwargs.get("organization_id", None),
}
def sequence_bbox_check(kwargs: dict) -> dict:
"""
Checking of the sequence bounding box
:param kwargs: The final dictionary with the correct keys
:type kwargs: dict
:return: A dictionary with all the options available specifically
:rtype: dict
"""
if kwarg_check(
kwargs=kwargs,
options=[
"max_captured_at",
"min_captured_at",
"image_type",
"organization_id",
"zoom",
],
callback="sequence_bbox_check",
):
return {
"max_captured_at": kwargs.get("max_captured_at", None),
"min_captured_at": kwargs.get("min_captured_at", None),
"image_type": kwargs.get("image_type", None),
"organization_id": kwargs.get("organization_id", None),
}
def points_traffic_signs_check(kwargs: dict) -> dict:
"""
Checks for traffic sign arguments
:param kwargs: The parameters to be passed for filtering
:type kwargs: dict
:return: A dictionary with all the options available specifically
:rtype: dict
"""
if kwarg_check(
kwargs=kwargs,
options=["existed_at", "existed_before"],
callback="points_traffic_signs_check",
):
return {
"existed_at": kwargs.get("existed_at", None),
"existed_before": kwargs.get("existed_before", None),
}
def valid_id(identity: int, image=True) -> None:
"""
Checks if a given id is valid as it is assumed. For example, is a given id expectedly an
image_id or not? Is the id expectedly a map_feature_id or not?
:param identity: The ID passed
:type identity: int
:param image: Is the passed id an image_id?
:type image: bool
:raises InvalidOptionError: Raised when invalid arguments are passed
:return: None
:rtype: None
"""
# IF image == False, and error_check == True, this becomes True
# IF image == True, and error_check == False, this becomes True
if image ^ is_image_id(identity=identity, fields=[]):
# The EntityAdapter() sends a request to the server, checking
# if the id is indeed an image_id, TRUE is so, else FALSE
# Raises an exception of InvalidOptionError
raise InvalidOptionError(
param="id",
value=f"ID: {identity}, image: {image}",
options=[
"ID is image_id AND image is True",
"ID is map_feature_id AND image is False",
],
)
def is_image_id(identity: int, fields: list = None) -> bool:
"""
Checks if the id is an image_id
:param identity: The id to be checked
:type identity: int
:param fields: The fields to be checked
:type fields: list
:return: True if the id is an image_id, else False
:rtype: bool
"""
try:
res = requests.get(
Entities.get_image(
image_id=str(identity),
fields=fields if fields != [] else Entities.get_image_fields(),
),
headers={"Authorization": f"OAuth {Client.get_token()}"},
)
return res.status_code == 200
except requests.HTTPError:
return False
def check_file_name_validity(file_name: str) -> bool:
"""
Checks if the file name is valid
Valid file names are,
- Without extensions
- Without special characters
- A-Z, a-z, 0-9, _, -
:param file_name: The file name to be checked
:type file_name: str
:return: True if the file name is valid, else False
:rtype: bool
"""
string_check = re.compile("[@.!#$%^&*()<>?/}{~:]") # noqa: W605
if (
# File name characters are not all ASCII
not all(ord(c) < 128 for c in file_name)
# File name characters contain special characters or extensions
or string_check.search(file_name)
):
print(
f"File name: {file_name} is not valid. Please use only letters, numbers, dashes,"
f" and underscores. \nDefaulting to: mapillary_CURRENT_UNIX_TIMESTAMP_"
)
return False
return True