Skip to content

Commit 6c4d3c1

Browse files
authored
Merge branch 'master' into earth-relief-invalid-resolution-registration
2 parents e9e838a + 17133d1 commit 6c4d3c1

File tree

6 files changed

+248
-36
lines changed

6 files changed

+248
-36
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# This workflow deploys documentation to Vercel for previewing PRs
2+
3+
name: Continuous Documentation
4+
5+
on:
6+
pull_request:
7+
paths:
8+
- 'doc/**'
9+
- 'examples/**'
10+
- 'pygmt/**'
11+
- 'README.rst'
12+
- '.github/workflows/continuous-documentation.yml'
13+
pull_request_target:
14+
paths:
15+
- 'doc/**'
16+
- 'examples/**'
17+
- 'pygmt/**'
18+
- 'README.rst'
19+
- '.github/workflows/continuous-documentation.yml'
20+
21+
jobs:
22+
vercel:
23+
name: Deploy to Vercel
24+
runs-on: ubuntu-latest
25+
defaults:
26+
run:
27+
shell: bash -l {0}
28+
29+
steps:
30+
- name: Cancel Previous Runs
31+
uses: styfle/[email protected]
32+
with:
33+
access_token: ${{ github.token }}
34+
35+
- name: Checkout
36+
uses: actions/[email protected]
37+
with:
38+
# fecth all history so that setuptools-scm works
39+
fetch-depth: 0
40+
41+
# Setup Miniconda
42+
- name: Setup Miniconda
43+
uses: conda-incubator/[email protected]
44+
with:
45+
activate-environment: pygmt
46+
python-version: 3.9
47+
channels: conda-forge
48+
miniconda-version: "latest"
49+
50+
- name: Install dependencies
51+
run: |
52+
conda install gmt=6.1.1 numpy pandas xarray netcdf4 packaging \
53+
ipython myst-parser sphinx sphinx-copybutton \
54+
sphinx-gallery sphinx_rtd_theme=0.4.3
55+
56+
- name: List installed packages
57+
run: conda list
58+
59+
- name: Download remote data from GitHub
60+
uses: dawidd6/[email protected]
61+
with:
62+
workflow: cache_data.yaml
63+
workflow_conclusion: success
64+
name: gmt-cache
65+
path: .gmt
66+
67+
- name: Move and list downloaded remote files
68+
run: |
69+
mkdir -p ~/.gmt
70+
mv .gmt/* ~/.gmt
71+
# Change modification times of the two files, so GMT won't refresh it
72+
touch ~/.gmt/server/gmt_data_server.txt ~/.gmt/server/gmt_hash_server.txt
73+
ls -lhR ~/.gmt
74+
75+
- name: Install the package
76+
run: |
77+
python setup.py sdist --formats=zip
78+
pip install dist/*
79+
80+
- name: Build the documentation
81+
run: make -C doc clean all
82+
83+
- name: Deploy documentation to Vercel
84+
uses: amondnet/[email protected]
85+
with:
86+
# Generate a vercel token at https://vercel.com/account/tokens,
87+
# and save the value in the secrets setting in the repository.
88+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
89+
# https://github.com/marketplace/actions/vercel-action#project-linking
90+
# Install the Vercel CLI and run `vercel` in the project directory.
91+
# After linking the repository with a Vercel project, `vercel` will
92+
# create a `.vercel` directory containing both the organization (vercel-org-id)
93+
# and project (vercel-project-id) id of the project.
94+
# Save the values in the secrets setting in the repository.
95+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
96+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
97+
github-token: ${{ secrets.GITHUB_TOKEN }}
98+
github-comment: true
99+
working-directory: ./doc/_build/html

MAINTENANCE.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ conda and the `Makefile` to run the tests and checks.
4747

4848
### GitHub Actions
4949

50-
There are 5 configuration files located in `.github/workflows`:
50+
There are 6 configuration files located in `.github/workflows`:
5151

5252
1. `style_checks.yaml` (Code lint and style checks)
5353

@@ -84,16 +84,19 @@ This workflow is ran to publish wheels to PyPI and TestPyPI (for testing only).
8484
Archives will be pushed to TestPyPI on every commit to the *master* branch and
8585
tagged releases, and to PyPI for tagged releases only.
8686

87+
6. `continuous-documentation.yml` (Deploy documentation to Vercel for preview)
88+
89+
This workflow builds and deploys the documentation in Pull Requests to Vercel,
90+
to make it easier to preview documentation changes.
8791

8892
## Continuous Documentation
8993

90-
We use the [Vercel for GitHub](https://github.com/apps/vercel) App to preview changes
91-
made to our documentation website every time we make a commit in a pull request.
92-
The service has a configuration file `vercel.json`, with a list of options to
93-
change the default behaviour at https://vercel.com/docs/configuration.
94-
The actual script `package.json` is used by Vercel to install the necessary packages,
95-
build the documentation, copy the files to a 'public' folder and deploy that to the web,
96-
see https://vercel.com/docs/build-step.
94+
We use a cloud platform service called [Vercel](https://vercel.com/) via
95+
[vercel-action](https://github.com/marketplace/actions/vercel-action) to
96+
preview changes made to our documentation website every time we make a commit
97+
in a pull request. The workflow `continuous-documentation.yml` builds and
98+
deploys the documentation to Vercel. The vercel bot will automatically make a
99+
comment with a URL to preview the deployed documentation for that pull request.
97100

98101
## Making a Release
99102

package.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

pygmt/clib/loading.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import subprocess as sp
1010
import sys
1111
from ctypes.util import find_library
12+
from pathlib import Path
1213

1314
from pygmt.exceptions import GMTCLibError, GMTCLibNotFoundError, GMTOSError
1415

@@ -98,33 +99,34 @@ def clib_full_names(env=None):
9899

99100
libnames = clib_names(os_name=sys.platform) # e.g. libgmt.so, libgmt.dylib, gmt.dll
100101

101-
# list of libraries paths to search, sort by priority from high to low
102-
# Search for libraries in GMT_LIBRARY_PATH if defined.
102+
# Search for the library in different ways, sorted by priority.
103+
# 1. Search for the library in GMT_LIBRARY_PATH if defined.
103104
libpath = env.get("GMT_LIBRARY_PATH", "") # e.g. $HOME/miniconda/envs/pygmt/lib
104105
if libpath:
105106
for libname in libnames:
106-
libfullpath = os.path.join(libpath, libname)
107-
if os.path.exists(libfullpath):
108-
yield libfullpath
107+
libfullpath = Path(libpath) / libname
108+
if libfullpath.exists():
109+
yield str(libfullpath)
109110

110-
# Search for the library returned by command "gmt --show-library"
111+
# 2. Search for the library returned by command "gmt --show-library"
112+
# Use `str(Path(realpath))` to avoid mixture of separators "\\" and "/"
111113
try:
112-
libfullpath = sp.check_output(
113-
["gmt", "--show-library"], encoding="utf-8"
114-
).rstrip("\n")
115-
assert os.path.exists(libfullpath)
116-
yield libfullpath
114+
libfullpath = Path(
115+
sp.check_output(["gmt", "--show-library"], encoding="utf-8").rstrip("\n")
116+
)
117+
assert libfullpath.exists()
118+
yield str(libfullpath)
117119
except (FileNotFoundError, AssertionError): # command not found
118120
pass
119121

120-
# Search for DLLs in PATH (done by calling "find_library")
122+
# 3. Search for DLLs in PATH by calling find_library() (Windows only)
121123
if sys.platform == "win32":
122124
for libname in libnames:
123125
libfullpath = find_library(libname)
124126
if libfullpath:
125127
yield libfullpath
126128

127-
# Search for library names in the system default path [the lowest priority]
129+
# 4. Search for library names in the system default path
128130
for libname in libnames:
129131
yield libname
130132

pygmt/tests/test_clib_loading.py

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"""
22
Test the functions that load libgmt.
33
"""
4+
import shutil
45
import subprocess
56
import sys
7+
import types
8+
from pathlib import PurePath
69

710
import pytest
8-
from pygmt.clib.loading import check_libgmt, clib_names, load_libgmt
11+
from pygmt.clib.loading import check_libgmt, clib_full_names, clib_names, load_libgmt
912
from pygmt.exceptions import GMTCLibError, GMTCLibNotFoundError, GMTOSError
1013

1114

@@ -73,3 +76,122 @@ def test_clib_names():
7376
assert clib_names(freebsd) == ["libgmt.so"]
7477
with pytest.raises(GMTOSError):
7578
clib_names("meh")
79+
80+
81+
###############################################################################
82+
# Tests for clib_full_names
83+
@pytest.fixture(scope="module", name="gmt_lib_names")
84+
def fixture_gmt_lib_names():
85+
"""
86+
Return a list of the library names for the current operating system.
87+
"""
88+
return clib_names(sys.platform)
89+
90+
91+
@pytest.fixture(scope="module", name="gmt_bin_dir")
92+
def fixture_gmt_bin_dir():
93+
"""
94+
Return GMT's bin directory.
95+
"""
96+
return str(PurePath(shutil.which("gmt")).parent)
97+
98+
99+
@pytest.fixture(scope="module", name="gmt_lib_realpath")
100+
def fixture_gmt_lib_realpath():
101+
"""
102+
Return the real path of the GMT library.
103+
"""
104+
lib_realpath = subprocess.check_output(
105+
["gmt", "--show-library"], encoding="utf-8"
106+
).rstrip("\n")
107+
# On Windows, clib_full_names() returns paths with separator "\\",
108+
# but "gmt --show-library" returns paths with separator "/".
109+
# Use `str(PurePath(realpath)` to mimic the behavior of clib_full_names()
110+
return str(PurePath(lib_realpath))
111+
112+
113+
def test_clib_full_names_gmt_library_path_undefined_path_empty(
114+
monkeypatch, gmt_lib_names
115+
):
116+
"""
117+
Make sure that clib_full_names() returns a generator with expected names
118+
when GMT_LIBRARY_PATH is undefined and PATH is empty.
119+
"""
120+
with monkeypatch.context() as mpatch:
121+
mpatch.delenv("GMT_LIBRARY_PATH", raising=False)
122+
mpatch.setenv("PATH", "")
123+
lib_fullpaths = clib_full_names()
124+
125+
assert isinstance(lib_fullpaths, types.GeneratorType)
126+
assert list(lib_fullpaths) == gmt_lib_names
127+
128+
129+
def test_clib_full_names_gmt_library_path_defined_path_empty(
130+
monkeypatch, gmt_lib_names, gmt_lib_realpath
131+
):
132+
"""
133+
Make sure that clib_full_names() returns a generator with expected names
134+
when GMT_LIBRARY_PATH is defined and PATH is empty.
135+
"""
136+
with monkeypatch.context() as mpatch:
137+
mpatch.setenv("GMT_LIBRARY_PATH", str(PurePath(gmt_lib_realpath).parent))
138+
mpatch.setenv("PATH", "")
139+
lib_fullpaths = clib_full_names()
140+
141+
assert isinstance(lib_fullpaths, types.GeneratorType)
142+
assert list(lib_fullpaths) == [gmt_lib_realpath] + gmt_lib_names
143+
144+
145+
def test_clib_full_names_gmt_library_path_undefined_path_included(
146+
monkeypatch, gmt_lib_names, gmt_lib_realpath, gmt_bin_dir
147+
):
148+
"""
149+
Make sure that clib_full_names() returns a generator with expected names
150+
when GMT_LIBRARY_PATH is undefined and PATH includes GMT's bin path.
151+
"""
152+
with monkeypatch.context() as mpatch:
153+
mpatch.delenv("GMT_LIBRARY_PATH", raising=False)
154+
mpatch.setenv("PATH", gmt_bin_dir)
155+
lib_fullpaths = clib_full_names()
156+
157+
assert isinstance(lib_fullpaths, types.GeneratorType)
158+
# Windows: find_library() searches the library in PATH, so one more
159+
npath = 2 if sys.platform == "win32" else 1
160+
assert list(lib_fullpaths) == [gmt_lib_realpath] * npath + gmt_lib_names
161+
162+
163+
def test_clib_full_names_gmt_library_path_defined_path_included(
164+
monkeypatch, gmt_lib_names, gmt_lib_realpath, gmt_bin_dir
165+
):
166+
"""
167+
Make sure that clib_full_names() returns a generator with expected names
168+
when GMT_LIBRARY_PATH is defined and PATH includes GMT's bin path.
169+
"""
170+
with monkeypatch.context() as mpatch:
171+
mpatch.setenv("GMT_LIBRARY_PATH", str(PurePath(gmt_lib_realpath).parent))
172+
mpatch.setenv("PATH", gmt_bin_dir)
173+
lib_fullpaths = clib_full_names()
174+
175+
assert isinstance(lib_fullpaths, types.GeneratorType)
176+
# Windows: find_library() searches the library in PATH, so one more
177+
npath = 3 if sys.platform == "win32" else 2
178+
assert list(lib_fullpaths) == [gmt_lib_realpath] * npath + gmt_lib_names
179+
180+
181+
def test_clib_full_names_gmt_library_path_incorrect_path_included(
182+
monkeypatch, gmt_lib_names, gmt_lib_realpath, gmt_bin_dir
183+
):
184+
"""
185+
Make sure that clib_full_names() returns a generator with expected names
186+
when GMT_LIBRARY_PATH is defined but incorrect and PATH includes GMT's bin
187+
path.
188+
"""
189+
with monkeypatch.context() as mpatch:
190+
mpatch.setenv("GMT_LIBRARY_PATH", "/not/a/valid/library/path")
191+
mpatch.setenv("PATH", gmt_bin_dir)
192+
lib_fullpaths = clib_full_names()
193+
194+
assert isinstance(lib_fullpaths, types.GeneratorType)
195+
# Windows: find_library() searches the library in PATH, so one more
196+
npath = 2 if sys.platform == "win32" else 1
197+
assert list(lib_fullpaths) == [gmt_lib_realpath] * npath + gmt_lib_names

vercel.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)