From e2019dbbb170fe9fc0c9c16c0593d16f597261f7 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 22 Aug 2024 13:19:35 +0800 Subject: [PATCH 1/9] Update the onboarding access checklist in Maintainers Guides (#3404) --- doc/maintenance.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/maintenance.md b/doc/maintenance.md index 2029f006e5d..5377f0b119e 100644 --- a/doc/maintenance.md +++ b/doc/maintenance.md @@ -3,9 +3,7 @@ This page contains instructions for project maintainers about how our setup works, making releases, creating packages, etc. -If you want to make a contribution to the project, see the -[Contributing Guide](https://github.com/GenericMappingTools/pygmt/blob/main/CONTRIBUTING.md) -instead. +If you want to make a contribution to the project, see the {doc}`contributing` instead. ## Onboarding Access Checklist @@ -19,14 +17,12 @@ communication tools we use. - Added to the [pygmt-contributors team](https://github.com/orgs/GenericMappingTools/teams/pygmt-contributors) (gives 'write' permission to the repository) - Added as a collaborator on [DAGsHub](https://dagshub.com/GenericMappingTools/pygmt/settings/collaboration) (gives 'write' permission to dvc remote storage) -- Added to the [PyGMT devs Slack channel](https://pygmtdevs.slack.com) (for casual conversations) -- Added to the {doc}`Team Gallery page ` - Added as a member on [HackMD](https://hackmd.io/@pygmt) (for draft announcements) [optional] ### As a Maintainer - Added to the [pygmt-maintainers team](https://github.com/orgs/GenericMappingTools/teams/pygmt-maintainers) (gives 'maintain' permission to the repository) -- Update the role on the {doc}`Team Gallery page ` +- Added to "Active Maintainers" on the {doc}`Team Gallery page ` - Added as a moderator on the [GMT forum](https://forum.generic-mapping-tools.org) (to see mod-only discussions) [optional] - Added as a maintainer on [ReadtheDocs](https://readthedocs.org/projects/pygmt-dev) [optional] - Added as a curator to the [GMT community](https://zenodo.org/communities/generic-mapping-tools/) on Zenodo (for making releases) [optional] From 991cafb047ecc2176f88e81de746d7b382344347 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 22 Aug 2024 23:20:53 +0800 Subject: [PATCH 2/9] CI: Fix the name of the 'build' package to 'python-build' on conda-forge (#3408) --- .github/workflows/cache_data.yaml | 2 +- .github/workflows/ci_docs.yml | 2 +- .github/workflows/ci_doctests.yaml | 2 +- .github/workflows/ci_tests.yaml | 2 +- .github/workflows/ci_tests_legacy.yaml | 2 +- ci/requirements/docs.yml | 2 +- environment.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/cache_data.yaml b/.github/workflows/cache_data.yaml index 6e3d774a191..83c78e5caac 100644 --- a/.github/workflows/cache_data.yaml +++ b/.github/workflows/cache_data.yaml @@ -58,7 +58,7 @@ jobs: xarray netCDF4 packaging - build + python-build # Install the package that we want to test - name: Install the package diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 7d435683b1a..3bcd2c98bde 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -104,9 +104,9 @@ jobs: geopandas<1.0 ipython rioxarray - build make pip + python-build myst-nb panel sphinx diff --git a/.github/workflows/ci_doctests.yaml b/.github/workflows/ci_doctests.yaml index 45bdcb47311..e5c07d21e6d 100644 --- a/.github/workflows/ci_doctests.yaml +++ b/.github/workflows/ci_doctests.yaml @@ -62,9 +62,9 @@ jobs: ipython pyarrow rioxarray - build make pip + python-build pytest pytest-doctestplus pytest-mpl diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index 732442ef43b..5b6410021cd 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -125,10 +125,10 @@ jobs: xarray${{ matrix.xarray-version }} netCDF4 packaging - build dvc make pip + python-build pytest pytest-cov pytest-doctestplus diff --git a/.github/workflows/ci_tests_legacy.yaml b/.github/workflows/ci_tests_legacy.yaml index ef8efc6e4fe..d38e3acde7e 100644 --- a/.github/workflows/ci_tests_legacy.yaml +++ b/.github/workflows/ci_tests_legacy.yaml @@ -72,9 +72,9 @@ jobs: pyarrow rioxarray sphinx-gallery - build make pip + python-build pytest pytest-doctestplus pytest-mpl diff --git a/ci/requirements/docs.yml b/ci/requirements/docs.yml index 605e5b750d5..4a7288206a4 100644 --- a/ci/requirements/docs.yml +++ b/ci/requirements/docs.yml @@ -18,9 +18,9 @@ dependencies: - ipython - rioxarray # Development dependencies (general) - - build - make - pip + - python-build # Dev dependencies (building documentation) - myst-nb - panel diff --git a/environment.yml b/environment.yml index 3d66bce5a5b..c38e0b6e6e8 100644 --- a/environment.yml +++ b/environment.yml @@ -18,11 +18,11 @@ dependencies: - ipython - rioxarray # Development dependencies (general) - - build - dvc - jupyter - make - pip + - python-build # Dev dependencies (style checks) - codespell - pre-commit From 8d6a06f67a072af1f8456b79bab1cb829bd0f561 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 27 Aug 2024 15:34:47 +0800 Subject: [PATCH 3/9] Refactor launch_external_viewer to use match-case statements (#3412) --- pygmt/_show_versions.py | 4 +--- pygmt/clib/loading.py | 4 +--- pygmt/helpers/utils.py | 45 +++++++++++++++++++++-------------------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/pygmt/_show_versions.py b/pygmt/_show_versions.py index b27033a0ed2..6371c3ea309 100644 --- a/pygmt/_show_versions.py +++ b/pygmt/_show_versions.py @@ -52,9 +52,7 @@ def _get_ghostscript_version() -> str | None: Get Ghostscript version. """ match sys.platform: - case "linux" | "darwin": - cmds = ["gs"] - case os_name if os_name.startswith("freebsd"): + case name if name in {"linux", "darwin"} or name.startswith("freebsd"): cmds = ["gs"] case "win32": cmds = ["gswin64c.exe", "gswin32c.exe"] diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index 9b785fe826e..60541c7186d 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -111,14 +111,12 @@ def clib_names(os_name: str) -> list[str]: If the operating system is not supported yet. """ match os_name: - case "linux": # Linux + case name if name == "linux" or name.startswith("freebsd"): # Linux or FreeBSD libnames = ["libgmt.so"] case "darwin": # macOS libnames = ["libgmt.dylib"] case "win32": # Windows libnames = ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"] - case name if name.startswith("freebsd"): # FreeBSD - libnames = ["libgmt.so"] case _: raise GMTOSError(f"Operating system '{os_name}' is not supported.") return libnames diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index cd54d6fc18e..337c27ffbd5 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -630,42 +630,43 @@ def is_nonstr_iter(value): return isinstance(value, Iterable) and not isinstance(value, str) -def launch_external_viewer(fname, waiting=0): +def launch_external_viewer(fname: str, waiting: float = 0): """ Open a file in an external viewer program. - Uses the ``xdg-open`` command on Linux, the ``open`` command on macOS, the - associated application on Windows, and the default web browser on other - systems. + Uses the ``xdg-open`` command on Linux/FreeBSD, the ``open`` command on macOS, the + associated application on Windows, and the default web browser on other systems. Parameters ---------- - fname : str + fname The file name of the file (preferably a full path). + waiting + Wait for a few seconds before exiting the function, to allow the external viewer + open the file before it's deleted. """ - # Redirect stdout and stderr to devnull so that the terminal isn't filled - # with noise + # Redirect stdout and stderr to devnull so that the terminal isn't filled with noise run_args = { "stdout": subprocess.DEVNULL, "stderr": subprocess.DEVNULL, } - # Open the file with the default viewer. - # Fall back to the browser if can't recognize the operating system. - os_name = sys.platform - if os_name.startswith(("linux", "freebsd")) and ( - xdgopen := shutil.which("xdg-open") - ): - subprocess.run([xdgopen, fname], check=False, **run_args) - elif os_name == "darwin": # Darwin is macOS - subprocess.run([shutil.which("open"), fname], check=False, **run_args) - elif os_name == "win32": - os.startfile(fname) # noqa: S606 - else: - webbrowser.open_new_tab(f"file://{fname}") + match sys.platform: + case name if ( + (name == "linux" or name.startswith("freebsd")) + and (xdgopen := shutil.which("xdg-open")) + ): # Linux/FreeBSD + subprocess.run([xdgopen, fname], check=False, **run_args) # type:ignore[call-overload] + case "darwin": # macOS + subprocess.run([shutil.which("open"), fname], check=False, **run_args) # type:ignore[call-overload] + case "win32": # Windows + os.startfile(fname) # type:ignore[attr-defined] # noqa: S606 + case _: # Fall back to the browser if can't recognize the operating system. + webbrowser.open_new_tab(f"file://{fname}") if waiting > 0: - # suspend the execution for a few seconds to avoid the images being - # deleted when a Python script exits + # Preview images will be deleted when a GMT modern-mode session ends, but the + # external viewer program may take a few seconds to open the images. + # Suspend the execution for a few seconds. time.sleep(waiting) From 9daa2cb708677b6ed292c9df995a43e87b195738 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 27 Aug 2024 17:36:47 +0800 Subject: [PATCH 4/9] Add pre-commit.ci configurations to enable auto updates of hooks (#3414) --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d758c6b5187..328813ae7bc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,3 +15,8 @@ repos: - id: remove-crlf - id: chmod args: ['644'] + +# https://pre-commit.ci/#configuration +ci: + autofix_prs: false + autoupdate_schedule: quarterly From 0faf52c2410601f551e7e8661cafdd28889dd0c0 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 27 Aug 2024 22:16:36 +0800 Subject: [PATCH 5/9] CI: Skip the chmod hook in pre-commit.ci (#3415) Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 328813ae7bc..1deeef23169 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,5 +18,6 @@ repos: # https://pre-commit.ci/#configuration ci: + skip: [chmod] autofix_prs: false autoupdate_schedule: quarterly From 347c5991f0ae9f7b4987096a81175667ac631128 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 28 Aug 2024 22:00:31 +0800 Subject: [PATCH 6/9] DOC: Add an offboarding access checklist for maintainers (#3411) Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- doc/maintenance.md | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/doc/maintenance.md b/doc/maintenance.md index 5377f0b119e..aa8ac38471e 100644 --- a/doc/maintenance.md +++ b/doc/maintenance.md @@ -5,7 +5,7 @@ making releases, creating packages, etc. If you want to make a contribution to the project, see the {doc}`contributing` instead. -## Onboarding Access Checklist +## Onboarding/Offboarding Access Checklist Note that anyone can contribute to PyGMT, even without being added to the [GenericMappingTools team](https://github.com/orgs/GenericMappingTools/teams). @@ -15,23 +15,31 @@ communication tools we use. ### As a Contributor -- Added to the [pygmt-contributors team](https://github.com/orgs/GenericMappingTools/teams/pygmt-contributors) (gives 'write' permission to the repository) -- Added as a collaborator on [DAGsHub](https://dagshub.com/GenericMappingTools/pygmt/settings/collaboration) (gives 'write' permission to dvc remote storage) -- Added as a member on [HackMD](https://hackmd.io/@pygmt) (for draft announcements) [optional] +- Add to the [pygmt-contributors team](https://github.com/orgs/GenericMappingTools/teams/pygmt-contributors) (gives 'write' permission to the repository) +- Add as a collaborator on [DAGsHub](https://dagshub.com/GenericMappingTools/pygmt) (gives 'write' permission to dvc remote storage) +- Add as a member on [HackMD](https://hackmd.io/@pygmt) (for draft announcements) [optional] ### As a Maintainer -- Added to the [pygmt-maintainers team](https://github.com/orgs/GenericMappingTools/teams/pygmt-maintainers) (gives 'maintain' permission to the repository) -- Added to "Active Maintainers" on the {doc}`Team Gallery page ` -- Added as a moderator on the [GMT forum](https://forum.generic-mapping-tools.org) (to see mod-only discussions) [optional] -- Added as a maintainer on [ReadtheDocs](https://readthedocs.org/projects/pygmt-dev) [optional] -- Added as a curator to the [GMT community](https://zenodo.org/communities/generic-mapping-tools/) on Zenodo (for making releases) [optional] +- Add to the [pygmt-maintainers team](https://github.com/orgs/GenericMappingTools/teams/pygmt-maintainers) (gives 'maintain' permission to the repository) +- Add to "Active Maintainers" on the {doc}`Team Gallery page ` +- Add as a moderator on the [GMT forum](https://forum.generic-mapping-tools.org) (to see mod-only discussions) [optional] +- Add as a maintainer on [ReadtheDocs](https://readthedocs.org/projects/pygmt-dev) [optional] +- Add as a curator to the [GMT community](https://zenodo.org/communities/generic-mapping-tools/) on Zenodo (for making releases) [optional] ### As an Administrator -- Added to the [pygmt-admin team](https://github.com/orgs/GenericMappingTools/teams/pygmt-admin) (gives 'admin' permission to the repository) -- Added as an admin on [DAGsHub](https://www.dagshub.com/GenericMappingTools/pygmt/settings/collaboration) -- Added as a maintainer on [PyPI](https://pypi.org/project/pygmt/) and [Test PyPI](https://test.pypi.org/project/pygmt) [optional] +- Add to the [pygmt-admin team](https://github.com/orgs/GenericMappingTools/teams/pygmt-admin) (gives 'admin' permission to the repository) +- Add as an admin on [DAGsHub](https://www.dagshub.com/GenericMappingTools/pygmt) +- Add as a maintainer on [PyPI](https://pypi.org/project/pygmt/) and [Test PyPI](https://test.pypi.org/project/pygmt) [optional] + +**Note**: When a maintainer is no longer active (no activity in one year), we will mirror +the onboarding access checklist: + +- Move from the [pygmt-maintainers team](https://github.com/orgs/GenericMappingTools/teams/pygmt-maintainers) + to [pygmt-contributors team](https://github.com/orgs/GenericMappingTools/teams/pygmt-contributors) +- Move from "Active Maintainers" to "Distinguished Contributors" on the {doc}`Team Gallery page ` +- Remove 'maintain' permission from GMT forum, ReadTheDocs, Zenodo ## Branches From 1d2306c3032e64e38e79fd3ee4e4aad29a89e94c Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 29 Aug 2024 22:48:57 +0800 Subject: [PATCH 7/9] Remove the non-official GMT wrappers from README (#3413) --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 7fd56461d74..c53cf2776e9 100644 --- a/README.md +++ b/README.md @@ -186,12 +186,6 @@ Other official wrappers for GMT: - [GMT.jl](https://github.com/GenericMappingTools/GMT.jl): A Julia wrapper for GMT. - [gmtmex](https://github.com/GenericMappingTools/gmtmex): A Matlab/Octave wrapper for GMT. -Other non-official Python wrappers for GMT (not maintained): - -- [gmtpy](https://github.com/emolch/gmtpy) by [Sebastian Heimann](https://github.com/emolch) -- [pygmt](https://github.com/ian-r-rose/pygmt) by [Ian Rose](https://github.com/ian-r-rose) -- [PyGMT](https://github.com/glimmer-cism/PyGMT) by [Magnus Hagdorn](https://github.com/mhagdorn) - ## Minimum supported versions From f5d867249c9cb4fd19bb0f8456d17499f455f904 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 29 Aug 2024 23:00:21 +0800 Subject: [PATCH 8/9] Figure.savefig: Add type hints and improve docstrings (#3395) --- pygmt/figure.py | 78 +++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/pygmt/figure.py b/pygmt/figure.py index ce8693a43f3..0509e765eb7 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -4,7 +4,7 @@ import base64 import os -from pathlib import Path +from pathlib import Path, PurePath from tempfile import TemporaryDirectory try: @@ -253,12 +253,12 @@ def psconvert(self, **kwargs): def savefig( # noqa: PLR0912 self, - fname, - transparent=False, - crop=True, - anti_alias=True, - show=False, - worldfile=False, + fname: str | PurePath, + transparent: bool = False, + crop: bool = True, + anti_alias: bool = True, + show: bool = False, + worldfile: bool = False, **kwargs, ): """ @@ -280,45 +280,39 @@ def savefig( # noqa: PLR0912 - EPS (``.eps``) - PDF (``.pdf``) - Beside the above formats, you can also save the figure to a KML file - (``.kml``), with a companion PNG file generated automatically. The KML - file can be viewed in Google Earth. + Besides the above formats, you can also save the figure to a KML file + (``.kml``), with a companion PNG file generated automatically. The KML file can + be viewed in Google Earth. - You can pass in any keyword arguments that - :meth:`pygmt.Figure.psconvert` accepts. + You can pass in any keyword arguments that :meth:`pygmt.Figure.psconvert` + accepts. Parameters ---------- - fname : str - The desired figure file name, including the extension. See the list - of supported formats and their extensions above. - transparent : bool - If ``True``, will use a transparent background for the figure. - Only valid for PNG format. - crop : bool - If ``True``, will crop the figure canvas (page) to the plot area. - anti_alias: bool - If ``True``, will use anti-aliasing when creating raster images. - More specifically, it passes the arguments ``"t2"`` and ``"g2"`` - to the ``anti_aliasing`` parameter of - :meth:`pygmt.Figure.psconvert`. Ignored if creating vector images. - show: bool - If ``True``, will open the figure in an external viewer. - worldfile : bool - If ``True``, will create a companion - `world file `__ for the - figure. The world file will have the same name as the figure file - but with different extension (e.g. tfw for tif). See - https://en.wikipedia.org/wiki/World_file#Filename_extension - for the convention of world file extensions. This parameter only - works for raster image formats (except GeoTIFF). - dpi : int - Set raster resolution in dpi [Default is ``720`` for PDF, ``300`` - for others]. + fname + The desired figure file name, including the extension. See the list of + supported formats and their extensions above. + transparent + Use a transparent background for the figure. Only valid for PNG format. + crop + Crop the figure canvas (page) to the plot area. + anti_alias + Use anti-aliasing when creating raster images. Ignored if creating vector + images. More specifically, it passes the arguments ``"t2"`` and ``"g2"`` to + the ``anti_aliasing`` parameter of :meth:`pygmt.Figure.psconvert`. + show + Display the figure in an external viewer. + worldfile + Create a companion `world file `__ + for the figure. The world file will have the same name as the figure file + but with different extension (e.g., ``.tfw`` for ``.tif``). See + https://en.wikipedia.org/wiki/World_file#Filename_extension for the + convention of world file extensions. This parameter only works for raster + image formats (except GeoTIFF). **kwargs : dict - Additional keyword arguments passed to - :meth:`pygmt.Figure.psconvert`. Valid parameters are ``gs_path``, - ``gs_option``, ``resize``, ``bb_style``, and ``verbose``. + Additional keyword arguments passed to :meth:`pygmt.Figure.psconvert`. Valid + parameters are ``dpi``, ``gs_path``, ``gs_option``, ``resize``, + ``bb_style``, and ``verbose``. """ # All supported formats fmts = { @@ -382,7 +376,7 @@ def savefig( # noqa: PLR0912 fname.with_suffix("." + ext).rename(fname) if show: - launch_external_viewer(fname) + launch_external_viewer(str(fname)) def show(self, dpi=300, width=500, method=None, waiting=0.5, **kwargs): """ From 2157333f4ed9341c592bb6d22d9e710f3216db0c Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 30 Aug 2024 07:47:22 +0800 Subject: [PATCH 9/9] Fix "sphinx-gallery" to "sphinx_gallery" when importing (#3419) --- pygmt/tests/test_sphinx_gallery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_sphinx_gallery.py b/pygmt/tests/test_sphinx_gallery.py index c40d4732a0b..1fc7d7f260c 100644 --- a/pygmt/tests/test_sphinx_gallery.py +++ b/pygmt/tests/test_sphinx_gallery.py @@ -9,7 +9,7 @@ from pygmt.figure import SHOWED_FIGURES, Figure from pygmt.sphinx_gallery import PyGMTScraper -pytest.importorskip("sphinx-gallery", reason="Requires sphinx-gallery to be installed") +pytest.importorskip("sphinx_gallery", reason="Requires sphinx-gallery to be installed") pytest.importorskip("IPython", reason="Requires IPython to be installed")