From a8118236163241b032870d28bc7be988cf4a1b9f Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 9 Oct 2024 10:57:29 +0800 Subject: [PATCH 1/3] pygmt.which: Use long-name arguments for the 'download' parameter --- pygmt/datasets/samples.py | 22 ++++---- pygmt/helpers/caching.py | 2 +- pygmt/src/which.py | 74 ++++++++++++++++----------- pygmt/tests/test_datatypes_dataset.py | 4 +- pygmt/tests/test_geopandas.py | 2 +- pygmt/tests/test_plot.py | 2 +- pygmt/tests/test_surface.py | 2 +- pygmt/tests/test_triangulate.py | 2 +- pygmt/tests/test_which.py | 6 +-- pygmt/tests/test_xarray_accessor.py | 2 +- 10 files changed, 65 insertions(+), 53 deletions(-) diff --git a/pygmt/datasets/samples.py b/pygmt/datasets/samples.py index f6305c65d10..7e5df0f9e56 100644 --- a/pygmt/datasets/samples.py +++ b/pygmt/datasets/samples.py @@ -23,7 +23,7 @@ def _load_japan_quakes() -> pd.DataFrame: The data table. The column names are "year", "month", "day", "latitude", "longitude", "depth_km", and "magnitude" of the earthquakes. """ - fname = which("@tut_quakes.ngdc", download="c") + fname = which("@tut_quakes.ngdc", download="cache") return pd.read_csv( fname, header=1, @@ -49,7 +49,7 @@ def _load_ocean_ridge_points() -> pd.DataFrame: data The data table. The column names are "longitude" and "latitude". """ - fname = which("@ridge.txt", download="c") + fname = which("@ridge.txt", download="cache") return pd.read_csv( fname, sep=r"\s+", @@ -68,7 +68,7 @@ def _load_baja_california_bathymetry() -> pd.DataFrame: data The data table. The column names are "longitude", "latitude", and "bathymetry". """ - fname = which("@tut_ship.xyz", download="c") + fname = which("@tut_ship.xyz", download="cache") return pd.read_csv( fname, sep="\t", header=None, names=["longitude", "latitude", "bathymetry"] ) @@ -83,7 +83,7 @@ def _load_usgs_quakes() -> pd.DataFrame: data The data table. Use ``print(data.describe())`` to see the available columns. """ - fname = which("@usgs_quakes_22.txt", download="c") + fname = which("@usgs_quakes_22.txt", download="cache") return pd.read_csv(fname) @@ -97,7 +97,7 @@ def _load_fractures_compilation() -> pd.DataFrame: data The data table. The column names are "length" and "azimuth" of the fractures. """ - fname = which("@fractures_06.txt", download="c") + fname = which("@fractures_06.txt", download="cache") data = pd.read_csv(fname, header=None, sep=r"\s+", names=["azimuth", "length"]) return data[["length", "azimuth"]] @@ -116,7 +116,7 @@ def _load_hotspots() -> pd.DataFrame: The data table. The column names are "longitude", "latitude", "symbol_size", and "place_name". """ - fname = which("@hotspots.txt", download="c") + fname = which("@hotspots.txt", download="cache") return pd.read_csv( fname, sep="\t", @@ -137,7 +137,7 @@ def _load_mars_shape() -> pd.DataFrame: data The data table. The column names are "longitude", "latitude", and "radius_m". """ - fname = which("@mars370d.txt", download="c") + fname = which("@mars370d.txt", download="cache") return pd.read_csv( fname, sep="\t", header=None, names=["longitude", "latitude", "radius_m"] ) @@ -153,7 +153,7 @@ def _load_rock_sample_compositions() -> pd.DataFrame: The data table. The column names are "limestone", "water", "air", and "permittivity". """ - fname = which("@ternary.txt", download="c") + fname = which("@ternary.txt", download="cache") return pd.read_csv( fname, sep=r"\s+", @@ -173,7 +173,7 @@ def _load_notre_dame_topography() -> pd.DataFrame: data The data table. The column names are "x", "y", and "z". """ - fname = which("@Table_5_11.txt", download="c") + fname = which("@Table_5_11.txt", download="cache") return pd.read_csv(fname, sep=r"\s+", header=None, names=["x", "y", "z"]) @@ -186,7 +186,7 @@ def _load_maunaloa_co2() -> pd.DataFrame: data The data table. The column names are "date" and "co2_ppm". """ - fname = which("@MaunaLoa_CO2.txt", download="c") + fname = which("@MaunaLoa_CO2.txt", download="cache") return pd.read_csv( fname, header=None, skiprows=1, sep=r"\s+", names=["date", "co2_ppm"] ) @@ -202,7 +202,7 @@ def _load_earth_relief_holes() -> xr.DataArray: The Earth relief grid. Coordinates are latitude and longitude in degrees. Relief is in meters. """ - fname = which("@earth_relief_20m_holes.grd", download="c") + fname = which("@earth_relief_20m_holes.grd", download="cache") return xr.load_dataarray(fname, engine="gmt", raster_kind="grid") diff --git a/pygmt/helpers/caching.py b/pygmt/helpers/caching.py index 6dc52e2fff8..4acce7143a2 100644 --- a/pygmt/helpers/caching.py +++ b/pygmt/helpers/caching.py @@ -134,4 +134,4 @@ def cache_data() -> None: "@tut_ship.xyz", "@usgs_quakes_22.txt", ] - which(fname=datasets, download="a") + which(fname=datasets, download="auto") diff --git a/pygmt/src/which.py b/pygmt/src/which.py index 1b96ac6c61f..b47af68d1af 100644 --- a/pygmt/src/which.py +++ b/pygmt/src/which.py @@ -6,56 +6,62 @@ from typing import Literal from pygmt._typing import PathLike -from pygmt.alias import AliasSystem +from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session -from pygmt.helpers import build_arg_list, fmt_docstring, is_nonstr_iter, use_alias +from pygmt.helpers import build_arg_list, fmt_docstring, is_nonstr_iter @fmt_docstring -@use_alias(G="download") def which( fname: PathLike | Sequence[PathLike], + download: Literal["auto", "cache", "local", "user"] | bool = False, verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, **kwargs, ) -> str | list[str]: - r""" + """ Find full path to specified files. - Reports the full paths to the files given through ``fname``. We look - for the file in (1) the current directory, (2) in $GMT_USERDIR (if - defined), (3) in $GMT_DATADIR (if defined), or (4) in $GMT_CACHEDIR - (if defined). + Reports the full paths to the files given through ``fname``. It looks for the file + in (1) the current directory, (2) in $GMT_USERDIR (if defined), (3) in $GMT_DATADIR + (if defined), or (4) in $GMT_CACHEDIR (if defined). - ``fname`` can also be a downloadable file (either a complete URL, an - @file for downloading from the GMT data server, or any of the remote - datasets at https://www.pygmt.org/latest/api/index.html#datasets). - In these cases, use the ``download`` parameter to set the desired - behavior. If ``download`` is not used (or ``False``), the file will - not be found. + ``fname`` can also be a downloadable file (either a complete URL, an @file for + downloading from the GMT data server, or any of the remote datasets at + :ref:`datasets`. In these cases, use the ``download`` parameter to set the desired + behavior. If ``download`` is not used (or ``False``), the file will not be found. Full GMT docs at :gmt-docs:`gmtwhich.html`. - $aliases + **Aliases:** + + .. hlist:: + :columns: 3 + + - G = download - V = verbose Parameters ---------- - fname : str or list - One or more file names of any data type (grids, tables, etc.). - download : bool or str - [**a**\|\ **c**\|\ **l**\|\ **u**]. - If the ``fname`` argument is a downloadable file (either a complete - URL, an @file for downloading from the GMT data server, or any of - the remote datasets at - https://www.pygmt.org/latest/api/index.html#datasets) - we will try to download the file if it is not found in your local - data or cache directories. If set to ``True`` or **l** is passed - the file is downloaded to the current directory. Use **a** to place - files in the appropriate folder under the user directory (this is - where GMT normally places downloaded files), **c** to place it in - the user cache directory, or **u** for the user data directory - instead (i.e., ignoring any subdirectory structure). + fname + One or more file names to find the full path. + download + Try to download the file if it is not found in your local data or cache + directories and the file is downloadable. Here, downloadable files include: + + - a file specified by a complete URL + - a GMT remote file on the GMT data server, specified with a leading ``@``. + - any of the GMT remote datasets at :ref:`datasets` + + Valid values are: + + - ``False``: Do not download the file. + - ``True`` or ``"local"``: Download the file to the current directory. + - ``"cache"``: Download the file to the user cache directory. + - ``"user"``: Download the file to the user data directory but ignore any + subdirectory structure. + - ``"auto"``: Download the file to appropriate folder under the user directory + (this is where GMT normally places downloaded files). $verbose Returns @@ -68,7 +74,13 @@ def which( FileNotFoundError If the file is not found. """ - aliasdict = AliasSystem().add_common( + aliasdict = AliasSystem( + G=Alias( + download, + name="download", + mapping={"auto": "a", "cache": "c", "local": "l", "user": "u"}, + ) + ).add_common( V=verbose, ) aliasdict.merge(kwargs) diff --git a/pygmt/tests/test_datatypes_dataset.py b/pygmt/tests/test_datatypes_dataset.py index 1d217e794a4..f170e22d7bf 100644 --- a/pygmt/tests/test_datatypes_dataset.py +++ b/pygmt/tests/test_datatypes_dataset.py @@ -160,7 +160,7 @@ def test_dataset_to_strings_with_none_values(): # Catch the FileNotFoundError exception so that we can focus on the bug. tiles = ["@N30E060.earth_age_01m_g.nc", "@N30E090.earth_age_01m_g.nc"] try: - paths = which(fname=tiles, download="a") + paths = which(fname=tiles, download="auto") assert len(paths) == 2 # 'paths' may contain an empty string or not, depending on if tiles are cached. @@ -170,7 +170,7 @@ def test_dataset_to_strings_with_none_values(): Path(path).unlink() with pytest.warns(expected_warning=RuntimeWarning) as record: # noqa: PT031 try: - paths = which(fname=tiles, download="a") + paths = which(fname=tiles, download="auto") assert len(record) == 1 assert len(paths) == 2 assert "" in paths diff --git a/pygmt/tests/test_geopandas.py b/pygmt/tests/test_geopandas.py index cccb95b28e2..9570b8b733c 100644 --- a/pygmt/tests/test_geopandas.py +++ b/pygmt/tests/test_geopandas.py @@ -52,7 +52,7 @@ def fixture_gdf_ridge(): # Read shapefile into a geopandas.GeoDataFrame shapefile = which( fname=["@RidgeTest.shp", "@RidgeTest.shx", "@RidgeTest.dbf", "@RidgeTest.prj"], - download="c", + download="cache", ) gdf = gpd.read_file(shapefile[0]) # Reproject the geometry diff --git a/pygmt/tests/test_plot.py b/pygmt/tests/test_plot.py index 20da1814cac..abfa69064eb 100644 --- a/pygmt/tests/test_plot.py +++ b/pygmt/tests/test_plot.py @@ -553,7 +553,7 @@ def test_plot_shapefile(): See https://github.com/GenericMappingTools/pygmt/issues/1616. """ datasets = ["@RidgeTest" + suffix for suffix in [".shp", ".shx", ".dbf", ".prj"]] - which(fname=datasets, download="a") + which(fname=datasets, download="auto") fig = Figure() fig.plot(data="@RidgeTest.shp", pen="1p", frame=True) return fig diff --git a/pygmt/tests/test_surface.py b/pygmt/tests/test_surface.py index a468a1e4c2b..9f25b8532cb 100644 --- a/pygmt/tests/test_surface.py +++ b/pygmt/tests/test_surface.py @@ -18,7 +18,7 @@ def fixture_data(): """ Load Table 5.11 in Davis: Statistics and Data Analysis in Geology. """ - fname = which("@Table_5_11_mean.xyz", download="c") + fname = which("@Table_5_11_mean.xyz", download="cache") return pd.read_csv( fname, sep=r"\s+", header=None, names=["x", "y", "z"], skiprows=1 ) diff --git a/pygmt/tests/test_triangulate.py b/pygmt/tests/test_triangulate.py index e4f19e03c92..114ebc31417 100644 --- a/pygmt/tests/test_triangulate.py +++ b/pygmt/tests/test_triangulate.py @@ -19,7 +19,7 @@ def fixture_dataframe(): """ Load the table data from the sample bathymetry dataset. """ - fname = which("@Table_5_11_mean.xyz", download="c") + fname = which("@Table_5_11_mean.xyz", download="cache") return pd.read_csv( fname, sep=r"\s+", header=None, names=["x", "y", "z"], skiprows=1 )[:10] diff --git a/pygmt/tests/test_which.py b/pygmt/tests/test_which.py index 0bc453bc118..fd07b32b94b 100644 --- a/pygmt/tests/test_which.py +++ b/pygmt/tests/test_which.py @@ -18,7 +18,7 @@ def test_which(): Make sure `which` returns file paths for @files correctly without errors. """ for fname in ["tut_quakes.ngdc", "tut_bathy.nc"]: - cached_file = which(fname=f"@{fname}", download="c") + cached_file = which(fname=f"@{fname}", download="cache") assert Path(cached_file).exists() assert Path(cached_file).name == fname @@ -29,7 +29,7 @@ def test_which_multiple(): Make sure `which` returns file paths for multiple @files correctly. """ filenames = ["ridge.txt", "tut_ship.xyz"] - cached_files = which([f"@{fname}" for fname in filenames], download="c") + cached_files = which([f"@{fname}" for fname in filenames], download="cache") for cached_file in cached_files: assert Path(cached_file).exists() assert Path(cached_file).name in filenames @@ -68,7 +68,7 @@ def test_which_nonascii_path(monkeypatch): # Start a new session begin() # GMT should download the remote file under the new home directory. - fname = which(fname="@static_earth_relief.nc", download="c") + fname = which(fname="@static_earth_relief.nc", download="cache") assert fname.startswith(fakehome) assert fname.endswith("static_earth_relief.nc") end() diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 6814245856e..d64de9e0689 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -122,7 +122,7 @@ def test_xarray_accessor_sliced_datacube(): try: fname = which( "https://github.com/pydata/xarray-data/raw/master/eraint_uvz.nc", - download="u", + download="user", ) with xr.open_dataset(fname, engine="netcdf4") as dataset: grid = dataset.sel(level=500, month=1, drop=True).z From 3fc35fffdd77b038ea6bfc6710a8fa1f6f59a38d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 2 Mar 2026 11:09:04 +0800 Subject: [PATCH 2/3] Fix referecen to datasets --- pygmt/src/which.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pygmt/src/which.py b/pygmt/src/which.py index b47af68d1af..8141e5338d2 100644 --- a/pygmt/src/which.py +++ b/pygmt/src/which.py @@ -27,9 +27,10 @@ def which( (if defined), or (4) in $GMT_CACHEDIR (if defined). ``fname`` can also be a downloadable file (either a complete URL, an @file for - downloading from the GMT data server, or any of the remote datasets at - :ref:`datasets`. In these cases, use the ``download`` parameter to set the desired - behavior. If ``download`` is not used (or ``False``), the file will not be found. + downloading from the GMT data server, or any of the remote datasets listed at + `PyGMT datasets `_. In these + cases, use the ``download`` parameter to set the desired behavior. If ``download`` + is not used (or ``False``), the file will not be found. Full GMT docs at :gmt-docs:`gmtwhich.html`. @@ -51,7 +52,8 @@ def which( - a file specified by a complete URL - a GMT remote file on the GMT data server, specified with a leading ``@``. - - any of the GMT remote datasets at :ref:`datasets` + - any of the GMT remote datasets listed at + `PyGMT datasets `_ Valid values are: From 8a3fe2af42be25eec08da322755e3e8c52229dac Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 4 Mar 2026 01:01:57 +0800 Subject: [PATCH 3/3] Link to https://www.generic-mapping-tools.org/remote-datasets/ --- pygmt/src/which.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pygmt/src/which.py b/pygmt/src/which.py index b47af68d1af..3dc884dd2e0 100644 --- a/pygmt/src/which.py +++ b/pygmt/src/which.py @@ -27,9 +27,10 @@ def which( (if defined), or (4) in $GMT_CACHEDIR (if defined). ``fname`` can also be a downloadable file (either a complete URL, an @file for - downloading from the GMT data server, or any of the remote datasets at - :ref:`datasets`. In these cases, use the ``download`` parameter to set the desired - behavior. If ``download`` is not used (or ``False``), the file will not be found. + downloading from the GMT data server, or any of the + `GMT remote datasets `__. + In these cases, use the ``download`` parameter to set the desired behavior. If + ``download`` is not used (or ``False``), the file will not be found. Full GMT docs at :gmt-docs:`gmtwhich.html`. @@ -51,7 +52,7 @@ def which( - a file specified by a complete URL - a GMT remote file on the GMT data server, specified with a leading ``@``. - - any of the GMT remote datasets at :ref:`datasets` + - any of the `GMT remote datasets `__ Valid values are: