Skip to content

Commit ebb3257

Browse files
committed
Merge branch 'main' into data_kind/vectors-none
2 parents 78fdfb1 + a5c0aa2 commit ebb3257

19 files changed

+987
-832
lines changed

.github/workflows/benchmarks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787

8888
# Run the benchmark tests
8989
- name: Run benchmarks
90-
uses: CodSpeedHQ/[email protected].0
90+
uses: CodSpeedHQ/[email protected].1
9191
with:
9292
# 'bash -el -c' is needed to use the custom shell.
9393
# See https://github.com/CodSpeedHQ/action/issues/65.

.github/workflows/check-links.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ jobs:
3535

3636
- name: Link Checker
3737
id: lychee
38-
uses: lycheeverse/lychee-action@v1.10.0
38+
uses: lycheeverse/lychee-action@v2.0.2
3939
with:
40+
fail: false # Don't fail action on broken links
4041
output: /tmp/lychee-out.md
4142
# 429: Too many requests
4243
args: >

.github/workflows/ci_tests_legacy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
strategy:
3535
fail-fast: false
3636
matrix:
37-
os: [ubuntu-20.04, macos-12, windows-2019]
37+
os: [ubuntu-20.04, macos-13, windows-2019]
3838
gmt_version: ['6.4']
3939
timeout-minutes: 30
4040
defaults:

doc/external_resources.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Andre Belem
107107
:text-align: center
108108
:margin: 0 3 0 0
109109

110-
![](https://github.com/tktmyd/pygmt-howto-jp/raw/main/docs/_images/01aed847a81445c7a002cce113d95886793f6236fbcccb233862486589f17ed1.png)
110+
![](https://github.com/tktmyd/pygmt-howto-jp/raw/main/docs/_images/inf_on_map_12_0.png)
111111
+++
112112
Takuto Maeda
113113
::::

pygmt/clib/session.py

Lines changed: 90 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import pathlib
1212
import sys
1313
import warnings
14-
from collections.abc import Generator, Sequence
14+
from collections.abc import Callable, Generator, Sequence
1515
from typing import Literal
1616

1717
import numpy as np
@@ -268,7 +268,9 @@ def get_enum(self, name: str) -> int:
268268
raise GMTCLibError(f"Constant '{name}' doesn't exist in libgmt.")
269269
return value
270270

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:
272274
"""
273275
Get a ctypes function from the libgmt shared library.
274276
@@ -278,14 +280,14 @@ def get_libgmt_func(self, name, argtypes=None, restype=None):
278280
279281
Parameters
280282
----------
281-
name : str
283+
name
282284
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.
286288
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.
289291
290292
Returns
291293
-------
@@ -312,43 +314,42 @@ def get_libgmt_func(self, name, argtypes=None, restype=None):
312314
function.restype = restype
313315
return function
314316

315-
def create(self, name):
317+
def create(self, name: str):
316318
"""
317319
Create a new GMT C API session.
318320
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.
321323
322324
.. warning::
323325
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
327328
:meth:`pygmt.clib.Session.destroy` manually.
328329
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.
332333
333334
Remember to terminate the current session using
334335
:meth:`pygmt.clib.Session.destroy` before creating a new one.
335336
336337
Parameters
337338
----------
338-
name : str
339+
name
339340
A name for this session. Doesn't really affect the outcome.
340341
"""
341342
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.
343344
_ = 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 = (
347347
"Failed to create a GMT API session: There is a currently open session."
348348
" Must destroy it first."
349349
)
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.
352353
except GMTCLibNoSessionError:
353354
pass
354355

@@ -358,9 +359,9 @@ def create(self, name):
358359
restype=ctp.c_void_p,
359360
)
360361

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] = []
364365

365366
@ctp.CFUNCTYPE(ctp.c_int, ctp.c_void_p, ctp.c_char_p)
366367
def print_func(file_pointer, message): # noqa: ARG001
@@ -382,24 +383,22 @@ def print_func(file_pointer, message): # noqa: ARG001
382383
print(message, file=sys.stderr, flush=True) # noqa: T201
383384
return 0
384385

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
387388
self._print_callback = print_func
388389

389390
padding = self["GMT_PAD_DEFAULT"]
390391
session_type = self["GMT_SESSION_EXTERNAL"]
391-
392392
session = c_create_session(name.encode(), padding, session_type, print_func)
393393

394394
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)
398397

399398
self.session_pointer = session
400399

401400
@property
402-
def _error_message(self):
401+
def _error_message(self) -> str:
403402
"""
404403
A string with all error messages emitted by the C API.
405404
@@ -416,19 +415,17 @@ def destroy(self):
416415
417416
.. warning::
418417
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
422420
:meth:`pygmt.clib.Session.destroy` manually.
423421
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).
427425
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.
432429
433430
Sets the ``session_pointer`` attribute to ``None``.
434431
"""
@@ -438,9 +435,8 @@ def destroy(self):
438435

439436
status = c_destroy_session(self.session_pointer)
440437
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)
444440

445441
self.session_pointer = None
446442

@@ -1203,41 +1199,46 @@ def write_data(self, family, geometry, mode, wesn, output, data):
12031199
raise GMTCLibError(f"Failed to write dataset to '{output}'")
12041200

12051201
@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]:
12071209
"""
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.
12091211
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.
12141216
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.
12181220
12191221
Parameters
12201222
----------
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.
12371238
12381239
Yields
12391240
------
1240-
vfname : str
1241+
vfname
12411242
The name of the virtual file that you can pass to a GMT module.
12421243
12431244
Examples
@@ -1270,19 +1271,19 @@ def open_virtualfile(self, family, geometry, direction, data):
12701271
c_open_virtualfile = self.get_libgmt_func(
12711272
"GMT_Open_VirtualFile",
12721273
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
12791280
],
12801281
restype=ctp.c_int,
12811282
)
12821283

12831284
c_close_virtualfile = self.get_libgmt_func(
12841285
"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
12861287
restype=ctp.c_int,
12871288
)
12881289

@@ -1297,19 +1298,24 @@ def open_virtualfile(self, family, geometry, direction, data):
12971298
self.session_pointer, family_int, geometry_int, direction_int, data, buff
12981299
)
12991300
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)
13011306

13021307
vfname = buff.value.decode()
13031308
try:
13041309
yield vfname
13051310
finally:
13061311
status = c_close_virtualfile(self.session_pointer, vfname.encode())
13071312
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)
13091315

13101316
def open_virtual_file(self, family, geometry, direction, data):
13111317
"""
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.
13131319
13141320
.. deprecated: 0.11.0
13151321
@@ -1822,6 +1828,7 @@ def virtualfile_in( # noqa: PLR0912
18221828
_data = (data,)
18231829
if data.dtype.kind not in "iuf":
18241830
_virtualfile_from = self.virtualfile_from_vectors
1831+
_data = data.T
18251832

18261833
# Finally create the virtualfile from the data, to be passed into GMT
18271834
file_context = _virtualfile_from(*_data)

pygmt/datasets/load_remote_dataset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ def _load_remote_dataset(
441441
"returned unless only the pixel-registered grid is available."
442442
)
443443

444-
fname = f"@{prefix}_{resolution}_{registration[0]}"
444+
fname = f"@{prefix}_{resolution}_{registration[0]}" # type: ignore[index]
445445
if resinfo.tiled and region is None:
446446
raise GMTInvalidInput(
447447
f"'region' is required for {dataset.description} resolution '{resolution}'."

0 commit comments

Comments
 (0)