@@ -248,8 +248,8 @@ def from_params(
248248
249249def _parse_position (
250250 position : Position | Sequence [float | str ] | str | None ,
251- kwdict : dict [ str , Any ] ,
252- default : Position | None ,
251+ default : Position | None = None ,
252+ kwdict : dict [ str , Any ] | None = None ,
253253) -> Position | str | None :
254254 """
255255 Parse the "position" parameter for embellishment-plotting functions.
@@ -264,12 +264,14 @@ def _parse_position(
264264 - A 2-character justification code
265265 - A raw GMT command string (for backward compatibility)
266266 - ``None``, in which case the default position is used
267- kwdict
268- The keyword arguments dictionary that conflicts with ``position`` if
269- ``position`` is given as a raw GMT command string.
270267 default
271268 The default Position object to use if ``position`` is ``None``. If ``default``
272269 is ``None``, use the GMT default.
270+ kwdict
271+ The keyword arguments dictionary that conflicts with ``position`` if
272+ ``position`` is given as a raw GMT command string. This is used for backward
273+ compatibility to raise an exception if there are conflicting parameters. If
274+ ``kwdict`` is ``None``, no conflict checking is performed (for new functions).
273275
274276 Returns
275277 -------
@@ -281,76 +283,104 @@ def _parse_position(
281283 >>> from pygmt.params import Position
282284 >>> _parse_position(
283285 ... Position((3, 3), cstype="mapcoords"),
284- ... kwdict={"width": None, "height": None},
285286 ... default=Position((0, 0), cstype="plotcoords"),
287+ ... kwdict={"width": None, "height": None},
286288 ... )
287289 Position(refpoint=(3, 3), cstype='mapcoords')
288290
289291 >>> _parse_position(
290292 ... (3, 3),
291- ... kwdict={"width": None, "height": None},
292293 ... default=Position((0, 0), cstype="plotcoords"),
294+ ... kwdict={"width": None, "height": None},
293295 ... )
294296 Position(refpoint=(3, 3), cstype='plotcoords')
295297 >>> _parse_position(
296298 ... "TL",
297- ... kwdict={"width": None, "height": None},
298299 ... default=Position((0, 0), cstype="plotcoords"),
300+ ... kwdict={"width": None, "height": None},
299301 ... )
300302 Position(refpoint='TL', cstype='inside')
301303
302304 >>> _parse_position(
303305 ... None,
304- ... kwdict={"width": None, "height": None},
305306 ... default=Position((0, 0), cstype="plotcoords"),
307+ ... kwdict={"width": None, "height": None},
306308 ... )
307309 Position(refpoint=(0, 0), cstype='plotcoords')
308310
309311 >>> _parse_position(
310312 ... None,
311- ... kwdict={"width": None, "height": None},
312313 ... default=None,
314+ ... kwdict={"width": None, "height": None},
313315 ... )
314316
315317 >>> _parse_position(
316318 ... "x3c/4c+w2c",
317- ... kwdict={"width": None, "height": None},
318319 ... default=Position((0, 0), cstype="plotcoords"),
320+ ... kwdict={"width": None, "height": None},
319321 ... )
320322 'x3c/4c+w2c'
321323
322324 >>> _parse_position(
323325 ... "x3c/4c+w2c",
324- ... kwdict={"width": 2, "height": None},
325326 ... default=Position((0, 0), cstype="plotcoords"),
327+ ... kwdict={"width": 2, "height": None},
326328 ... )
327329 Traceback (most recent call last):
328330 ...
329331 pygmt.exceptions.GMTInvalidInput: Parameter 'position' is given with a raw GMT...
330332
331333 >>> _parse_position(
332334 ... 123,
333- ... kwdict={"width": None, "height": None},
334335 ... default=Position((0, 0), cstype="plotcoords"),
336+ ... kwdict={"width": None, "height": None},
335337 ... )
336338 Traceback (most recent call last):
337339 ...
338340 pygmt.exceptions.GMTInvalidInput: Invalid type for parameter 'position':...
341+
342+ >>> # Below are examples without kwdict (for new functions).
343+ >>> _parse_position(
344+ ... "BL",
345+ ... default=Position((0, 0), cstype="plotcoords"),
346+ ... )
347+ Position(refpoint='BL', cstype='inside')
348+
349+ >>> _parse_position(
350+ ... "invalid",
351+ ... default=Position((0, 0), cstype="plotcoords"),
352+ ... )
353+ Traceback (most recent call last):
354+ ...
355+ pygmt.exceptions.GMTValueError: Invalid position: 'invalid'...
339356 """
340357
341358 _valid_anchors = {f"{ h } { v } " for v in "TMB" for h in "LCR" } | {
342359 f"{ v } { h } " for v in "TMB" for h in "LCR"
343360 }
344361 match position :
345- case str () if position in _valid_anchors : # Anchor code
346- position = Position (position , cstype = "inside" )
347- case str (): # Raw GMT command string.
348- if any (v is not None and v is not False for v in kwdict .values ()):
349- msg = (
350- "Parameter 'position' is given with a raw GMT command string, and "
351- f"conflicts with parameters { ', ' .join (repr (c ) for c in kwdict )} ."
362+ case str (): # String for anchor code or raw GMT command.
363+ if position in _valid_anchors : # Anchor code
364+ position = Position (position , cstype = "inside" )
365+ elif kwdict is not None : # Raw GMT command string with potential conflicts.
366+ if any (v is not None and v is not False for v in kwdict .values ()):
367+ msg = (
368+ "Parameter 'position' is given with a raw GMT command string, "
369+ "and conflicts with parameters "
370+ f"{ ', ' .join (repr (c ) for c in kwdict )} ."
371+ )
372+ raise GMTInvalidInput (msg )
373+ else :
374+ # No conflicting parameters to check, indicating it's a new function.
375+ # The string must be an anchor code.
376+ raise GMTValueError (
377+ position ,
378+ description = "position" ,
379+ reason = (
380+ "Parameter 'position' must be a two-character anchor code, "
381+ "a coordinate, or a Position object."
382+ ),
352383 )
353- raise GMTInvalidInput (msg )
354384 case Sequence () if len (position ) == 2 : # A sequence of x and y coordinates.
355385 position = Position (position , cstype = "plotcoords" )
356386 case Position (): # Already a Position object.
0 commit comments