From 32c97d596d08e40f5192cf52e6f7423f6771e3b3 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 23 Mar 2024 16:32:32 +0800 Subject: [PATCH] Add a function strings_to_ctypes_array to convert a sequence of strings into a ctypes array --- pygmt/clib/conversion.py | 28 ++++++++++++++++++++++++++++ pygmt/clib/session.py | 14 +++++--------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index 27cda9f971c..6d4fd92e5aa 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -2,7 +2,9 @@ Functions to convert data types into ctypes friendly formats. """ +import ctypes as ctp import warnings +from collections.abc import Sequence import numpy as np from pygmt.exceptions import GMTInvalidInput @@ -280,6 +282,32 @@ def kwargs_to_ctypes_array(argument, kwargs, dtype): return None +def strings_to_ctypes_array(strings: Sequence[str]): + """ + Convert a sequence (e.g., a list) of strings into a ctypes array. + + Parameters + ---------- + strings + A sequence of strings. + + Returns + ------- + ctypes_array + A ctypes array of strings. + + Examples + -------- + >>> strings = ["first", "second", "third"] + >>> ctypes_array = strings_to_ctypes_array(strings) + >>> type(ctypes_array) + + >>> [s.decode() for s in ctypes_array] + ['first', 'second', 'third'] + """ + return (ctp.c_char_p * len(strings))(*[s.encode() for s in strings]) + + def array_to_datetime(array): """ Convert a 1-D datetime array from various types into numpy.datetime64. diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 1bea0e4b886..bc77e1a75ad 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -20,6 +20,7 @@ as_c_contiguous, dataarray_to_matrix, kwargs_to_ctypes_array, + strings_to_ctypes_array, vectors_to_arrays, ) from pygmt.clib.loading import load_libgmt @@ -890,13 +891,9 @@ def put_vector(self, dataset, column, vector): gmt_type = self._check_dtype_and_dim(vector, ndim=1) if gmt_type in (self["GMT_TEXT"], self["GMT_DATETIME"]): - vector_pointer = (ctp.c_char_p * len(vector))() if gmt_type == self["GMT_DATETIME"]: - vector_pointer[:] = np.char.encode( - np.datetime_as_string(array_to_datetime(vector)) - ) - else: - vector_pointer[:] = np.char.encode(vector) + vector = np.datetime_as_string(array_to_datetime(vector)) + vector_pointer = strings_to_ctypes_array(vector) else: vector_pointer = vector.ctypes.data_as(ctp.c_void_p) status = c_put_vector( @@ -953,13 +950,12 @@ def put_strings(self, dataset, family, strings): restype=ctp.c_int, ) - strings_pointer = (ctp.c_char_p * len(strings))() - strings_pointer[:] = np.char.encode(strings) - family_int = self._parse_constant( family, valid=FAMILIES, valid_modifiers=METHODS ) + strings_pointer = strings_to_ctypes_array(strings) + status = c_put_strings( self.session_pointer, family_int, dataset, strings_pointer )