Skip to content
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

data_kind: Refactor the if-else statements into match-case statements #3481

Merged
merged 8 commits into from
Oct 7, 2024
74 changes: 40 additions & 34 deletions pygmt/helpers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,22 +188,27 @@ def _check_encoding(


def data_kind(
data: Any = None, required: bool = True
data: Any, required: bool = True
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making data a required parameter here.

) -> Literal[
"arg", "file", "geojson", "grid", "image", "matrix", "stringio", "vectors"
]:
r"""
Check the kind of data that is provided to a module.

The ``data`` argument can be in any type, but only following types are supported:

- a string or a :class:`pathlib.PurePath` object or a sequence of them, representing
a file name or a list of file names
- a 2-D or 3-D :class:`xarray.DataArray` object
- a 2-D matrix
- None, bool, int or float type representing an optional arguments
- a geo-like Python object that implements ``__geo_interface__`` (e.g.,
geopandas.GeoDataFrame or shapely.geometry)
The argument passed to the ``data`` parameter can have any data type. The
following data kinds are recognized and returned as ``kind``:

- ``"arg"``: ``data`` is ``None`` and ``required=False``, or bool, int, float,
representing an optional argument, used for dealing with optional virtual files
- ``"file"``: a string or a :class:`pathlib.PurePath` object or a sequence of them,
representing one or more file names
- ``"geojson"``: a geo-like Python object that implements ``__geo_interface__``
(e.g., geopandas.GeoDataFrame or shapely.geometry)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this highlighting exists also for shapely.geometry?

Suggested change
(e.g., geopandas.GeoDataFrame or shapely.geometry)
(e.g., :class:`geopandas.GeoDataFrame` or shapely.geometry)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is not documented in the API documentation page, so linking shapely.geometry or not makes little difference.

- ``"grid"``: a :class:`xarray.DataArray` object that is not 3-D
- ``"image"``: a 3-D :class:`xarray.DataArray` object
- ``"stringio"``: a :class:`io.StringIO` object
- ``"matrix"``: anything that is not ``None``
- ``"vectors"``: ``data`` is ``None`` and ``required=True``

Parameters
----------
Expand Down Expand Up @@ -287,30 +292,31 @@ def data_kind(
>>> data_kind(data=None)
'vectors'
"""
kind: Literal[
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type hint is no longer needed.

"arg", "file", "geojson", "grid", "image", "matrix", "stringio", "vectors"
]
if isinstance(data, str | pathlib.PurePath) or (
isinstance(data, list | tuple)
and all(isinstance(_file, str | pathlib.PurePath) for _file in data)
):
# One or more files
kind = "file"
elif isinstance(data, bool | int | float) or (data is None and not required):
kind = "arg"
elif isinstance(data, io.StringIO):
kind = "stringio"
elif isinstance(data, xr.DataArray):
kind = "image" if len(data.dims) == 3 else "grid"
elif hasattr(data, "__geo_interface__"):
# geo-like Python object that implements ``__geo_interface__``
# (geopandas.GeoDataFrame or shapely.geometry)
kind = "geojson"
elif data is not None:
kind = "matrix"
else:
kind = "vectors"
return kind
match data:
case str() | pathlib.PurePath(): # One file.
kind = "file"
case list() | tuple() if all(
isinstance(_file, str | pathlib.PurePath) for _file in data
): # A list/tuple of files.
kind = "file"
case io.StringIO():
kind = "stringio"
case (bool() | int() | float()) | None if not required:
# An option argument, mainly for dealing optional virtual files.
kind = "arg"
case xr.DataArray():
# An xarray.DataArray object, representing either a grid or an image.
kind = "image" if len(data.dims) == 3 else "grid"
case x if hasattr(x, "__geo_interface__"):
# Geo-like Python object that implements ``__geo_interface__`` (e.g.,
# geopandas.GeoDataFrame or shapely.geometry).
# Reference: https://gist.github.com/sgillies/2217756
kind = "geojson"
case x if x is not None: # Any not-None is considered as a matrix.
kind = "matrix"
case _: # Fall back to "vectors" if data is None and required=True.
kind = "vectors"
return kind # type: ignore[return-value]


def non_ascii_to_octal(
Expand Down