From 27d74723b2f436d7e9814c715e8a36a4c3a40d21 Mon Sep 17 00:00:00 2001 From: JCruiz15 Date: Mon, 24 Jun 2024 15:42:14 +0200 Subject: [PATCH] feat: Console client, file created --- .gitignore | 3 +- sigpac_tools/__main__.py | 207 +++++++++++++++++++++++++++++++++++++++ sigpac_tools/anotate.py | 4 +- sigpac_tools/locate.py | 10 +- sigpac_tools/utils.py | 2 +- tests/test_locate.py | 43 ++++++-- 6 files changed, 253 insertions(+), 16 deletions(-) create mode 100644 sigpac_tools/__main__.py diff --git a/.gitignore b/.gitignore index ec45caf..54a731d 100644 --- a/.gitignore +++ b/.gitignore @@ -169,5 +169,4 @@ cython_debug/ # Others *inspo* -wip-file* -__main__.py \ No newline at end of file +wip-file* \ No newline at end of file diff --git a/sigpac_tools/__main__.py b/sigpac_tools/__main__.py new file mode 100644 index 0000000..51d2e43 --- /dev/null +++ b/sigpac_tools/__main__.py @@ -0,0 +1,207 @@ +import argparse +import structlog + +logger = structlog.get_logger() + + +def get_parser(): + parser = argparse.ArgumentParser(description="SIGPAC Tools") + + subparsers = parser.add_subparsers(dest="command", help="Available commands") + subparsers.required = True + + # Search command + + search_parser = subparsers.add_parser( + "search", help="Search for a reference in the SIGPAC database" + ) + search_parser.add_argument( + "--community", + type=int, + help="Community of the location", + required=False, + metavar="INT", + ) + search_parser.add_argument( + "--province", + type=int, + help="Province of the location", + required=False, + metavar="INT", + ) + search_parser.add_argument( + "--municipality", + type=int, + help="Municipality of the location", + required=False, + metavar="INT", + ) + search_parser.add_argument( + "--polygon", + type=int, + help="Polygon of the location", + required=False, + metavar="INT", + ) + search_parser.add_argument( + "--parcel", + type=int, + help="Parcel of the location", + required=False, + metavar="INT", + ) + + # Locate command + + geom_parser = subparsers.add_parser( + "geometry", + help="Locate a geometry given the coordinates in the SIGPAC database", + ) + geom_parser.add_argument( + "--layer", + choices=["parcela", "recinto"], + help="Layer to search from", + metavar="STRING", + required=True, + ) + geom_parser.add_argument( + "--lat", + type=float, + help="Latitude of the location", + metavar="FLOAT", + required=True, + ) + geom_parser.add_argument( + "--lon", + type=float, + help="Longitude of the location", + metavar="FLOAT", + required=True, + ) + geom_parser.add_argument( + "--reference", + type=int, + help="Reference to search for", + required=False, + metavar="INT", + ) + + # Get metadata command + + annotate_parser = subparsers.add_parser( + "get-metadata", help="Get metadata of a location in the SIGPAC database" + ) + annotate_parser.add_argument( + "--layer", + choices=["parcela", "recinto"], + help="Layer to search from", + metavar="STRING", + required=True, + ) + annotate_parser.add_argument( + "--province", + type=int, + help="Province of the location", + metavar="INT", + required=True, + ) + annotate_parser.add_argument( + "--aggregate", + type=int, + default=0, + help="Aggregate of the location", + metavar="INT", + ) + annotate_parser.add_argument( + "--zone", type=int, default=0, help="Zone of the location", metavar="INT" + ) + annotate_parser.add_argument( + "--municipality", + type=int, + help="Municipality of the location", + metavar="INT", + required=True, + ) + annotate_parser.add_argument( + "--polygon", + type=int, + help="Polygon of the location", + metavar="INT", + required=True, + ) + annotate_parser.add_argument( + "--parcel", + type=int, + help="Parcel of the location", + metavar="INT", + required=True, + ) + annotate_parser.add_argument( + "--enclosure", + type=int, + help="Enclosure of the location", + required=False, + metavar="INT", + ) + + return parser + + +def main(): + args, _ = get_parser().parse_known_args() + + match args.command: + case "search": + from sigpac_tools.search import search + import json + + data = { + "community": args.community, + "province": args.province, + "municipality": args.municipality, + "polygon": args.polygon, + "parcel": args.parcel, + } + search_res = search(data) + logger.info(f"Search results:\n{json.dumps(search_res, indent=2)}") + return search_res + + case "geometry": + from sigpac_tools.locate import geometry_from_coords + import json + + print(args) + + layer = args.layer + lat = args.lat + lon = args.lon + reference = args.reference + geom = geometry_from_coords(layer, lat, lon, reference) + logger.info( + f"Geometry for coords ({lat}, {lon}):\n{json.dumps(geom, indent=2)}" + ) + return geom + + case "get-metadata": + from sigpac_tools.anotate import get_metadata + import json + + layer = args.layer + data = { + "province": args.province, + "aggregate": args.aggregate, + "zone": args.zone, + "municipality": args.municipality, + "polygon": args.polygon, + "parcel": args.parcel, + "enclosure": args.enclosure, + } + metadata = get_metadata(layer, data) + logger.info(f"Metadata:\n{json.dumps(metadata, indent=2)}") + return metadata + case _: + raise ValueError("Invalid command") + + +if __name__ == "__main__": + main() diff --git a/sigpac_tools/anotate.py b/sigpac_tools/anotate.py index c610867..9870cff 100644 --- a/sigpac_tools/anotate.py +++ b/sigpac_tools/anotate.py @@ -122,7 +122,9 @@ def get_metadata(layer: str, data: dict): if not encl and layer == "recinto": raise ValueError("Enclosure not specified") - logger.info(f"Searching for the metadata of the location (province {prov}, municipality {muni}, polygon {polg}, parcel {parc}) in the SIGPAC database...") + logger.info( + f"Searching for the metadata of the location (province {prov}, municipality {muni}, polygon {polg}, parcel {parc}) in the SIGPAC database..." + ) return __query( layer=layer, province=prov, diff --git a/sigpac_tools/locate.py b/sigpac_tools/locate.py index e161e7b..c4d1719 100644 --- a/sigpac_tools/locate.py +++ b/sigpac_tools/locate.py @@ -58,8 +58,8 @@ def geometry_from_coords(layer: str, lat: float, lon: float, reference: int) -> KeyError If the layer is not supported """ - if not layer or not lat or not lon or not reference: - raise ValueError("Layer, latitude, longitude or reference not specified") + if not layer or not lat or not lon: + raise ValueError("Layer, latitude or longitude not specified") tile_x, tile_y = lng_lat_to_tile(lon, lat, 15) @@ -69,6 +69,12 @@ def geometry_from_coords(layer: str, lat: float, lon: float, reference: int) -> geojson_features = response.json() + if not reference: + logger.info( + f"No reference specified. Returning all features in the layer {layer} for coordinates ({lat}, {lon})" + ) + return geojson_features + if layer in ["parcela", "recinto"]: logger.info(f"Searching for reference {reference} in the layer {layer}...") result = __locate_in_feature_collection( diff --git a/sigpac_tools/utils.py b/sigpac_tools/utils.py index 0727da9..729a1e2 100644 --- a/sigpac_tools/utils.py +++ b/sigpac_tools/utils.py @@ -15,7 +15,7 @@ def lng_lat_to_tile(lng: float, lat: float, zoom: float) -> tuple[int, int]: Latitude of the location zoom : float Zoom level to get the tile coordinates - + Returns ------- tuple[int, int] diff --git a/tests/test_locate.py b/tests/test_locate.py index ea2c493..9bf69c7 100644 --- a/tests/test_locate.py +++ b/tests/test_locate.py @@ -21,11 +21,14 @@ ], } + class TestGeometryFromCoords: @patch("sigpac_tools.locate.requests.get") @patch("sigpac_tools.locate.lng_lat_to_tile") @patch("sigpac_tools.locate.transform_coords") - def test_geometry_from_coords_parcela(self, mock_transform_coords, mock_lng_lat_to_tile, mock_get): + def test_geometry_from_coords_parcela( + self, mock_transform_coords, mock_lng_lat_to_tile, mock_get + ): mock_lng_lat_to_tile.return_value = (1234, 5678) mock_response = Mock() mock_response.json.return_value = mock_geojson_response @@ -39,14 +42,18 @@ def test_geometry_from_coords_parcela(self, mock_transform_coords, mock_lng_lat_ result = geometry_from_coords(layer, lat, lon, reference) mock_lng_lat_to_tile.assert_called_once_with(lon, lat, 15) - mock_get.assert_called_once_with(f"{BASE_URL}/vectorsdg/vector/parcela@3857/15.1234.5678.geojson") + mock_get.assert_called_once_with( + f"{BASE_URL}/vectorsdg/vector/parcela@3857/15.1234.5678.geojson" + ) mock_transform_coords.assert_called_once() assert result == mock_geojson_response["features"][0]["geometry"] @patch("sigpac_tools.locate.requests.get") @patch("sigpac_tools.locate.lng_lat_to_tile") @patch("sigpac_tools.locate.transform_coords") - def test_geometry_from_coords_recinto(self, mock_transform_coords, mock_lng_lat_to_tile, mock_get): + def test_geometry_from_coords_recinto( + self, mock_transform_coords, mock_lng_lat_to_tile, mock_get + ): mock_lng_lat_to_tile.return_value = (1234, 5678) mock_response = Mock() mock_response.json.return_value = mock_geojson_response @@ -60,7 +67,9 @@ def test_geometry_from_coords_recinto(self, mock_transform_coords, mock_lng_lat_ result = geometry_from_coords(layer, lat, lon, reference) mock_lng_lat_to_tile.assert_called_once_with(lon, lat, 15) - mock_get.assert_called_once_with(f"{BASE_URL}/vectorsdg/vector/recinto@3857/15.1234.5678.geojson") + mock_get.assert_called_once_with( + f"{BASE_URL}/vectorsdg/vector/recinto@3857/15.1234.5678.geojson" + ) mock_transform_coords.assert_called_once() assert result == mock_geojson_response["features"][0]["geometry"] @@ -80,22 +89,36 @@ def test_geometry_not_found(self, mock_lng_lat_to_tile, mock_get): result = geometry_from_coords(layer, lat, lon, reference) mock_lng_lat_to_tile.assert_called_once_with(lon, lat, 15) - mock_get.assert_called_once_with(f"{BASE_URL}/vectorsdg/vector/parcela@3857/15.1234.5678.geojson") + mock_get.assert_called_once_with( + f"{BASE_URL}/vectorsdg/vector/parcela@3857/15.1234.5678.geojson" + ) assert result is None def test_invalid_layer(self): - with pytest.raises(KeyError, match='Layer "invalid" not supported. Supported layers: "parcela", "recinto"'): + with pytest.raises( + KeyError, + match='Layer "invalid" not supported. Supported layers: "parcela", "recinto"', + ): geometry_from_coords("invalid", 40.0, -3.0, 123) def test_missing_parameters(self): - with pytest.raises(ValueError, match="Layer, latitude, longitude or reference not specified"): + with pytest.raises( + ValueError, match="Layer, latitude, longitude or reference not specified" + ): geometry_from_coords("", 40.0, -3.0, 123) - with pytest.raises(ValueError, match="Layer, latitude, longitude or reference not specified"): + with pytest.raises( + ValueError, match="Layer, latitude, longitude or reference not specified" + ): geometry_from_coords("parcela", None, -3.0, 123) - with pytest.raises(ValueError, match="Layer, latitude, longitude or reference not specified"): + with pytest.raises( + ValueError, match="Layer, latitude, longitude or reference not specified" + ): geometry_from_coords("parcela", 40.0, None, 123) - with pytest.raises(ValueError, match="Layer, latitude, longitude or reference not specified"): + with pytest.raises( + ValueError, match="Layer, latitude, longitude or reference not specified" + ): geometry_from_coords("parcela", 40.0, -3.0, None) + if __name__ == "__main__": pytest.main()