Skip to content

Commit b1c6330

Browse files
committed
Merge branch 'main' into AliasSystem/params/base
2 parents 926a690 + 2021de7 commit b1c6330

39 files changed

+440
-300
lines changed

.github/workflows/ci_tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ jobs:
151151
GH_TOKEN: ${{ github.token }}
152152

153153
- name: Install uv
154-
uses: astral-sh/setup-uv@7edac99f961f18b581bbd960d59d049f04c0002f # v6.4.1
154+
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
155155
with:
156156
activate-environment: true
157157
python-version: ${{ matrix.python-version }}

pygmt/alias.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def _to_string(
1515
value: Any,
1616
prefix: str = "", # Default to an empty string to simplify the code logic.
1717
mapping: Mapping | None = None,
18-
separator: Literal["/", ","] | None = None,
18+
sep: Literal["/", ","] | None = None,
1919
size: int | Sequence[int] | None = None,
2020
ndim: int = 1,
2121
name: str | None = None,
@@ -41,8 +41,8 @@ def _to_string(
4141
string.
4242
4343
To avoid extra overhead, this function does not validate parameter combinations. For
44-
example, if ``value`` is a sequence but ``separator`` is not specified, the function
45-
will return a sequence of strings. In this case, ``prefix`` has no effect, but the
44+
example, if ``value`` is a sequence but ``sep`` is not specified, the function will
45+
return a sequence of strings. In this case, ``prefix`` has no effect, but the
4646
function does not check for such inconsistencies. The maintainer should ensure that
4747
the parameter combinations are valid.
4848
@@ -54,7 +54,7 @@ def _to_string(
5454
The string to add as a prefix to the returned value.
5555
mapping
5656
A mapping dictionary to map PyGMT's long-form arguments to GMT's short-form.
57-
separator
57+
sep
5858
The separator to use if the value is a sequence.
5959
size
6060
Expected size of the 1-D sequence. It can be either an integer or a sequence of
@@ -97,15 +97,18 @@ def _to_string(
9797
...
9898
pygmt...GMTValueError: Invalid value: 'invalid'. Expected one of: 'mean', ...
9999
100-
>>> _to_string((12, 34), separator="/")
100+
>>> _to_string((12, 34), sep="/")
101101
'12/34'
102-
>>> _to_string(("12p", "34p"), separator=",")
102+
>>> _to_string(("12p", "34p"), sep=",")
103103
'12p,34p'
104-
>>> _to_string(("12p", "34p"), prefix="+o", separator="/")
104+
>>> _to_string(("12p", "34p"), prefix="+o", sep="/")
105105
'+o12p/34p'
106106
107107
>>> _to_string(["xaf", "yaf", "WSen"])
108108
['xaf', 'yaf', 'WSen']
109+
110+
>>> _to_string([[1, 2], [3, 4]], sep="/", ndim=2)
111+
['1/2', '3/4']
109112
"""
110113
# None and False are converted to None.
111114
if value is None or value is False:
@@ -127,12 +130,12 @@ def _to_string(
127130

128131
# Return the sequence if separator is not specified for options like '-B'.
129132
# True in a sequence will be converted to an empty string.
130-
if separator is None:
133+
if sep is None:
131134
return [str(item) if item is not True else "" for item in value]
132135
# Join the sequence of values with the separator.
133136
# "prefix" and "mapping" are ignored. We can enable them when needed.
134-
_value = sequence_join(value, separator=separator, size=size, ndim=ndim, name=name)
135-
return f"{prefix}{_value}"
137+
_value = sequence_join(value, sep=sep, size=size, ndim=ndim, name=name)
138+
return _value if is_nonstr_iter(_value) else f"{prefix}{_value}"
136139

137140

138141
class Alias:
@@ -149,7 +152,7 @@ class Alias:
149152
The string to add as a prefix to the returned value.
150153
mapping
151154
A mapping dictionary to map PyGMT's long-form arguments to GMT's short-form.
152-
separator
155+
sep
153156
The separator to use if the value is a sequence.
154157
size
155158
Expected size of the 1-D sequence. It can be either an integer or a sequence
@@ -160,7 +163,7 @@ class Alias:
160163
161164
Examples
162165
--------
163-
>>> par = Alias((3.0, 3.0), prefix="+o", separator="/")
166+
>>> par = Alias((3.0, 3.0), prefix="+o", sep="/")
164167
>>> par._value
165168
'+o3.0/3.0'
166169
@@ -179,7 +182,7 @@ def __init__(
179182
name: str | None = None,
180183
prefix: str = "",
181184
mapping: Mapping | None = None,
182-
separator: Literal["/", ","] | None = None,
185+
sep: Literal["/", ","] | None = None,
183186
size: int | Sequence[int] | None = None,
184187
ndim: int = 1,
185188
):
@@ -190,7 +193,7 @@ def __init__(
190193
name=name,
191194
prefix=prefix,
192195
mapping=mapping,
193-
separator=separator,
196+
sep=sep,
194197
size=size,
195198
ndim=ndim,
196199
)
@@ -219,11 +222,11 @@ class AliasSystem(UserDict):
219222
... aliasdict = AliasSystem(
220223
... A=[
221224
... Alias(par1, name="par1"),
222-
... Alias(par2, name="par2", prefix="+o", separator="/"),
225+
... Alias(par2, name="par2", prefix="+o", sep="/"),
223226
... ],
224227
... B=Alias(frame, name="frame"),
225228
... D=Alias(repeat, name="repeat"),
226-
... c=Alias(panel, name="panel", separator=","),
229+
... c=Alias(panel, name="panel", sep=","),
227230
... ).merge(kwargs)
228231
... return build_arg_list(aliasdict)
229232
>>> func(

pygmt/datasets/load_remote_dataset.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55
import contextlib
6-
from collections.abc import Sequence
6+
from collections.abc import Mapping, Sequence
77
from typing import Any, Literal, NamedTuple
88

99
import xarray as xr
@@ -58,8 +58,8 @@ class GMTRemoteDataset(NamedTuple):
5858
description: str
5959
kind: Literal["grid", "image"]
6060
units: str | None
61-
resolutions: dict[str, Resolution]
62-
extra_attributes: dict[str, Any]
61+
resolutions: Mapping[str, Resolution]
62+
extra_attributes: Mapping[str, Any]
6363
crs: str | None = None
6464

6565

pygmt/datatypes/header.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import ctypes as ctp
6+
from collections.abc import Mapping
67
from typing import Any, ClassVar
78

89
import numpy as np
@@ -199,7 +200,7 @@ def name(self) -> str:
199200
return "z"
200201

201202
@property
202-
def data_attrs(self) -> dict[str, Any]:
203+
def data_attrs(self) -> Mapping[str, Any]:
203204
"""
204205
Attributes for the data variable from the grid header.
205206
"""

pygmt/helpers/utils.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import subprocess
1010
import sys
1111
import time
12+
import warnings
1213
import webbrowser
1314
from collections.abc import Iterable, Mapping, Sequence
1415
from itertools import islice
@@ -481,7 +482,7 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str:
481482

482483

483484
def build_arg_list( # noqa: PLR0912
484-
kwdict: dict[str, Any],
485+
kwdict: Mapping[str, Any],
485486
confdict: Mapping[str, Any] | None = None,
486487
infile: PathLike | Sequence[PathLike] | None = None,
487488
outfile: PathLike | None = None,
@@ -724,9 +725,11 @@ def args_in_kwargs(args: Sequence[str], kwargs: dict[str, Any]) -> bool:
724725
)
725726

726727

728+
# TODO(PyGMT>=0.19.0): Remove the deprecate_parameter decorator.
727729
def sequence_join(
728730
value: Any,
729-
separator: str = "/",
731+
sep: str = "/",
732+
separator: str | None = None,
730733
size: int | Sequence[int] | None = None,
731734
ndim: int = 1,
732735
name: str | None = None,
@@ -741,8 +744,14 @@ def sequence_join(
741744
----------
742745
value
743746
The 1-D or 2-D sequence of values to join.
747+
sep
748+
The separator to join the values.
744749
separator
745750
The separator to join the values.
751+
752+
.. versionchanged:: v0.17.0
753+
754+
Deprecated and will be removed in v0.19.0. Use ``sep`` instead.
746755
size
747756
Expected size of the 1-D sequence. It can be either an integer or a sequence of
748757
integers. If an integer, it is the expected size of the 1-D sequence. If it is a
@@ -774,43 +783,53 @@ def sequence_join(
774783
775784
>>> sequence_join([1, 2, 3, 4])
776785
'1/2/3/4'
777-
>>> sequence_join([1, 2, 3, 4], separator=",")
786+
>>> sequence_join([1, 2, 3, 4], sep=",")
778787
'1,2,3,4'
779-
>>> sequence_join([1, 2, 3, 4], separator="/", size=4)
788+
>>> sequence_join([1, 2, 3, 4], sep="/", size=4)
780789
'1/2/3/4'
781-
>>> sequence_join([1, 2, 3, 4], separator="/", size=[2, 4])
790+
>>> sequence_join([1, 2, 3, 4], sep="/", size=[2, 4])
782791
'1/2/3/4'
783-
>>> sequence_join([1, 2, 3, 4], separator="/", size=[2, 4], ndim=2)
792+
>>> sequence_join([1, 2, 3, 4], sep="/", size=[2, 4], ndim=2)
784793
'1/2/3/4'
785-
>>> sequence_join([1, 2, 3, 4], separator="/", size=2)
794+
>>> sequence_join([1, 2, 3, 4], sep="/", size=2)
786795
Traceback (most recent call last):
787796
...
788797
pygmt.exceptions.GMTInvalidInput: Expected a sequence of 2 values, but got 4 values.
789-
>>> sequence_join([1, 2, 3, 4, 5], separator="/", size=[2, 4], name="parname")
798+
>>> sequence_join([1, 2, 3, 4, 5], sep="/", size=[2, 4], name="parname")
790799
Traceback (most recent call last):
791800
...
792801
pygmt.exceptions.GMTInvalidInput: Parameter 'parname': Expected ...
793802
794-
>>> sequence_join([[1, 2], [3, 4]], separator="/")
803+
>>> sequence_join([[1, 2], [3, 4]], sep="/")
795804
Traceback (most recent call last):
796805
...
797806
pygmt.exceptions.GMTInvalidInput: Expected a 1-D ..., but a 2-D sequence is given.
798-
>>> sequence_join([[1, 2], [3, 4]], separator="/", ndim=2)
807+
>>> sequence_join([[1, 2], [3, 4]], sep="/", ndim=2)
799808
['1/2', '3/4']
800-
>>> sequence_join([[1, 2], [3, 4]], separator="/", size=2, ndim=2)
809+
>>> sequence_join([[1, 2], [3, 4]], sep="/", size=2, ndim=2)
801810
['1/2', '3/4']
802-
>>> sequence_join([[1, 2], [3, 4]], separator="/", size=4, ndim=2)
811+
>>> sequence_join([[1, 2], [3, 4]], sep="/", size=4, ndim=2)
803812
Traceback (most recent call last):
804813
...
805814
pygmt.exceptions.GMTInvalidInput: Expected a sequence of 4 values.
806-
>>> sequence_join([[1, 2], [3, 4]], separator="/", size=[2, 4], ndim=2)
815+
>>> sequence_join([[1, 2], [3, 4]], sep="/", size=[2, 4], ndim=2)
807816
['1/2', '3/4']
817+
>>> sequence_join([1, 2, 3, 4], separator=",")
818+
'1,2,3,4'
808819
"""
809820
# Return the original value if it is not a sequence (e.g., None, bool, or str).
810821
if not is_nonstr_iter(value):
811822
return value
812823
# Now it must be a sequence.
813824

825+
if separator is not None:
826+
sep = separator # Deprecated, use sep instead.
827+
msg = (
828+
"Parameter 'separator' has been deprecated since v0.17.0 and will be "
829+
"removed in v0.19.0. Please use 'sep' instead."
830+
)
831+
warnings.warn(msg, category=FutureWarning, stacklevel=2)
832+
814833
# Change size to a list to simplify the checks.
815834
size = [size] if isinstance(size, int) else size
816835
errmsg = {
@@ -829,7 +848,7 @@ def sequence_join(
829848
f"but got {len(value)} values."
830849
)
831850
raise GMTInvalidInput(msg)
832-
return separator.join(str(v) for v in value)
851+
return sep.join(str(v) for v in value)
833852

834853
# Now it must be a 2-D sequence.
835854
if ndim == 1:
@@ -838,4 +857,4 @@ def sequence_join(
838857
if size is not None and any(len(i) not in size for i in value):
839858
msg = f"{errmsg['name']}Expected a sequence of {errmsg['sizes']} values."
840859
raise GMTInvalidInput(msg)
841-
return [separator.join(str(j) for j in sub) for sub in value]
860+
return [sep.join(str(j) for j in sub) for sub in value]

pygmt/src/_common.py

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -244,55 +244,3 @@ def from_params(
244244
if set(param_list).issubset(set(params)):
245245
return cls(convention, component=component)
246246
raise GMTValueError(params, description="focal mechanism parameters")
247-
248-
249-
def _parse_coastline_resolution(
250-
resolution: Literal["auto", "full", "high", "intermediate", "low", "crude", None],
251-
) -> Literal["a", "f", "h", "i", "l", "c", None]:
252-
"""
253-
Parse the 'resolution' parameter for coastline-related functions.
254-
255-
Parameters
256-
----------
257-
resolution
258-
The resolution of the coastline dataset to use. The available resolutions from
259-
highest to lowest are: ``"full"``, ``"high"``, ``"intermediate"``, ``"low"``,
260-
and ``"crude"``, which drops by 80% between levels. Alternatively, choose
261-
``"auto"`` to automatically select the most suitable resolution given the chosen
262-
map scale or region. ``None`` means using the default resolution.
263-
264-
Returns
265-
-------
266-
The single-letter resolution code or ``None``.
267-
268-
Raises
269-
------
270-
GMTValueError
271-
If the resolution is invalid.
272-
273-
Examples
274-
--------
275-
>>> _parse_coastline_resolution("full")
276-
'f'
277-
>>> _parse_coastline_resolution("f")
278-
'f'
279-
>>> _parse_coastline_resolution(None)
280-
>>> _parse_coastline_resolution("invalid")
281-
Traceback (most recent call last):
282-
...
283-
pygmt...GMTValueError: Invalid .... Expected ....
284-
"""
285-
if resolution is None:
286-
return None
287-
288-
_valid_res = {"auto", "full", "high", "intermediate", "low", "crude"}
289-
290-
if resolution in _valid_res: # Long-form arguments.
291-
return resolution[0] # type: ignore[return-value]
292-
293-
if resolution in {_res[0] for _res in _valid_res}: # Short-form arguments.
294-
return resolution # type: ignore[return-value]
295-
296-
raise GMTValueError(
297-
resolution, choices=_valid_res, description="GSHHG coastline resolution"
298-
)

pygmt/src/basemap.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
basemap - Plot base maps and frames.
33
"""
44

5+
from pygmt.alias import Alias, AliasSystem
56
from pygmt.clib import Session
67
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias
78

89

910
@fmt_docstring
1011
@use_alias(
1112
R="region",
12-
J="projection",
1313
Jz="zscale",
1414
JZ="zsize",
1515
B="frame",
@@ -24,7 +24,7 @@
2424
t="transparency",
2525
)
2626
@kwargs_to_strings(R="sequence", c="sequence_comma", p="sequence")
27-
def basemap(self, **kwargs):
27+
def basemap(self, projection=None, **kwargs):
2828
r"""
2929
Plot base maps and frames.
3030
@@ -39,6 +39,7 @@ def basemap(self, **kwargs):
3939
Full GMT docs at :gmt-docs:`basemap.html`.
4040
4141
{aliases}
42+
- J=projection
4243
4344
Parameters
4445
----------
@@ -83,5 +84,8 @@ def basemap(self, **kwargs):
8384
{transparency}
8485
"""
8586
self._activate_figure()
87+
aliasdict = AliasSystem(
88+
J=Alias(projection, name="projection"),
89+
).merge(kwargs)
8690
with Session() as lib:
87-
lib.call_module(module="basemap", args=build_arg_list(kwargs))
91+
lib.call_module(module="basemap", args=build_arg_list(aliasdict))

0 commit comments

Comments
 (0)