Skip to content

Commit b0f364d

Browse files
Chuan1937seisman
andauthored
BREAKING: Raise GMTParameterError exception for missing required parameters. Previously raise GMTInvalidInput (#4374)
Co-authored-by: Dongdong Tian <seisman.info@gmail.com>
1 parent 3100302 commit b0f364d

34 files changed

Lines changed: 144 additions & 100 deletions

doc/api/index.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,15 @@ All custom exceptions are derived from :class:`pygmt.exceptions.GMTError`.
293293
:toctree: generated
294294

295295
exceptions.GMTError
296-
exceptions.GMTInvalidInput
297-
exceptions.GMTVersionError
298-
exceptions.GMTOSError
299296
exceptions.GMTCLibError
300297
exceptions.GMTCLibNoSessionError
301298
exceptions.GMTCLibNotFoundError
299+
exceptions.GMTInvalidInput
300+
exceptions.GMTOSError
301+
exceptions.GMTParameterError
302302
exceptions.GMTTypeError
303303
exceptions.GMTValueError
304+
exceptions.GMTVersionError
304305

305306

306307
.. currentmodule:: pygmt

pygmt/datasets/load_remote_dataset.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing import Any, Literal, NamedTuple
88

99
import xarray as xr
10-
from pygmt.exceptions import GMTInvalidInput, GMTValueError
10+
from pygmt.exceptions import GMTParameterError, GMTValueError
1111

1212
with contextlib.suppress(ImportError):
1313
# rioxarray is needed to register the rio accessor
@@ -564,11 +564,10 @@ def _load_remote_dataset(
564564
reg = registration[0]
565565

566566
if resinfo.tiled and region is None:
567-
msg = (
568-
f"The 'region' parameter is required for {dataset.description} "
569-
f"resolution '{resolution}'."
567+
raise GMTParameterError(
568+
required="region",
569+
reason=f"Required for {dataset.description} resolution {resolution!r}.",
570570
)
571-
raise GMTInvalidInput(msg)
572571

573572
fname = f"@{prefix}_{resolution}_{reg}"
574573
grid = xr.load_dataarray(

pygmt/exceptions.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,35 @@ def __init__(self, dtype: object, /, reason: str | None = None):
130130
if reason:
131131
msg += f" {reason}"
132132
super().__init__(msg)
133+
134+
135+
class GMTParameterError(GMTError):
136+
"""
137+
Raised when parameters are missing or invalid.
138+
139+
Parameters
140+
----------
141+
required
142+
Name or a set of names of required parameters.
143+
reason
144+
Detailed reason why the parameters are invalid.
145+
"""
146+
147+
def __init__(
148+
self,
149+
*,
150+
required: str | set[str] | None = None,
151+
reason: str | None = None,
152+
):
153+
msg = []
154+
if required:
155+
if isinstance(required, str):
156+
msg.append(f"Missing required parameter: {required!r}.")
157+
else:
158+
msg.append(
159+
"Missing required parameters: "
160+
f"{', '.join(repr(par) for par in required)}."
161+
)
162+
if reason:
163+
msg.append(reason)
164+
super().__init__(" ".join(msg))

pygmt/helpers/validators.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Literal
77

88
from pygmt._typing import PathLike
9-
from pygmt.exceptions import GMTInvalidInput, GMTValueError
9+
from pygmt.exceptions import GMTParameterError, GMTValueError
1010

1111

1212
def validate_output_table_type(
@@ -43,7 +43,7 @@ def validate_output_table_type(
4343
>>> validate_output_table_type("file", outfile=None)
4444
Traceback (most recent call last):
4545
...
46-
pygmt.exceptions.GMTInvalidInput: Must specify 'outfile' for output_type='file'.
46+
pygmt.exceptions.GMTParameterError: Missing required parameter: 'outfile'. ...
4747
>>> with warnings.catch_warnings(record=True) as w:
4848
... validate_output_table_type("pandas", outfile="not-none.txt")
4949
... assert len(w) == 1
@@ -57,8 +57,9 @@ def validate_output_table_type(
5757
choices=_valids,
5858
)
5959
if output_type == "file" and outfile is None:
60-
msg = "Must specify 'outfile' for output_type='file'."
61-
raise GMTInvalidInput(msg)
60+
raise GMTParameterError(
61+
required="outfile", reason="Required when output_type='file'."
62+
)
6263
if output_type != "file" and outfile is not None:
6364
msg = (
6465
f"Changing 'output_type' from '{output_type}' to 'file' since 'outfile' "

pygmt/params/box.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from collections.abc import Sequence
77

88
from pygmt.alias import Alias
9-
from pygmt.exceptions import GMTInvalidInput, GMTValueError
9+
from pygmt.exceptions import GMTParameterError, GMTValueError
1010
from pygmt.helpers import is_nonstr_iter
1111
from pygmt.params.base import BaseParam
1212

@@ -65,8 +65,9 @@ def _validate(self):
6565
"""
6666
# inner_pen is required when inner_gap is set.
6767
if self.inner_gap is not None and self.inner_pen is None:
68-
msg = "Parameter 'inner_pen' is required when 'inner_gap' is set."
69-
raise GMTInvalidInput(msg)
68+
raise GMTParameterError(
69+
required="inner_pen", reason="Required when 'inner_gap' is set."
70+
)
7071

7172
# shade_offset must be a sequence of two values or None.
7273
if self.shade_offset and not (

pygmt/src/filter1d.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pygmt._typing import PathLike, TableLike
1010
from pygmt.alias import AliasSystem
1111
from pygmt.clib import Session
12-
from pygmt.exceptions import GMTInvalidInput
12+
from pygmt.exceptions import GMTParameterError
1313
from pygmt.helpers import (
1414
build_arg_list,
1515
fmt_docstring,
@@ -112,8 +112,7 @@ def filter1d(
112112
(depends on ``output_type``)
113113
"""
114114
if kwargs.get("F") is None:
115-
msg = "Pass a required argument to 'filter_type'."
116-
raise GMTInvalidInput(msg)
115+
raise GMTParameterError(required="filter_type")
117116

118117
output_type = validate_output_table_type(output_type, outfile=outfile)
119118

pygmt/src/grdgradient.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pygmt._typing import PathLike
1010
from pygmt.alias import Alias, AliasSystem
1111
from pygmt.clib import Session
12-
from pygmt.exceptions import GMTInvalidInput
12+
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
1313
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias
1414

1515
__doctest_skip__ = ["grdgradient"]
@@ -166,8 +166,9 @@ def grdgradient(
166166
>>> new_grid = pygmt.grdgradient(grid=grid, azimuth=10)
167167
"""
168168
if kwargs.get("Q") is not None and kwargs.get("N") is None:
169-
msg = "Must specify normalize if tiles is specified."
170-
raise GMTInvalidInput(msg)
169+
raise GMTParameterError(
170+
required="normalize", reason="Required when 'tiles' is set."
171+
)
171172
if (
172173
kwargs.get("A", azimuth) is None
173174
and kwargs.get("D") is None

pygmt/src/grdlandmask.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pygmt._typing import PathLike
1010
from pygmt.alias import Alias, AliasSystem
1111
from pygmt.clib import Session
12-
from pygmt.exceptions import GMTInvalidInput
12+
from pygmt.exceptions import GMTParameterError
1313
from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias
1414

1515
__doctest_skip__ = ["grdlandmask"]
@@ -119,8 +119,7 @@ def grdlandmask(
119119
>>> landmask = pygmt.grdlandmask(spacing=1, region=[125, 130, 30, 35])
120120
"""
121121
if kwargs.get("I", spacing) is None or kwargs.get("R", region) is None:
122-
msg = "Both 'region' and 'spacing' must be specified."
123-
raise GMTInvalidInput(msg)
122+
raise GMTParameterError(required={"region", "spacing"})
124123

125124
aliasdict = AliasSystem(
126125
D=Alias(

pygmt/src/grdproject.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pygmt._typing import PathLike
1010
from pygmt.alias import Alias, AliasSystem
1111
from pygmt.clib import Session
12-
from pygmt.exceptions import GMTInvalidInput
12+
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
1313
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias
1414

1515
__doctest_skip__ = ["grdproject"]
@@ -118,8 +118,7 @@ def grdproject( # noqa: PLR0913
118118
>>> new_grid = pygmt.grdproject(grid=grid, projection="M10c", region=region)
119119
"""
120120
if kwargs.get("J", projection) is None:
121-
msg = "Parameter 'projection' must be specified."
122-
raise GMTInvalidInput(msg)
121+
raise GMTParameterError(required="projection")
123122

124123
if kwargs.get("M", unit) is not None and kwargs.get("F", scaling) is not False:
125124
msg = "Cannot use both 'unit' and 'scaling'."

pygmt/src/grdtrack.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pygmt._typing import PathLike, TableLike
1212
from pygmt.alias import AliasSystem
1313
from pygmt.clib import Session
14-
from pygmt.exceptions import GMTInvalidInput
14+
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
1515
from pygmt.helpers import (
1616
build_arg_list,
1717
fmt_docstring,
@@ -307,8 +307,9 @@ def grdtrack(
307307
raise GMTInvalidInput(msg)
308308

309309
if hasattr(points, "columns") and newcolname is None:
310-
msg = "Please pass in a str to 'newcolname'."
311-
raise GMTInvalidInput(msg)
310+
raise GMTParameterError(
311+
required="newcolname", reason="Pass in a string to 'newcolname'."
312+
)
312313

313314
output_type = validate_output_table_type(output_type, outfile=outfile)
314315

0 commit comments

Comments
 (0)