diff --git a/README.md b/README.md index 34e7d74..02c984c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # AHN CLI [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -[![Version: 1.0.0](https://img.shields.io/badge/Version-0.1.8-green.svg)](https://github.com/HideBa/ahn-cli/releases/tag/v0.1.8) +[![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-green.svg)](https://github.com/HideBa/ahn-cli/releases/tag/v0.2.0) [![CICD Status: Passing](https://img.shields.io/badge/CICD-Passing-brightgreen.svg)](https://github.com/HideBa/ahn-cli/actions) ## Description diff --git a/ahn_cli/main.py b/ahn_cli/main.py index ba1d0d7..40a7754 100644 --- a/ahn_cli/main.py +++ b/ahn_cli/main.py @@ -9,8 +9,8 @@ """ Options: - -c, --city Specify the name of the city to download point cloud data for. - -o, --output Set the name of the output file where the data will be saved. + -c, --city Required (when bbox is None): Specify the name of the city to download point cloud data for. + -o, --output Required: Set the name of the output file where the data will be saved. -i, --include-class Include specific point cloud classes in the download. Classes should be specified in a comma-separated list. -e, --exclude-class Exclude specific point cloud classes from the download. @@ -20,7 +20,7 @@ -cf, --clip-file Specify a file path to a clipping boundary file. The tool will use this file to clip the point cloud data to a specific area. -e, --epsg Set the EPSG code for user's clip file. - -b, --bbox Specify a bounding box to clip the point cloud data. It should be comma-separated list with minx,miny,maxx,maxy + -b, --bbox Required (when city is None): Specify a bounding box to clip the point cloud data. It should be comma-separated list with minx,miny,maxx,maxy -p, --preview Preview the point cloud data in a 3D viewer. -h, --help [category] Display help information. Optionally, specify a category to get more detailed help for a specific command. @@ -29,11 +29,12 @@ @click.command() -@click.version_option(version="0.1.8", prog_name="ahn_cli") +@click.version_option(version="0.2.0", prog_name="ahn_cli") @click.option( "-o", "--output", type=str, + required=True, help="Set the name of the output file where the data will be saved.", ) @click.option( diff --git a/ahn_cli/validator.py b/ahn_cli/validator.py index 0ff3bd9..b613990 100644 --- a/ahn_cli/validator.py +++ b/ahn_cli/validator.py @@ -1,25 +1,27 @@ import os import geopandas as gpd - +from click import ClickException from ahn_cli import config -AHN_CLASSES = [0, 1, 2, 6, 7, 4, 6] +AHN_CLASSES = [0, 1, 2, 6, 9, 14, 26] def validate_output(output: str) -> str: if output is None: - raise ValueError("Output path is required.") + raise ClickException("Output path is required.") if not os.path.exists(os.path.dirname(output)): - raise ValueError("Output directory does not exist.") + raise ClickException("Output directory does not exist.") return output def validate_city(cityname: str, cityfile_path: str) -> str: if cityname is None: - raise ValueError("City name is required.") + raise ClickException("City name is required.") city_df = gpd.read_file(cityfile_path) if cityname.lower() not in city_df["name"].str.lower().tolist(): - raise ValueError("City name not found in city list.") + raise ClickException( + "City name not found in city list. Please check if city name is correct." + ) return cityname @@ -28,7 +30,7 @@ def validate_include_classes(classes: list[int] | None) -> list[int] | None: return None for c in classes: if c not in AHN_CLASSES: - raise ValueError(f"Class {c} is not a valid AHN class.") + raise ClickException(f"Class {c} is not a valid AHN class.") return classes @@ -37,7 +39,7 @@ def validate_exclude_classes(classes: list[int] | None) -> list[int] | None: return None for c in classes: if c not in AHN_CLASSES: - raise ValueError(f"Class {c} is not a valid AHN class.") + raise ClickException(f"Class {c} is not a valid AHN class.") return classes @@ -48,7 +50,7 @@ def validate_include_exclude( return for c in include_classes: if c in exclude_classes: - raise ValueError( + raise ClickException( f"Class {c} is in both include and exclude classes." ) @@ -57,7 +59,7 @@ def validate_clip_file(clip_file: str | None) -> str | None: if clip_file is None: return None if not os.path.exists(clip_file): - raise ValueError("Clip file does not exist.") + raise ClickException("Clip file does not exist.") return clip_file @@ -65,7 +67,7 @@ def validate_epsg(epsg: int | None) -> int | None: if epsg is None: return None if epsg < 1000 or epsg > 999999: - raise ValueError("EPSG code is not valid.") + raise ClickException("EPSG code is not valid.") return epsg @@ -73,7 +75,7 @@ def validate_decimate(decimate: int | None) -> int | None: if decimate is None: return None if decimate < 1: - raise ValueError("Decimate must be greater than 0.") + raise ClickException("Decimate must be greater than 0.") return decimate @@ -81,12 +83,19 @@ def validate_bbox(bbox: list[float] | None) -> list[float] | None: if bbox is None: return None if len(bbox) != 4: - raise ValueError("Bounding box must have 4 coordinates.") + raise ClickException("Bounding box must have 4 coordinates.") if bbox[0] >= bbox[2] or bbox[1] >= bbox[3]: - raise ValueError("Bounding box coordinates are not valid.") + raise ClickException("Bounding box coordinates are not valid.") return bbox +def validate_exclusive_args(bbox: list[float] | None, cityname: str) -> None: + if bbox is not None and cityname is not None: + raise ClickException( + "Cannot specify both a bounding box and a city name." + ) + + def validate_all( cfg: config.Config, output_path: str, @@ -109,4 +118,5 @@ def validate_all( validate_epsg(epsg) validate_decimate(decimate) validate_bbox(bbox) + validate_exclusive_args(bbox, city_name) return True diff --git a/pyproject.toml b/pyproject.toml index 46f904e..c9a9bbc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ahn_cli" -version = "0.1.8" +version = "0.2.0" description = "" authors = ["HideBa "] license = "MIT" diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..1f89fac --- /dev/null +++ b/renovate.json @@ -0,0 +1,42 @@ +{ + "extends": [ + "config:base" + ], + "prConcurrentLimit": 0, + "rebaseWhen": "never", + "masterIssue": true, + "poetry": { + "fileMatch": [ + "pyproject.toml" + ] + }, + "pip_requirements": { + "fileMatch": [ + "requirements.txt" + ] + }, + "ignorePaths": [], + "packageRules": [ + { + "matchUpdateTypes": [ + "minor" + ], + "extends": [ + "schedule:monthly" + ] + }, + { + "matchUpdateTypes": [ + "patch" + ], + "extends": [ + "schedule:quarterly" + ] + } + ], + "vulnerabilityAlerts": { + "schedule": [ + "at any time" + ] + } +} \ No newline at end of file