4
4
5
5
import dataclasses
6
6
import warnings
7
- from collections import defaultdict
8
7
from collections .abc import Mapping , Sequence
9
8
from typing import Any , Literal
10
9
@@ -227,8 +226,8 @@ class AliasSystem:
227
226
... B=Alias(frame, name="frame"),
228
227
... D=Alias(repeat, name="repeat"),
229
228
... c=Alias(panel, name="panel", separator=","),
230
- ... )
231
- ... return build_arg_list(alias.kwdict | kwargs )
229
+ ... ).update(kwargs)
230
+ ... return build_arg_list(alias.kwdict)
232
231
>>> func(
233
232
... "infile",
234
233
... par1="mytext",
@@ -241,60 +240,67 @@ class AliasSystem:
241
240
['-Amytext+o12/12', '-B', '-D1', '-D2', '-D3', '-JX10c/10c', '-c1,2']
242
241
"""
243
242
244
- def __init__ (self , ** kwargs ):
243
+ def __init__ (self , ** kwargs : Mapping [ str , Alias | Sequence [ Alias ]] ):
245
244
"""
246
245
Initialize the alias system and create the keyword dictionary that stores the
247
246
current parameter values.
248
247
"""
249
- # Keyword dictionary with an empty string as default value.
250
- self .kwdict = defaultdict (str )
251
- for option , aliases in kwargs .items ():
252
- if not is_nonstr_iter (aliases ): # A single alias.
248
+ # Storing the aliases as a dictionary for easy access.
249
+ self .aliasdict = kwargs
250
+
251
+ # Storing option-value as a keyword dictionary.
252
+ self .kwdict = {}
253
+ # Loop over the alias dictionary.
254
+ # The value of each key is an Alias object or a sequence of Alias objects.
255
+ # If it is a single Alias object, we will use its _value property.
256
+ # If it is a sequence of Alias objects, we will concatenate their _value
257
+ # properties into a single string.
258
+
259
+ # Note that alias._value is converted by the _to_string method and can only be
260
+ # None, string or sequence of strings.
261
+ # - None means the parameter is not specified.
262
+ # - Sequence of strings means this is a repeatable option, so it can only have
263
+ # one long-form parameter.
264
+ for option , aliases in self .aliasdict .items ():
265
+ if isinstance (aliases , Sequence ): # A sequence of Alias objects.
266
+ values = [alias ._value for alias in aliases if alias ._value is not None ]
267
+ if values :
268
+ self .kwdict [option ] = "" .join (values )
269
+ elif aliases ._value is not None : # A single Alias object and not None.
253
270
self .kwdict [option ] = aliases ._value
254
- continue
255
-
256
- for alias in aliases : # List of aliases.
257
- match alias ._value :
258
- case None :
259
- continue
260
- case str ():
261
- self .kwdict [option ] += alias ._value
262
- case list ():
263
- # A repeatable option should have only one alias, so break.
264
- self .kwdict [option ] = alias ._value
265
- break
266
-
267
- # Dictionary mapping option flags to their alias objects.
268
- self ._aliasdict = {}
269
- for option , aliases in kwargs .items ():
270
- if not is_nonstr_iter (aliases ):
271
- self ._aliasdict [option ] = [aliases .name ]
272
- else :
273
- self ._aliasdict [option ] = [alias .name for alias in aliases ]
274
-
275
- def merge (self , kwargs ):
271
+ # Now, the dictionary value should be a string or a sequence of strings.
272
+
273
+ def update (self , kwargs : Mapping [str , Any ]):
276
274
"""
277
- Merge additional keyword arguments into the existing keyword dictionary .
275
+ Update the kwdict dictionary with additional keyword arguments .
278
276
279
277
This method is necessary to allow users to use the single-letter parameters for
280
278
option flags that are not aliased.
281
279
"""
282
- # Loop over short-form parameters passed in kwargs.
280
+ # Loop over short-form parameters passed via kwargs.
283
281
for short_param , value in kwargs .items ():
284
- if self ._aliasdict .get (short_param ):
285
- long_form = ", " .join (repr (r ) for r in self ._aliasdict .get (short_param ))
286
-
287
- # Long-form exists and is already given.
288
- if short_param in self .kwdict and self .kwdict [short_param ] is not None :
289
- msg = f"Parameters in short-form { short_param !r} and long-form { long_form } can't coexist."
290
- raise GMTInvalidInput (msg )
291
-
292
- # Long-form exists, but not given.
293
- if short_param in self ._aliasdict :
282
+ # Long-form parameters exist.
283
+ if aliases := self .aliasdict .get (short_param ):
284
+ long_params = ", " .join (
285
+ [repr (alias .name ) for alias in aliases ]
286
+ if isinstance (aliases , Sequence )
287
+ else [repr (aliases .name )]
288
+ )
289
+ # Long-form parameters are already specified.
290
+ if short_param in self .kwdict :
291
+ msg = (
292
+ f"Parameter in short-form { short_param !r} conflicts with "
293
+ f"long-form parameter { long_params } ."
294
+ )
295
+ raise GMTInvalidInput (msg )
296
+
297
+ # Long-form parameters are not specified.
294
298
msg = (
295
299
f"Short-form parameter { short_param !r} is not recommended. "
296
- f"Use long-form parameter { long_form } instead."
300
+ f"Use long-form parameter { long_params } instead."
297
301
)
298
302
warnings .warn (msg , category = SyntaxWarning , stacklevel = 2 )
303
+
304
+ # Update the kwdict with the short-form parameter anyway.
299
305
self .kwdict [short_param ] = value
300
306
return self
0 commit comments