diff --git a/.travis.yml b/.travis.yml index 2dab4395..9b4742c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ install: - source devtools/travis-ci/install.sh - export PYTHONUNBUFFERED=true # Add org channel - - conda config --add channels omnia --add channels conda-forge --add channels salilab + - conda config --add channels omnia --add channels conda-forge # Add omnia dev channels - if [ $DEVOMNIA ]; then conda config --add channels omnia/label/dev; fi # Update everything @@ -34,10 +34,8 @@ script: - conda create --quiet --yes -n test python=$python # Activate the test environment - source activate test - # Install extras for OpenEye and testing - - conda install --yes --quiet pip nose nose-timer coverage - # Install extras for Modeller - - conda install --yes modeller + # Install extras for OpenEye, Modeller and testing + - conda install --yes --quiet pip nose nose-timer coverage modeller # Install OpenEye toolkit - pip install $OPENEYE_CHANNEL openeye-toolkits && python -c "import openeye; print(openeye.__version__)" # Build the recipe diff --git a/Yank/pipeline.py b/Yank/pipeline.py index 28032944..99c7f12a 100644 --- a/Yank/pipeline.py +++ b/Yank/pipeline.py @@ -945,6 +945,7 @@ def add_missing_atoms(value): # Write the final structure PDBFile.writeFile(fixer.topology, fixer.positions, open(output_file_path, 'w')) + def apply_modeller(input_file_path, output_file_path, directives): """ Apply Salilab Modeller to make changes to the specified molecule. @@ -969,14 +970,13 @@ def apply_modeller(input_file_path, output_file_path, directives): Dict containing directives for modeller. """ - try: - import modeller - except ImportError: + if not utils.is_modeller_installed(): raise ImportError('Modeller and license must be installed to use this feature.') + import modeller directives = copy.deepcopy(directives) - # Silence unecessart output to the log files + # Silence unnecessary output to the log files modeller.log.none() # Create modeller environment and point it to the PDB file @@ -994,7 +994,6 @@ def apply_modeller(input_file_path, output_file_path, directives): model_original_numbering = modeller.model(env, file=atom_file_name) alignment.append_model(model, atom_files=atom_file_name, align_codes=atom_file_name) - def apply_mutations_modeller(value): # Extract chain id chain_id = None @@ -1033,6 +1032,7 @@ def apply_mutations_modeller(value): model.res_num_from(model_original_numbering, alignment) model.write(file=output_file_path) + def read_csv_lines(file_path, lines): """Return a list of CSV records. diff --git a/Yank/tests/test_experiment.py b/Yank/tests/test_experiment.py index 2c12e2bf..8058980c 100644 --- a/Yank/tests/test_experiment.py +++ b/Yank/tests/test_experiment.py @@ -1309,6 +1309,8 @@ def test_pdbfixer_mutations(): break assert has_mut_residue + +@unittest.skipIf(not utils.is_modeller_installed(), "This test requires Salilab Modeller") def test_modeller_mutations(): """Test that modeller can apply mutations correctly.""" mol_id = 'Abl' @@ -1334,8 +1336,8 @@ def test_modeller_mutations(): # Now we set the strip_protons options and repeat exp_builder._db.molecules[mol_id]['modeller'] = { - 'apply_mutations' : { - 'chain_id' : 'A', + 'apply_mutations': { + 'chain_id': 'A', 'mutations': 'T85I', } } diff --git a/Yank/utils.py b/Yank/utils.py index 9655d879..92619512 100644 --- a/Yank/utils.py +++ b/Yank/utils.py @@ -1210,6 +1210,27 @@ def _compute_net_charge(residue): return tot_charge +def is_modeller_installed(): + """ + Check if a Salilab Modeller tool is installed and Licensed. + + If Modeller is not installed and licensed, returns False. + + Returns + ------- + installed : bool + True if all tools in ``oetools`` are installed and licensed, False otherwise. + """ + try: + import modeller + except: + # This has to be broad because we cant trap the ModellerError invalid license + # since the act of even trying to import Modeller triggers it, + # and its NOT an import error which is raised. + return False + return True + + # ----------------- # OpenEye functions # ----------------- diff --git a/docs/whatsnew.rst b/docs/whatsnew.rst index b55e6331..a3d5b504 100644 --- a/docs/whatsnew.rst +++ b/docs/whatsnew.rst @@ -7,10 +7,11 @@ This section features and improvements of note in each release. The full release history can be viewed `at the GitHub yank releases page `_. 0.23.3 Adds support for single mutations using Modeller ------------------------------------- -- - Adds an optional ``modeller` directive to the ``molecules`` section of the YAML file +------------------------------------------------------- +- Adds an optional ``modeller` directive to the ``molecules`` section of the YAML file through `Modeller `_, a tool for comparative modeling of protein structures. - The following options are accessible through the ``modeller`` directive. `(docs) `__ + - ``apply_mutations``: Specify protein single mutations (e.g., T315I). `(docs) `_ diff --git a/docs/yamlpages/molecules.rst b/docs/yamlpages/molecules.rst index 345b113e..34ed7555 100644 --- a/docs/yamlpages/molecules.rst +++ b/docs/yamlpages/molecules.rst @@ -258,6 +258,9 @@ PDBFixer is applied after ``strip_protons`` if both are requested. Specifies whether modeller should be used to model in mutations. Can only be used on proteins, on files with ``.pdb`` file extensions. +This feature requires the Modeller from the Sali Lab, which can be fetched from +Omnia's Conda channel. You will need to provide your own license however. + Mutations ^^^^^^^^^ diff --git a/setup.py b/setup.py index cb0c26ca..4a808652 100644 --- a/setup.py +++ b/setup.py @@ -12,8 +12,8 @@ ######################## VERSION = "0.23.3" # Primary base version of the build -DEVBUILD = 0 # Dev build status, Either None or Integer -ISRELEASED = False # Are we releasing this as a full cut? +DEVBUILD = None # Dev build status, Either None or Integer +ISRELEASED = True # Are we releasing this as a full cut? __version__ = VERSION ######################## CLASSIFIERS = """\