Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion devtools/conda-envs/openeye-examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ dependencies:
- openff-forcefields >=2023.11
- openff-amber-ff-ports >=0.0.3
- openff-units
- openff-utilities >=0.1.5
- openff-interchange-base >=0.5
- openff-nagl-base >=0.4.0
- openff-nagl-models >=0.3.0
Expand Down
1 change: 0 additions & 1 deletion devtools/conda-envs/openeye.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ dependencies:
- openff-forcefields >=2023.05.1
- openff-units
- openff-amber-ff-ports
- openff-utilities >=0.1.5
- openff-interchange-base >=0.5
- openff-nagl-base =0.4.0
- openff-nagl-models >=0.3.0
Expand Down
1 change: 0 additions & 1 deletion devtools/conda-envs/rdkit-examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ dependencies:
- openff-forcefields >=2023.11
- openff-amber-ff-ports >=0.0.3
- openff-units
- openff-utilities >=0.1.5
- openff-interchange-base >=0.5
- openff-nagl-base >=0.4.0
- openff-nagl-models >=0.3.0
Expand Down
1 change: 0 additions & 1 deletion devtools/conda-envs/rdkit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ dependencies:
- openff-forcefields >=2023.05.1
- openff-units
- openff-amber-ff-ports
- openff-utilities >=0.1.5
- openff-interchange-base >=0.5
- openff-nagl-base >=0.4.0
- openff-nagl-models >=0.3.0
Expand Down
1 change: 0 additions & 1 deletion devtools/conda-envs/test_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ dependencies:
- openff-forcefields >=2023.05.1
- openff-units
- openff-amber-ff-ports
- openff-utilities >=0.1.5
- openff-interchange-base >=0.5
- openff-nagl-base >=0.4.0
- openff-nagl-models >=0.3.0
Expand Down
1 change: 0 additions & 1 deletion docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ dependencies:
- ambertools
- packaging
- openff-units
- openff-utilities
- cachetools
- python-constraint
- mdtraj
Expand Down
2 changes: 1 addition & 1 deletion openff/toolkit/_tests/test_interchange.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
from openff.utilities import requires_package as requires_pkg

from openff.toolkit._utilities import requires_package as requires_pkg
from openff.toolkit.topology import Molecule
from openff.toolkit.typing.engines.smirnoff.forcefield import ForceField

Expand Down
2 changes: 1 addition & 1 deletion openff/toolkit/_tests/test_nagl.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import numpy
import pytest
from openff.utilities import has_package, skip_if_missing

from openff.toolkit import Molecule, unit
from openff.toolkit._tests.create_molecules import (
Expand All @@ -14,6 +13,7 @@
create_reversed_ethanol,
)
from openff.toolkit._tests.utils import requires_openeye
from openff.toolkit._utilities import has_package, skip_if_missing
from openff.toolkit.utils import GLOBAL_TOOLKIT_REGISTRY
from openff.toolkit.utils.exceptions import (
ToolkitUnavailableException,
Expand Down
2 changes: 1 addition & 1 deletion openff/toolkit/_tests/test_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import openmm.unit
import pytest
from openff.units.openmm import from_openmm
from openff.utilities import skip_if_missing

from openff.toolkit import Molecule, Quantity, Topology, unit
from openff.toolkit._tests.create_molecules import (
Expand All @@ -41,6 +40,7 @@
requires_pkg,
requires_rdkit,
)
from openff.toolkit._utilities import skip_if_missing
from openff.toolkit.topology import (
Atom,
ImproperDict,
Expand Down
Empty file.
17 changes: 17 additions & 0 deletions openff/toolkit/_tests/test_utilities/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest

from openff.toolkit._utilities.exceptions import MissingOptionalDependencyError, OpenFFError


def test_exceptions():
with pytest.raises(
MissingOptionalDependencyError,
match=r"The required foobar module could not be imported.*Try installing.*conda-forge.*",
):
raise MissingOptionalDependencyError(library_name="foobar")

with pytest.raises(MissingOptionalDependencyError, match=r".*barbaz.*missing license."):
raise MissingOptionalDependencyError(library_name="barbaz", license_issue=True)

with pytest.raises(OpenFFError):
raise MissingOptionalDependencyError("numpy")
54 changes: 54 additions & 0 deletions openff/toolkit/_tests/test_utilities/test_provenance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import importlib

import pytest

from openff.toolkit._utilities.provenance import (
_get_conda_list_package_versions,
get_ambertools_version,
)
from openff.toolkit._utilities.warnings import CondaExecutableNotFoundWarning


def mock_has_executable(executable_name: str) -> bool:
return False


@pytest.mark.leaky
def test_conda_unavailable_returns_empty_dict(monkeypatch):
"""
Test that if `conda|etc. list` fails, with or without AmberTools (properly) installed,
get_ambertools_version returns `None`.

This test leaks! Do not run it alongside other tests! Select either it "pytest -m leaky"
or avoid it "pytest -m 'not leaky'"
"""
with (
monkeypatch.context() as m,
pytest.warns(CondaExecutableNotFoundWarning, match="No .* executable found"),
):
m.setenv("PIXI_IN_SHELL", "0")
m.setenv("CONDA_SHLVL", "0")

assert _get_conda_list_package_versions() == dict()


def test_conda_available_get_ambertools_version_found():
# Skip if ambertools is not installed - sander would a better import test
# for AmberTools (since parmed could come from the standalone
# parmed package), however it's currently broken on ARM macs.
pytest.importorskip("parmed")

assert get_ambertools_version() is not None, (
f"note that len of package versions is {len(_get_conda_list_package_versions())}"
)


def test_conda_available_get_ambertools_version_not_found():
try:
importlib.import_module("parmed")
except ImportError:
assert len(_get_conda_list_package_versions()) > 0
assert get_ambertools_version() is None
return

pytest.skip("only run when ambertools is not installed.")
16 changes: 16 additions & 0 deletions openff/toolkit/_tests/test_utilities/test_testing_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import pytest

from openff.toolkit._utilities.testing import skip_if_missing, skip_if_missing_exec


def test_skips():
assert not skip_if_missing("pip").args[0]
assert skip_if_missing("numpynumpy").args[0]

assert not skip_if_missing_exec("python").args[0]
assert skip_if_missing_exec("python4").args[0]
assert not skip_if_missing_exec(["python", "python4"]).args[0]
assert skip_if_missing_exec(["python4", "python5"]).args[0]

with pytest.raises(ValueError, match=r"Bad type.*int"):
skip_if_missing_exec(0)
181 changes: 181 additions & 0 deletions openff/toolkit/_tests/test_utilities/test_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import os

import pytest

from openff.toolkit._utilities.exceptions import MissingOptionalDependencyError
from openff.toolkit._utilities.testing import skip_if_missing
from openff.toolkit._utilities.utilities import (
get_data_dir_path,
get_data_file_path,
has_executable,
has_package,
requires_oe_module,
requires_package,
temporary_cd,
)


def compare_paths(path_1: str, path_2: str) -> bool:
"""Checks whether two paths are the same.

Parameters
----------
path_1
The first path.
path_2
The second path.

Returns
-------
True if the paths are equivalent.
"""
return os.path.normpath(path_1) == os.path.normpath(path_2)


def test_get_data_dir_path():
"""Tests that the `get_data_dir_path` can correctly find
data directories.
"""

# Test a path which should exist.
data_file_path = get_data_dir_path("data/more", package_name="openff.toolkit._utilities")
assert os.path.isdir(data_file_path)

# Ensure a double-checking through data/ takes place
data_file_path = get_data_dir_path("more", package_name="openff.toolkit._utilities")
assert os.path.isdir(data_file_path)

# Test a path which should not exist.
with pytest.raises(NotADirectoryError):
get_data_dir_path("missing", package_name="openff.toolkit._utilities")

# Test that a file directory raises NotaDirectoryError
with pytest.raises(NotADirectoryError):
get_data_dir_path("data/data.dat", package_name="openff.toolkit._utilities")


def test_get_data_file_path():
"""Tests that the `get_data_file_path` can correctly find
data files.
"""

# Test a path which should exist.
data_file_path = get_data_file_path("data/data.dat", package_name="openff.toolkit._utilities")
assert os.path.isfile(data_file_path)

# Ensure a double-checking through data/ takes place
data_file_path = get_data_file_path("data.dat", package_name="openff.toolkit._utilities")
assert os.path.isfile(data_file_path)

# Test a path which should not exist.
with pytest.raises(FileNotFoundError):
get_data_file_path("missing.file", package_name="openff.toolkit._utilities")

# Test that a directory raises FileNotFoundError
with pytest.raises(FileNotFoundError):
get_data_file_path("data/", package_name="openff.toolkit._utilities")


def test_temporary_cd():
"""Tests that temporary cd works as expected"""

original_directory = os.getcwd()

# Move to the parent directory
with temporary_cd(os.pardir):
current_directory = os.getcwd()
expected_directory = os.path.abspath(os.path.join(original_directory, os.pardir))

assert compare_paths(current_directory, expected_directory)

assert compare_paths(os.getcwd(), original_directory)

# Move to a temporary directory
with temporary_cd():
assert not compare_paths(os.getcwd(), original_directory)

assert compare_paths(os.getcwd(), original_directory)

# Move to the same directory
with temporary_cd(""):
assert compare_paths(os.getcwd(), original_directory)

assert compare_paths(os.getcwd(), original_directory)

with temporary_cd(os.curdir):
assert compare_paths(os.getcwd(), original_directory)

assert compare_paths(os.getcwd(), original_directory)


def test_has_package():
assert has_package("os")
assert has_package("pytest")
assert not has_package("nummmmmmpy")


def test_has_executable():
assert has_executable("pwd")
assert has_executable("pytest")

assert has_executable("/usr/bin/whoami")

assert not has_package("pyyyyython")


def test_requires_package():
"""Tests that the ``requires_package`` utility behaves as expected."""

def dummy_function():
pass

# sys should always be found so this should not raise an exception.
requires_package("sys")(dummy_function)()

with pytest.raises(MissingOptionalDependencyError) as error_info:
requires_package("fake-lib")(dummy_function)()

assert error_info.value.library_name == "fake-lib"


@skip_if_missing("openeye.oechem")
@pytest.mark.skipif("OE_LICENSE" not in os.environ, reason="Requires an OpenEye license is NOT set up")
def test_requires_oe_module():
"""Tests that the ``requires_package`` utility behaves as expected when an OpenEye license is set up."""

def dummy_function():
pass

requires_oe_module("oechem")(dummy_function)()


@pytest.mark.parametrize("oe_module", ["oechem", "oeiupac", "oeomega", "oequacpac", "oedepict"])
@skip_if_missing("openeye")
@pytest.mark.skipif("OE_LICENSE" in os.environ, reason="Requires an OpenEye license is NOT set up")
def test_requires_oe_module_installed_missing_license(oe_module):
"""Tests that the ``requires_package`` utility behaves as expected while OpenEye toolkits are
installed but no OpenEye license is set up."""

def dummy_function():
pass

with pytest.raises(MissingOptionalDependencyError) as error_info:
requires_oe_module(oe_module)(dummy_function)()

assert oe_module in str(error_info.value)
assert "conda-forge" not in str(error_info.value)


@pytest.mark.skipif(has_package("openeye.oechem"), reason="Requires OpenEye toolkits are NOT installed")
def test_requires_oe_module_not_installed():
"""Tests that the ``requires_package`` utility behaves as expected while OpenEye toolkits are
installed."""

def dummy_function():
pass

with pytest.raises(MissingOptionalDependencyError) as error_info:
requires_oe_module("oechem")(dummy_function)()

assert "oechem" in str(error_info.value)
assert "conda-forge" not in str(error_info.value)
2 changes: 1 addition & 1 deletion openff/toolkit/_tests/test_utils_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

import numpy as np
import pytest
from openff.utilities import requires_package as requires_pkg

from openff.toolkit._utilities import requires_package as requires_pkg
from openff.toolkit.utils.serialization import Serializable
from openff.toolkit.utils.utils import deserialize_numpy, serialize_numpy

Expand Down
26 changes: 26 additions & 0 deletions openff/toolkit/_utilities/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from openff.toolkit._utilities.exceptions import MissingOptionalDependencyError
from openff.toolkit._utilities.provenance import get_ambertools_version
from openff.toolkit._utilities.testing import skip_if_missing, skip_if_missing_exec
from openff.toolkit._utilities.utilities import (
get_data_dir_path,
get_data_file_path,
has_executable,
has_package,
requires_oe_module,
requires_package,
temporary_cd,
)

__all__ = (
"MissingOptionalDependencyError",
"get_ambertools_version",
"get_data_dir_path",
"get_data_file_path",
"has_executable",
"has_package",
"requires_oe_module",
"requires_package",
"skip_if_missing",
"skip_if_missing_exec",
"temporary_cd",
)
2 changes: 2 additions & 0 deletions openff/toolkit/_utilities/data/data.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 0
0 1
Empty file.
Loading
Loading