From 8f51190d4f87ae62ab3a17cd78a4890eed30a39f Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 15:06:16 -0400 Subject: [PATCH 1/7] Remove GMT_LIBRARY_PATH --- .azure-pipelines.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 36da775bcd9..d0b1606b670 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -163,8 +163,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: From 628b061377a4c4e7d6a3296d7c81ede109d7132c Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 18:00:55 -0400 Subject: [PATCH 2/7] Add the function clib_full_names which return full names to library --- pygmt/clib/loading.py | 23 +++++++++++++++-------- pygmt/tests/test_clib_loading.py | 8 +------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index a0b9b18c043..7a4295d30bd 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -11,7 +11,7 @@ from ..exceptions import GMTOSError, GMTCLibError, GMTCLibNotFoundError -def load_libgmt(env=None): +def load_libgmt(): """ Find and load ``libgmt`` as a :py:class:`ctypes.CDLL`. @@ -37,14 +37,11 @@ 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 @@ -52,7 +49,7 @@ def load_libgmt(env=None): 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 @@ -84,6 +81,16 @@ def clib_name(os_name): return libname +def clib_full_names(env=None): + if env is None: + env = os.environ + libnames = clib_name(os_name=sys.platform) + libpath = env.get("GMT_LIBRARY_PATH", "") + + lib_fullnames = [os.path.join(libpath, libname) for libname in libnames] + return lib_fullnames + + def check_libgmt(libgmt): """ Make sure that libgmt was loaded correctly. diff --git a/pygmt/tests/test_clib_loading.py b/pygmt/tests/test_clib_loading.py index 1cc6dc4f4df..abb02ea2836 100644 --- a/pygmt/tests/test_clib_loading.py +++ b/pygmt/tests/test_clib_loading.py @@ -18,13 +18,6 @@ def test_load_libgmt(): check_libgmt(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"} - with pytest.raises(GMTCLibNotFoundError): - load_libgmt(env=env) - - def test_clib_name(): "Make sure we get the correct library name for different OS names" for linux in ["linux", "linux2", "linux3"]: @@ -33,3 +26,4 @@ def test_clib_name(): assert clib_name("win32") == ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"] with pytest.raises(GMTOSError): clib_name("meh") + From 9273528846619af42557ee4a542325e03887611e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 18:06:12 -0400 Subject: [PATCH 3/7] Use find_library search for DLLs in PATH --- pygmt/clib/loading.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index 7a4295d30bd..37c21eb9725 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -7,6 +7,7 @@ import os import sys import ctypes +from ctypes.util import find_library from ..exceptions import GMTOSError, GMTCLibError, GMTCLibNotFoundError @@ -88,6 +89,13 @@ def clib_full_names(env=None): libpath = env.get("GMT_LIBRARY_PATH", "") 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 sys.platform == "win32" and not libpath: + for libname in libnames: + libfullpath = find_library(libname) + if libfullpath: + lib_fullnames.append(libfullpath) return lib_fullnames From c783bffff7c9d237bb189ca9d45c18b812b5362d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 18:18:41 -0400 Subject: [PATCH 4/7] Add more docstrings --- pygmt/clib/loading.py | 28 +++++++++++++++++++--------- pygmt/tests/test_clib_loading.py | 1 - 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index 37c21eb9725..3074fdbc8ab 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -20,12 +20,6 @@ def load_libgmt(): 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 @@ -50,7 +44,9 @@ def load_libgmt(): error = err if error: raise GMTCLibNotFoundError( - "Error loading the GMT shared library '{}':".format(", ".join(lib_fullnames)) + "Error loading the GMT shared library '{}':".format( + ", ".join(lib_fullnames) + ) ) return libgmt @@ -83,15 +79,29 @@ def clib_name(os_name): 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_name(os_name=sys.platform) libpath = env.get("GMT_LIBRARY_PATH", "") 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 sys.platform == "win32" and not libpath: + if not libpath and sys.platform == "win32": for libname in libnames: libfullpath = find_library(libname) if libfullpath: diff --git a/pygmt/tests/test_clib_loading.py b/pygmt/tests/test_clib_loading.py index abb02ea2836..b2be3ef69b0 100644 --- a/pygmt/tests/test_clib_loading.py +++ b/pygmt/tests/test_clib_loading.py @@ -26,4 +26,3 @@ def test_clib_name(): assert clib_name("win32") == ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"] with pytest.raises(GMTOSError): clib_name("meh") - From 1d121f70ba10d7fbed250c2c4784a8cb0df222f7 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 19:31:22 -0400 Subject: [PATCH 5/7] Add some comments to make it more readable Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/clib/loading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index 3074fdbc8ab..4b30692135b 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -96,8 +96,8 @@ def clib_full_names(env=None): """ if env is None: env = os.environ - libnames = clib_name(os_name=sys.platform) - libpath = env.get("GMT_LIBRARY_PATH", "") + libnames = clib_name(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] From 9251d7c1196a35f6ed9a73718e710fc91952d075 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 19:54:51 -0400 Subject: [PATCH 6/7] Add a test for failing load_libgmt --- pygmt/tests/test_clib_loading.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pygmt/tests/test_clib_loading.py b/pygmt/tests/test_clib_loading.py index b2be3ef69b0..16b4a1767e9 100644 --- a/pygmt/tests/test_clib_loading.py +++ b/pygmt/tests/test_clib_loading.py @@ -1,6 +1,7 @@ """ Test the functions that load libgmt """ +import os import pytest from ..clib.loading import clib_name, load_libgmt, check_libgmt @@ -18,6 +19,22 @@ def test_load_libgmt(): check_libgmt(load_libgmt()) +def test_load_libgmt_fail(): + "Test that loading fails when given a bad library 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() + + # 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(): "Make sure we get the correct library name for different OS names" for linux in ["linux", "linux2", "linux3"]: From 4bc0bd754783df22b4fc956da6588be671c53e11 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 20 May 2020 19:57:33 -0400 Subject: [PATCH 7/7] Rename clib_name() to clib_names() and libname to libnames --- pygmt/clib/loading.py | 14 +++++++------- pygmt/tests/test_clib_loading.py | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index 4b30692135b..4b552fc8444 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -51,7 +51,7 @@ def load_libgmt(): return libgmt -def clib_name(os_name): +def clib_names(os_name): """ Return the name of GMT's shared library for the current OS. @@ -62,20 +62,20 @@ 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): @@ -96,7 +96,7 @@ def clib_full_names(env=None): """ if env is None: env = os.environ - libnames = clib_name(os_name=sys.platform) # e.g. libgmt.so, libgmt.dylib, gmt.dll + 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] diff --git a/pygmt/tests/test_clib_loading.py b/pygmt/tests/test_clib_loading.py index 16b4a1767e9..9c11cb698c1 100644 --- a/pygmt/tests/test_clib_loading.py +++ b/pygmt/tests/test_clib_loading.py @@ -4,7 +4,7 @@ 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 @@ -35,11 +35,11 @@ def test_load_libgmt_fail(): 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")