@@ -711,3 +711,110 @@ def args_in_kwargs(args: Sequence[str], kwargs: dict[str, Any]) -> bool:
711
711
return any (
712
712
kwargs .get (arg ) is not None and kwargs .get (arg ) is not False for arg in args
713
713
)
714
+
715
+
716
+ def sequence_join (
717
+ value : Any ,
718
+ separator : str = "/" ,
719
+ size : int | Sequence [int ] | None = None ,
720
+ ndim : int = 1 ,
721
+ name : str | None = None ,
722
+ ) -> str | list [str ] | None | Any :
723
+ """
724
+ Join a sequence of values into a string separated by a separator.
725
+
726
+ A 1-D sequence will be joined into a single string. A 2-D sequence will be joined
727
+ into a list of strings. Non-sequence values will be returned as is.
728
+
729
+ Parameters
730
+ ----------
731
+ value
732
+ The 1-D or 2-D sequence of values to join.
733
+ separator
734
+ The separator to join the values.
735
+ size
736
+ Expected size of the 1-D sequence. It can be either an integer or a sequence of
737
+ integers. If an integer, it is the expected size of the 1-D sequence. If it is a
738
+ sequence, it is the allowed sizes of the 1-D sequence.
739
+ ndim
740
+ The expected maximum number of dimensions of the sequence.
741
+ name
742
+ The name of the parameter to be used in the error message.
743
+
744
+ Returns
745
+ -------
746
+ joined_value
747
+ The joined string or list of strings.
748
+
749
+ Examples
750
+ --------
751
+ >>> sequence_join("abc")
752
+ 'abc'
753
+ >>> sequence_join(None)
754
+ >>> sequence_join([])
755
+ []
756
+
757
+ >>> sequence_join([1, 2, 3, 4])
758
+ '1/2/3/4'
759
+ >>> sequence_join([1, 2, 3, 4], separator=",")
760
+ '1,2,3,4'
761
+ >>> sequence_join([1, 2, 3, 4], separator="/", size=4)
762
+ '1/2/3/4'
763
+ >>> sequence_join([1, 2, 3, 4], separator="/", size=[2, 4])
764
+ '1/2/3/4'
765
+ >>> sequence_join([1, 2, 3, 4], separator="/", size=[2, 4], ndim=2)
766
+ '1/2/3/4'
767
+ >>> sequence_join([1, 2, 3, 4], separator="/", size=2)
768
+ Traceback (most recent call last):
769
+ ...
770
+ pygmt.exceptions.GMTInvalidInput: Expected a sequence of 2 values, but got 4 values.
771
+ >>> sequence_join([1, 2, 3, 4, 5], separator="/", size=[2, 4], name="parname")
772
+ Traceback (most recent call last):
773
+ ...
774
+ pygmt.exceptions.GMTInvalidInput: Parameter 'parname': Expected ...
775
+
776
+ >>> sequence_join([[1, 2], [3, 4]], separator="/")
777
+ Traceback (most recent call last):
778
+ ...
779
+ pygmt.exceptions.GMTInvalidInput: Expected a 1-D ..., but a 2-D sequence is given.
780
+ >>> sequence_join([[1, 2], [3, 4]], separator="/", ndim=2)
781
+ ['1/2', '3/4']
782
+ >>> sequence_join([[1, 2], [3, 4]], separator="/", size=2, ndim=2)
783
+ ['1/2', '3/4']
784
+ >>> sequence_join([[1, 2], [3, 4]], separator="/", size=4, ndim=2)
785
+ Traceback (most recent call last):
786
+ ...
787
+ pygmt.exceptions.GMTInvalidInput: Expected a sequence of 4 values.
788
+ >>> sequence_join([[1, 2], [3, 4]], separator="/", size=[2, 4], ndim=2)
789
+ ['1/2', '3/4']
790
+ """
791
+ # Return the original value if it is not a sequence (e.g., None or str) or empty.
792
+ if not is_nonstr_iter (value ) or len (value ) == 0 :
793
+ return value
794
+
795
+ # Change size to a list to simplify the checks.
796
+ size = [size ] if isinstance (size , int ) else size
797
+
798
+ errmsg = {
799
+ "name" : f"Parameter '{ name } ': " if name else "" ,
800
+ "sizes" : ", " .join (str (s ) for s in size ) if size is not None else "" ,
801
+ }
802
+
803
+ # Now it must be a sequence.
804
+ if not is_nonstr_iter (value [0 ]): # 1-D sequence.
805
+ if size is not None and len (value ) not in size :
806
+ msg = (
807
+ f"{ errmsg ['name' ]} Expected a sequence of { errmsg ['sizes' ]} values, "
808
+ f"but got { len (value )} values."
809
+ )
810
+ raise GMTInvalidInput (msg )
811
+ return separator .join (str (v ) for v in value )
812
+
813
+ # Now it must be a 2-D sequence.
814
+ if ndim == 1 :
815
+ msg = f"{ errmsg ['name' ]} Expected a 1-D sequence, but a 2-D sequence is given."
816
+ raise GMTInvalidInput (msg )
817
+ if size is not None and any (len (i ) not in size for i in value ):
818
+ msg = f"{ errmsg ['name' ]} Expected a sequence of { errmsg ['sizes' ]} values."
819
+ raise GMTInvalidInput (msg )
820
+ return [separator .join (str (j ) for j in value [i ]) for i in range (len (value ))]
0 commit comments