Skip to content

Commit 71a51de

Browse files
committed
New Alias System: Add the private _to_string function (#3986)
1 parent 61410c8 commit 71a51de

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

pygmt/alias.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""
2+
The PyGMT alias system to convert PyGMT's long-form arguments to GMT's short-form.
3+
"""
4+
5+
from collections.abc import Mapping, Sequence
6+
from typing import Any, Literal
7+
8+
from pygmt.exceptions import GMTValueError
9+
from pygmt.helpers.utils import is_nonstr_iter, sequence_join
10+
11+
12+
def _to_string(
13+
value: Any,
14+
prefix: str = "", # Default to an empty string to simplify the code logic.
15+
mapping: Mapping | None = None,
16+
separator: Literal["/", ","] | None = None,
17+
size: int | Sequence[int] | None = None,
18+
ndim: int = 1,
19+
name: str | None = None,
20+
) -> str | list[str] | None:
21+
"""
22+
Convert any value to a string, a sequence of strings or None.
23+
24+
The general rules are:
25+
26+
- ``None``/``False`` will be converted to ``None``.
27+
- ``True`` will be converted to an empty string.
28+
- A sequence will be joined by the separator if a separator is provided. Otherwise,
29+
each item in the sequence will be converted to a string and a sequence of strings
30+
will be returned. It's also possible to validate the size and dimension of the
31+
sequence.
32+
- Any other type of values will be converted to a string if possible.
33+
34+
If a mapping dictionary is provided, the value will be converted to the short-form
35+
string that GMT accepts (e.g., mapping PyGMT's long-form argument ``"high"`` to
36+
GMT's short-form argument ``"h"``).
37+
38+
An optional prefix (e.g., `"+o"`) can be added to the beginning of the converted
39+
string.
40+
41+
To avoid extra overhead, this function does not validate parameter combinations. For
42+
example, if ``value`` is a sequence but ``separator`` is not specified, the function
43+
will return a sequence of strings. In this case, ``prefix`` has no effect, but the
44+
function does not check for such inconsistencies. The maintaner should ensure that
45+
the parameter combinations are valid.
46+
47+
Parameters
48+
----------
49+
value
50+
The value to convert.
51+
prefix
52+
The string to add as a prefix to the returned value.
53+
mapping
54+
A mapping dictionary to map PyGMT's long-form arguments to GMT's short-form.
55+
separator
56+
The separator to use if the value is a sequence.
57+
size
58+
Expected size of the 1-D sequence. It can be either an integer or a sequence of
59+
integers. If an integer, it is the expected size of the 1-D sequence. If it is a
60+
sequence, it is the allowed sizes of the 1-D sequence.
61+
ndim
62+
The expected maximum number of dimensions of the sequence.
63+
name
64+
The name of the parameter to be used in the error message.
65+
66+
Returns
67+
-------
68+
ret
69+
The converted value.
70+
71+
Examples
72+
--------
73+
>>> _to_string("text")
74+
'text'
75+
>>> _to_string(12)
76+
'12'
77+
>>> _to_string(True)
78+
''
79+
>>> _to_string(False)
80+
>>> _to_string(None)
81+
82+
>>> _to_string("text", prefix="+a")
83+
'+atext'
84+
>>> _to_string(12, prefix="+a")
85+
'+a12'
86+
>>> _to_string(True, prefix="+a")
87+
'+a'
88+
>>> _to_string(False, prefix="+a")
89+
>>> _to_string(None, prefix="+a")
90+
91+
>>> _to_string("mean", mapping={"mean": "a", "mad": "d", "full": "g"})
92+
'a'
93+
>>> _to_string("invalid", mapping={"mean": "a", "mad": "d", "full": "g"})
94+
Traceback (most recent call last):
95+
...
96+
pygmt...GMTValueError: Invalid value: 'invalid'. Expected one of: 'mean', ...
97+
98+
>>> _to_string((12, 34), separator="/")
99+
'12/34'
100+
>>> _to_string(("12p", "34p"), separator=",")
101+
'12p,34p'
102+
>>> _to_string(("12p", "34p"), prefix="+o", separator="/")
103+
'+o12p/34p'
104+
105+
>>> _to_string(["xaf", "yaf", "WSen"])
106+
['xaf', 'yaf', 'WSen']
107+
"""
108+
# None and False are converted to None.
109+
if value is None or value is False:
110+
return None
111+
# True is converted to an empty string with the optional prefix.
112+
if value is True:
113+
return f"{prefix}"
114+
# Any non-sequence value is converted to a string.
115+
if not is_nonstr_iter(value):
116+
if mapping:
117+
if value not in mapping and value not in mapping.values():
118+
raise GMTValueError(
119+
value,
120+
description="value for parameter {name!r}" if name else "value",
121+
choices=mapping.keys(),
122+
)
123+
value = mapping.get(value, value)
124+
return f"{prefix}{value}"
125+
126+
# Return the sequence if separator is not specified for options like '-B'.
127+
# True in a sequence will be converted to an empty string.
128+
if separator is None:
129+
return [str(item) if item is not True else "" for item in value]
130+
# Join the sequence of values with the separator.
131+
# "prefix" and "mapping" are ignored. We can enable them when needed.
132+
_value = sequence_join(value, separator=separator, size=size, ndim=ndim, name=name)
133+
return f"{prefix}{_value}"

0 commit comments

Comments
 (0)