Skip to content

Commit e9c164a

Browse files
Chuan1937seisman
andauthored
BREAKING: Raise GMTParameterError exception for as_most_one parameters. Previously raise GMTInvalidInput (#4383)
Co-authored-by: Dongdong Tian <seisman.info@gmail.com>
1 parent 30db887 commit e9c164a

21 files changed

+68
-80
lines changed

pygmt/exceptions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ class GMTParameterError(GMTError):
142142
Name or a set of names of required parameters.
143143
at_least_one
144144
A set of parameter names, of which at least one must be specified.
145+
at_most_one
146+
A set of mutually exclusive parameter names, of which at most one can be
147+
specified.
145148
reason
146149
Detailed reason why the parameters are invalid.
147150
"""
@@ -151,6 +154,7 @@ def __init__(
151154
*,
152155
required: str | set[str] | None = None,
153156
at_least_one: set[str] | None = None,
157+
at_most_one: set[str] | None = None,
154158
reason: str | None = None,
155159
):
156160
msg = []
@@ -167,6 +171,12 @@ def __init__(
167171
"Missing parameter: requires at least one of "
168172
f"{', '.join(repr(par) for par in at_least_one)}."
169173
)
174+
if at_most_one:
175+
msg.append(
176+
"Mutually exclusive parameters: "
177+
f"{', '.join(repr(par) for par in at_most_one)}. "
178+
"Specify at most one of them."
179+
)
170180
if reason:
171181
msg.append(reason)
172182
super().__init__(" ".join(msg))

pygmt/src/grd2cpt.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, fmt_docstring, kwargs_to_strings, use_alias
1414

1515
__doctest_skip__ = ["grd2cpt"]
@@ -199,8 +199,7 @@ def grd2cpt(
199199
>>> fig.show()
200200
"""
201201
if kwargs.get("W") is not None and kwargs.get("Ww") is not None:
202-
msg = "Set only 'categorical' or 'cyclic' to True, not both."
203-
raise GMTInvalidInput(msg)
202+
raise GMTParameterError(at_most_one={"categorical", "cyclic"})
204203

205204
if (output := kwargs.pop("H", None)) is not None:
206205
kwargs["H"] = True

pygmt/src/grdfill.py

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from pygmt._typing import PathLike
1111
from pygmt.alias import Alias, AliasSystem
1212
from pygmt.clib import Session
13-
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
13+
from pygmt.exceptions import GMTParameterError
1414
from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias
1515

1616
__doctest_skip__ = ["grdfill"]
@@ -31,41 +31,31 @@ def _validate_params(
3131
>>> _validate_params(constant_fill=20.0, grid_fill="bggrid.nc")
3232
Traceback (most recent call last):
3333
...
34-
pygmt.exceptions.GMTInvalidInput: Parameters ... are mutually exclusive.
34+
pygmt.exceptions.GMTParameterError: Mutually exclusive parameters: ...
3535
>>> _validate_params(constant_fill=20.0, inquire=True)
3636
Traceback (most recent call last):
3737
...
38-
pygmt.exceptions.GMTInvalidInput: Parameters ... are mutually exclusive.
38+
pygmt.exceptions.GMTParameterError: Mutually exclusive parameters: ...
3939
>>> _validate_params()
4040
Traceback (most recent call last):
4141
...
4242
pygmt.exceptions.GMTParameterError: Missing parameter: requires at least one ...
4343
"""
44-
_fill_params = "'constant_fill'/'grid_fill'/'neighbor_fill'/'spline_fill'"
45-
46-
n_given = sum(
47-
param is not None and param is not False
48-
for param in [
49-
constant_fill,
50-
grid_fill,
51-
neighbor_fill,
52-
spline_fill,
53-
inquire,
54-
]
55-
)
56-
if n_given > 1: # More than one mutually exclusive parameter is given.
57-
msg = f"Parameters {_fill_params}/'inquire' are mutually exclusive."
58-
raise GMTInvalidInput(msg)
59-
if n_given == 0: # No parameters are given.
60-
raise GMTParameterError(
61-
at_least_one={
62-
"constant_fill",
63-
"grid_fill",
64-
"neighbor_fill",
65-
"spline_fill",
66-
"inquire",
67-
}
68-
)
44+
params = {
45+
"constant_fill": constant_fill,
46+
"grid_fill": grid_fill,
47+
"neighbor_fill": neighbor_fill,
48+
"spline_fill": spline_fill,
49+
"inquire": inquire,
50+
}
51+
n_given = sum(param is not None and param is not False for param in params.values())
52+
match n_given:
53+
case 0:
54+
raise GMTParameterError(at_least_one=params)
55+
case 1:
56+
pass
57+
case _:
58+
raise GMTParameterError(at_most_one=params)
6959

7060

7161
@fmt_docstring

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, GMTParameterError
12+
from pygmt.exceptions import GMTParameterError
1313
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias
1414

1515
__doctest_skip__ = ["grdproject"]
@@ -121,8 +121,7 @@ def grdproject( # noqa: PLR0913
121121
raise GMTParameterError(required="projection")
122122

123123
if kwargs.get("M", unit) is not None and kwargs.get("F", scaling) is not False:
124-
msg = "Cannot use both 'unit' and 'scaling'."
125-
raise GMTInvalidInput(msg)
124+
raise GMTParameterError(at_most_one={"unit", "scaling"})
126125

127126
aliasdict = AliasSystem(
128127
C=Alias(center, name="center", sep="/", size=2),

pygmt/src/grdsample.py

Lines changed: 2 additions & 4 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 (
1414
build_arg_list,
1515
deprecate_parameter,
@@ -100,10 +100,8 @@ def grdsample(
100100
>>> # and set both x- and y-spacings to 0.5 arc-degrees
101101
>>> new_grid = pygmt.grdsample(grid=grid, toggle=True, spacing=[0.5, 0.5])
102102
"""
103-
# Enforce mutual exclusivity between -T (toggle) and -r (registration)
104103
if kwargs.get("T", toggle) and kwargs.get("r", registration):
105-
msg = "Parameters 'toggle' and 'registration' cannot be used together."
106-
raise GMTInvalidInput(msg)
104+
raise GMTParameterError(at_most_one={"toggle", "registration"})
107105

108106
aliasdict = AliasSystem(
109107
I=Alias(spacing, name="spacing", sep="/", size=2),

pygmt/src/grdtrack.py

Lines changed: 3 additions & 5 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, GMTParameterError
14+
from pygmt.exceptions import GMTParameterError
1515
from pygmt.helpers import (
1616
build_arg_list,
1717
fmt_docstring,
@@ -299,12 +299,10 @@ def grdtrack(
299299
... )
300300
"""
301301
if points is not None and kwargs.get("E") is not None:
302-
msg = "Can't set both 'points' and 'profile'."
303-
raise GMTInvalidInput(msg)
302+
raise GMTParameterError(at_most_one={"points", "profile"})
304303

305304
if points is None and kwargs.get("E") is None:
306-
msg = "Must give 'points' or set 'profile'."
307-
raise GMTInvalidInput(msg)
305+
raise GMTParameterError(at_least_one={"points", "profile"})
308306

309307
if hasattr(points, "columns") and newcolname is None:
310308
raise GMTParameterError(

pygmt/src/logo.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pygmt._typing import AnchorCode
99
from pygmt.alias import Alias, AliasSystem
1010
from pygmt.clib import Session
11-
from pygmt.exceptions import GMTInvalidInput
11+
from pygmt.exceptions import GMTParameterError
1212
from pygmt.helpers import build_arg_list, fmt_docstring
1313
from pygmt.params import Box, Position
1414
from pygmt.src._common import _parse_position
@@ -103,10 +103,8 @@ def logo( # noqa: PLR0913
103103
kwdict={"width": width, "height": height},
104104
)
105105

106-
# width and height are mutually exclusive.
107106
if width is not None and height is not None:
108-
msg = "Cannot specify both 'width' and 'height'."
109-
raise GMTInvalidInput(msg)
107+
raise GMTParameterError(at_most_one={"width", "height"})
110108

111109
aliasdict = AliasSystem(
112110
D=[

pygmt/src/makecpt.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from pygmt.alias import Alias, AliasSystem
99
from pygmt.clib import Session
10-
from pygmt.exceptions import GMTInvalidInput
10+
from pygmt.exceptions import GMTParameterError
1111
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias
1212

1313

@@ -169,8 +169,7 @@ def makecpt(
169169
``categorical=True``.
170170
"""
171171
if kwargs.get("W") is not None and kwargs.get("Ww") is not None:
172-
msg = "Set only categorical or cyclic to True, not both."
173-
raise GMTInvalidInput(msg)
172+
raise GMTParameterError(at_most_one={"categorical", "cyclic"})
174173

175174
if (output := kwargs.pop("H", None)) is not None:
176175
kwargs["H"] = True

pygmt/src/plot.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pygmt._typing import PathLike, TableLike
99
from pygmt.alias import Alias, AliasSystem
1010
from pygmt.clib import Session
11-
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
11+
from pygmt.exceptions import GMTParameterError, GMTTypeError
1212
from pygmt.helpers import (
1313
build_arg_list,
1414
data_kind,
@@ -272,8 +272,7 @@ def plot( # noqa: PLR0912, PLR0913
272272
data["symbol"] = symbol
273273
else:
274274
if any(v is not None for v in (x, y)):
275-
msg = "Too much data. Use either data or x/y/z."
276-
raise GMTInvalidInput(msg)
275+
raise GMTParameterError(at_most_one={"data", "x/y/z"})
277276
for name, value in [
278277
("direction", direction),
279278
("fill", kwargs.get("G")),

pygmt/src/plot3d.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pygmt._typing import PathLike, TableLike
99
from pygmt.alias import Alias, AliasSystem
1010
from pygmt.clib import Session
11-
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
11+
from pygmt.exceptions import GMTParameterError, GMTTypeError
1212
from pygmt.helpers import (
1313
build_arg_list,
1414
data_kind,
@@ -252,8 +252,7 @@ def plot3d( # noqa: PLR0912, PLR0913
252252
data["symbol"] = symbol
253253
else:
254254
if any(v is not None for v in (x, y, z)):
255-
msg = "Too much data. Use either data or x/y/z."
256-
raise GMTInvalidInput(msg)
255+
raise GMTParameterError(at_most_one={"data", "x/y/z"})
257256

258257
for name, value in [
259258
("direction", direction),

0 commit comments

Comments
 (0)