11
11
import pathlib
12
12
import sys
13
13
import warnings
14
- from collections .abc import Generator , Sequence
14
+ from collections .abc import Callable , Generator , Sequence
15
15
from typing import Literal
16
16
17
17
import numpy as np
@@ -268,7 +268,9 @@ def get_enum(self, name: str) -> int:
268
268
raise GMTCLibError (f"Constant '{ name } ' doesn't exist in libgmt." )
269
269
return value
270
270
271
- def get_libgmt_func (self , name , argtypes = None , restype = None ):
271
+ def get_libgmt_func (
272
+ self , name : str , argtypes : list | None = None , restype = None
273
+ ) -> Callable :
272
274
"""
273
275
Get a ctypes function from the libgmt shared library.
274
276
@@ -278,14 +280,14 @@ def get_libgmt_func(self, name, argtypes=None, restype=None):
278
280
279
281
Parameters
280
282
----------
281
- name : str
283
+ name
282
284
The name of the GMT API function.
283
- argtypes : list
284
- List of ctypes types used to convert the Python input arguments for
285
- the API function.
285
+ argtypes
286
+ List of ctypes types used to convert the Python input arguments for the API
287
+ function.
286
288
restype : ctypes type
287
- The ctypes type used to convert the input returned by the function
288
- into a Python type.
289
+ The ctypes type used to convert the input returned by the function into a
290
+ Python type.
289
291
290
292
Returns
291
293
-------
@@ -312,43 +314,42 @@ def get_libgmt_func(self, name, argtypes=None, restype=None):
312
314
function .restype = restype
313
315
return function
314
316
315
- def create (self , name ):
317
+ def create (self , name : str ):
316
318
"""
317
319
Create a new GMT C API session.
318
320
319
- This is required before most other methods of
320
- :class:`pygmt.clib.Session` can be called.
321
+ This is required before most other methods of :class:`pygmt.clib.Session` can be
322
+ called.
321
323
322
324
.. warning::
323
325
324
- Usage of :class:`pygmt.clib.Session` as a context manager in a
325
- ``with`` block is preferred over calling
326
- :meth:`pygmt.clib.Session.create` and
326
+ Usage of :class:`pygmt.clib.Session` as a context manager in a ``with``
327
+ block is preferred over calling :meth:`pygmt.clib.Session.create` and
327
328
:meth:`pygmt.clib.Session.destroy` manually.
328
329
329
- Calls ``GMT_Create_Session`` and generates a new ``GMTAPI_CTRL``
330
- struct, which is a :class:`ctypes.c_void_p` pointer. Sets the
331
- ``session_pointer`` attribute to this pointer.
330
+ Calls ``GMT_Create_Session`` and generates a new ``GMTAPI_CTRL`` struct, which
331
+ is a :class:`ctypes.c_void_p` pointer. Sets the ``session_pointer`` attribute to
332
+ this pointer.
332
333
333
334
Remember to terminate the current session using
334
335
:meth:`pygmt.clib.Session.destroy` before creating a new one.
335
336
336
337
Parameters
337
338
----------
338
- name : str
339
+ name
339
340
A name for this session. Doesn't really affect the outcome.
340
341
"""
341
342
try :
342
- # Won't raise an exception if there is a currently open session
343
+ # Won't raise an exception if there is a currently open session.
343
344
_ = self .session_pointer
344
- # In this case, fail to create a new session until the old one is
345
- # destroyed
346
- raise GMTCLibError (
345
+ # In this case, fail to create a new session until the old one is destroyed.
346
+ msg = (
347
347
"Failed to create a GMT API session: There is a currently open session."
348
348
" Must destroy it first."
349
349
)
350
- # If the exception is raised, this means that there is no open session
351
- # and we're free to create a new one.
350
+ raise GMTCLibError (msg )
351
+ # If the exception is raised, this means that there is no open session and we're
352
+ # free to create a new one.
352
353
except GMTCLibNoSessionError :
353
354
pass
354
355
@@ -358,9 +359,9 @@ def create(self, name):
358
359
restype = ctp .c_void_p ,
359
360
)
360
361
361
- # Capture the output printed by GMT into this list. Will use it later
362
- # to generate error messages for the exceptions raised by API calls.
363
- self ._error_log = []
362
+ # Capture the output printed by GMT into this list. Will use it later to
363
+ # generate error messages for the exceptions raised by API calls.
364
+ self ._error_log : list [ str ] = []
364
365
365
366
@ctp .CFUNCTYPE (ctp .c_int , ctp .c_void_p , ctp .c_char_p )
366
367
def print_func (file_pointer , message ): # noqa: ARG001
@@ -382,24 +383,22 @@ def print_func(file_pointer, message): # noqa: ARG001
382
383
print (message , file = sys .stderr , flush = True ) # noqa: T201
383
384
return 0
384
385
385
- # Need to store a copy of the function because ctypes doesn't and it
386
- # will be garbage collected otherwise
386
+ # Need to store a copy of the function because ctypes doesn't and it will be
387
+ # garbage collected otherwise
387
388
self ._print_callback = print_func
388
389
389
390
padding = self ["GMT_PAD_DEFAULT" ]
390
391
session_type = self ["GMT_SESSION_EXTERNAL" ]
391
-
392
392
session = c_create_session (name .encode (), padding , session_type , print_func )
393
393
394
394
if session is None :
395
- raise GMTCLibError (
396
- f"Failed to create a GMT API session:\n { self ._error_message } "
397
- )
395
+ msg = f"Failed to create a GMT API session:\n { self ._error_message } "
396
+ raise GMTCLibError (msg )
398
397
399
398
self .session_pointer = session
400
399
401
400
@property
402
- def _error_message (self ):
401
+ def _error_message (self ) -> str :
403
402
"""
404
403
A string with all error messages emitted by the C API.
405
404
@@ -416,19 +415,17 @@ def destroy(self):
416
415
417
416
.. warning::
418
417
419
- Usage of :class:`pygmt.clib.Session` as a context manager in a
420
- ``with`` block is preferred over calling
421
- :meth:`pygmt.clib.Session.create` and
418
+ Usage of :class:`pygmt.clib.Session` as a context manager in a ``with``
419
+ block is preferred over calling :meth:`pygmt.clib.Session.create` and
422
420
:meth:`pygmt.clib.Session.destroy` manually.
423
421
424
- Calls ``GMT_Destroy_Session`` to terminate and free the memory of a
425
- registered ``GMTAPI_CTRL`` session (the pointer for this struct is
426
- stored in the ``session_pointer`` attribute).
422
+ Calls ``GMT_Destroy_Session`` to terminate and free the memory of a registered
423
+ ``GMTAPI_CTRL`` session (the pointer for this struct is stored in the
424
+ ``session_pointer`` attribute).
427
425
428
- Always use this method after you are done using a C API session. The
429
- session needs to be destroyed before creating a new one. Otherwise,
430
- some of the configuration files might be left behind and can influence
431
- subsequent API calls.
426
+ Always use this method after you are done using a C API session. The session
427
+ needs to be destroyed before creating a new one. Otherwise, some of the
428
+ configuration files might be left behind and can influence subsequent API calls.
432
429
433
430
Sets the ``session_pointer`` attribute to ``None``.
434
431
"""
@@ -438,9 +435,8 @@ def destroy(self):
438
435
439
436
status = c_destroy_session (self .session_pointer )
440
437
if status :
441
- raise GMTCLibError (
442
- f"Failed to destroy GMT API session:\n { self ._error_message } "
443
- )
438
+ msg = f"Failed to destroy GMT API session:\n { self ._error_message } "
439
+ raise GMTCLibError (msg )
444
440
445
441
self .session_pointer = None
446
442
@@ -1203,41 +1199,46 @@ def write_data(self, family, geometry, mode, wesn, output, data):
1203
1199
raise GMTCLibError (f"Failed to write dataset to '{ output } '" )
1204
1200
1205
1201
@contextlib .contextmanager
1206
- def open_virtualfile (self , family , geometry , direction , data ):
1202
+ def open_virtualfile (
1203
+ self ,
1204
+ family : str ,
1205
+ geometry : str ,
1206
+ direction : str ,
1207
+ data : ctp .c_void_p | None ,
1208
+ ) -> Generator [str , None , None ]:
1207
1209
"""
1208
- Open a GMT virtual file to pass data to and from a module .
1210
+ Open a GMT virtual file associated with a data object for reading or writing .
1209
1211
1210
- GMT uses a virtual file scheme to pass in data or get data from API
1211
- modules. Use it to pass in your GMT data structure (created using
1212
- :meth:`pygmt.clib.Session.create_data`) to a module that expects an
1213
- input file, or get the output from a module that writes to a file.
1212
+ GMT uses a virtual file scheme to pass in data or get data from API modules. Use
1213
+ it to pass in your GMT data structure (created using
1214
+ :meth:`pygmt.clib.Session.create_data`) to a module that expects an input file,
1215
+ or get the output from a module that writes to a file.
1214
1216
1215
- Use in a ``with`` block. Will automatically close the virtual file when
1216
- leaving the ``with`` block. Because of this, no wrapper for
1217
- ``GMT_Close_VirtualFile`` is provided.
1217
+ Use in a ``with`` block. Will automatically close the virtual file when leaving
1218
+ the ``with`` block. Because of this, no wrapper for ``GMT_Close_VirtualFile``
1219
+ is provided.
1218
1220
1219
1221
Parameters
1220
1222
----------
1221
- family : str
1222
- A valid GMT data family name (e.g., ``"GMT_IS_DATASET"``). Should
1223
- be the same as the one you used to create your data structure.
1224
- geometry : str
1225
- A valid GMT data geometry name (e.g., ``"GMT_IS_POINT"``). Should
1226
- be the same as the one you used to create your data structure.
1227
- direction : str
1228
- Either ``"GMT_IN"`` or ``"GMT_OUT"`` to indicate if passing data to
1229
- GMT or getting it out of GMT, respectively.
1230
- By default, GMT can modify the data you pass in. Add modifier
1231
- ``"GMT_IS_REFERENCE"`` to tell GMT the data are read-only, or
1232
- ``"GMT_IS_DUPLICATE"`` to tell GMT to duplicate the data.
1233
- data : int or None
1234
- The ctypes void pointer to your GMT data structure. For output
1235
- (i.e., ``direction="GMT_OUT"``), it can be ``None`` to have GMT
1236
- automatically allocate the output GMT data structure.
1223
+ family
1224
+ A valid GMT data family name (e.g., ``"GMT_IS_DATASET"``). Should be the
1225
+ same as the one you used to create your data structure.
1226
+ geometry
1227
+ A valid GMT data geometry name (e.g., ``"GMT_IS_POINT"``). Should be the
1228
+ same as the one you used to create your data structure.
1229
+ direction
1230
+ Either ``"GMT_IN"`` or ``"GMT_OUT"`` to indicate if passing data to GMT or
1231
+ getting it out of GMT, respectively. By default, GMT can modify the data you
1232
+ pass in. Add modifier ``"GMT_IS_REFERENCE"`` to tell GMT the data are
1233
+ read-only, or ``"GMT_IS_DUPLICATE"`` to tell GMT to duplicate the data.
1234
+ data
1235
+ The ctypes void pointer to the GMT data structure. For output (i.e.,
1236
+ ``direction="GMT_OUT"``), it can be ``None`` to have GMT automatically
1237
+ allocate the output GMT data structure.
1237
1238
1238
1239
Yields
1239
1240
------
1240
- vfname : str
1241
+ vfname
1241
1242
The name of the virtual file that you can pass to a GMT module.
1242
1243
1243
1244
Examples
@@ -1270,19 +1271,19 @@ def open_virtualfile(self, family, geometry, direction, data):
1270
1271
c_open_virtualfile = self .get_libgmt_func (
1271
1272
"GMT_Open_VirtualFile" ,
1272
1273
argtypes = [
1273
- ctp .c_void_p ,
1274
- ctp .c_uint ,
1275
- ctp .c_uint ,
1276
- ctp .c_uint ,
1277
- ctp .c_void_p ,
1278
- ctp .c_char_p ,
1274
+ ctp .c_void_p , # V_API
1275
+ ctp .c_uint , # family
1276
+ ctp .c_uint , # geometry
1277
+ ctp .c_uint , # direction
1278
+ ctp .c_void_p , # data
1279
+ ctp .c_char_p , # name
1279
1280
],
1280
1281
restype = ctp .c_int ,
1281
1282
)
1282
1283
1283
1284
c_close_virtualfile = self .get_libgmt_func (
1284
1285
"GMT_Close_VirtualFile" ,
1285
- argtypes = [ctp .c_void_p , ctp .c_char_p ],
1286
+ argtypes = [ctp .c_void_p , ctp .c_char_p ], # V_API, name
1286
1287
restype = ctp .c_int ,
1287
1288
)
1288
1289
@@ -1297,19 +1298,24 @@ def open_virtualfile(self, family, geometry, direction, data):
1297
1298
self .session_pointer , family_int , geometry_int , direction_int , data , buff
1298
1299
)
1299
1300
if status != 0 :
1300
- raise GMTCLibError ("Failed to create a virtual file." )
1301
+ msg = (
1302
+ f"Failed to create a virtual file with { family = } , { geometry = } , "
1303
+ f"{ direction = } ."
1304
+ )
1305
+ raise GMTCLibError (msg )
1301
1306
1302
1307
vfname = buff .value .decode ()
1303
1308
try :
1304
1309
yield vfname
1305
1310
finally :
1306
1311
status = c_close_virtualfile (self .session_pointer , vfname .encode ())
1307
1312
if status != 0 :
1308
- raise GMTCLibError (f"Failed to close virtual file '{ vfname } '." )
1313
+ msg = f"Failed to close virtual file '{ vfname } '."
1314
+ raise GMTCLibError (msg )
1309
1315
1310
1316
def open_virtual_file (self , family , geometry , direction , data ):
1311
1317
"""
1312
- Open a GMT virtual file to pass data to and from a module .
1318
+ Open a GMT virtual file associated with a data object for reading or writing .
1313
1319
1314
1320
.. deprecated: 0.11.0
1315
1321
@@ -1822,6 +1828,7 @@ def virtualfile_in( # noqa: PLR0912
1822
1828
_data = (data ,)
1823
1829
if data .dtype .kind not in "iuf" :
1824
1830
_virtualfile_from = self .virtualfile_from_vectors
1831
+ _data = data .T
1825
1832
1826
1833
# Finally create the virtualfile from the data, to be passed into GMT
1827
1834
file_context = _virtualfile_from (* _data )
0 commit comments