@@ -592,25 +592,36 @@ def get_common(self, option):
592
592
# the function return value (i.e., 'status')
593
593
return status
594
594
595
- def call_module (self , module , args ):
595
+ def call_module (self , module : str , args : str | list [ str ] ):
596
596
"""
597
597
Call a GMT module with the given arguments.
598
598
599
- Makes a call to ``GMT_Call_Module`` from the C API using mode
600
- ``GMT_MODULE_CMD`` (arguments passed as a single string).
599
+ Wraps ``GMT_Call_Module``.
601
600
602
- Most interactions with the C API are done through this function.
601
+ The ``GMT_Call_Module`` API function supports passing module arguments in three
602
+ different ways:
603
+
604
+ 1. Pass a single string that contains whitespace-separated module arguments.
605
+ 2. Pass a list of strings and each string contains a module argument.
606
+ 3. Pass a list of ``GMT_OPTION`` data structure.
607
+
608
+ Both options 1 and 2 are implemented in this function, but option 2 is preferred
609
+ because it can correctly handle special characters like whitespaces and
610
+ quotation marks in module arguments.
603
611
604
612
Parameters
605
613
----------
606
- module : str
607
- Module name (``'coast'``, ``'basemap'``, etc).
608
- args : str
609
- String with the command line arguments that will be passed to the
610
- module (for example, ``'-R0/5/0/10 -JM'``).
614
+ module
615
+ The GMT module name to be called (``"coast"``, ``"basemap"``, etc).
616
+ args
617
+ Module arguments that will be passed to the GMT module. It can be either
618
+ a single string (e.g., ``"-R0/5/0/10 -JX10c -BWSen+t'My Title'"``) or a list
619
+ of strings (e.g., ``["-R0/5/0/10", "-JX10c", "-BWSEN+tMy Title"]``).
611
620
612
621
Raises
613
622
------
623
+ GMTInvalidInput
624
+ If the ``args`` argument is not a string or a list of strings.
614
625
GMTCLibError
615
626
If the returned status code of the function is non-zero.
616
627
"""
@@ -620,10 +631,29 @@ def call_module(self, module, args):
620
631
restype = ctp .c_int ,
621
632
)
622
633
623
- mode = self ["GMT_MODULE_CMD" ]
624
- status = c_call_module (
625
- self .session_pointer , module .encode (), mode , args .encode ()
626
- )
634
+ # 'args' can be (1) a single string or (2) a list of strings.
635
+ argv : bytes | ctp .Array [ctp .c_char_p ] | None
636
+ if isinstance (args , str ):
637
+ # 'args' is a single string that contains whitespace-separated arguments.
638
+ # In this way, we need to correctly handle option arguments that contain
639
+ # whitespaces or quotation marks. It's used in PyGMT <= v0.11.0 but is no
640
+ # longer recommended.
641
+ mode = self ["GMT_MODULE_CMD" ]
642
+ argv = args .encode ()
643
+ elif isinstance (args , list ):
644
+ # 'args' is a list of strings and each string contains a module argument.
645
+ # In this way, GMT can correctly handle option arguments with whitespaces or
646
+ # quotation marks. This is the preferred way to pass arguments to the GMT
647
+ # API and is used for PyGMT >= v0.12.0.
648
+ mode = len (args ) # 'mode' is the number of arguments.
649
+ # Pass a null pointer if no arguments are specified.
650
+ argv = strings_to_ctypes_array (args ) if mode != 0 else None
651
+ else :
652
+ raise GMTInvalidInput (
653
+ "'args' must be either a string or a list of strings."
654
+ )
655
+
656
+ status = c_call_module (self .session_pointer , module .encode (), mode , argv )
627
657
if status != 0 :
628
658
raise GMTCLibError (
629
659
f"Module '{ module } ' failed with status code { status } :\n { self ._error_message } "
0 commit comments