diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62bbc124980..ce306bc3aa3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,34 +9,5 @@ Quick links * [Pull request (PR) checklist](https://docs.pymc.io/en/latest/contributing/pr_checklist.html) * [Python style guide with pre-commit](https://docs.pymc.io/en/latest/contributing/python_style.html) * [Running the test suite](https://docs.pymc.io/en/latest/contributing/running_the_test_suite.html) +* [Running PyMC in Docker](https://docs.pymc.io/en/latest/contributing/docker_container.html) * [Submitting a bug report or feature request](https://github.com/pymc-devs/pymc/issues) - - diff --git a/docs/source/contributing/docker_container.md b/docs/source/contributing/docker_container.md new file mode 100644 index 00000000000..b625d9b28f6 --- /dev/null +++ b/docs/source/contributing/docker_container.md @@ -0,0 +1,18 @@ +(docker_container)= +# Running PyMC in Docker + +We have provided a Dockerfile which helps for isolating build problems, and local development. +Install [Docker](https://www.docker.com/) for your operating system, clone this repo, then +run the following commands to build a `pymc` docker image. + +```bash +cd pymc +bash scripts/docker_container.sh build +``` + +After successfully building the docker image, you can start a local docker container called `pymc` either from `bash` or from [`jupyter`](http://jupyter.org/) notebook server running on port 8888. + +```bash +bash scripts/docker_container.sh bash # running the container with bash +bash scripts/docker_container.sh jupyter # running the container with jupyter notebook +``` diff --git a/scripts/Dockerfile b/scripts/Dockerfile index 3473c1bafd9..7de54f6f182 100644 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -1,18 +1,30 @@ -FROM jupyter/minimal-notebook +FROM jupyter/base-notebook:python-3.9.12 -ARG SRC_DIR=. +LABEL name="pymc" +LABEL description="Environment for PyMC version 4" -MAINTAINER Austin Rochford +ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 -ADD $SRC_DIR /home/jovyan/ -RUN /bin/bash /home/jovyan/scripts/create_testenv.sh --global --no-setup +# Switch to jovyan to avoid container runs as root +USER $NB_UID -# matplotlib nonsense -ENV XDG_CACHE_HOME /home/$NB_USER/.cache/ -ENV MPLBACKEND=Agg -# for prettier default plot styling -RUN pip install seaborn -# Import matplotlib the first time to build the font cache. -RUN python -c "import matplotlib.pyplot" +COPY /conda-envs/environment-dev-py39.yml . +RUN mamba env create -f environment-dev-py39.yml && \ + /bin/bash -c ". activate pymc-dev-py39 && \ + mamba install -c conda-forge -y pymc" && \ + conda clean --all -f -y -ENV PYTHONPATH $PYTHONPATH:"$HOME" +# Fix PkgResourcesDeprecationWarning +RUN pip install --upgrade --user setuptools==58.3.0 + +#Setup working folder +WORKDIR /home/jovyan/work + +# For running from bash +SHELL ["/bin/bash","-c"] +RUN echo "conda activate pymc-dev-py39" >> ~/.bashrc && \ + source ~/.bashrc + +# For running from jupyter notebook +EXPOSE 8888 +CMD ["conda", "run", "--no-capture-output", "-n", "pymc-dev-py39", "jupyter","notebook","--ip=0.0.0.0","--port=8888","--no-browser"] diff --git a/scripts/create_testenv.sh b/scripts/create_testenv.sh deleted file mode 100755 index 418d3dacc69..00000000000 --- a/scripts/create_testenv.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -set -ex # fail on first error, print commands - -while test $# -gt 0; do - case "$1" in - --global) - GLOBAL=1 - ;; - --no-setup) - NO_SETUP=1 - ;; - esac - shift -done - -command -v conda >/dev/null 2>&1 || { - echo "Requires conda but it is not installed. Run install_miniconda.sh." >&2 - exit 1 -} - -ENVNAME="${ENVNAME:-testenv}" # if no ENVNAME is specified, use testenv - -if [ -z ${GLOBAL} ]; then - source $(dirname $(dirname $(which conda)))/etc/profile.d/conda.sh - if conda env list | grep -q ${ENVNAME}; then - echo "Environment ${ENVNAME} already exists, keeping up to date" - conda activate ${ENVNAME} - mamba env update -f environment-dev.yml - else - conda config --add channels conda-forge - conda config --set channel_priority strict - conda install -c conda-forge mamba --yes - mamba env create -f environment-dev.yml - conda activate ${ENVNAME} - fi -fi - -# Install editable using the setup.py -if [ -z ${NO_SETUP} ]; then - python setup.py build_ext --inplace -fi diff --git a/scripts/docker_container.sh b/scripts/docker_container.sh new file mode 100755 index 00000000000..56114338518 --- /dev/null +++ b/scripts/docker_container.sh @@ -0,0 +1,24 @@ +#! /bin/bash + +COMMAND="${1:-jupyter}" +SRC_DIR=${SRC_DIR:-`pwd`} +CONTAINER_NAME=${CONTAINER_NAME:-pymc} +PORT=${PORT:-8888} + +# stop and remove previous instances of the pymc container to avoid naming conflicts +if [[ $(docker ps -aq -f name=${CONTAINER_NAME}) ]]; then + echo "Shutting down and removing previous instance of ${CONTAINER_NAME} container..." + docker rm -f ${CONTAINER_NAME} +fi + +# $COMMAND can be either `build` or `bash` or `jupyter` +if [[ $COMMAND = 'build' ]]; then + docker build \ + -t ${CONTAINER_NAME} \ + -f $SRC_DIR/scripts/Dockerfile $SRC_DIR + +elif [[ $COMMAND = 'bash' ]]; then + docker run -it -v $SRC_DIR:/home/jovyan/work --rm --name ${CONTAINER_NAME} ${CONTAINER_NAME} bash +else + docker run -it -p $PORT:8888 -v $SRC_DIR:/home/jovyan/work --rm --name ${CONTAINER_NAME} ${CONTAINER_NAME} +fi diff --git a/scripts/install_miniconda.sh b/scripts/install_miniconda.sh deleted file mode 100755 index 6db6f64934e..00000000000 --- a/scripts/install_miniconda.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash - -set -e # fail on first error - -if conda --version > /dev/null 2>&1; then - echo "conda appears to already be installed" - exit 0 - fi - -PYTHON_VERSION=${PYTHON_VERSION:-3.6} # if no python specified, use 3.6 - -if [ ${PYTHON_VERSION} == "2.7" ]; then - INSTALL_FOLDER="$HOME/miniconda2" -else - INSTALL_FOLDER="$HOME/miniconda3" -fi - - -if [ ! -d $INSTALL_FOLDER ] || [ ! -e $INSTALL_FOLDER/bin/conda ]; then - if [ "$(uname)" == "Darwin" ]; then - URL_OS="MacOSX" - elif [ "$(expr substr "$(uname -s)" 1 5)" == "Linux" ]; then - URL_OS="Linux" - elif [ "$(expr substr "$(uname -s)" 1 10)" == "MINGW32_NT" ]; then - URL_OS="Windows" - fi - - echo "Downloading miniconda for $URL_OS" - DOWNLOAD_PATH="miniconda.sh" - if [ ${PYTHON_VERSION} == "2.7" ]; then - wget http://repo.continuum.io/miniconda/Miniconda-latest-$URL_OS-x86_64.sh -O ${DOWNLOAD_PATH}; - else - wget http://repo.continuum.io/miniconda/Miniconda3-latest-$URL_OS-x86_64.sh -O ${DOWNLOAD_PATH}; - fi - - echo "Installing miniconda for python-$PYTHON_VERSION to $INSTALL_FOLDER" - # install miniconda to home folder - bash ${DOWNLOAD_PATH} -b -f -p $INSTALL_FOLDER - - # tidy up - rm ${DOWNLOAD_PATH} -else - echo "Miniconda already installed at ${INSTALL_FOLDER}. Updating, adding to path and exiting" -fi - -export PATH="$INSTALL_FOLDER/bin:$PATH" -echo "Adding $INSTALL_FOLDER to PATH. Consider adding it in your .rc file as well." -conda update -q -y conda diff --git a/scripts/start_container.sh b/scripts/start_container.sh deleted file mode 100755 index ddff730bf09..00000000000 --- a/scripts/start_container.sh +++ /dev/null @@ -1,32 +0,0 @@ -#! /bin/bash - -PORT=${PORT:-8888} -SRC_DIR=${SRC_DIR:-`pwd`} -NOTEBOOK_DIR=${NOTEBOOK_DIR:-$SRC_DIR/notebooks} -TOKEN=$(openssl rand -hex 24) -CONTAINER_NAME=${CONTAINER_NAME:-pymc} - -# stop and remove previous instances of the pymc container to avoid naming conflicts -if [[ $(docker ps -aq -f name=${CONTAINER_NAME}) ]]; then - echo "Shutting down and removing previous instance of ${CONTAINER_NAME} container..." - docker rm -f ${CONTAINER_NAME} -fi - -# note that all paths are relative to the build context, so . represents -# SRC_DIR to Docker -docker build \ - -t ${CONTAINER_NAME} \ - -f $SRC_DIR/scripts/Dockerfile \ - --build-arg SRC_DIR=. \ - $SRC_DIR - -docker run -d \ - -p $PORT:8888 \ - -v $SRC_DIR:/home/jovyan/ \ - -v $NOTEBOOK_DIR:/home/jovyan/work/ \ - --name ${CONTAINER_NAME} ${CONTAINER_NAME} \ - start-notebook.sh --NotebookApp.token=${TOKEN} - -if [[ $* != *--no-browser* ]]; then - python -m webbrowser "http://localhost:${PORT}/?token=${TOKEN}" -fi