From 3c630f69a814b016f6176b8311f22662b106c320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Ignacio=20Torres?= Date: Sun, 12 Sep 2021 20:09:05 -0400 Subject: [PATCH] Add support for passing pathlib.Path objects as filenames (#1382) Co-authored-by: Dongdong Tian Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/clib/session.py | 12 ++++++++---- pygmt/helpers/utils.py | 13 +++++++++---- pygmt/tests/test_info.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 89026a71b94..a775a119c80 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1376,9 +1376,10 @@ def virtualfile_from_data( check_kind : str Used to validate the type of data that can be passed in. Choose from 'raster', 'vector' or None. Default is None (no validation). - data : str or xarray.DataArray or {table-like} or None - Any raster or vector data format. This could be a file name, a - raster grid, a vector matrix/arrays, or other supported data input. + data : str or pathlib.Path or xarray.DataArray or {table-like} or None + Any raster or vector data format. This could be a file name or + path, a raster grid, a vector matrix/arrays, or other supported + data input. x/y/z : 1d arrays or None x, y and z columns as numpy arrays. extra_arrays : list of 1d arrays @@ -1439,8 +1440,11 @@ def virtualfile_from_data( }[kind] # Ensure the data is an iterable (Python list or tuple) - if kind in ("file", "geojson", "grid"): + if kind in ("geojson", "grid"): _data = (data,) + elif kind == "file": + # Useful to handle `pathlib.Path` and string file path alike + _data = (str(data),) elif kind == "vectors": _data = [np.atleast_1d(x), np.atleast_1d(y)] if z is not None: diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 177e3d23f62..fe4910c28ff 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -2,6 +2,7 @@ Utilities and common tasks for wrapping the GMT modules. """ import os +import pathlib import shutil import subprocess import sys @@ -21,6 +22,7 @@ def data_kind(data, x=None, y=None, z=None): Possible types: * a file name provided as 'data' + * a pathlib.Path provided as 'data' * an xarray.DataArray provided as 'data' * a matrix provided as 'data' * 1D arrays x and y (and z, optionally) @@ -30,9 +32,9 @@ def data_kind(data, x=None, y=None, z=None): Parameters ---------- - data : str or xarray.DataArray or {table-like} or None - Pass in either a file name to an ASCII data table, an - :class:`xarray.DataArray`, a 1D/2D + data : str or pathlib.Path or xarray.DataArray or {table-like} or None + Pass in either a file name or :class:`pathlib.Path` to an ASCII data + table, an :class:`xarray.DataArray`, a 1D/2D {table-classes}. x/y : 1d arrays or None x and y columns as numpy arrays. @@ -50,12 +52,15 @@ def data_kind(data, x=None, y=None, z=None): >>> import numpy as np >>> import xarray as xr + >>> import pathlib >>> data_kind(data=None, x=np.array([1, 2, 3]), y=np.array([4, 5, 6])) 'vectors' >>> data_kind(data=np.arange(10).reshape((5, 2)), x=None, y=None) 'matrix' >>> data_kind(data="my-data-file.txt", x=None, y=None) 'file' + >>> data_kind(data=pathlib.Path("my-data-file.txt"), x=None, y=None) + 'file' >>> data_kind(data=xr.DataArray(np.random.rand(4, 3))) 'grid' """ @@ -66,7 +71,7 @@ def data_kind(data, x=None, y=None, z=None): if data is None and (x is None or y is None): raise GMTInvalidInput("Must provided both x and y.") - if isinstance(data, str): + if isinstance(data, (str, pathlib.PurePath)): kind = "file" elif isinstance(data, xr.DataArray): kind = "grid" diff --git a/pygmt/tests/test_info.py b/pygmt/tests/test_info.py index b364a33b612..e5b593c9885 100644 --- a/pygmt/tests/test_info.py +++ b/pygmt/tests/test_info.py @@ -2,6 +2,8 @@ Tests for gmtinfo. """ import os +import pathlib +import sys import numpy as np import numpy.testing as npt @@ -29,6 +31,40 @@ def test_info(): assert output == expected_output +@pytest.mark.parametrize( + "table", + [ + pathlib.Path(POINTS_DATA), + pytest.param( + pathlib.PureWindowsPath(POINTS_DATA), + marks=pytest.mark.skipif( + sys.platform != "win32", + reason="PureWindowsPath is only available on Windows", + ), + ), + pytest.param( + pathlib.PurePosixPath(POINTS_DATA), + marks=pytest.mark.skipif( + sys.platform == "win32", + reason="PurePosixPath is not available on Windows", + ), + ), + ], +) +def test_info_path(table): + """ + Make sure info works on a pathlib.Path input. + """ + output = info(table=table) + expected_output = ( + f"{POINTS_DATA}: N = 20 " + "<11.5309/61.7074> " + "<-2.9289/7.8648> " + "<0.1412/0.9338>\n" + ) + assert output == expected_output + + def test_info_2d_list(): """ Make sure info works on a 2d list.