Skip to content

BREAKING: Raise GMTTypeError exception for invalid types. Previously raise GMTInvalidInput #3999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ All custom exceptions are derived from :class:`pygmt.exceptions.GMTError`.
exceptions.GMTCLibNoSessionError
exceptions.GMTCLibNotFoundError
exceptions.GMTValueError
exceptions.GMTTypeError


.. currentmodule:: pygmt
Expand Down
22 changes: 12 additions & 10 deletions pygmt/clib/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
GMTCLibError,
GMTCLibNoSessionError,
GMTInvalidInput,
GMTTypeError,
GMTValueError,
)
from pygmt.helpers import (
Expand Down Expand Up @@ -629,7 +630,7 @@ def call_module(self, module: str, args: str | list[str]) -> None:

Raises
------
GMTInvalidInput
GMTTypeError
If the ``args`` argument is not a string or a list of strings.
GMTCLibError
If the returned status code of the function is non-zero.
Expand Down Expand Up @@ -658,8 +659,10 @@ def call_module(self, module: str, args: str | list[str]) -> None:
mode = self["GMT_MODULE_CMD"]
argv = args.encode()
else:
msg = "'args' must either be a list of strings (recommended) or a string."
raise GMTInvalidInput(msg)
raise GMTTypeError(
type(args),
reason="Parameter 'args' must either be a list of strings (recommended) or a string.",
)

status = c_call_module(self.session_pointer, module.encode(), mode, argv)
if status != 0:
Expand Down Expand Up @@ -913,9 +916,8 @@ def _check_dtype_and_dim(self, array: np.ndarray, ndim: int) -> int:

Raises
------
GMTInvalidInput
If the array has the wrong number of dimensions or is an unsupported data
type.
GMTTypeError
If the array is an unsupported data type.

Examples
--------
Expand All @@ -939,8 +941,7 @@ def _check_dtype_and_dim(self, array: np.ndarray, ndim: int) -> int:
# 1-D arrays can be numeric or text, 2-D arrays can only be numeric.
valid_dtypes = DTYPES if ndim == 1 else DTYPES_NUMERIC
if (dtype := array.dtype.type) not in valid_dtypes:
msg = f"Unsupported numpy data type '{dtype}'."
raise GMTInvalidInput(msg)
raise GMTTypeError(dtype)
return self[DTYPES[dtype]]

def put_vector(
Expand Down Expand Up @@ -1867,8 +1868,9 @@ def virtualfile_in( # noqa: PLR0912
elif check_kind == "vector":
valid_kinds += ("empty", "matrix", "vectors", "geojson")
if kind not in valid_kinds:
msg = f"Unrecognized data type for {check_kind}: {type(data)}."
raise GMTInvalidInput(msg)
raise GMTTypeError(
type(data), reason=f"Unrecognized for {check_kind!r} kind."
)

# Decide which virtualfile_from_ function to use
_virtualfile_from = {
Expand Down
15 changes: 15 additions & 0 deletions pygmt/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,18 @@ def __init__(
if reason:
msg += f" {reason}"
super().__init__(msg)


class GMTTypeError(GMTError, TypeError):
"""
Raised when an invalid type is passed to a function/method.

This exception is used to indicate that the type of an argument does not match
the expected type.
"""

def __init__(self, dtype: object, /, reason: str | None = None):
msg = f"Unrecognized data type: {dtype!r}."
if reason:
msg += f" {reason}"
super().__init__(msg)
5 changes: 2 additions & 3 deletions pygmt/src/grdcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import xarray as xr
from pygmt._typing import PathLike
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput, GMTValueError
from pygmt.exceptions import GMTTypeError, GMTValueError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -122,8 +122,7 @@ def grdcut(
case "file":
outkind = kind
case _:
msg = f"Unsupported data type {type(grid)}."
raise GMTInvalidInput(msg)
raise GMTTypeError(type(grid))

with Session() as lib:
with (
Expand Down
10 changes: 5 additions & 5 deletions pygmt/src/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from pygmt._typing import PathLike
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -91,11 +91,11 @@ def legend(

kind = data_kind(spec)
if kind not in {"empty", "file", "stringio"}:
msg = f"Unrecognized data type: {type(spec)}"
raise GMTInvalidInput(msg)
raise GMTTypeError(type(spec))
if kind == "file" and is_nonstr_iter(spec):
msg = "Only one legend specification file is allowed."
raise GMTInvalidInput(msg)
raise GMTTypeError(
type(spec), reason="Only one legend specification file is allowed."
)

with Session() as lib:
with lib.virtualfile_in(data=spec, required=False) as vintbl:
Expand Down
8 changes: 5 additions & 3 deletions pygmt/src/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from pygmt._typing import PathLike, TableLike
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -272,8 +272,10 @@ def plot( # noqa: PLR0912
("symbol", symbol),
]:
if is_nonstr_iter(value):
msg = f"'{name}' can't be a 1-D array if 'data' is used."
raise GMTInvalidInput(msg)
raise GMTTypeError(
type(value),
reason=f"Parameter {name!r} can't be a 1-D array if 'data' is used.",
)

# Set the default style if data has a geometry of Point or MultiPoint
if kwargs.get("S") is None and _data_geometry_is_point(data, kind):
Expand Down
8 changes: 5 additions & 3 deletions pygmt/src/plot3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from pygmt._typing import PathLike, TableLike
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -251,8 +251,10 @@ def plot3d( # noqa: PLR0912
("symbol", symbol),
]:
if is_nonstr_iter(value):
msg = f"'{name}' can't be a 1-D array if 'data' is used."
raise GMTInvalidInput(msg)
raise GMTTypeError(
type(value),
reason=f"Parameter {name!r} can't be a 1-D array if 'data' is used.",
)

# Set the default style if data has a geometry of Point or MultiPoint
if kwargs.get("S") is None and _data_geometry_is_point(data, kind):
Expand Down
8 changes: 5 additions & 3 deletions pygmt/src/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import numpy as np
from pygmt._typing import AnchorCode, PathLike, StringArrayTypes, TableLike
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.helpers import (
_check_encoding,
build_arg_list,
Expand Down Expand Up @@ -257,8 +257,10 @@

for arg, _, name in [*array_args, (kwargs.get("t"), "", "transparency")]:
if is_nonstr_iter(arg):
msg = f"Argument of '{name}' must be a single value or True."
raise GMTInvalidInput(msg)
raise GMTTypeError(

Check warning on line 260 in pygmt/src/text.py

View check run for this annotation

Codecov / codecov/patch

pygmt/src/text.py#L260

Added line #L260 was not covered by tests
type(arg),
reason=f"Parameter {name!r} expects a scalar value or True.",
)

with Session() as lib:
with lib.virtualfile_in(
Expand Down
5 changes: 2 additions & 3 deletions pygmt/src/x2sys_cross.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pandas as pd
from pygmt._typing import PathLike
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers import (
build_arg_list,
data_kind,
Expand Down Expand Up @@ -213,8 +213,7 @@ def x2sys_cross(
# Save pandas.DataFrame track data to temporary file
file_contexts.append(tempfile_from_dftrack(track=track, suffix=suffix))
case _:
msg = f"Unrecognized data type: {type(track)}."
raise GMTInvalidInput(msg)
raise GMTTypeError(type(track))

with Session() as lib:
with lib.virtualfile_out(kind="dataset", fname=outfile) as vouttbl:
Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_blockm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import xarray as xr
from pygmt import blockmean, blockmode
from pygmt.datasets import load_sample_data
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers import GMTTempFile


Expand Down Expand Up @@ -68,7 +68,7 @@ def test_blockmean_wrong_kind_of_input_table_grid(dataframe):
Run blockmean using table input that is not a pandas.DataFrame or file but a grid.
"""
invalid_table = dataframe.bathymetry.to_xarray()
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
blockmean(data=invalid_table, spacing="5m", region=[245, 255, 20, 30])


Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_blockmedian.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest
from pygmt import blockmedian
from pygmt.datasets import load_sample_data
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers import GMTTempFile


Expand Down Expand Up @@ -65,7 +65,7 @@ def test_blockmedian_wrong_kind_of_input_table_grid(dataframe):
Run blockmedian using table input that is not a pandas.DataFrame or file but a grid.
"""
invalid_table = dataframe.bathymetry.to_xarray()
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
blockmedian(data=invalid_table, spacing="5m", region=[245, 255, 20, 30])


Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_clib_call_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest
from pygmt import Figure, clib
from pygmt.exceptions import GMTCLibError, GMTInvalidInput
from pygmt.exceptions import GMTCLibError, GMTTypeError
from pygmt.helpers import GMTTempFile

POINTS_DATA = Path(__file__).parent / "data" / "points.txt"
Expand Down Expand Up @@ -53,7 +53,7 @@ def test_call_module_invalid_argument_type():
call_module only accepts a string or a list of strings as module arguments.
"""
with clib.Session() as lib:
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
lib.call_module("get", ("FONT_TITLE", "FONT_TAG"))


Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_clib_put_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pytest
from pygmt import clib
from pygmt.clib.session import DTYPES_NUMERIC
from pygmt.exceptions import GMTCLibError, GMTInvalidInput
from pygmt.exceptions import GMTCLibError, GMTInvalidInput, GMTTypeError
from pygmt.helpers import GMTTempFile


Expand Down Expand Up @@ -225,7 +225,7 @@ def test_put_vector_invalid_dtype():
dim=[2, 3, 0, 0], # ncolumns, nrows, dtype, unused
)
data = np.array([37, 12, 556], dtype=dtype)
with pytest.raises(GMTInvalidInput, match="Unsupported numpy data type"):
with pytest.raises(GMTTypeError, match="Unrecognized data type"):
lib.put_vector(dataset, column=0, vector=data)


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
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -62,7 +62,7 @@ def test_grd2cpt_unrecognized_data_type():
"""
Test that an error will be raised if an invalid data type is passed to grid.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
grd2cpt(grid=0)


Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdcontour.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import numpy as np
import pytest
from pygmt import Figure
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers.testing import load_static_earth_relief

TEST_CONTOUR_FILE = Path(__file__).parent / "data" / "contours.txt"
Expand Down Expand Up @@ -123,5 +123,5 @@ def test_grdcontour_fails():
Should fail for unrecognized input.
"""
fig = Figure()
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
fig.grdcontour(np.arange(20).reshape((4, 5)))
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pytest
import xarray as xr
from pygmt import grdcut
from pygmt.exceptions import GMTInvalidInput, GMTValueError
from pygmt.exceptions import GMTTypeError, GMTValueError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -68,7 +68,7 @@ def test_grdcut_fails():
"""
Check that grdcut fails correctly.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
grdcut(np.arange(10).reshape((5, 2)))


Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdfilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import xarray as xr
from pygmt import grdfilter
from pygmt.enums import GridRegistration, GridType
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -79,5 +79,5 @@ def test_grdfilter_fails():
"""
Check that grdfilter fails correctly.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
grdfilter(np.arange(10).reshape((5, 2)))
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pygmt.clib import __gmt_version__
from pygmt.datasets import load_earth_relief
from pygmt.enums import GridRegistration, GridType
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.helpers.testing import check_figures_equal


Expand Down Expand Up @@ -156,7 +156,7 @@ def test_grdimage_fails():
Should fail for unrecognized input.
"""
fig = Figure()
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
fig.grdimage(np.arange(20).reshape((4, 5)))


Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_grdinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
import pytest
from pygmt import grdinfo
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTTypeError
from pygmt.helpers.testing import load_static_earth_relief


Expand All @@ -30,7 +30,7 @@ def test_grdinfo_fails():
"""
Check that grdinfo fails correctly.
"""
with pytest.raises(GMTInvalidInput):
with pytest.raises(GMTTypeError):
grdinfo(np.arange(10).reshape((5, 2)))


Expand Down
Loading
Loading