-
Notifications
You must be signed in to change notification settings - Fork 225
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
Conversation
pygmt/helpers/utils.py
Outdated
@@ -187,23 +187,26 @@ def _check_encoding( | |||
return "ISOLatin1+" | |||
|
|||
|
|||
def data_kind( | |||
def data_kind( # noqa: PLR0911 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PLR0911 means "too-many-return-statements".
https://docs.astral.sh/ruff/rules/too-many-return-statements/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR refactors the data_kind function, to use if-return statements instead of if-else statements. The new if-return statements are easier to read and maintain.
I don't see much of an improvement in readability/maintainability between the previous if-elif-else
statements and the if-return
style in this PR. Looking at https://stackoverflow.com/questions/72024229/how-to-solve-pylint-too-many-return-statements-elegantly, I'm thinking if we could either keep the if-elif-else
syntax, or use match-case
instead.
If using match-case
, would it be more readable to do the isinstance()
checks first, and then have a nested if-elif
for case _
for the more complex cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel match-case
would make it more complicated:
match data:
case x if isinstance(x, io.StringIO):
return "stringio"
case x if isinstance(x, xr.DataArray):
return "image" if len(x.dims) == 3 else "grid"
case x if isinstance(x, bool | int | float) or (x is None and not required):
return "arg"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using match-case
also has the too-many-return-statements
warning, and using if-elif-else
means we need to type hints the kind
variable like:
kind: Literal["arg", "file", "geojson", "grid", "image", "matrix", "stringio", "vectors"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't run tests on this, but we can remove some of the isinstance()
calls like so using class patterns (xref https://stackoverflow.com/questions/67524641/convert-multiple-isinstance-checks-to-structural-pattern-matching/67524642#67524642)
match data:
case str() | pathlib.PurePath():
kind = "file"
case list() | tuple() if all(
isinstance(_file, str | pathlib.PurePath) for _file in data
):
kind = "file"
case io.StringIO():
kind = "stringio"
case (bool() | int() | float()) | None if not required:
kind = "arg"
case xr.DataArray():
kind = "image" if len(data.dims) == 3 else "grid"
case x if hasattr(x, "__geo_interface__"):
kind = "geojson"
case x if x is not None:
kind = "matrix"
case _:
kind = "vectors"
return kind
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The match-case
statements look more compact. Done in 33051ac.
The mypy warning is also suppressed.
@@ -287,30 +290,36 @@ def data_kind( | |||
>>> data_kind(data=None) | |||
'vectors' | |||
""" | |||
kind: Literal[ |
There was a problem hiding this comment.
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.
def data_kind( | ||
data: Any = None, required: bool = True | ||
def data_kind( # noqa: PLR0911 | ||
data: Any, required: bool = True |
There was a problem hiding this comment.
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.
Will merge in 24 hours. |
- ``"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) |
There was a problem hiding this comment.
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
?
(e.g., geopandas.GeoDataFrame or shapely.geometry) | |
(e.g., :class:`geopandas.GeoDataFrame` or shapely.geometry) |
There was a problem hiding this comment.
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.
Co-authored-by: Yvonne Fröhlich <[email protected]>
Co-authored-by: Wei Ji <[email protected]>
Description of proposed changes
Follow-up PR after PR #3480.
This PR refactors the
data_kind
function, to usematch-case
statements instead ofif-else
statements.This PR also updates the docstrings.