alessandro trinca tornidor commited on
Commit
ef29145
1 Parent(s): 690d96f

[refactor] import aws_lambda_powertools and define tests about aws lambda integration only when IS_AWS_LAMBDA is defined

Browse files
Dockerfile CHANGED
@@ -5,6 +5,7 @@ ARG LAMBDA_TASK_ROOT="/var/task"
5
  ARG PYTHONPATH="${LAMBDA_TASK_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
6
  ENV VIRTUAL_ENV=${LAMBDA_TASK_ROOT}/.venv \
7
  PATH="${LAMBDA_TASK_ROOT}/.venv/bin:$PATH"
 
8
 
9
  # Set working directory to function root directory
10
  WORKDIR ${LAMBDA_TASK_ROOT}
 
5
  ARG PYTHONPATH="${LAMBDA_TASK_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
6
  ENV VIRTUAL_ENV=${LAMBDA_TASK_ROOT}/.venv \
7
  PATH="${LAMBDA_TASK_ROOT}/.venv/bin:$PATH"
8
+ ENV IS_AWS_LAMBDA=""
9
 
10
  # Set working directory to function root directory
11
  WORKDIR ${LAMBDA_TASK_ROOT}
dockerfiles/dockerfile-lambda-fastsam-api CHANGED
@@ -5,6 +5,7 @@ ARG LAMBDA_TASK_ROOT="/var/task"
5
  ARG PYTHONPATH="${LAMBDA_TASK_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
6
  ENV VIRTUAL_ENV=${LAMBDA_TASK_ROOT}/.venv \
7
  PATH="${LAMBDA_TASK_ROOT}/.venv/bin:$PATH"
 
8
 
9
  # Set working directory to function root directory
10
  WORKDIR ${LAMBDA_TASK_ROOT}
 
5
  ARG PYTHONPATH="${LAMBDA_TASK_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
6
  ENV VIRTUAL_ENV=${LAMBDA_TASK_ROOT}/.venv \
7
  PATH="${LAMBDA_TASK_ROOT}/.venv/bin:$PATH"
8
+ ENV IS_AWS_LAMBDA="True"
9
 
10
  # Set working directory to function root directory
11
  WORKDIR ${LAMBDA_TASK_ROOT}
samgis/__init__.py CHANGED
@@ -1,17 +1,24 @@
1
  """Get machine learning predictions from geodata raster images"""
 
 
2
  # not used here but contextily_tile is imported in samgis.io.tms2geotiff
3
  from contextily import tile as contextily_tile
4
  from pathlib import Path
5
-
6
  from samgis.utilities.constants import SERVICE_NAME
7
 
8
  PROJECT_ROOT_FOLDER = Path(globals().get("__file__", "./_")).absolute().parent.parent
9
  MODEL_FOLDER = Path(PROJECT_ROOT_FOLDER / "machine_learning_models")
10
- try:
11
- from aws_lambda_powertools import Logger
12
 
13
- app_logger = Logger(service=SERVICE_NAME)
14
- except ModuleNotFoundError:
 
 
 
 
 
 
 
 
15
  from samgis_core.utilities.fastapi_logger import setup_logging
16
 
17
  app_logger = setup_logging(debug=True)
 
1
  """Get machine learning predictions from geodata raster images"""
2
+ import os
3
+
4
  # not used here but contextily_tile is imported in samgis.io.tms2geotiff
5
  from contextily import tile as contextily_tile
6
  from pathlib import Path
 
7
  from samgis.utilities.constants import SERVICE_NAME
8
 
9
  PROJECT_ROOT_FOLDER = Path(globals().get("__file__", "./_")).absolute().parent.parent
10
  MODEL_FOLDER = Path(PROJECT_ROOT_FOLDER / "machine_learning_models")
 
 
11
 
12
+ IS_AWS_LAMBDA = bool(os.getenv("IS_AWS_LAMBDA", ""))
13
+
14
+ if IS_AWS_LAMBDA:
15
+ try:
16
+ from aws_lambda_powertools import Logger
17
+
18
+ app_logger = Logger(service=SERVICE_NAME)
19
+ except ModuleNotFoundError:
20
+ print("this should be AWS LAMBDA environment but we miss the required aws lambda powertools package")
21
+ else:
22
  from samgis_core.utilities.fastapi_logger import setup_logging
23
 
24
  app_logger = setup_logging(debug=True)
samgis/io/wrappers_helpers.py CHANGED
@@ -1,5 +1,9 @@
1
  """lambda helper functions"""
 
 
2
  from typing import Dict
 
 
3
  from xyzservices import providers, TileProvider
4
 
5
  from samgis import app_logger
@@ -131,6 +135,12 @@ def get_parsed_request_body(event: Dict or str) -> ApiRequestBody:
131
  from json import dumps, loads
132
  from logging import getLevelName
133
 
 
 
 
 
 
 
134
  app_logger.info(f"event:{dumps(event)}...")
135
  try:
136
  raw_body = event["body"]
@@ -146,8 +156,13 @@ def get_parsed_request_body(event: Dict or str) -> ApiRequestBody:
146
 
147
  parsed_body = ApiRequestBody.model_validate(raw_body)
148
  log_level = "DEBUG" if parsed_body.debug else "INFO"
149
- app_logger.setLevel(log_level)
150
- app_logger.warning(f"set log level to {getLevelName(app_logger.log_level)}.")
 
 
 
 
 
151
 
152
  return parsed_body
153
 
 
1
  """lambda helper functions"""
2
+ import logging
3
+ from sys import stdout
4
  from typing import Dict
5
+
6
+ import loguru
7
  from xyzservices import providers, TileProvider
8
 
9
  from samgis import app_logger
 
135
  from json import dumps, loads
136
  from logging import getLevelName
137
 
138
+ def _get_current_log_level(logger: loguru.logger) -> [str, loguru._logger.Level]:
139
+ levels = logger._core.levels
140
+ current_log_level = logger._core.min_level
141
+ level_filt = [l for l in levels.items() if l[1].no == current_log_level]
142
+ return level_filt[0]
143
+
144
  app_logger.info(f"event:{dumps(event)}...")
145
  try:
146
  raw_body = event["body"]
 
156
 
157
  parsed_body = ApiRequestBody.model_validate(raw_body)
158
  log_level = "DEBUG" if parsed_body.debug else "INFO"
159
+ app_logger.remove()
160
+ app_logger.add(stdout, level=log_level)
161
+ try:
162
+ current_log_level_name, _ = _get_current_log_level(app_logger)
163
+ app_logger.warning(f"set log level to {getLevelName(current_log_level_name)}.")
164
+ except Exception as ex:
165
+ print("failing setting parsing bbox, logger is ok? ex:", ex, "#")
166
 
167
  return parsed_body
168
 
tests/io/test_wrappers_helpers.py CHANGED
@@ -133,4 +133,3 @@ class WrappersHelpersTest(unittest.TestCase):
133
  'url': 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', 'max_zoom': 19,
134
  'html_attribution': html_attribution_hot, 'attribution': attribution_hot, 'name': 'OpenStreetMap.HOT'
135
  }
136
-
 
133
  'url': 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', 'max_zoom': 19,
134
  'html_attribution': html_attribution_hot, 'attribution': attribution_hot, 'name': 'OpenStreetMap.HOT'
135
  }
 
tests/test_lambda_app.py CHANGED
@@ -3,215 +3,230 @@ import time
3
  import unittest
4
  from unittest.mock import patch
5
 
6
- try:
7
- from awslambdaric.lambda_context import LambdaContext
8
- except ImportError:
9
- import pip
10
- pip.main(['install', 'awslambdaric'])
11
-
12
-
13
- from samgis.io import wrappers_helpers
14
- from wrappers import lambda_wrapper
15
- from tests.local_tiles_http_server import LocalTilesHttpServer
16
-
17
-
18
- class TestLambdaApp(unittest.TestCase):
19
- @patch.object(time, "time")
20
- @patch.object(lambda_wrapper, "samexporter_predict")
21
- @patch.object(lambda_wrapper, "get_parsed_bbox_points")
22
- @patch.object(lambda_wrapper, "get_parsed_request_body")
23
- def test_lambda_handler_500(
24
- self,
25
- get_parsed_request_body_mocked,
26
- get_parsed_bbox_points_mocked,
27
- samexporter_predict_mocked,
28
- time_mocked
29
- ):
30
- from wrappers.lambda_wrapper import lambda_handler
31
-
32
- time_mocked.return_value = 0
33
- get_parsed_request_body_mocked.value = {}
34
- get_parsed_bbox_points_mocked.return_value = {"bbox": "bbox_object", "prompt": "prompt_object", "zoom": 1}
35
- samexporter_predict_mocked.side_effect = ValueError("I raise a value error!")
36
-
37
- event = {"body": {}, "version": 1.0}
38
- lambda_context = LambdaContext(
39
- invoke_id="test_invoke_id",
40
- client_context=None,
41
- cognito_identity=None,
42
- epoch_deadline_time_in_ms=time.time()
43
- )
44
- expected_response_500 = '{"statusCode": 500, "header": {"Content-Type": "application/json"}, '
45
- expected_response_500 += '"body": "{\\"duration_run\\": 0, \\"message\\": \\"Internal server error\\", '
46
- expected_response_500 += '\\"request_id\\": \\"test_invoke_id\\"}", "isBase64Encoded": false}'
47
-
48
- assert lambda_handler(event, lambda_context) == expected_response_500
49
-
50
- @patch.object(time, "time")
51
- @patch.object(lambda_wrapper, "get_parsed_request_body")
52
- def test_lambda_handler_400(self, get_parsed_request_body_mocked, time_mocked):
53
- from wrappers.lambda_wrapper import lambda_handler
54
-
55
- time_mocked.return_value = 0
56
- get_parsed_request_body_mocked.return_value = {}
57
-
58
- event = {"body": {}, "version": 1.0}
59
- lambda_context = LambdaContext(
60
- invoke_id="test_invoke_id",
61
- client_context=None,
62
- cognito_identity=None,
63
- epoch_deadline_time_in_ms=time.time()
64
- )
65
-
66
- assert lambda_handler(event, lambda_context) == (
67
- '{"statusCode": 400, "header": {"Content-Type": "application/json"}, '
68
- '"body": "{\\"duration_run\\": 0, \\"message\\": \\"Bad Request\\", '
69
- '\\"request_id\\": \\"test_invoke_id\\"}", "isBase64Encoded": false}')
70
-
71
- @patch.object(time, "time")
72
- def test_lambda_handler_422(self, time_mocked):
73
- from wrappers.lambda_wrapper import lambda_handler
74
-
75
- time_mocked.return_value = 0
76
- event = {"body": {}, "version": 1.0}
77
- lambda_context = LambdaContext(
78
- invoke_id="test_invoke_id",
79
- client_context=None,
80
- cognito_identity=None,
81
- epoch_deadline_time_in_ms=time.time()
82
- )
83
-
84
- response_422 = lambda_handler(event, lambda_context)
85
- expected_response_422 = '{"statusCode": 422, "header": {"Content-Type": "application/json"}, '
86
- expected_response_422 += '"body": "{\\"duration_run\\": 0, \\"message\\": \\"Missing required parameter\\", '
87
- expected_response_422 += '\\"request_id\\": \\"test_invoke_id\\"}", "isBase64Encoded": false}'
88
-
89
- assert response_422 == expected_response_422
90
-
91
- @patch.object(time, "time")
92
- @patch.object(lambda_wrapper, "samexporter_predict")
93
- @patch.object(lambda_wrapper, "get_response")
94
- @patch.object(lambda_wrapper, "get_parsed_bbox_points")
95
- @patch.object(lambda_wrapper, "get_parsed_request_body")
96
- def test_lambda_handler_200_mocked(
97
- self,
98
- get_parsed_request_body_mocked,
99
- get_parsed_bbox_points_mocked,
100
- get_response_mocked,
101
- samexporter_predict_mocked,
102
- time_mocked
103
- ):
104
- from wrappers.lambda_wrapper import lambda_handler
105
- from tests import TEST_EVENTS_FOLDER
106
-
107
- time_mocked.return_value = 0
108
- get_parsed_request_body_mocked.value = {}
109
- get_parsed_bbox_points_mocked.return_value = {"bbox": "bbox_object", "prompt": "prompt_object", "zoom": 1}
110
-
111
- response_type = "200"
112
- with open(TEST_EVENTS_FOLDER / "get_response.json") as tst_json_get_response:
113
- get_response_io = json.load(tst_json_get_response)
114
-
115
- input_200 = {
116
- "bbox": {
117
- "ne": {"lat": 38.03932961278458, "lng": 15.36808069832851},
118
- "sw": {"lat": 37.455509218936974, "lng": 14.632807441554068}
119
- },
120
- "prompt": [{
121
- "type": "point",
122
- "data": {"lat": 37.0, "lng": 15.0},
123
- "label": 0
124
- }],
125
- "zoom": 10,
126
- "source_type": "OpenStreetMap.Mapnik",
127
- "debug": True
128
- }
129
-
130
- samexporter_predict_output = get_response_io[response_type]["input"]
131
- samexporter_predict_mocked.return_value = samexporter_predict_output
132
- samexporter_predict_mocked.side_effect = None
133
- get_response_mocked.return_value = get_response_io[response_type]["output"]
134
-
135
- event = {"body": input_200, "version": 1.0}
136
-
137
- lambda_context = LambdaContext(
138
- invoke_id="test_invoke_id",
139
- client_context=None,
140
- cognito_identity=None,
141
- epoch_deadline_time_in_ms=time.time()
142
- )
143
-
144
- response_200 = lambda_handler(event, lambda_context)
145
- expected_response_200 = get_response_io[response_type]["output"]
146
- print(f"types: response_200:{type(response_200)}, expected:{type(expected_response_200)}.")
147
- assert response_200 == expected_response_200
148
-
149
- @patch.object(wrappers_helpers, "get_url_tile")
150
- def test_lambda_handler_200_real_single_multi_point(self, get_url_tile_mocked):
151
- import xyzservices
152
- import shapely
153
-
154
- from wrappers.lambda_wrapper import lambda_handler
155
- from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
156
-
157
- local_tile_provider = xyzservices.TileProvider(name="local_tile_provider", url=LOCAL_URL_TILE, attribution="")
158
- get_url_tile_mocked.return_value = local_tile_provider
159
- fn_name = "lambda_handler"
160
- invoke_id = "test_invoke_id"
161
-
162
- for json_filename in [
163
- "single_point",
164
- "multi_prompt",
165
- "single_rectangle"
166
- ]:
167
- with open(TEST_EVENTS_FOLDER / f"{fn_name}_{json_filename}.json") as tst_json:
168
- inputs_outputs = json.load(tst_json)
169
  lambda_context = LambdaContext(
170
- invoke_id=invoke_id,
171
  client_context=None,
172
  cognito_identity=None,
173
  epoch_deadline_time_in_ms=time.time()
174
  )
175
- expected_response_dict = inputs_outputs["output"]
176
- listen_port = 8000
177
- expected_response_body = json.loads(expected_response_dict["body"])
178
-
179
- with LocalTilesHttpServer.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
180
- input_event = inputs_outputs["input"]
181
- input_event_body = json.loads(input_event["body"])
182
- input_event["body"] = json.dumps(input_event_body)
183
- response = lambda_handler(event=input_event, context=lambda_context)
184
-
185
- response_dict = json.loads(response)
186
- assert response_dict["statusCode"] == 200
187
- body_dict = json.loads(response_dict["body"])
188
- assert body_dict["n_predictions"] == 1
189
- assert body_dict["request_id"] == invoke_id
190
- assert body_dict["message"] == "ok"
191
- assert body_dict["n_shapes_geojson"] == expected_response_body["n_shapes_geojson"]
192
-
193
- output_geojson = shapely.from_geojson(body_dict["geojson"])
194
- print("output_geojson::", type(output_geojson))
195
- assert isinstance(output_geojson, shapely.GeometryCollection)
196
- assert len(output_geojson.geoms) == expected_response_body["n_shapes_geojson"]
197
-
198
- def test_debug(self):
199
- from wrappers.lambda_wrapper import lambda_handler
200
-
201
- input_event = {
202
- 'bbox': {
203
- 'ne': {'lat': 46.302592089330524, 'lng': 9.49493408203125},
204
- 'sw': {'lat': 46.14011755129237, 'lng': 9.143371582031252}},
205
- 'prompt': [
206
- {'id': 166, 'type': 'point', 'data': {'lat': 46.18244521829928, 'lng': 9.418544769287111}, 'label': 1}
207
- ],
208
- 'zoom': 12, 'source_type': 'OpenStreetMap'
209
- }
210
- lambda_context = LambdaContext(
211
- invoke_id="test_invoke_id",
212
- client_context=None,
213
- cognito_identity=None,
214
- epoch_deadline_time_in_ms=time.time()
215
- )
216
- response = lambda_handler(event=input_event, context=lambda_context)
217
- print(response)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import unittest
4
  from unittest.mock import patch
5
 
6
+ from samgis import IS_AWS_LAMBDA
7
+
8
+ if IS_AWS_LAMBDA:
9
+ try:
10
+ from awslambdaric.lambda_context import LambdaContext
11
+
12
+ from samgis.io import wrappers_helpers
13
+ from wrappers import lambda_wrapper
14
+ from tests.local_tiles_http_server import LocalTilesHttpServer
15
+
16
+
17
+ class TestLambdaApp(unittest.TestCase):
18
+ @patch.object(time, "time")
19
+ @patch.object(lambda_wrapper, "samexporter_predict")
20
+ @patch.object(lambda_wrapper, "get_parsed_bbox_points")
21
+ @patch.object(lambda_wrapper, "get_parsed_request_body")
22
+ def test_lambda_handler_500(
23
+ self,
24
+ get_parsed_request_body_mocked,
25
+ get_parsed_bbox_points_mocked,
26
+ samexporter_predict_mocked,
27
+ time_mocked
28
+ ):
29
+ from wrappers.lambda_wrapper import lambda_handler
30
+
31
+ time_mocked.return_value = 0
32
+ get_parsed_request_body_mocked.value = {}
33
+ get_parsed_bbox_points_mocked.return_value = {"bbox": "bbox_object", "prompt": "prompt_object",
34
+ "zoom": 1}
35
+ samexporter_predict_mocked.side_effect = ValueError("I raise a value error!")
36
+
37
+ event = {"body": {}, "version": 1.0}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  lambda_context = LambdaContext(
39
+ invoke_id="test_invoke_id",
40
  client_context=None,
41
  cognito_identity=None,
42
  epoch_deadline_time_in_ms=time.time()
43
  )
44
+ expected_response_500 = '{"statusCode": 500, "header": {"Content-Type": "application/json"}, '
45
+ expected_response_500 += '"body": "{\\"duration_run\\": 0, \\"message\\": \\"Internal server error\\", '
46
+ expected_response_500 += '\\"request_id\\": \\"test_invoke_id\\"}", "isBase64Encoded": false}'
47
+
48
+ assert lambda_handler(event, lambda_context) == expected_response_500
49
+
50
+
51
+ @patch.object(time, "time")
52
+ @patch.object(lambda_wrapper, "get_parsed_request_body")
53
+ def test_lambda_handler_400(self, get_parsed_request_body_mocked, time_mocked):
54
+ from wrappers.lambda_wrapper import lambda_handler
55
+
56
+ time_mocked.return_value = 0
57
+ get_parsed_request_body_mocked.return_value = {}
58
+
59
+ event = {"body": {}, "version": 1.0}
60
+ lambda_context = LambdaContext(
61
+ invoke_id="test_invoke_id",
62
+ client_context=None,
63
+ cognito_identity=None,
64
+ epoch_deadline_time_in_ms=time.time()
65
+ )
66
+
67
+ assert lambda_handler(event, lambda_context) == (
68
+ '{"statusCode": 400, "header": {"Content-Type": "application/json"}, '
69
+ '"body": "{\\"duration_run\\": 0, \\"message\\": \\"Bad Request\\", '
70
+ '\\"request_id\\": \\"test_invoke_id\\"}", "isBase64Encoded": false}')
71
+
72
+
73
+ @patch.object(time, "time")
74
+ def test_lambda_handler_422(self, time_mocked):
75
+ from wrappers.lambda_wrapper import lambda_handler
76
+
77
+ time_mocked.return_value = 0
78
+ event = {"body": {}, "version": 1.0}
79
+ lambda_context = LambdaContext(
80
+ invoke_id="test_invoke_id",
81
+ client_context=None,
82
+ cognito_identity=None,
83
+ epoch_deadline_time_in_ms=time.time()
84
+ )
85
+
86
+ response_422 = lambda_handler(event, lambda_context)
87
+ expected_response_422 = '{"statusCode": 422, "header": {"Content-Type": "application/json"}, '
88
+ expected_response_422 += '"body": "{\\"duration_run\\": 0, \\"message\\": \\"Missing required parameter\\", '
89
+ expected_response_422 += '\\"request_id\\": \\"test_invoke_id\\"}", "isBase64Encoded": false}'
90
+
91
+ assert response_422 == expected_response_422
92
+
93
+
94
+ @patch.object(time, "time")
95
+ @patch.object(lambda_wrapper, "samexporter_predict")
96
+ @patch.object(lambda_wrapper, "get_response")
97
+ @patch.object(lambda_wrapper, "get_parsed_bbox_points")
98
+ @patch.object(lambda_wrapper, "get_parsed_request_body")
99
+ def test_lambda_handler_200_mocked(
100
+ self,
101
+ get_parsed_request_body_mocked,
102
+ get_parsed_bbox_points_mocked,
103
+ get_response_mocked,
104
+ samexporter_predict_mocked,
105
+ time_mocked
106
+ ):
107
+ from wrappers.lambda_wrapper import lambda_handler
108
+ from tests import TEST_EVENTS_FOLDER
109
+
110
+ time_mocked.return_value = 0
111
+ get_parsed_request_body_mocked.value = {}
112
+ get_parsed_bbox_points_mocked.return_value = {"bbox": "bbox_object", "prompt": "prompt_object", "zoom": 1}
113
+
114
+ response_type = "200"
115
+ with open(TEST_EVENTS_FOLDER / "get_response.json") as tst_json_get_response:
116
+ get_response_io = json.load(tst_json_get_response)
117
+
118
+ input_200 = {
119
+ "bbox": {
120
+ "ne": {"lat": 38.03932961278458, "lng": 15.36808069832851},
121
+ "sw": {"lat": 37.455509218936974, "lng": 14.632807441554068}
122
+ },
123
+ "prompt": [{
124
+ "type": "point",
125
+ "data": {"lat": 37.0, "lng": 15.0},
126
+ "label": 0
127
+ }],
128
+ "zoom": 10,
129
+ "source_type": "OpenStreetMap.Mapnik",
130
+ "debug": True
131
+ }
132
+
133
+ samexporter_predict_output = get_response_io[response_type]["input"]
134
+ samexporter_predict_mocked.return_value = samexporter_predict_output
135
+ samexporter_predict_mocked.side_effect = None
136
+ get_response_mocked.return_value = get_response_io[response_type]["output"]
137
+
138
+ event = {"body": input_200, "version": 1.0}
139
+
140
+ lambda_context = LambdaContext(
141
+ invoke_id="test_invoke_id",
142
+ client_context=None,
143
+ cognito_identity=None,
144
+ epoch_deadline_time_in_ms=time.time()
145
+ )
146
+
147
+ response_200 = lambda_handler(event, lambda_context)
148
+ expected_response_200 = get_response_io[response_type]["output"]
149
+ print(f"types: response_200:{type(response_200)}, expected:{type(expected_response_200)}.")
150
+ assert response_200 == expected_response_200
151
+
152
+
153
+ @patch.object(wrappers_helpers, "get_url_tile")
154
+ def test_lambda_handler_200_real_single_multi_point(self, get_url_tile_mocked):
155
+ import xyzservices
156
+ import shapely
157
+
158
+ from wrappers.lambda_wrapper import lambda_handler
159
+ from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
160
+
161
+ local_tile_provider = xyzservices.TileProvider(name="local_tile_provider", url=LOCAL_URL_TILE,
162
+ attribution="")
163
+ get_url_tile_mocked.return_value = local_tile_provider
164
+ fn_name = "lambda_handler"
165
+ invoke_id = "test_invoke_id"
166
+
167
+ for json_filename in [
168
+ "single_point",
169
+ "multi_prompt",
170
+ "single_rectangle"
171
+ ]:
172
+ with open(TEST_EVENTS_FOLDER / f"{fn_name}_{json_filename}.json") as tst_json:
173
+ inputs_outputs = json.load(tst_json)
174
+ lambda_context = LambdaContext(
175
+ invoke_id=invoke_id,
176
+ client_context=None,
177
+ cognito_identity=None,
178
+ epoch_deadline_time_in_ms=time.time()
179
+ )
180
+ expected_response_dict = inputs_outputs["output"]
181
+ listen_port = 8000
182
+ expected_response_body = json.loads(expected_response_dict["body"])
183
+
184
+ with LocalTilesHttpServer.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
185
+ input_event = inputs_outputs["input"]
186
+ input_event_body = json.loads(input_event["body"])
187
+ input_event["body"] = json.dumps(input_event_body)
188
+ response = lambda_handler(event=input_event, context=lambda_context)
189
+
190
+ response_dict = json.loads(response)
191
+ assert response_dict["statusCode"] == 200
192
+ body_dict = json.loads(response_dict["body"])
193
+ assert body_dict["n_predictions"] == 1
194
+ assert body_dict["request_id"] == invoke_id
195
+ assert body_dict["message"] == "ok"
196
+ assert body_dict["n_shapes_geojson"] == expected_response_body["n_shapes_geojson"]
197
+
198
+ output_geojson = shapely.from_geojson(body_dict["geojson"])
199
+ print("output_geojson::", type(output_geojson))
200
+ assert isinstance(output_geojson, shapely.GeometryCollection)
201
+ assert len(output_geojson.geoms) == expected_response_body["n_shapes_geojson"]
202
+
203
+
204
+ def test_debug(self):
205
+ from wrappers.lambda_wrapper import lambda_handler
206
+
207
+ input_event = {
208
+ 'bbox': {
209
+ 'ne': {'lat': 46.302592089330524, 'lng': 9.49493408203125},
210
+ 'sw': {'lat': 46.14011755129237, 'lng': 9.143371582031252}},
211
+ 'prompt': [
212
+ {'id': 166, 'type': 'point', 'data': {'lat': 46.18244521829928, 'lng': 9.418544769287111},
213
+ 'label': 1}
214
+ ],
215
+ 'zoom': 12, 'source_type': 'OpenStreetMap'
216
+ }
217
+ lambda_context = LambdaContext(
218
+ invoke_id="test_invoke_id",
219
+ client_context=None,
220
+ cognito_identity=None,
221
+ epoch_deadline_time_in_ms=time.time()
222
+ )
223
+ response = lambda_handler(event=input_event, context=lambda_context)
224
+ print(response)
225
+ except ModuleNotFoundError as mnfe:
226
+ print("missing awslambdaric...")
227
+ raise mnfe
228
+
229
+
230
+ if __name__ == '__main__':
231
+ if IS_AWS_LAMBDA:
232
+ unittest.main()