From 3afaf2b35cab3fbe678adf28d22c078cd0f8d6f9 Mon Sep 17 00:00:00 2001 From: Aaron Virshup Date: Thu, 5 Oct 2017 10:20:14 -0700 Subject: [PATCH 1/3] Docker build updates --- .dockerignore | 1 + .gitignore | 2 +- DockerMakefiles/DockerMake.yml | 2 +- DockerMakefiles/Moldesign.yml | 26 +++++++++++++++---- DockerMakefiles/PythonTools.yml | 6 +---- DockerMakefiles/SymMol.yml | 11 +++++--- .../moldesign/moldesign.dockerignore | 22 ++++++++++++++++ .../buildfiles/moldesign/moldesign.yml | 4 +++ .../buildfiles/notebook/run_notebook.sh | 2 +- deployment/build-env.dockerfile | 3 ++- requirements.txt | 2 +- 11 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 DockerMakefiles/buildfiles/moldesign/moldesign.dockerignore create mode 100644 DockerMakefiles/buildfiles/moldesign/moldesign.yml diff --git a/.dockerignore b/.dockerignore index bbff344..12ba0fb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,3 +17,4 @@ docs/_build **/tokens **/codeship.aes **/tmp +**/Untitled*.ipynb \ No newline at end of file diff --git a/.gitignore b/.gitignore index 38acb0a..34f0134 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ moldesign/_static_data/components.ci* moldesign/_static_data/aa-variants-v1.ci* tmp *.bak - +Untitled*.ipynb diff --git a/DockerMakefiles/DockerMake.yml b/DockerMakefiles/DockerMake.yml index 1dd766a..16a6327 100644 --- a/DockerMakefiles/DockerMake.yml +++ b/DockerMakefiles/DockerMake.yml @@ -17,7 +17,7 @@ _ALL_: - moldesign_complete_py2 - moldesign_minimal - moldesign_minimal_py2 - # - moldesign_notebook + - moldesign_notebook - nucleic_acid_builder - nwchem_build - openblas diff --git a/DockerMakefiles/Moldesign.yml b/DockerMakefiles/Moldesign.yml index 0ca6287..73e9da7 100644 --- a/DockerMakefiles/Moldesign.yml +++ b/DockerMakefiles/Moldesign.yml @@ -5,12 +5,12 @@ moldesign_requirements: RUN conda install -qy -c omnia parmed biopython - moldesign_minimal_requirements: description: Base installation of the MDT library. Built from the current directory. requires: - moldesign_requirements build_directory: ../ + ignorefile: buildfiles/moldesign/moldesign.dockerignore build: | COPY requirements.txt /tmp/mdtreqs.txt RUN apt-get update \ @@ -49,12 +49,28 @@ moldesign_complete_py2: moldesign_notebook: - description: OUT OF DATE A production-ready, fully outfitted jupyter server container + description: A production-ready, fully outfitted jupyter server container requires: - moldesign_complete - notebook build: | - RUN pip install nbmolviz # == 0.7.0 + RUN adduser --disabled-password --gecos '' nbuser + RUN pip install nbmolviz==0.7.0rc4 + USER nbuser + RUN python -m nbmolviz activate --user + USER root RUN python -m moldesign copyexamples - RUN jupyter nbextension enable --python --sys-prefix widgetsnbextension \ - && jupyter nbextension enable --python --sys-prefix nbmolviz + + +moldesign_stack: + description: An extra-large image with everything needed to run the example notebooks + build_directory: buildfiles/moldesign + requires: + - moldesign_notebook + - opsin + - symmol_base + - nucleic_acid_builder + build: | + USER nbuser + RUN mkdir -p ~/.moldesign + ADD moldesign.yml ~/.moldesign/moldesign.yml diff --git a/DockerMakefiles/PythonTools.yml b/DockerMakefiles/PythonTools.yml index 5e69332..bdd2375 100644 --- a/DockerMakefiles/PythonTools.yml +++ b/DockerMakefiles/PythonTools.yml @@ -3,16 +3,12 @@ notebook: - python_deploy_base build_directory: buildfiles/notebook/ build: | - RUN conda install -yq matplotlib jupyter ipywidgets + RUN conda install -yq matplotlib jupyter ipywidgets nbformat ENTRYPOINT /run_notebook.sh EXPOSE 8888 RUN mkdir /notebooks WORKDIR /notebooks COPY run_notebook.sh /run_notebook.sh - # workaround below, not sure why it's necessary or even whose fault it is - RUN pip uninstall -y backports.ssl_match_hostname backports.shutil_get_terminal_size \ - && pip install backports.ssl_match_hostname backports.shutil_get_terminal_size - pyquante2: requires: diff --git a/DockerMakefiles/SymMol.yml b/DockerMakefiles/SymMol.yml index 637fe7c..df814f8 100644 --- a/DockerMakefiles/SymMol.yml +++ b/DockerMakefiles/SymMol.yml @@ -17,9 +17,7 @@ symmol_build: && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN mv /src/symmol/symmol /usr/local/bin -symmol: - requires: - - deploybase +symmol_base: build: | RUN apt-get update \ && apt-get install -y --no-install-recommends \ @@ -27,4 +25,9 @@ symmol: && cleanapt copy_from: symmol_build: - /usr/local/bin/symmol: /usr/local/bin \ No newline at end of file + /usr/local/bin/symmol: /usr/local/bin + +symmol: + requires: + - deploybase + - symmol_base \ No newline at end of file diff --git a/DockerMakefiles/buildfiles/moldesign/moldesign.dockerignore b/DockerMakefiles/buildfiles/moldesign/moldesign.dockerignore new file mode 100644 index 0000000..a5b0b77 --- /dev/null +++ b/DockerMakefiles/buildfiles/moldesign/moldesign.dockerignore @@ -0,0 +1,22 @@ +**/*.pyc +**/*.pyo +.idea +**/.ipynb_checkpoints/ +**/pyquante.log +**/_docker_make_tmp +**/lastfailed +dist +build +**/*.egg-info +**/__pycache__ +moldesign/_static_data/components.ci* +moldesign/_static_data/aa-variants-v1.ci* +**/*.bak +**/.coverage +docs/_build +**/tokens +**/codeship.aes +**/tmp +**/Untitled*.ipynb +DockerMakefiles +docs diff --git a/DockerMakefiles/buildfiles/moldesign/moldesign.yml b/DockerMakefiles/buildfiles/moldesign/moldesign.yml new file mode 100644 index 0000000..a4647c9 --- /dev/null +++ b/DockerMakefiles/buildfiles/moldesign/moldesign.yml @@ -0,0 +1,4 @@ +run_local: + nab.exe: true + opsin: true + symmol: true diff --git a/DockerMakefiles/buildfiles/notebook/run_notebook.sh b/DockerMakefiles/buildfiles/notebook/run_notebook.sh index 6b4438f..ea5b1f1 100755 --- a/DockerMakefiles/buildfiles/notebook/run_notebook.sh +++ b/DockerMakefiles/buildfiles/notebook/run_notebook.sh @@ -1,3 +1,3 @@ #!/bin/bash -jupyter notebook --ip=0.0.0.0 --no-browser --port=8888 $@ +jupyter notebook --ip=0.0.0.0 --no-browser --port=8888 --allow-root $@ diff --git a/deployment/build-env.dockerfile b/deployment/build-env.dockerfile index 015f6d6..c92465d 100644 --- a/deployment/build-env.dockerfile +++ b/deployment/build-env.dockerfile @@ -1,5 +1,6 @@ FROM python:2.7-slim - +# This is the environment that "docker-make" will run in on the CI server +# The expected build context is the root of the MDT repository RUN apt-get update && apt-get install -y curl # Install docker CLI only, not the full engine diff --git a/requirements.txt b/requirements.txt index 8d020fd..36930c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ numpy >= 1.12 pathlib2 ; python_version < '3.3' parmed >= 2.7.3 pint >= 0.8.1 -pyccc >= 0.7.12 +pyccc >= 0.7.13 pyyaml requests scipy From 6a41e725bb0ad353e83ac6f1f443859e5bd8a1ea Mon Sep 17 00:00:00 2001 From: Aaron Virshup Date: Thu, 5 Oct 2017 14:23:55 -0700 Subject: [PATCH 2/3] Add test for cif file that only contains C-alpha atoms --- moldesign/_tests/data/3b5x.cif.bz2 | Bin 0 -> 34550 bytes moldesign/_tests/test_pdb_processing.py | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 moldesign/_tests/data/3b5x.cif.bz2 diff --git a/moldesign/_tests/data/3b5x.cif.bz2 b/moldesign/_tests/data/3b5x.cif.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..05dd98bd212eb1ba12467eba1eb587558f936052 GIT binary patch literal 34550 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 Date: Thu, 5 Oct 2017 14:25:24 -0700 Subject: [PATCH 3/3] Fix an off-by-one error ... --- moldesign/molecules/residue.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/moldesign/molecules/residue.py b/moldesign/molecules/residue.py index 4bcc05e..b8325e9 100644 --- a/moldesign/molecules/residue.py +++ b/moldesign/molecules/residue.py @@ -247,11 +247,10 @@ def _is_ending_residue(self): except KeyError: # If we're here, the residue is missing some atoms. We'll fall back to checking the # next residues in line - if self.index == len(self.molecule.residues): + if self.index == len(self.molecule.residues) - 1: return True else: - print('WARNING: %s is missing expected atoms. Attempting to infer chain end' % \ - self) + print('WARNING: %s is missing expected atoms. Attempting to infer chain end' % self) nextres = self.molecule.residues[self.index + 1] return not self._same_polymer(nextres)