Skip to content

Commit

Permalink
Merge branch 'master' into gmt_compat_6
Browse files Browse the repository at this point in the history
  • Loading branch information
seisman authored May 21, 2020
2 parents 36c810f + ce5de0e commit 8df13da
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 30 deletions.
34 changes: 32 additions & 2 deletions .azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ jobs:
conda list
displayName: List installed packages
# Cache the ${HOME}/.gmt directory, for docs and testing
- task: Cache@2
inputs:
key: cachedata | 20200519
path: $(HOME)/.gmt
cacheHitVar: CACHE_CACHEDATA_RESTORED
displayName: Cache GMT remote data for testing

# Download remote files, if not already cached
- bash: |
set -x -e
source activate testing
gmt which -Gu @earth_relief_10m @earth_relief_60m @ridge.txt @Table_5_11.txt @tut_bathy.nc @tut_quakes.ngdc @tut_ship.xyz
displayName: Download remote data
condition: ne(variables['CACHE_CACHEDATA_RESTORED'], true)
# Install the package
- bash: |
set -x -e
Expand Down Expand Up @@ -163,8 +179,6 @@ jobs:
CONDA_REQUIREMENTS: requirements.txt
CONDA_REQUIREMENTS_DEV: requirements-dev.txt
CONDA_INSTALL_EXTRA: "codecov gmt=6.0.0"
# ctypes.CDLL cannot find conda's libraries
GMT_LIBRARY_PATH: 'C:\Miniconda\envs\testing\Library\bin'

strategy:
matrix:
Expand Down Expand Up @@ -198,6 +212,22 @@ jobs:
conda list
displayName: List installed packages
# Cache the ${HOME}/.gmt directory, for docs and testing
- task: Cache@2
inputs:
key: cachedata | 20200519
path: $(HOMEPATH)/.gmt
cacheHitVar: CACHE_CACHEDATA_RESTORED
displayName: Cache GMT remote data for testing

# Download remote files, if not already cached
- bash: |
set -x -e
source activate testing
gmt which -Gu @earth_relief_10m @earth_relief_60m @ridge.txt @Table_5_11.txt @tut_bathy.nc @tut_quakes.ngdc @tut_ship.xyz
displayName: Download remote data
condition: ne(variables['CACHE_CACHEDATA_RESTORED'], true)
# Install the package that we want to test
- bash: |
set -x -e
Expand Down
65 changes: 45 additions & 20 deletions pygmt/clib/loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,19 @@
import os
import sys
import ctypes
from ctypes.util import find_library

from ..exceptions import GMTOSError, GMTCLibError, GMTCLibNotFoundError


def load_libgmt(env=None):
def load_libgmt():
"""
Find and load ``libgmt`` as a :py:class:`ctypes.CDLL`.
By default, will look for the shared library in the directory specified by
the environment variable ``GMT_LIBRARY_PATH``. If it's not set, will let
ctypes try to find the library.
Parameters
----------
env : dict or None
A dictionary containing the environment variables. If ``None``, will
default to ``os.environ``.
Returns
-------
:py:class:`ctypes.CDLL` object
Expand All @@ -37,27 +32,26 @@ def load_libgmt(env=None):
couldn't access the functions).
"""
if env is None:
env = os.environ
libnames = clib_name(os_name=sys.platform)
libpath = env.get("GMT_LIBRARY_PATH", "")
lib_fullnames = clib_full_names()
error = True
for libname in libnames:
for libname in lib_fullnames:
try:
libgmt = ctypes.CDLL(os.path.join(libpath, libname))
libgmt = ctypes.CDLL(libname)
check_libgmt(libgmt)
error = False
break
except OSError as err:
error = err
if error:
raise GMTCLibNotFoundError(
"Error loading the GMT shared library '{}':".format(", ".join(libnames))
"Error loading the GMT shared library '{}':".format(
", ".join(lib_fullnames)
)
)
return libgmt


def clib_name(os_name):
def clib_names(os_name):
"""
Return the name of GMT's shared library for the current OS.
Expand All @@ -68,20 +62,51 @@ def clib_name(os_name):
Returns
-------
libname : list of str
libnames : list of str
List of possible names of GMT's shared library.
"""
if os_name.startswith("linux"):
libname = ["libgmt.so"]
libnames = ["libgmt.so"]
elif os_name == "darwin":
# Darwin is macOS
libname = ["libgmt.dylib"]
libnames = ["libgmt.dylib"]
elif os_name == "win32":
libname = ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"]
libnames = ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"]
else:
raise GMTOSError('Operating system "{}" not supported.'.format(sys.platform))
return libname
return libnames


def clib_full_names(env=None):
"""
Return the full path of GMT's shared library for the current OS.
Parameters
----------
env : dict or None
A dictionary containing the environment variables. If ``None``, will
default to ``os.environ``.
Returns
-------
lib_fullnames: list of str
List of possible full names of GMT's shared library.
"""
if env is None:
env = os.environ
libnames = clib_names(os_name=sys.platform) # e.g. libgmt.so, libgmt.dylib, gmt.dll
libpath = env.get("GMT_LIBRARY_PATH", "") # e.g. $HOME/miniconda/envs/pygmt/lib

lib_fullnames = [os.path.join(libpath, libname) for libname in libnames]
# Search for DLLs in PATH if GMT_LIBRARY_PATH is not defined [Windows only]
if not libpath and sys.platform == "win32":
for libname in libnames:
libfullpath = find_library(libname)
if libfullpath:
lib_fullnames.append(libfullpath)
return lib_fullnames


def check_libgmt(libgmt):
Expand Down
26 changes: 18 additions & 8 deletions pygmt/tests/test_clib_loading.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""
Test the functions that load libgmt
"""
import os
import pytest

from ..clib.loading import clib_name, load_libgmt, check_libgmt
from ..clib.loading import clib_names, load_libgmt, check_libgmt
from ..exceptions import GMTCLibError, GMTOSError, GMTCLibNotFoundError


Expand All @@ -20,16 +21,25 @@ def test_load_libgmt():

def test_load_libgmt_fail():
"Test that loading fails when given a bad library path."
env = {"GMT_LIBRARY_PATH": "not/a/real/path"}
# save the old value (if any) before setting a fake "GMT_LIBRARY_PATH"
old_gmt_library_path = os.environ.get("GMT_LIBRARY_PATH")

os.environ["GMT_LIBRARY_PATH"] = "/not/a/real/path"
with pytest.raises(GMTCLibNotFoundError):
load_libgmt(env=env)
load_libgmt()

# revert back to the original status (if any)
if old_gmt_library_path:
os.environ["GMT_LIBRARY_PATH"] = old_gmt_library_path
else:
del os.environ["GMT_LIBRARY_PATH"]


def test_clib_name():
def test_clib_names():
"Make sure we get the correct library name for different OS names"
for linux in ["linux", "linux2", "linux3"]:
assert clib_name(linux) == ["libgmt.so"]
assert clib_name("darwin") == ["libgmt.dylib"]
assert clib_name("win32") == ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"]
assert clib_names(linux) == ["libgmt.so"]
assert clib_names("darwin") == ["libgmt.dylib"]
assert clib_names("win32") == ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"]
with pytest.raises(GMTOSError):
clib_name("meh")
clib_names("meh")

0 comments on commit 8df13da

Please sign in to comment.