Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8fe6a13
Add GMTParameterError and deprecate GMTInvalidInput
Chuan1937 Jan 28, 2026
737defa
fix format
Chuan1937 Jan 28, 2026
ae59d2f
focus on required parameters
Chuan1937 Jan 28, 2026
73b9c42
Update pygmt/exceptions.py
Chuan1937 Jan 28, 2026
8a778e4
add support for single parameter: string input, list input, and tuple…
Chuan1937 Jan 28, 2026
db5d047
fix doctest and check GMTParameterError
Chuan1937 Jan 28, 2026
a2e65c1
Merge branch 'main' into add-gmt-parameter-error
Chuan1937 Jan 29, 2026
a5743fd
Merge branch 'main' into add-gmt-parameter-error
Chuan1937 Jan 29, 2026
c5d26b2
Update pygmt/exceptions.py
Chuan1937 Jan 29, 2026
c6c4b7f
sort all the exceptions alphabetically
Chuan1937 Jan 29, 2026
f9ffe43
Update pygmt/exceptions.py
Chuan1937 Jan 29, 2026
3904c56
Update pygmt/helpers/validators.py
Chuan1937 Jan 29, 2026
b08f26a
Update pygmt/params/box.py
Chuan1937 Jan 29, 2026
18975aa
Update pygmt/src/text.py
Chuan1937 Jan 29, 2026
0c8e4dc
Merge branch 'main' into add-gmt-parameter-error
Chuan1937 Jan 29, 2026
f113ebd
fix typo in GMTParameterError
Chuan1937 Jan 29, 2026
a7fadb5
Update pygmt/helpers/validators.py
Chuan1937 Jan 29, 2026
22a4b39
Update pygmt/src/text.py
Chuan1937 Jan 29, 2026
1b8fe43
Update pygmt/src/grdtrack.py
Chuan1937 Jan 29, 2026
7235041
fix format
Chuan1937 Jan 29, 2026
ab642f9
change GMTInvalidInput to GMTParameterError in filter1d, grdlandmask,…
Chuan1937 Jan 29, 2026
7b3e955
Update pygmt/src/project.py
Chuan1937 Jan 30, 2026
99c6b04
Update pygmt/src/velo.py
Chuan1937 Jan 30, 2026
40942f0
Update pygmt/src/text.py
Chuan1937 Jan 30, 2026
94e8985
Merge branch 'main' into add-gmt-parameter-error
Chuan1937 Jan 30, 2026
9ceec08
update GMTParameterError for load_remote_dataset, grdgradient, histog…
Chuan1937 Jan 30, 2026
784c5cd
Update pygmt/datasets/load_remote_dataset.py
Chuan1937 Jan 30, 2026
04c8a8d
Update pygmt/src/grdgradient.py
Chuan1937 Jan 30, 2026
9981c91
Update pygmt/src/inset.py
Chuan1937 Jan 30, 2026
fba11bd
fix test check for GMTParameterError
Chuan1937 Jan 30, 2026
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
7 changes: 4 additions & 3 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -293,14 +293,15 @@ All custom exceptions are derived from :class:`pygmt.exceptions.GMTError`.
:toctree: generated

exceptions.GMTError
exceptions.GMTInvalidInput
exceptions.GMTVersionError
exceptions.GMTOSError
exceptions.GMTCLibError
exceptions.GMTCLibNoSessionError
exceptions.GMTCLibNotFoundError
exceptions.GMTInvalidInput
exceptions.GMTOSError
exceptions.GMTParameterError
exceptions.GMTTypeError
exceptions.GMTValueError
exceptions.GMTVersionError


.. currentmodule:: pygmt
Expand Down
9 changes: 4 additions & 5 deletions pygmt/datasets/load_remote_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Any, Literal, NamedTuple

import xarray as xr
from pygmt.exceptions import GMTInvalidInput, GMTValueError
from pygmt.exceptions import GMTParameterError, GMTValueError

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

if resinfo.tiled and region is None:
msg = (
f"The 'region' parameter is required for {dataset.description} "
f"resolution '{resolution}'."
raise GMTParameterError(
required="region",
reason=f"Required for {dataset.description} resolution {resolution!r}.",
)
raise GMTInvalidInput(msg)

fname = f"@{prefix}_{resolution}_{reg}"
grid = xr.load_dataarray(
Expand Down
32 changes: 32 additions & 0 deletions pygmt/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,35 @@ def __init__(self, dtype: object, /, reason: str | None = None):
if reason:
msg += f" {reason}"
super().__init__(msg)


class GMTParameterError(GMTError):
"""
Raised when parameters are missing or invalid.

Parameters
----------
required
Name or a set of names of required parameters.
reason
Detailed reason why the parameters are invalid.
"""

def __init__(
self,
*,
required: str | set[str] | None = None,
reason: str | None = None,
):
msg = []
if required:
if isinstance(required, str):
msg.append(f"Missing required parameter: {required!r}.")
else:
msg.append(
"Missing required parameters: "
f"{', '.join(repr(par) for par in required)}."
)
if reason:
msg.append(reason)
super().__init__(" ".join(msg))
9 changes: 5 additions & 4 deletions pygmt/helpers/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Literal

from pygmt._typing import PathLike
from pygmt.exceptions import GMTInvalidInput, GMTValueError
from pygmt.exceptions import GMTParameterError, GMTValueError


def validate_output_table_type(
Expand Down Expand Up @@ -43,7 +43,7 @@ def validate_output_table_type(
>>> validate_output_table_type("file", outfile=None)
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Must specify 'outfile' for output_type='file'.
pygmt.exceptions.GMTParameterError: Missing required parameter: 'outfile'. ...
>>> with warnings.catch_warnings(record=True) as w:
... validate_output_table_type("pandas", outfile="not-none.txt")
... assert len(w) == 1
Expand All @@ -57,8 +57,9 @@ def validate_output_table_type(
choices=_valids,
)
if output_type == "file" and outfile is None:
msg = "Must specify 'outfile' for output_type='file'."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="outfile", reason="Required when output_type='file'."
)
if output_type != "file" and outfile is not None:
msg = (
f"Changing 'output_type' from '{output_type}' to 'file' since 'outfile' "
Expand Down
7 changes: 4 additions & 3 deletions pygmt/params/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from collections.abc import Sequence

from pygmt.alias import Alias
from pygmt.exceptions import GMTInvalidInput, GMTValueError
from pygmt.exceptions import GMTParameterError, GMTValueError
from pygmt.helpers import is_nonstr_iter
from pygmt.params.base import BaseParam

Expand Down Expand Up @@ -65,8 +65,9 @@ def _validate(self):
"""
# inner_pen is required when inner_gap is set.
if self.inner_gap is not None and self.inner_pen is None:
msg = "Parameter 'inner_pen' is required when 'inner_gap' is set."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="inner_pen", reason="Required when 'inner_gap' is set."
)

# shade_offset must be a sequence of two values or None.
if self.shade_offset and not (
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/filter1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pygmt._typing import PathLike, TableLike
from pygmt.alias import 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,
Expand Down Expand Up @@ -112,8 +112,7 @@ def filter1d(
(depends on ``output_type``)
"""
if kwargs.get("F") is None:
msg = "Pass a required argument to 'filter_type'."
raise GMTInvalidInput(msg)
raise GMTParameterError(required="filter_type")

output_type = validate_output_table_type(output_type, outfile=outfile)

Expand Down
7 changes: 4 additions & 3 deletions pygmt/src/grdgradient.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 GMTInvalidInput, GMTParameterError
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias

__doctest_skip__ = ["grdgradient"]
Expand Down Expand Up @@ -166,8 +166,9 @@ def grdgradient(
>>> new_grid = pygmt.grdgradient(grid=grid, azimuth=10)
"""
if kwargs.get("Q") is not None and kwargs.get("N") is None:
msg = "Must specify normalize if tiles is specified."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="normalize", reason="Required when 'tiles' is set."
)
if (
kwargs.get("A", azimuth) is None
and kwargs.get("D") is None
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/grdlandmask.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, fmt_docstring, use_alias

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

aliasdict = AliasSystem(
D=Alias(
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
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias

__doctest_skip__ = ["grdproject"]
Expand Down Expand Up @@ -118,8 +118,7 @@ def grdproject( # noqa: PLR0913
>>> new_grid = pygmt.grdproject(grid=grid, projection="M10c", region=region)
"""
if kwargs.get("J", projection) is None:
msg = "Parameter 'projection' must be specified."
raise GMTInvalidInput(msg)
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'."
Expand Down
7 changes: 4 additions & 3 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
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.helpers import (
build_arg_list,
fmt_docstring,
Expand Down Expand Up @@ -307,8 +307,9 @@ def grdtrack(
raise GMTInvalidInput(msg)

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

output_type = validate_output_table_type(output_type, outfile=outfile)

Expand Down
7 changes: 4 additions & 3 deletions pygmt/src/histogram.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
from pygmt.exceptions import GMTParameterError
from pygmt.helpers import (
build_arg_list,
deprecate_parameter,
Expand Down Expand Up @@ -163,8 +163,9 @@ def histogram( # noqa: PLR0913
self._activate_figure()

if bar_offset is not None and bar_width is None:
msg = "Setting 'bar_offset' requires setting 'bar_width'."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="bar_width", reason="Required when 'bar_offset' is set."
)

aliasdict = AliasSystem(
E=[
Expand Down
8 changes: 5 additions & 3 deletions pygmt/src/inset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,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,
deprecate_parameter,
Expand Down Expand Up @@ -139,8 +139,10 @@ def inset(
and width is None
and (projection is None or region is None)
):
msg = "Parameter 'width' must be specified."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="width",
reason="Required unless 'projection' and 'region' are set.",
)

aliasdict = AliasSystem(
D=[
Expand Down
8 changes: 5 additions & 3 deletions pygmt/src/magnetic_rose.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 @@ -111,8 +111,10 @@ def magnetic_rose( # noqa: PLR0913
position = _parse_position(position, default=Position("BL", cstype="inside"))

if declination_label is not None and declination is None:
msg = "Parameter 'declination' must be set when 'declination_label' is set."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="declination",
reason="Required when 'declination_label' is set.",
)

aliasdict = AliasSystem(
F=Alias(box, name="box"),
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/meca.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pygmt._typing import PathLike, TableLike
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,
data_kind,
Expand All @@ -31,8 +31,7 @@ def _get_focal_convention(spec, convention, component) -> _FocalMechanismConvent

# Determine the convention from the 'convention' parameter.
if convention is None:
msg = "Parameter 'convention' must be specified."
raise GMTInvalidInput(msg)
raise GMTParameterError(required="convention")
return _FocalMechanismConvention(convention=convention, component=component)


Expand Down
10 changes: 5 additions & 5 deletions pygmt/src/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pygmt._typing import PathLike, TableLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTInvalidInput, GMTParameterError
from pygmt.helpers import (
build_arg_list,
fmt_docstring,
Expand Down Expand Up @@ -221,11 +221,11 @@ def project( # noqa: PLR0913
(depends on ``output_type``)
"""
if kwargs.get("C", center) is None:
msg = "Parameter 'center' must be specified."
raise GMTInvalidInput(msg)
raise GMTParameterError(required="center")
if kwargs.get("G") is None and data is None:
msg = "The 'data' parameter must be specified unless 'generate' is used."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="data", reason="Required unless 'generate' is set."
)
if kwargs.get("G") is not None and kwargs.get("F") is not None:
msg = "The 'convention' parameter is not allowed with 'generate'."
raise GMTInvalidInput(msg)
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/sphdistance.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pygmt._typing import PathLike, TableLike
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, use_alias

__doctest_skip__ = ["sphdistance"]
Expand Down Expand Up @@ -123,8 +123,7 @@ def sphdistance(
... )
"""
if kwargs.get("I", spacing) is None or kwargs.get("R", region) is None:
msg = "Both 'region' and 'spacing' must be specified."
raise GMTInvalidInput(msg)
raise GMTParameterError(required={"region", "spacing"})

aliasdict = AliasSystem(
I=Alias(spacing, name="spacing", sep="/", size=2),
Expand Down
12 changes: 7 additions & 5 deletions pygmt/src/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pygmt._typing import AnchorCode, PathLike, StringArrayTypes, TableLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.exceptions import GMTInvalidInput, GMTParameterError, GMTTypeError
from pygmt.helpers import (
_check_encoding,
build_arg_list,
Expand Down Expand Up @@ -199,8 +199,9 @@ def text_( # noqa: PLR0912, PLR0913, PLR0915

if position is not None:
if text is None:
msg = "'text' can't be None when 'position' is given."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="text", reason="Required when 'position' is set."
)
if is_nonstr_iter(text):
raise GMTTypeError(
type(text),
Expand All @@ -211,8 +212,9 @@ def text_( # noqa: PLR0912, PLR0913, PLR0915
msg = "'text' can't be specified when 'textfiles' is given."
raise GMTInvalidInput(msg)
if kind == "empty" and text is None:
msg = "Must provide text with x/y pairs."
raise GMTInvalidInput(msg)
raise GMTParameterError(
required="text", reason="Required when 'x' and 'y' are set."
)

# Arguments that can accept arrays.
array_args = [
Expand Down
Loading
Loading