alessandro trinca tornidor commited on
Commit
9881eef
1 Parent(s): d801599

refactor: complete refactor because of samgis-lisa

Browse files
dockerfiles/dockerfile-lisa-predictions CHANGED
@@ -23,7 +23,6 @@ RUN ls -l ${LAMBDA_TASK_ROOT}
23
  RUN ls -ld ${LAMBDA_TASK_ROOT}
24
  RUN ls -l ${LAMBDA_TASK_ROOT}/machine_learning_models
25
  RUN python -c "import sys; print(sys.path)"
26
- RUN python -c "import cv2"
27
  RUN python -c "import fastapi"
28
  RUN python -c "import geopandas"
29
  RUN python -c "import loguru"
 
23
  RUN ls -ld ${LAMBDA_TASK_ROOT}
24
  RUN ls -l ${LAMBDA_TASK_ROOT}/machine_learning_models
25
  RUN python -c "import sys; print(sys.path)"
 
26
  RUN python -c "import fastapi"
27
  RUN python -c "import geopandas"
28
  RUN python -c "import loguru"
scripts/create_folders_and_variables_if_not_exists.py DELETED
@@ -1,51 +0,0 @@
1
- import json
2
- import logging
3
- import os
4
- from pathlib import Path
5
-
6
-
7
- def stats_pathname(pathname: Path | str):
8
- current_pathname = Path(pathname)
9
- return current_pathname.is_dir()
10
-
11
-
12
- def create_folder_if_not_exists(pathname: Path | str):
13
- current_pathname = Path(pathname)
14
- try:
15
- print(f"Pathname exists? {current_pathname.exists()}, That's a folder? {current_pathname.is_dir()}...")
16
- logging.info(f"Pathname exists? {current_pathname.exists()}, That's a folder? {current_pathname.is_dir()}...")
17
- current_pathname.unlink(missing_ok=True)
18
- except PermissionError as pe:
19
- print(f"permission denied on removing pathname before folder creation:{pe}.")
20
- logging.error(f"permission denied on removing pathname before folder creation:{pe}.")
21
- except IsADirectoryError as errdir:
22
- print(f"that's a directory:{errdir}.")
23
- logging.error(f"that's a directory:{errdir}.")
24
-
25
- print(f"Creating pathname: {current_pathname} ...")
26
- logging.info(f"Creating pathname: {current_pathname} ...")
27
- current_pathname.mkdir(mode=0o770, parents=True, exist_ok=True)
28
-
29
- print(f"assertion: pathname exists and is a folder: {current_pathname} ...")
30
- logging.info(f"assertion: pathname exists and is a folder: {current_pathname} ...")
31
- assert current_pathname.is_dir()
32
-
33
-
34
- if __name__ == '__main__':
35
- folders_string = os.getenv("FOLDERS_MAP")
36
- try:
37
- folders_dict = json.loads(folders_string)
38
- for folder_env_ref, folder_env_path in folders_dict.items():
39
- print(f"folder_env_ref:{folder_env_ref}, folder_env_path:{folder_env_path}.")
40
- logging.info(f"folder_env_ref:{folder_env_ref}, folder_env_path:{folder_env_path}.")
41
- create_folder_if_not_exists(folder_env_path)
42
- print("========")
43
- assert os.getenv(folder_env_ref) == folder_env_path
44
- except (json.JSONDecodeError, TypeError) as jde:
45
- print(f"jde:{jde}.")
46
- logging.error(f"jde:{jde}.")
47
- print("double check your variables, e.g. for mispelling like 'FOLDER_MAP'...")
48
- logging.info("double check your variables, e.g. for mispelling like 'FOLDER_MAP' instead than 'FOLDERS_MAP'...")
49
- for k_env, v_env in dict(os.environ).items():
50
- print(f"{k_env}, v_env:{v_env}.")
51
- logging.info(f"{k_env}, v_env:{v_env}.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/extract-openapi-fastapi.py CHANGED
@@ -3,12 +3,13 @@ import argparse
3
  import json
4
  import logging
5
  import sys
 
6
 
7
  import yaml
8
  from uvicorn.importer import import_from_string
9
 
10
- from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
11
 
 
12
  parser = argparse.ArgumentParser(prog="extract-openapi-fastapi.py")
13
  parser.add_argument("app", help='App import string. Eg. "main:app"', default="main:app")
14
  parser.add_argument("--app-dir", help="Directory containing the app", default=None)
 
3
  import json
4
  import logging
5
  import sys
6
+ from pathlib import Path
7
 
8
  import yaml
9
  from uvicorn.importer import import_from_string
10
 
 
11
 
12
+ PROJECT_ROOT_FOLDER = Path(globals().get("__file__", "./_")).absolute().parent.parent
13
  parser = argparse.ArgumentParser(prog="extract-openapi-fastapi.py")
14
  parser.add_argument("app", help='App import string. Eg. "main:app"', default="main:app")
15
  parser.add_argument("--app-dir", help="Directory containing the app", default=None)
scripts/extract-openapi-lambda.py DELETED
@@ -1,13 +0,0 @@
1
- import json
2
-
3
- from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
4
-
5
- if __name__ == '__main__':
6
- from samgis_lisa_on_zero.utilities.type_hints import ApiRequestBody, ApiResponseBodyFailure, ApiResponseBodySuccess
7
-
8
- with open(PROJECT_ROOT_FOLDER / "docs" / "specs" / "openapi_lambda_wip.json", "w") as output_json:
9
- json.dump({
10
- "ApiRequestBody": ApiRequestBody.model_json_schema(),
11
- "ApiResponseBodyFailure": ApiResponseBodyFailure.model_json_schema(),
12
- "ApiResponseBodySuccess": ApiResponseBodySuccess.model_json_schema()
13
- }, output_json)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
- from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
2
 
3
 
 
4
  TEST_ROOT_FOLDER = PROJECT_ROOT_FOLDER / "tests"
5
  TEST_EVENTS_FOLDER = TEST_ROOT_FOLDER / "events"
6
  LOCAL_URL_TILE = "http://localhost:8000/lambda_handler/{z}/{x}/{y}.png"
 
1
+ from pathlib import Path
2
 
3
 
4
+ PROJECT_ROOT_FOLDER = Path(globals().get("__file__", "./_")).absolute().parent.parent
5
  TEST_ROOT_FOLDER = PROJECT_ROOT_FOLDER / "tests"
6
  TEST_EVENTS_FOLDER = TEST_ROOT_FOLDER / "events"
7
  LOCAL_URL_TILE = "http://localhost:8000/lambda_handler/{z}/{x}/{y}.png"
tests/io_package/__init__.py DELETED
File without changes
tests/io_package/test_coordinates_pixel_conversion.py DELETED
@@ -1,27 +0,0 @@
1
- import json
2
-
3
- from samgis_lisa_on_zero.io_package.coordinates_pixel_conversion import get_latlng_to_pixel_coordinates
4
- from samgis_lisa_on_zero.utilities.type_hints import LatLngDict
5
- from tests import TEST_EVENTS_FOLDER
6
-
7
-
8
- def test_get_latlng_to_pixel_coordinates():
9
- name_fn = "get_latlng_to_pixel_coordinates"
10
-
11
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
12
- inputs_outputs = json.load(tst_json)
13
- for k, input_output in inputs_outputs.items():
14
- print(f"k:{k}")
15
- current_input = input_output["input"]
16
- zoom = current_input["zoom"]
17
- latlng_origin_ne = LatLngDict.model_validate(current_input["latlng_origin_ne"])
18
- latlng_origin_sw = LatLngDict.model_validate(current_input["latlng_origin_sw"])
19
- latlng_current_point = LatLngDict.model_validate(current_input["latlng_current_point"])
20
- output = get_latlng_to_pixel_coordinates(
21
- latlng_origin_ne=latlng_origin_ne,
22
- latlng_origin_sw=latlng_origin_sw,
23
- latlng_current_point=latlng_current_point,
24
- zoom=zoom,
25
- k=k
26
- )
27
- assert output == input_output["output"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/io_package/test_geo_helpers.py DELETED
@@ -1,103 +0,0 @@
1
- import json
2
- import unittest
3
- import numpy as np
4
- import shapely
5
-
6
- from samgis_lisa_on_zero.io_package.geo_helpers import load_affine_transformation_from_matrix
7
- from tests import TEST_EVENTS_FOLDER
8
-
9
-
10
- class TestGeoHelpers(unittest.TestCase):
11
- def test_load_affine_transformation_from_matrix(self):
12
- name_fn = "samexporter_predict"
13
-
14
- expected_output = {
15
- 'europe': (
16
- 1524458.6551710723, 0.0, 152.87405657035242, 4713262.318571913, -762229.3275855362, -2356860.470370812
17
- ),
18
- 'north_america': (
19
- -13855281.495084189, 0.0, 1222.9924525628194, 6732573.451358326, 6927640.747542094, -3368121.214358007
20
- ),
21
- 'oceania': (
22
- 7269467.138033403, 0.0, 9783.93962050256, -166326.9735485418, -3634733.5690167015, 68487.57734351706
23
- ),
24
- 'south_america': (
25
- -7922544.351904369, 0.0, 305.74811314070394, -5432228.234830927, 3961272.1759521845, 2715655.4952457524
26
- )}
27
-
28
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
29
- inputs_outputs = json.load(tst_json)
30
- for k, input_output in inputs_outputs.items():
31
- print(f"k:{k}.")
32
-
33
- output = load_affine_transformation_from_matrix(input_output["input"]["matrix"])
34
- assert output.to_shapely() == expected_output[k]
35
-
36
- def test_load_affine_transformation_from_matrix_value_error(self):
37
- name_fn = "samexporter_predict"
38
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
39
- inputs_outputs = json.load(tst_json)
40
- with self.assertRaises(ValueError):
41
- try:
42
- io_value_error = inputs_outputs["europe"]["input"]["matrix"][:5]
43
- load_affine_transformation_from_matrix(io_value_error)
44
- except ValueError as ve:
45
- print(f"ve:{ve}.")
46
- self.assertEqual(str(ve), "Expected 6 coefficients, found 5; argument type: <class 'list'>.")
47
- raise ve
48
-
49
- def test_load_affine_transformation_from_matrix_exception(self):
50
- name_fn = "samexporter_predict"
51
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
52
- inputs_outputs = json.load(tst_json)
53
- with self.assertRaises(Exception):
54
- try:
55
- io_exception = inputs_outputs["europe"]["input"]["matrix"]
56
- io_exception[0] = "ciao"
57
- load_affine_transformation_from_matrix(io_exception)
58
- except Exception as e:
59
- print(f"e:{e}.")
60
- self.assertEqual(str(e), "exception:could not convert string to float: 'ciao', "
61
- "check https://github.com/rasterio/affine project for updates")
62
- raise e
63
-
64
- def test_get_vectorized_raster_as_geojson_ok(self):
65
- from rasterio.transform import Affine
66
- from samgis_lisa_on_zero.io_package.geo_helpers import get_vectorized_raster_as_geojson
67
-
68
- name_fn = "samexporter_predict"
69
-
70
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
71
- inputs_outputs = json.load(tst_json)
72
- for k, input_output in inputs_outputs.items():
73
- print(f"k:{k}.")
74
- mask = np.load(TEST_EVENTS_FOLDER / name_fn / k / "mask.npy")
75
-
76
- transform = Affine.from_gdal(*input_output["input"]["matrix"])
77
- output = get_vectorized_raster_as_geojson(mask=mask, transform=transform)
78
- assert output["n_shapes_geojson"] == input_output["output"]["n_shapes_geojson"]
79
- output_geojson = shapely.from_geojson(output["geojson"])
80
- expected_output_geojson = shapely.from_geojson(input_output["output"]["geojson"])
81
- assert shapely.equals_exact(output_geojson, expected_output_geojson, tolerance=0.000006)
82
-
83
- def test_get_vectorized_raster_as_geojson_fail(self):
84
- from samgis_lisa_on_zero.io_package.geo_helpers import get_vectorized_raster_as_geojson
85
-
86
- name_fn = "samexporter_predict"
87
-
88
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
89
- inputs_outputs = json.load(tst_json)
90
- for k, input_output in inputs_outputs.items():
91
- print(f"k:{k}.")
92
- mask = np.load(TEST_EVENTS_FOLDER / name_fn / k / "mask.npy")
93
-
94
- # Could be also another generic Exception, here we intercept TypeError caused by wrong matrix input on
95
- # rasterio.Affine.from_gdal() wrapped by get_affine_transform_from_gdal()
96
- with self.assertRaises(IndexError):
97
- try:
98
- wrong_matrix = 1.0,
99
- get_vectorized_raster_as_geojson(mask=mask, transform=wrong_matrix)
100
- except IndexError as te:
101
- print(f"te:{te}.")
102
- self.assertEqual(str(te), 'tuple index out of range')
103
- raise te
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/io_package/test_raster_helpers.py DELETED
@@ -1,255 +0,0 @@
1
- import unittest
2
- from unittest.mock import patch
3
- import numpy as np
4
-
5
- from samgis_core.utilities.utilities import hash_calculate
6
- from samgis_lisa_on_zero.io_package import raster_helpers
7
-
8
-
9
- def get_three_channels(size=5, param1=1000, param2=3, param3=-88):
10
- arr_base = np.arange(size*size).reshape(size, size) / size**2
11
- channel_0 = arr_base * param1
12
- channel_1 = arr_base * param2
13
- channel_2 = arr_base * param3
14
- return channel_0, channel_1, channel_2
15
-
16
-
17
- def helper_bell(size=10, param1=0.1, param2=2):
18
- x = np.linspace(-size, size, num=size**2)
19
- y = np.linspace(-size, size, num=size**2)
20
- x, y = np.meshgrid(x, y)
21
- return np.exp(-param1 * x ** param2 - param1 * y ** param2)
22
-
23
-
24
- arr_5x5x5 = np.arange(125).reshape((5, 5, 5)) / 25
25
- arr = np.arange(25).resize((5, 5))
26
- channel0, channel1, channel2 = get_three_channels()
27
- z = helper_bell()
28
- slope_z_cellsize3, curvature_z_cellsize3 = raster_helpers.get_slope_curvature(z, slope_cellsize=3)
29
-
30
-
31
- class Test(unittest.TestCase):
32
-
33
- def test_get_rgb_prediction_image_real(self):
34
- output = raster_helpers.get_rgb_prediction_image(z, slope_cellsize=61, invert_image=True)
35
- hash_output = hash_calculate(output)
36
- assert hash_output == b'QpQ9yxgCLw9cf3klNFKNFXIDHaSkuiZxkbpeQApR8pA='
37
- output = raster_helpers.get_rgb_prediction_image(z, slope_cellsize=61, invert_image=False)
38
- hash_output = hash_calculate(output)
39
- assert hash_output == b'Y+iXO9w/sKzNVOw2rBh2JrVGJUFRqaa8/0F9hpevmLs='
40
-
41
- @patch.object(raster_helpers, "get_slope_curvature")
42
- @patch.object(raster_helpers, "normalize_array_list")
43
- @patch.object(raster_helpers, "get_rgb_image")
44
- def test_get_rgb_prediction_image_mocked(self, get_rgb_image_mocked, normalize_array_list, get_slope_curvature):
45
- local_arr = np.array(z * 100, dtype=np.uint8)
46
-
47
- get_slope_curvature.return_value = slope_z_cellsize3, curvature_z_cellsize3
48
- normalize_array_list.side_effect = None
49
- get_rgb_image_mocked.return_value = np.bitwise_not(local_arr)
50
- output = raster_helpers.get_rgb_prediction_image(local_arr, slope_cellsize=61, invert_image=True)
51
- hash_output = hash_calculate(output)
52
- assert hash_output == b'BPIyVH64RgVunj42EuQAx4/v59Va8ZAjcMnuiGNqTT0='
53
- get_rgb_image_mocked.return_value = local_arr
54
- output = raster_helpers.get_rgb_prediction_image(local_arr, slope_cellsize=61, invert_image=False)
55
- hash_output = hash_calculate(output)
56
- assert hash_output == b'XX54sdLQQUrhkUHT6ikQZYSloMYDSfh/AGITDq6jnRM='
57
-
58
- @patch.object(raster_helpers, "get_slope_curvature")
59
- def test_get_rgb_prediction_image_value_error(self, get_slope_curvature):
60
- msg = "this is a value error"
61
- get_slope_curvature.side_effect = ValueError(msg)
62
-
63
- with self.assertRaises(ValueError):
64
- try:
65
- raster_helpers.get_rgb_prediction_image(arr, slope_cellsize=3)
66
- except ValueError as ve:
67
- self.assertEqual(str(ve), msg)
68
- raise ve
69
-
70
- def test_get_rgb_image(self):
71
- output = raster_helpers.get_rgb_image(channel0, channel1, channel2, invert_image=True)
72
- hash_output = hash_calculate(output)
73
- assert hash_output == b'YVnRWla5Ptfet6reSfM+OEIsGytLkeso6X+CRs34YHk='
74
- output = raster_helpers.get_rgb_image(channel0, channel1, channel2, invert_image=False)
75
- hash_output = hash_calculate(output)
76
- assert hash_output == b'LC/kIZGUZULSrwwSXCeP1My2spTZdW9D7LH+tltwERs='
77
-
78
- def test_get_rgb_image_value_error_1(self):
79
- with self.assertRaises(ValueError):
80
- try:
81
- raster_helpers.get_rgb_image(arr_5x5x5, arr_5x5x5, arr_5x5x5, invert_image=True)
82
- except ValueError as ve:
83
- self.assertEqual(f"arr_size, wrong type:{type(arr_5x5x5)} or arr_size:{arr_5x5x5.shape}.", str(ve))
84
- raise ve
85
-
86
- def test_get_rgb_image_value_error2(self):
87
- arr_0 = np.arange(25).reshape((5, 5))
88
- arr_1 = np.arange(4).reshape((2, 2))
89
- with self.assertRaises(ValueError):
90
- try:
91
- raster_helpers.get_rgb_image(arr_0, arr_1, channel2, invert_image=True)
92
- except ValueError as ve:
93
- self.assertEqual('could not broadcast input array from shape (2,2) into shape (5,5)', str(ve))
94
- raise ve
95
-
96
- def test_get_slope_curvature(self):
97
- slope_output, curvature_output = raster_helpers.get_slope_curvature(z, slope_cellsize=3)
98
- hash_curvature = hash_calculate(curvature_output)
99
- hash_slope = hash_calculate(slope_output)
100
- assert hash_curvature == b'LAL9JFOjJP9D6X4X3fVCpnitx9VPM9drS5YMHwMZ3iE='
101
- assert hash_slope == b'IYf6x4G0lmR47j6HRS5kUYWdtmimhLz2nak8py75nwc='
102
-
103
- def test_get_slope_curvature_value_error(self):
104
- from samgis_lisa_on_zero.io_package import raster_helpers
105
-
106
- with self.assertRaises(ValueError):
107
- try:
108
- raster_helpers.get_slope_curvature(np.array(1), slope_cellsize=3)
109
- except ValueError as ve:
110
- self.assertEqual('not enough values to unpack (expected 2, got 0)', str(ve))
111
- raise ve
112
-
113
- def test_calculate_slope(self):
114
- slope_output = raster_helpers.calculate_slope(z, cell_size=3)
115
- hash_output = hash_calculate(slope_output)
116
- assert hash_output == b'IYf6x4G0lmR47j6HRS5kUYWdtmimhLz2nak8py75nwc='
117
-
118
- def test_calculate_slope_value_error(self):
119
- with self.assertRaises(ValueError):
120
- try:
121
- raster_helpers.calculate_slope(np.array(1), cell_size=3)
122
- except ValueError as ve:
123
- self.assertEqual('not enough values to unpack (expected 2, got 0)', str(ve))
124
- raise ve
125
-
126
- def test_normalize_array(self):
127
- def check_ndarrays_almost_equal(cls, arr1, arr2, places, check_type="float", check_ndiff=1):
128
- count_abs_diff = 0
129
- for list00, list01 in zip(arr1.tolist(), arr2.tolist()):
130
- for el00, el01 in zip(list00, list01):
131
- ndiff = abs(el00 - el01)
132
- if el00 != el01:
133
- count_abs_diff += 1
134
- if check_type == "float":
135
- cls.assertAlmostEqual(el00, el01, places=places)
136
- cls.assertLess(ndiff, check_ndiff) # cls.assertTrue(ndiff < check_ndiff)
137
- print("count_abs_diff:", count_abs_diff)
138
-
139
- normalized_array = raster_helpers.normalize_array(z)
140
- hash_output = hash_calculate(normalized_array)
141
- assert hash_output == b'MPkQwiiQa5NxL7LDvCS9V143YUEJT/Qh1aNEKc/Ehvo='
142
-
143
- mult_variable = 3.423
144
- test_array_input = np.arange(256).reshape((16, 16))
145
- test_array_output = raster_helpers.normalize_array(test_array_input * mult_variable)
146
- check_ndarrays_almost_equal(self, test_array_output, test_array_input, places=8)
147
-
148
- test_array_output1 = raster_helpers.normalize_array(test_array_input * mult_variable, high=128, norm_type="int")
149
- o = np.arange(256).reshape((16, 16)) / 2
150
- expected_array_output1 = o.astype(int)
151
- check_ndarrays_almost_equal(
152
- self, test_array_output1, expected_array_output1, places=2, check_type="int", check_ndiff=2)
153
-
154
- @patch.object(np, "nanmin")
155
- @patch.object(np, "nanmax")
156
- def test_normalize_array_floating_point_error_mocked(self, nanmax_mocked, nanmin_mocked):
157
- nanmax_mocked.return_value = 100
158
- nanmin_mocked.return_value = 100
159
-
160
- with self.assertRaises(ValueError):
161
- try:
162
- raster_helpers.normalize_array(
163
- np.arange(25).reshape((5, 5))
164
- )
165
- except ValueError as ve:
166
- self.assertEqual(
167
- "normalize_array:::h_arr_max:100,h_min_arr:100,fe:divide by zero encountered in divide.",
168
- str(ve)
169
- )
170
- raise ve
171
-
172
- @patch.object(np, "nanmin")
173
- @patch.object(np, "nanmax")
174
- def test_normalize_array_exception_error_mocked(self, nanmax_mocked, nanmin_mocked):
175
- nanmax_mocked.return_value = 100
176
- nanmin_mocked.return_value = np.NaN
177
-
178
- with self.assertRaises(ValueError):
179
- try:
180
- raster_helpers.normalize_array(
181
- np.arange(25).reshape((5, 5))
182
- )
183
- except ValueError as ve:
184
- self.assertEqual("cannot convert float NaN to integer", str(ve))
185
- raise ve
186
-
187
- def test_normalize_array_value_error(self):
188
- with self.assertRaises(ValueError):
189
- try:
190
- raster_helpers.normalize_array(
191
- np.zeros((5, 5))
192
- )
193
- except ValueError as ve:
194
- self.assertEqual(
195
- "normalize_array::empty array '',h_min_arr:0.0,h_arr_max:0.0,h_diff:0.0, " 'dtype:float64.',
196
- str(ve)
197
- )
198
- raise ve
199
-
200
- def test_normalize_array_list(self):
201
- normalized_array = raster_helpers.normalize_array_list([channel0, channel1, channel2])
202
- hash_output = hash_calculate(normalized_array)
203
- assert hash_output == b'+6IbhIpyb3vPElTgqqPkQdIR0umf4uFP2c7t5IaBVvI='
204
-
205
- test_norm_list_output2 = raster_helpers.normalize_array_list(
206
- [channel0, channel1, channel2], exaggerations_list=[2.0, 3.0, 5.0])
207
- hash_variable2 = hash_calculate(test_norm_list_output2)
208
- assert hash_variable2 == b'yYCYWCKO3i8NYsWk/wgYOzSRRLSLUprEs7mChJkdL+A='
209
-
210
- def test_normalize_array_list_value_error(self):
211
- with self.assertRaises(ValueError):
212
- try:
213
- raster_helpers.normalize_array_list([])
214
- except ValueError as ve:
215
- self.assertEqual("input list can't be empty:[].", str(ve))
216
- raise ve
217
-
218
- def test_check_empty_array(self):
219
- a = np.zeros((10, 10))
220
- b = np.ones((10, 10))
221
- c = np.ones((10, 10)) * 2
222
- d = np.zeros((10, 10))
223
- d[1, 1] = np.nan
224
- e = np.ones((10, 10)) * 3
225
- e[1, 1] = np.nan
226
-
227
- self.assertTrue(raster_helpers.check_empty_array(a, 999))
228
- self.assertTrue(raster_helpers.check_empty_array(b, 0))
229
- self.assertTrue(raster_helpers.check_empty_array(c, 2))
230
- self.assertTrue(raster_helpers.check_empty_array(d, 0))
231
- self.assertTrue(raster_helpers.check_empty_array(e, 3))
232
- self.assertFalse(raster_helpers.check_empty_array(z, 3))
233
-
234
- def test_get_nextzen_terrain_rgb_formula(self):
235
- output = raster_helpers.get_nextzen_terrain_rgb_formula(channel0, channel1, channel2)
236
- hash_output = hash_calculate(output)
237
- assert hash_output == b'3KJ81YKmQRdccRZARbByfwo1iMVLj8xxz9mfsWki/qA='
238
-
239
- def test_get_mapbox__terrain_rgb_formula(self):
240
- output = raster_helpers.get_mapbox__terrain_rgb_formula(channel0, channel1, channel2)
241
- hash_output = hash_calculate(output)
242
- assert hash_output == b'RU7CcoKoR3Fkh5LE+m48DHRVUy/vGq6UgfOFUMXx07M='
243
-
244
- def test_get_raster_terrain_rgb_like(self):
245
- from samgis_lisa_on_zero.utilities.type_hints import XYZTerrainProvidersNames
246
-
247
- arr_input = raster_helpers.get_rgb_image(channel0, channel1, channel2, invert_image=True)
248
- output_nextzen = raster_helpers.get_raster_terrain_rgb_like(
249
- arr_input, XYZTerrainProvidersNames.NEXTZEN_TERRAIN_TILES_NAME)
250
- hash_nextzen = hash_calculate(output_nextzen)
251
- assert hash_nextzen == b'+o2OTJliJkkBoqiAIGnhJ4s0xoLQ4MxHOvevLhNxysE='
252
- output_mapbox = raster_helpers.get_raster_terrain_rgb_like(
253
- arr_input, XYZTerrainProvidersNames.MAPBOX_TERRAIN_TILES_NAME)
254
- hash_mapbox = hash_calculate(output_mapbox)
255
- assert hash_mapbox == b'zWmekyKrpnmHnuDACnveCJl+o4GuhtHJmGlRDVwsce4='
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/io_package/test_tms2geotiff.py DELETED
@@ -1,138 +0,0 @@
1
- import unittest
2
-
3
- import numpy as np
4
- from samgis_core.utilities.utilities import hash_calculate
5
-
6
- from samgis_lisa_on_zero import app_logger
7
- from samgis_lisa_on_zero.io_package.tms2geotiff import download_extent
8
- from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
9
-
10
-
11
- input_bbox = [[39.036252959636606, 15.040283203125002], [38.302869955150044, 13.634033203125002]]
12
-
13
-
14
- class TestTms2geotiff(unittest.TestCase):
15
- # def test_download_extent_simple_source(self):
16
- # from rasterio import Affine
17
- # from xyzservices import TileProvider
18
- # from tests.local_tiles_http_server import LocalTilesHttpServer
19
- #
20
- # listen_port = 8000
21
- #
22
- # with LocalTilesHttpServer.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
23
- # pt0, pt1 = input_bbox
24
- # zoom = 10
25
- #
26
- # n_lat = pt0[0]
27
- # e_lng = pt0[1]
28
- # s_lat = pt1[0]
29
- # w_lng = pt1[1]
30
- #
31
- # source = TileProvider(name="local_tile_provider", url=LOCAL_URL_TILE, attribution="")
32
- # img, matrix = download_extent(w=w_lng, s=s_lat, e=e_lng, n=n_lat, zoom=zoom, source=source)
33
- # app_logger.info(f"# DOWNLOAD ENDED, shape: {img.shape} #")
34
- # np_img = np.ascontiguousarray(img)
35
- # output_hash = hash_calculate(np_img)
36
- # assert output_hash == b'UmbkwbPJpRT1XXcLnLUapUDP320w7YhS/AmT3H7u+b4='
37
- # assert Affine.to_gdal(matrix) == (
38
- # 1517657.1966021745, 152.8740565703525, 0.0, 4726942.266183584, 0.0, -152.87405657034955)
39
-
40
- def test_download_extent_source_with_parameter(self):
41
- from rasterio import Affine
42
- from xyzservices import TileProvider
43
- from tests.local_tiles_http_server import LocalTilesHttpServer
44
-
45
- listen_port = 8000
46
-
47
- with LocalTilesHttpServer.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
48
- pt0, pt1 = input_bbox
49
- zoom = 10
50
-
51
- n_lat = pt0[0]
52
- e_lng = pt0[1]
53
- s_lat = pt1[0]
54
- w_lng = pt1[1]
55
-
56
- local_url = "http://localhost:8000/{parameter}/{z}/{x}/{y}.png"
57
- download_extent_args_no_parameter = {"name": "local_tile_provider", "url": LOCAL_URL_TILE, "attribution": ""}
58
- download_extent_args = {
59
- "no_parameter": download_extent_args_no_parameter,
60
- "with_parameter": {"url": local_url, "parameter": "lambda_handler", **download_extent_args_no_parameter}
61
- }
62
- for _args_names, _args in download_extent_args.items():
63
- app_logger.info(f"args_names:{_args_names}.")
64
- source = TileProvider(**_args)
65
- img, matrix = download_extent(w=w_lng, s=s_lat, e=e_lng, n=n_lat, zoom=zoom, source=source)
66
- app_logger.info(f"# DOWNLOAD ENDED, shape: {img.shape} #")
67
- np_img = np.ascontiguousarray(img)
68
- output_hash = hash_calculate(np_img)
69
- assert output_hash == b'UmbkwbPJpRT1XXcLnLUapUDP320w7YhS/AmT3H7u+b4='
70
- assert Affine.to_gdal(matrix) == (
71
- 1517657.1966021745, 152.8740565703525, 0.0, 4726942.266183584, 0.0, -152.87405657034955)
72
-
73
- def test_download_extent_source_with_parameter_key_error(self):
74
- from xyzservices import TileProvider
75
-
76
- with self.assertRaises(KeyError):
77
- try:
78
- pt0, pt1 = input_bbox
79
- zoom = 10
80
-
81
- n_lat = pt0[0]
82
- e_lng = pt0[1]
83
- s_lat = pt1[0]
84
- w_lng = pt1[1]
85
-
86
- local_url_tile2 = "http://localhost:8000/{parameter}/{z}/{x}/{y}.png"
87
- source = TileProvider(name="local_tile_provider", url=local_url_tile2, attribution="")
88
- download_extent(w=w_lng, s=s_lat, e=e_lng, n=n_lat, zoom=zoom, source=source)
89
- except KeyError as ke:
90
- assert str(ke) == "'parameter'"
91
- raise ke
92
-
93
- def test_download_extent_io_error1(self):
94
-
95
- with self.assertRaises(Exception):
96
- try:
97
- pt0, pt1 = input_bbox
98
- zoom = 10
99
-
100
- n_lat = pt0[0]
101
- e_lng = pt0[1]
102
- s_lat = pt1[0]
103
- w_lng = pt1[1]
104
-
105
- download_extent(w=w_lng, s=s_lat, e=e_lng, n=n_lat, zoom=zoom, source=f"http://{LOCAL_URL_TILE}")
106
- print("exception not raised")
107
- except ConnectionError as ioe1:
108
- app_logger.error(f"ioe1:{ioe1}.")
109
- msg0 = "HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /lambda_handler"
110
- msg1 = "Caused by NewConnectionError"
111
- msg2 = ": Failed to establish a new connection: [Errno 61] Connection refused'))"
112
- assert msg0 in str(ioe1)
113
- assert msg1 in str(ioe1)
114
- assert msg2 in str(ioe1)
115
- raise ioe1
116
-
117
- def test_download_extent_io_error2(self):
118
- from requests import HTTPError
119
- from tests.local_tiles_http_server import LocalTilesHttpServer
120
-
121
- listen_port = 8000
122
- with LocalTilesHttpServer.http_server("localhost", listen_port, directory=TEST_EVENTS_FOLDER):
123
- pt0, pt1 = input_bbox
124
- zoom = 10
125
-
126
- with self.assertRaises(HTTPError):
127
- try:
128
- n_lat = pt0[0]
129
- e_lng = pt0[1]
130
- s_lat = pt1[0]
131
- w_lng = pt1[1]
132
-
133
- download_extent(w=w_lng, s=s_lat, e=e_lng, n=n_lat, zoom=zoom,
134
- source=LOCAL_URL_TILE + "_not_found_raster!")
135
- except HTTPError as http_e:
136
- app_logger.error(f"ae:{http_e}.")
137
- assert "Tile URL resulted in a 404 error. Double-check your tile url:" in str(http_e)
138
- raise http_e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/io_package/test_wrappers_helpers.py DELETED
@@ -1,78 +0,0 @@
1
- import json
2
- import unittest
3
- from unittest.mock import patch
4
-
5
- from samgis_lisa_on_zero.io_package import wrappers_helpers
6
- from samgis_lisa_on_zero.io_package.wrappers_helpers import get_parsed_bbox_points_with_dictlist_prompt
7
- from samgis_lisa_on_zero.utilities.type_hints import ApiRequestBody
8
- from tests import TEST_EVENTS_FOLDER
9
-
10
-
11
- class WrappersHelpersTest(unittest.TestCase):
12
- @staticmethod
13
- def test_get_parsed_bbox_other_inputs():
14
- for json_filename in ["single_rectangle", "multi_prompt"]:
15
- with open(TEST_EVENTS_FOLDER / f"get_parsed_bbox_prompts_{json_filename}.json") as tst_json:
16
- inputs_outputs = json.load(tst_json)
17
- parsed_input = ApiRequestBody.model_validate(inputs_outputs["input"])
18
- output = get_parsed_bbox_points_with_dictlist_prompt(parsed_input)
19
- assert output == inputs_outputs["output"]
20
-
21
- def test_get_parsed_bbox_points_with_string_prompt(self):
22
- from samgis_lisa_on_zero.io_package.wrappers_helpers import get_parsed_bbox_points_with_string_prompt
23
- req = {
24
- "bbox":{
25
- "ne":{"lat":46.17271333276639,"lng":10.079505443573},"sw":{"lat":46.1677724417049,"lng":10.068830251693727}
26
- },
27
- "string_prompt":"You are a ...",
28
- "zoom":17,
29
- "source_type":"Esri.WorldImagery"
30
- }
31
- print(req)
32
- out = get_parsed_bbox_points_with_string_prompt(json.dumps(req))
33
- assert isinstance(out, dict)
34
- for out_k, req_k in zip(out.keys(), req.keys()):
35
- assert isinstance(out_k, str)
36
- assert isinstance(req_k, str)
37
-
38
- @patch.object(wrappers_helpers, "providers")
39
- def test_get_url_tile(self, providers_mocked):
40
- import xyzservices
41
- from samgis_lisa_on_zero.io_package.wrappers_helpers import get_url_tile
42
-
43
- from tests import LOCAL_URL_TILE
44
-
45
- local_tile_provider = xyzservices.TileProvider(name="local_tile_provider", url=LOCAL_URL_TILE, attribution="")
46
- expected_output = {'name': 'local_tile_provider', 'url': LOCAL_URL_TILE, 'attribution': ''}
47
- providers_mocked.query_name.return_value = local_tile_provider
48
- assert get_url_tile("OpenStreetMap") == expected_output
49
-
50
- local_url = 'http://localhost:8000/{parameter}/{z}/{x}/{y}.png'
51
- local_tile_provider = xyzservices.TileProvider(
52
- name="local_tile_provider_param", url=local_url, attribution="", parameter="lamda_handler"
53
- )
54
- providers_mocked.query_name.return_value = local_tile_provider
55
- assert get_url_tile("OpenStreetMap.HOT") == {
56
- "parameter": "lamda_handler", 'name': 'local_tile_provider_param', 'url': local_url, 'attribution': ''
57
- }
58
-
59
- @staticmethod
60
- def test_get_url_tile_real():
61
- from samgis_lisa_on_zero.io_package.wrappers_helpers import get_url_tile
62
-
63
- assert get_url_tile("OpenStreetMap") == {
64
- 'url': 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'max_zoom': 19,
65
- 'html_attribution': '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
66
- 'attribution': '(C) OpenStreetMap contributors',
67
- 'name': 'OpenStreetMap.Mapnik'}
68
-
69
- html_attribution_hot = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, '
70
- html_attribution_hot += 'Tiles style by <a href="https://www.hotosm.org/" target="_blank">Humanitarian '
71
- html_attribution_hot += 'OpenStreetMap Team</a> hosted by <a href="https://openstreetmap.fr/" target="_blank">'
72
- html_attribution_hot += 'OpenStreetMap France</a>'
73
- attribution_hot = '(C) OpenStreetMap contributors, Tiles style by Humanitarian OpenStreetMap Team hosted by '
74
- attribution_hot += 'OpenStreetMap France'
75
- assert get_url_tile("OpenStreetMap.HOT") == {
76
- 'url': 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', 'max_zoom': 19,
77
- 'html_attribution': html_attribution_hot, 'attribution': attribution_hot, 'name': 'OpenStreetMap.HOT'
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/local_tiles_http_server.py DELETED
@@ -1,46 +0,0 @@
1
- import logging
2
- import time
3
- import unittest
4
-
5
-
6
- class LocalTilesHttpServer(unittest.TestCase):
7
- from contextlib import contextmanager
8
-
9
- @staticmethod
10
- @contextmanager
11
- def http_server(host: str, port: int, directory: str):
12
- """Function http_server defined within this test class to avoid pytest error "fixture 'host' not found"."""
13
- from functools import partial
14
- from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
15
- from threading import Thread
16
-
17
- server = ThreadingHTTPServer(
18
- (host, port), partial(SimpleHTTPRequestHandler, directory=directory)
19
- )
20
- print("dir:", directory, "#")
21
- server_thread = Thread(target=server.serve_forever, name="http_server")
22
- server_thread.start()
23
- logging.info(f"listen:: host {host}, port {port}.")
24
-
25
- try:
26
- yield
27
- finally:
28
- server.shutdown()
29
- server_thread.join()
30
-
31
-
32
- if __name__ == '__main__':
33
- # from tests import TEST_ROOT_FOLDER
34
- from pathlib import Path
35
-
36
- PROJECT_ROOT_FOLDER = Path(globals().get("__file__", "./_")).absolute().parent.parent
37
-
38
- TEST_ROOT_FOLDER = PROJECT_ROOT_FOLDER / "tests"
39
- TEST_EVENTS_FOLDER = TEST_ROOT_FOLDER / "events"
40
-
41
- main_listen_port = 8000
42
- logging.info(f"http_basedir_serve: {TEST_ROOT_FOLDER}.")
43
- with LocalTilesHttpServer.http_server("localhost", main_listen_port, directory=str(TEST_ROOT_FOLDER)):
44
- time.sleep(1000)
45
- logging.info("""import time; time.sleep(10)""")
46
- # logging.info("Http server stopped.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/prediction_api/__init__.py DELETED
File without changes
tests/prediction_api/test_predictors.py DELETED
@@ -1,64 +0,0 @@
1
- import json
2
- from unittest.mock import patch
3
-
4
- import numpy as np
5
-
6
- from samgis_lisa_on_zero.prediction_api import predictors
7
- from samgis_lisa_on_zero.prediction_api.predictors import get_raster_inference, samexporter_predict
8
- from tests import TEST_EVENTS_FOLDER
9
-
10
-
11
- @patch.object(predictors, "SegmentAnythingONNX")
12
- def test_get_raster_inference(segment_anything_onnx_mocked):
13
- name_fn = "samexporter_predict"
14
-
15
- with open(TEST_EVENTS_FOLDER / f"{name_fn}.json") as tst_json:
16
- inputs_outputs = json.load(tst_json)
17
- for k, input_output in inputs_outputs.items():
18
- model_mocked = segment_anything_onnx_mocked()
19
-
20
- img = np.load(TEST_EVENTS_FOLDER / f"{name_fn}" / k / "img.npy")
21
- inference_out = np.load(TEST_EVENTS_FOLDER / f"{name_fn}" / k / "inference_out.npy")
22
- mask = np.load(TEST_EVENTS_FOLDER / f"{name_fn}" / k / "mask.npy")
23
- prompt = input_output["input"]["prompt"]
24
- model_name = input_output["input"]["model_name"]
25
-
26
- model_mocked.embed.return_value = np.array(img)
27
- model_mocked.embed.side_effect = None
28
- model_mocked.predict_masks.return_value = inference_out
29
- model_mocked.predict_masks.side_effect = None
30
- print(f"k:{k}.")
31
- output_mask, len_inference_out = get_raster_inference(
32
- img=img,
33
- prompt=prompt,
34
- models_instance=model_mocked,
35
- model_name=model_name
36
- )
37
- assert np.array_equal(output_mask, mask)
38
- assert len_inference_out == input_output["output"]["n_predictions"]
39
-
40
-
41
- @patch.object(predictors, "get_raster_inference")
42
- @patch.object(predictors, "SegmentAnythingONNX")
43
- @patch.object(predictors, "download_extent")
44
- @patch.object(predictors, "get_vectorized_raster_as_geojson")
45
- def test_samexporter_predict(
46
- get_vectorized_raster_as_geojson_mocked,
47
- download_extent_mocked,
48
- segment_anything_onnx_mocked,
49
- get_raster_inference_mocked
50
- ):
51
- """
52
- model_instance = SegmentAnythingONNX()
53
- img, matrix = download_extent(DEFAULT_TMS, pt0[0], pt0[1], pt1[0], pt1[1], zoom)
54
- transform = get_affine_transform_from_gdal(matrix)
55
- mask, n_predictions = get_raster_inference(img, prompt, models_instance, model_name)
56
- get_vectorized_raster_as_geojson(mask, matrix)
57
- """
58
- aff = 1, 2, 3, 4, 5, 6
59
- segment_anything_onnx_mocked.return_value = "SegmentAnythingONNX_instance"
60
- download_extent_mocked.return_value = np.zeros((10, 10)), aff
61
- get_raster_inference_mocked.return_value = np.ones((10, 10)), 1
62
- get_vectorized_raster_as_geojson_mocked.return_value = {"geojson": "{}", "n_shapes_geojson": 2}
63
- output = samexporter_predict(bbox=[[1, 2], [3, 4]], prompt=[{}], zoom=10, model_name_key="fastsam")
64
- assert output == {"n_predictions": 1, "geojson": "{}", "n_shapes_geojson": 2}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/{test_fastapi_app.py → test_app.py} RENAMED
@@ -4,19 +4,15 @@ import unittest
4
  from unittest.mock import patch
5
 
6
  from fastapi.testclient import TestClient
7
-
8
- from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
9
- from samgis_lisa_on_zero.io_package import wrappers_helpers
10
- from tests import TEST_EVENTS_FOLDER
11
- from tests.local_tiles_http_server import LocalTilesHttpServer
12
  import app
13
- from app import app
14
-
15
 
16
  infer_samgis = "/infer_samgis"
17
  response_status_code = "response.status_code:{}."
18
  response_body_loaded = "response.body_loaded:{}."
19
- client = TestClient(app)
20
  source = {
21
  'url': 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'max_zoom': 19,
22
  'html_attribution': '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
@@ -81,18 +77,18 @@ class TestFastapiApp(unittest.TestCase):
81
  body = response.json()
82
  assert body == {'msg': 'Error - Unprocessable Entity'}
83
 
84
- def test_index(self):
85
- import subprocess
86
-
87
- subprocess.run(["pnpm", "build"], cwd=PROJECT_ROOT_FOLDER / "static")
88
- subprocess.run(["pnpm", "tailwindcss", "-i", "./src/input.css", "-o", "./dist/output.css"],
89
- cwd=PROJECT_ROOT_FOLDER / "static")
90
- response = client.get("/")
91
- assert response.status_code == 200
92
- html_body = response.read().decode("utf-8")
93
- assert "html" in html_body
94
- assert "head" in html_body
95
- assert "body" in html_body
96
 
97
  def test_404(self):
98
  response = client.get("/404")
@@ -119,7 +115,7 @@ class TestFastapiApp(unittest.TestCase):
119
  assert body_loaded == {'success': False}
120
 
121
  @patch.object(time, "time")
122
- @patch.object(fastapi_wrapper, "samexporter_predict")
123
  def test_infer_samgis_500(self, samexporter_predict_mocked, time_mocked):
124
  time_mocked.return_value = 0
125
  samexporter_predict_mocked.side_effect = ValueError("I raise a value error!")
@@ -131,11 +127,12 @@ class TestFastapiApp(unittest.TestCase):
131
  print(response_body_loaded.format(body))
132
  assert body == {'msg': 'Error - Internal Server Error'}
133
 
134
- @patch.object(wrappers_helpers, "get_url_tile")
135
  @patch.object(time, "time")
136
  def test_infer_samgis_real_200(self, time_mocked, get_url_tile_mocked):
137
  import shapely
138
  import xyzservices
 
139
  from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
140
 
141
  time_mocked.return_value = 0
@@ -162,7 +159,7 @@ class TestFastapiApp(unittest.TestCase):
162
  assert len(output_geojson.geoms) == 3
163
 
164
  @patch.object(time, "time")
165
- @patch.object(fastapi_wrapper, "samexporter_predict")
166
  def test_infer_samgis_mocked_200(self, samexporter_predict_mocked, time_mocked):
167
  self.maxDiff = None
168
 
 
4
  from unittest.mock import patch
5
 
6
  from fastapi.testclient import TestClient
7
+ from samgis_web.web import web_helpers
 
 
 
 
8
  import app
9
+ from tests import TEST_EVENTS_FOLDER
10
+ from samgis_core.utilities import frontend_builder
11
 
12
  infer_samgis = "/infer_samgis"
13
  response_status_code = "response.status_code:{}."
14
  response_body_loaded = "response.body_loaded:{}."
15
+ client = TestClient(app.app)
16
  source = {
17
  'url': 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'max_zoom': 19,
18
  'html_attribution': '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
 
77
  body = response.json()
78
  assert body == {'msg': 'Error - Unprocessable Entity'}
79
 
80
+ # def test_index(self):
81
+ # import subprocess
82
+ #
83
+ # subprocess.run(["pnpm", "build"], cwd=PROJECT_ROOT_FOLDER / "static")
84
+ # subprocess.run(["pnpm", "tailwindcss", "-i", "./src/input.css", "-o", "./dist/output.css"],
85
+ # cwd=PROJECT_ROOT_FOLDER / "static")
86
+ # response = client.get("/")
87
+ # assert response.status_code == 200
88
+ # html_body = response.read().decode("utf-8")
89
+ # assert "html" in html_body
90
+ # assert "head" in html_body
91
+ # assert "body" in html_body
92
 
93
  def test_404(self):
94
  response = client.get("/404")
 
115
  assert body_loaded == {'success': False}
116
 
117
  @patch.object(time, "time")
118
+ @patch.object(app, "samexporter_predict")
119
  def test_infer_samgis_500(self, samexporter_predict_mocked, time_mocked):
120
  time_mocked.return_value = 0
121
  samexporter_predict_mocked.side_effect = ValueError("I raise a value error!")
 
127
  print(response_body_loaded.format(body))
128
  assert body == {'msg': 'Error - Internal Server Error'}
129
 
130
+ @patch.object(web_helpers, "get_url_tile")
131
  @patch.object(time, "time")
132
  def test_infer_samgis_real_200(self, time_mocked, get_url_tile_mocked):
133
  import shapely
134
  import xyzservices
135
+ from samgis_web.utilities.local_tiles_http_server import LocalTilesHttpServer
136
  from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
137
 
138
  time_mocked.return_value = 0
 
159
  assert len(output_geojson.geoms) == 3
160
 
161
  @patch.object(time, "time")
162
+ @patch.object(app, "samexporter_predict")
163
  def test_infer_samgis_mocked_200(self, samexporter_predict_mocked, time_mocked):
164
  self.maxDiff = None
165
 
tests/test_lambda_app.py DELETED
@@ -1,232 +0,0 @@
1
- import json
2
- import time
3
- import unittest
4
- from unittest.mock import patch
5
-
6
- from samgis_lisa_on_zero import IS_AWS_LAMBDA
7
-
8
- if IS_AWS_LAMBDA:
9
- try:
10
- from awslambdaric.lambda_context import LambdaContext
11
-
12
- from samgis_lisa_on_zero.io_package 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()