Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pygmt/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ class GMTParameterError(GMTError):
Name or a set of names of required parameters.
at_least_one
A set of parameter names, of which at least one must be specified.
at_most_one
A set of mutually exclusive parameter names, of which at most one can be
specified.
reason
Detailed reason why the parameters are invalid.
"""
Expand All @@ -151,6 +154,7 @@ def __init__(
*,
required: str | set[str] | None = None,
at_least_one: set[str] | None = None,
at_most_one: set[str] | None = None,
reason: str | None = None,
):
msg = []
Expand All @@ -167,6 +171,12 @@ def __init__(
"Missing parameter: requires at least one of "
f"{', '.join(repr(par) for par in at_least_one)}."
)
if at_most_one:
msg.append(
"Mutually exclusive parameters: "
f"{', '.join(repr(par) for par in at_most_one)}. "
"Specify at most one of them."
)
if reason:
msg.append(reason)
super().__init__(" ".join(msg))
5 changes: 2 additions & 3 deletions pygmt/src/grd2cpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pygmt._typing import PathLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias

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

if (output := kwargs.pop("H", None)) is not None:
kwargs["H"] = True
Expand Down
46 changes: 18 additions & 28 deletions pygmt/src/grdfill.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pygmt._typing import PathLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias

__doctest_skip__ = ["grdfill"]
Expand All @@ -31,41 +31,31 @@ def _validate_params(
>>> _validate_params(constant_fill=20.0, grid_fill="bggrid.nc")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Parameters ... are mutually exclusive.
pygmt.exceptions.GMTParameterError: Mutually exclusive parameters: ...
>>> _validate_params(constant_fill=20.0, inquire=True)
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Parameters ... are mutually exclusive.
pygmt.exceptions.GMTParameterError: Mutually exclusive parameters: ...
>>> _validate_params()
Traceback (most recent call last):
...
pygmt.exceptions.GMTParameterError: Missing parameter: requires at least one ...
"""
_fill_params = "'constant_fill'/'grid_fill'/'neighbor_fill'/'spline_fill'"

n_given = sum(
param is not None and param is not False
for param in [
constant_fill,
grid_fill,
neighbor_fill,
spline_fill,
inquire,
]
)
if n_given > 1: # More than one mutually exclusive parameter is given.
msg = f"Parameters {_fill_params}/'inquire' are mutually exclusive."
raise GMTInvalidInput(msg)
if n_given == 0: # No parameters are given.
raise GMTParameterError(
at_least_one={
"constant_fill",
"grid_fill",
"neighbor_fill",
"spline_fill",
"inquire",
}
)
params = {
"constant_fill": constant_fill,
"grid_fill": grid_fill,
"neighbor_fill": neighbor_fill,
"spline_fill": spline_fill,
"inquire": inquire,
}
n_given = sum(param is not None and param is not False for param in params.values())
match n_given:
case 0:
raise GMTParameterError(at_least_one=params)
case 1:
pass
case _:
raise GMTParameterError(at_most_one=params)


@fmt_docstring
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/grdproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pygmt._typing import PathLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias

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

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

aliasdict = AliasSystem(
C=Alias(center, name="center", sep="/", size=2),
Expand Down
6 changes: 2 additions & 4 deletions pygmt/src/grdsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pygmt._typing import PathLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import (
build_arg_list,
deprecate_parameter,
Expand Down Expand Up @@ -100,10 +100,8 @@ def grdsample(
>>> # and set both x- and y-spacings to 0.5 arc-degrees
>>> new_grid = pygmt.grdsample(grid=grid, toggle=True, spacing=[0.5, 0.5])
"""
# Enforce mutual exclusivity between -T (toggle) and -r (registration)
if kwargs.get("T", toggle) and kwargs.get("r", registration):
msg = "Parameters 'toggle' and 'registration' cannot be used together."
raise GMTInvalidInput(msg)
raise GMTParameterError(at_most_one={"toggle", "registration"})

aliasdict = AliasSystem(
I=Alias(spacing, name="spacing", sep="/", size=2),
Expand Down
8 changes: 3 additions & 5 deletions pygmt/src/grdtrack.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pygmt._typing import PathLike, TableLike
from pygmt.alias import AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import (
build_arg_list,
fmt_docstring,
Expand Down Expand Up @@ -299,12 +299,10 @@ def grdtrack(
... )
"""
if points is not None and kwargs.get("E") is not None:
msg = "Can't set both 'points' and 'profile'."
raise GMTInvalidInput(msg)
raise GMTParameterError(at_most_one={"points", "profile"})

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

if hasattr(points, "columns") and newcolname is None:
raise GMTParameterError(
Expand Down
6 changes: 2 additions & 4 deletions pygmt/src/logo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pygmt._typing import AnchorCode
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import build_arg_list, fmt_docstring
from pygmt.params import Box, Position
from pygmt.src._common import _parse_position
Expand Down Expand Up @@ -103,10 +103,8 @@ def logo( # noqa: PLR0913
kwdict={"width": width, "height": height},
)

# width and height are mutually exclusive.
if width is not None and height is not None:
msg = "Cannot specify both 'width' and 'height'."
raise GMTInvalidInput(msg)
raise GMTParameterError(at_most_one={"width", "height"})

aliasdict = AliasSystem(
D=[
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/makecpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias


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

if (output := kwargs.pop("H", None)) is not None:
kwargs["H"] = True
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pygmt._typing import PathLike, TableLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.exceptions import GMTParameterError, GMTTypeError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -272,8 +272,7 @@ def plot( # noqa: PLR0912, PLR0913
data["symbol"] = symbol
else:
if any(v is not None for v in (x, y)):
msg = "Too much data. Use either data or x/y/z."
raise GMTInvalidInput(msg)
raise GMTParameterError(at_most_one={"data", "x/y/z"})
for name, value in [
("direction", direction),
("fill", kwargs.get("G")),
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/plot3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pygmt._typing import PathLike, TableLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.exceptions import GMTParameterError, GMTTypeError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -252,8 +252,7 @@ def plot3d( # noqa: PLR0912, PLR0913
data["symbol"] = symbol
else:
if any(v is not None for v in (x, y, z)):
msg = "Too much data. Use either data or x/y/z."
raise GMTInvalidInput(msg)
raise GMTParameterError(at_most_one={"data", "x/y/z"})

for name, value in [
("direction", direction),
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/subplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTValueError
from pygmt.exceptions import GMTParameterError, GMTValueError
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias


Expand Down Expand Up @@ -166,8 +166,7 @@ def subplot(
)

if kwargs.get("Ff") and kwargs.get("Fs"):
msg = "Please provide either one of 'figsize' or 'subsize' only."
raise GMTInvalidInput(msg)
raise GMTParameterError(at_most_one={"figsize", "subsize"})

aliasdict = AliasSystem(
M=Alias(margins, name="margins", sep="/", size=(2, 4)),
Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_grd2cpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest
from pygmt import Figure, grd2cpt
from pygmt.exceptions import GMTInvalidInput, GMTTypeError, GMTValueError
from pygmt.exceptions import GMTParameterError, GMTTypeError, GMTValueError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -70,5 +70,5 @@ def test_grd2cpt_categorical_and_cyclic(grid):
"""
Use incorrect setting by setting both categorical and cyclic to True.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
grd2cpt(grid=grid, cmap="SCM/batlow", categorical=True, cyclic=True)
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdfill.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import xarray as xr
from pygmt import grdfill
from pygmt.enums import GridRegistration, GridType
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -154,5 +154,5 @@ def test_grdfill_inquire_and_fill(grid):
"""
Test that grdfill fails if both inquire and fill parameters are given.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
grdfill(grid=grid, inquire=True, constant_fill=20)
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import xarray as xr
from pygmt import grdproject
from pygmt.enums import GridRegistration, GridType
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -86,7 +86,7 @@ def test_grdproject_unit_scaling(grid):
Test that the input validation to prevent passing both 'unit' and
'scaling' is performed.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
grdproject(
grid=grid,
projection="M10c",
Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import xarray as xr
from pygmt import grdsample
from pygmt.enums import GridRegistration, GridType
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -101,5 +101,5 @@ def test_grdsample_toggle_and_registration_mutually_exclusive(grid):
"""
Raise an exception if toggle and registration are both set.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
grdsample(grid=grid, toggle=True, registration="pixel")
6 changes: 3 additions & 3 deletions pygmt/tests/test_grdtrack.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pandas as pd
import pytest
from pygmt import grdtrack
from pygmt.exceptions import GMTInvalidInput, GMTParameterError, GMTTypeError
from pygmt.exceptions import GMTParameterError, GMTTypeError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -162,13 +162,13 @@ def test_grdtrack_no_points_and_profile(dataarray):
"""
Run grdtrack but don't set 'points' and 'profile'.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
grdtrack(grid=dataarray)


def test_grdtrack_set_points_and_profile(dataarray, dataframe):
"""
Run grdtrack but set both 'points' and 'profile'.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
grdtrack(grid=dataarray, points=dataframe, profile="BL/TR")
4 changes: 2 additions & 2 deletions pygmt/tests/test_logo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest
from pygmt import Figure
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.params import Position


Expand Down Expand Up @@ -57,7 +57,7 @@ def test_logo_width_and_height():
Test that an error is raised when both width and height are specified.
"""
fig = Figure()
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTParameterError):
fig.logo(width="5c", height="5c")


Expand Down
Loading
Loading