Skip to content

Commit

Permalink
restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
mrsmrynk committed Dec 16, 2023
1 parent 5578aa1 commit 60b6b70
Show file tree
Hide file tree
Showing 20 changed files with 561 additions and 598 deletions.
3 changes: 2 additions & 1 deletion src/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .remote_sensing_data_downloader import *
from .remote_sensing_data_fetcher import RemoteSensingDataFetcher
from .web_map_service import WebMapService, WebMapServiceProtocol
113 changes: 113 additions & 0 deletions src/data/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from natsort import natsorted


class WMSError(Exception):

def __init__(self,
message='Invalid web map service in the config!'):
"""
| Initializer method
:param str message: message
:returns: None
:rtype: None
"""
super().__init__(message)


class WMSConnectionError(WMSError):

def __init__(self,
url,
passed_exception):
"""
| Initializer method
:param str url: url
:param Exception passed_exception: passed exception
:returns: None
:rtype: None
"""
message = (
'Invalid url in the config!\n'
f'An exception is raised while connecting to the web map service ({url}).\n'
f'{passed_exception}')

super().__init__(message)


class WMSEPSGCodeError(WMSError):

def __init__(self,
epsg_code,
epsg_codes_valid):
"""
| Initializer method
:param int epsg_code: epsg code
:param list[int] epsg_codes_valid: valid epsg codes
:returns: None
:rtype: None
"""
if len(epsg_codes_valid) == 1:
epsg_codes_valid = epsg_codes_valid[0]
else:
epsg_codes_valid = natsorted(epsg_codes_valid)

epsg_codes_valid = (
f"{', '.join(map(str, epsg_codes_valid[:-1]))} "
f'or {epsg_codes_valid[-1]}')

message = (
'Invalid epsg_code in the config!\n'
f'Expected {epsg_codes_valid}, got {epsg_code} instead.')

super().__init__(message)


class WMSFetchingError(WMSError):

def __init__(self,
url,
passed_exception):
"""
| Initializer method
:param str url: url
:param Exception passed_exception: passed exception
:returns: None
:rtype: None
"""
message = (
f'An exception is raised while fetching the image from the web map service ({url}).\n'
f'{passed_exception}')

super().__init__(message)


class WMSLayerError(WMSError):

def __init__(self,
layer,
layers_valid):
"""
| Initializer method
:param str layer: layer
:param list[str] layers_valid: valid layers
:returns: None
:rtype: None
"""
if len(layers_valid) == 1:
layers_valid = layers_valid[0]
else:
layers_valid = natsorted(layers_valid)
layers_valid = (
f"{', '.join(map(str, layers_valid[:-1]))} "
f'or {layers_valid[-1]}')

message = (
'Invalid layer in the config!\n'
f'Expected {layers_valid}, got {layer} instead.')

super().__init__(message)
110 changes: 0 additions & 110 deletions src/data/remote_sensing_data_downloader.py

This file was deleted.

100 changes: 100 additions & 0 deletions src/data/remote_sensing_data_fetcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import numpy as np # noqa: F401 (used for type hinting)

from src.utils.settings import (
IMAGE_SIZE,
IMAGE_SIZE_METERS,
PADDING_SIZE,
PADDING_SIZE_METERS)

from .web_map_service import WebMapServiceProtocol # noqa: F401 (used for type hinting)


class RemoteSensingDataFetcher:

def __init__(self,
web_map_service,
layer,
epsg_code):
"""
| Initializer method
:param WebMapServiceProtocol web_map_service: web map service
:param str layer: layer
:param int epsg_code: epsg code
:returns: None
:rtype: None
"""
assert isinstance(layer, str)

assert isinstance(epsg_code, int)

self.web_map_service = web_map_service
self.layer = layer
self.epsg_code = epsg_code

@staticmethod
def compute_bounding_box(coordinates,
apply_padding=False):
"""
| Returns the bounding box of a tile.
:param (int, int) coordinates: coordinates (x_min, y_max)
:param bool apply_padding: if True, the bounding box is increased by PADDING_SIZE_METERS
:returns: bounding box (x_min, y_min, x_max, y_max)
:rtype: (int, int, int, int)
"""
assert isinstance(coordinates, tuple)
assert len(coordinates) == 2
assert all(isinstance(coordinate, int) for coordinate in coordinates)

assert isinstance(apply_padding, bool)

x_min, y_max = coordinates

if apply_padding:
bounding_box = (
(x_min - PADDING_SIZE_METERS,
y_max - IMAGE_SIZE_METERS - PADDING_SIZE_METERS,
x_min + IMAGE_SIZE_METERS + PADDING_SIZE_METERS,
y_max + PADDING_SIZE_METERS))

else:
bounding_box = (
(x_min,
y_max - IMAGE_SIZE_METERS,
x_min + IMAGE_SIZE_METERS,
y_max))

return bounding_box

def fetch_image(self,
coordinates,
apply_padding=False):
"""
| Returns the fetched image.
:param (int, int) coordinates: coordinates (x_min, y_max)
:param bool apply_padding: if True, the image size is increased by PADDING_SIZE
:returns: fetched image
:rtype: np.ndarray[np.uint8]
"""
assert isinstance(coordinates, tuple)
assert len(coordinates) == 2
assert all(isinstance(coordinate, int) for coordinate in coordinates)

assert isinstance(apply_padding, bool)

bounding_box = self.compute_bounding_box(coordinates=coordinates,
apply_padding=apply_padding)

if apply_padding:
image_size = IMAGE_SIZE + 2 * PADDING_SIZE
else:
image_size = IMAGE_SIZE

image = self.web_map_service.fetch_image(layer=self.layer,
bounding_box=bounding_box,
image_size=image_size,
epsg_code=self.epsg_code)

return image
1 change: 0 additions & 1 deletion src/data/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
from .test_remote_sensing_data_downloader import *
49 changes: 22 additions & 27 deletions src/data/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,35 @@
import unittest.mock as mock

import pytest
from unittest import mock

from src.data.remote_sensing_data_downloader import RemoteSensingDataDownloader
from src.data.remote_sensing_data_fetcher import RemoteSensingDataFetcher
from src.data.web_map_service import WebMapServiceProtocol


@pytest.fixture(scope='session')
@mock.patch('src.data.remote_sensing_data_downloader.WebMapService', return_value=mock.MagicMock)
def remote_sensing_data_downloader_no_clip_border(_mocked_wms):
@pytest.fixture(scope='function')
def remote_sensing_data_fetcher_with_mocked_web_map_service(mocked_web_map_service):
"""
| Returns a remote_sensing_data_downloader instance.
| Border clipping is not used.
| Returns a remote sensing data fetcher object with a mocked web map service.
:returns: remote_sensing_data_downloader
:rtype: RemoteSensingDataDownloader
:param WebMapServiceProtocol mocked_web_map_service: mocked web map service fixture
:returns: remote sensing data fetcher fixture
:rtype: (RemoteSensingDataFetcher, WebMapServiceProtocol)
"""
remote_sensing_data_downloader = RemoteSensingDataDownloader(wms_url='https://www.wms.de/wms_url',
wms_layer='wms_layer',
epsg_code=25832,
clip_border=False)
remote_sensing_data_fetcher = RemoteSensingDataFetcher(web_map_service=mocked_web_map_service,
layer='test_layer',
epsg_code=25832)

return remote_sensing_data_downloader
return remote_sensing_data_fetcher, mocked_web_map_service


@pytest.fixture(scope='session')
@mock.patch('src.data.remote_sensing_data_downloader.WebMapService', return_value=mock.MagicMock)
def remote_sensing_data_downloader_clip_border(_mocked_wms):
@pytest.fixture(scope='function')
def mocked_web_map_service():
"""
| Returns a remote_sensing_data_downloader instance.
| Border clipping is used.
| Returns a mocked web map service object.
:returns: remote_sensing_data_downloader
:rtype: RemoteSensingDataDownloader
:returns: mocked web map service fixture
:rtype: WebMapServiceProtocol
"""
remote_sensing_data_downloader = RemoteSensingDataDownloader(wms_url='https://www.wms.de/wms_url',
wms_layer='wms_layer',
epsg_code=25832,
clip_border=True)

return remote_sensing_data_downloader
mocked_web_map_service = mock.Mock(spec=WebMapServiceProtocol)
mocked_web_map_service.url = 'https://wms.com'
return mocked_web_map_service
1 change: 0 additions & 1 deletion src/data/tests/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
from .data_test_get_bounding_box import *
Loading

0 comments on commit 60b6b70

Please sign in to comment.