From 9f2129c4b0a507c23c77baf271ef1c31add3bf0c Mon Sep 17 00:00:00 2001 From: mfhepp Date: Sat, 13 Jan 2024 04:24:00 +0100 Subject: [PATCH] Notebook support; lock file export --- Dockerfile | 7 +- README.md | 110 +++++++++++++++++++- build.sh | 13 +++ dataviz.yaml | 30 ++++++ dataviz.yaml.lock | 252 +++++++++++++++++++++++++++++++++++++++++++++ env.yaml.lock | 61 +++++++++++ mini.yaml | 12 +++ mini.yaml.lock | 28 +++++ notebook.yaml | 9 ++ notebook.yaml.lock | 179 ++++++++++++++++++++++++++++++++ openai.yaml | 26 +++++ openai.yaml.lock | 185 +++++++++++++++++++++++++++++++++ run_notebook.sh | 81 +++++++++++++++ 13 files changed, 986 insertions(+), 7 deletions(-) create mode 100644 dataviz.yaml create mode 100644 dataviz.yaml.lock create mode 100644 env.yaml.lock create mode 100644 mini.yaml create mode 100644 mini.yaml.lock create mode 100644 notebook.yaml.lock create mode 100644 openai.yaml create mode 100644 openai.yaml.lock create mode 100755 run_notebook.sh diff --git a/Dockerfile b/Dockerfile index 0bd8442..820752f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,14 +28,13 @@ COPY --chown=$MAMBA_USER:$MAMBA_USER ${ENVIRONMENT_FILE} /tmp/env.yaml # This is due to the way micromamba-docker works RUN micromamba install -y -n base -f /tmp/env.yaml && \ micromamba clean --all --yes -# Install Kernels for Jupyter Notebook etc. -# TODO: Add -RUN echo Notebook mode is "$NOTEBOOK_MODE" -RUN if [[ -n "$NOTEBOOK_MODE" ]] ; then echo DEBUG Notebook mode ; fi WORKDIR /usr/app/src +# TODO: This is not needed for notebook images COPY --chown=$MAMBA_USER:$MAMBA_USER src/ ./ ARG MAMBA_DOCKERFILE_ACTIVATE=1 ENTRYPOINT ["/usr/local/bin/_entrypoint.sh"] +# Add the base environment as the default Jupyter Python kernel +RUN if [[ -n "$NOTEBOOK_MODE" ]] ; then python -m ipykernel install --user ; fi # For debugging, use this one # ENTRYPOINT ["/usr/local/bin/_entrypoint.sh", "/bin/sh"] # In a final application, you may want to hard-wire the entrypoint to the script: diff --git a/README.md b/README.md index 85c1c24..c81ed41 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Based on [`micromamba-docker`](https://github.com/mamba-org/micromamba-docker) a - Removed [Linux Kernel capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) - Adding new kernel capabilities is blocked - **Development mode,** in which the local version of the Python code can be run inside the container +- **Jupyter Notebook / JupyterLab**: You can also run Jupyter Notebook and JupyterLab inside the isolated container. ## Installation @@ -305,11 +306,95 @@ It is **strongly recommended to use an absolute path in the alias** (otherwise, **Warning:** An alias will allow you to run the script from any folder on your system, and that folder will be available for read-access to the script as `/usr/app/data`. +## Jupyter Notebook and JupyterLab + +You can build isolated containers with Juypter Notebook and JupyterLab. + +### Building a Notebook Image + +#### Using the default environment file `notebook.yaml` + +```bash +# This will build /notebook:latest +./build.sh -n +``` + +#### Using one of the pre-defined environment files + +```bash +# This will build /notebook:dataviz from dataviz.yaml +./build.sh -n dataviz +# This will build /notebook:openai from openai.yaml +./build.sh -n openai +``` + +#### Using your own environment file + +1. Copy `notebook.yaml` to a new YAML file (e.g. `foo.yaml`) and add modules as needed. +2. Build the image with +```bash +# This will build /notebook:foo from foo.yaml +./build.sh -n foo +``` + +### Creating an Alias `nbh` (for 'notebook here') + +Add the following lines to your `.bash_profile` file, like so: + +```bash +# ~/foo/bar/py4docker/ is the absolute path to the project in this example +alias nbh="bash ~/foo/bar/py4docker/run_notebook.sh" +``` +**Warning:** +1. An alias will allow you to run the notebook container from any folder on your system, and that folder will be available for read- and write-access to all code and libraries inside the container. +2. Symbolic links may allow access to resources outside the current working directory! + +#### Starting a Notebook Container + +The notebook containers need write-access and a network connection and are hence not as well isolated as in the Python script modus. + +The current working directory will be mapped to `/usr/app/src` inside the container. + +For a list of available notebook images (=environments), you can use the alias `nbh` + +```bash +nbh --list +``` + +or + +```bash +./run_notebook.sh --list +``` + +#### Using the default environment `notebook.yaml` + +```bash +# This will start /notebook:latest +nbh +``` + +#### Using one of the pre-defined environments + +```bash +# This will start /notebook:dataviz +nbh dataviz +# This will start /notebook:openai +nbh openai +``` + +#### Using your own environment + +```bash +# This will start /notebook:foo built from foo.yaml +nbh foo +``` + ## Advanced Topics ### Access to the Local File System -The current working directory will be available as `/usr/app/data` from within the container. By default, it is read-only. If you want to make this writeable, change the line +The current working directory will be available as `/usr/app/data` from within the container. By default, it is read-only (except in the Jupyter Notebook mode). If you want to make this writeable, change the line `--mount type=bind,source=$REAL_PWD,target=/usr/app/data,readonly \` @@ -323,7 +408,6 @@ You can also mount additional local paths using the same syntax. If you want to grant your code **write-access** to the `src` folder in **development mode** permanently, you can use the option `-D`, like so: - ```bash ./run_script.sh -D ``` @@ -379,10 +463,30 @@ from `run_script.sh`. More advanced settings are possible, e.g. adding a proxy or firewall inside the container that permits access only to a known set of IP addresses or domains and / or logs the outbound traffic. +## Updating + +For updating the Python packages, you should re-built the respective image with `-f` (for 'force'): + +```bash +# Script +./build.sh -f +# Script development image +./build.sh -f -d +# Default notebook image +./build.sh -fn +# Notebook image from dataviz.yaml +./build.sh -fn dataviz +# Notebook image from openai.yaml +./build.sh -fn openai +``` + ## Limitations and Ideas for Improvement - The code is currently maintained for Docker Desktop on Apple Silicon only. It may work on other platforms, but I have no time for testing at the moment. It seems to work on Debian. -- Expand support for blocking and logging Internet access e.g. by domain or IP ranges is a priority at my side, but non-trivial. +- Better support for blocking and logging Internet access e.g. by domain or IP ranges is a priority at my side, but non-trivial. +- The Jupyter Notebook mode has currently no support for bind mounts in Linux file-systems and will hence only work with Docker Desktop. +- Jupyter Notebook requires a writeable OS. +- The image size can likely be reduced further. ## LICENSE diff --git a/build.sh b/build.sh index ae9748e..ca9eb2d 100755 --- a/build.sh +++ b/build.sh @@ -75,6 +75,7 @@ else ENVIRONMENT_FILE="$1.yaml" # user:test_app:env-dev # user:test_app:env + # user:notebook:env DIGEST="$1${DIGEST:+-$DIGEST}" echo "INFO: Environment file = $ENVIRONMENT_FILE" fi @@ -91,3 +92,15 @@ docker build $PARAMETERS \ --build-arg="ENVIRONMENT_FILE=$ENVIRONMENT_FILE" \ $BUILD_NOTEBOOK \ --progress=plain --tag $IMAGE_NAME . +echo INFO: Writing lock file of installed packages for $ENVIRONMENT_FILE +docker run \ + --security-opt seccomp=seccomp-default.json \ + --security-opt=no-new-privileges \ + --read-only --tmpfs /tmp \ + --cap-drop all \ + --rm \ + $IMAGE_NAME \ + micromamba env export -n base > $ENVIRONMENT_FILE.lock +echo INFO: Build completed. + + diff --git a/dataviz.yaml b/dataviz.yaml new file mode 100644 index 0000000..acd6827 --- /dev/null +++ b/dataviz.yaml @@ -0,0 +1,30 @@ +# Using an environment name other than "base" is not recommended! +# Read https://github.com/mamba-org/micromamba-docker#multiple-environments +# if you must use a different environment name. +name: base +channels: + - conda-forge +dependencies: + - pip + - python>=3.9 + - typer + - requests + - httpx + - nest-asyncio + - black[jupyter] + - jupyter + - ipykernel + - jupytext + - pandas + - numpy + - openpyxl + - tabulate + - matplotlib + - beautifulsoup4 + - graphviz + - python-graphviz + - seaborn +# - jupyter_ai +# PyPi modules +# - pip: +# - black[jupyter] diff --git a/dataviz.yaml.lock b/dataviz.yaml.lock new file mode 100644 index 0000000..5f98b16 --- /dev/null +++ b/dataviz.yaml.lock @@ -0,0 +1,252 @@ +name: base +channels: +- conda-forge +dependencies: +- _openmp_mutex=4.5=2_gnu +- anyio=4.2.0=pyhd8ed1ab_0 +- argon2-cffi=23.1.0=pyhd8ed1ab_0 +- argon2-cffi-bindings=21.2.0=py312hdd3e373_4 +- arrow=1.3.0=pyhd8ed1ab_0 +- asttokens=2.4.1=pyhd8ed1ab_0 +- async-lru=2.0.4=pyhd8ed1ab_0 +- atk-1.0=2.38.0=hf4e84e4_1 +- attrs=23.2.0=pyh71513ae_0 +- babel=2.14.0=pyhd8ed1ab_0 +- beautifulsoup4=4.12.2=pyha770c72_0 +- black=23.12.1=py312h996f985_0 +- bleach=6.1.0=pyhd8ed1ab_0 +- brotli=1.1.0=h31becfc_1 +- brotli-bin=1.1.0=h31becfc_1 +- brotli-python=1.1.0=py312h2aa54b4_1 +- bzip2=1.0.8=h31becfc_5 +- ca-certificates=2023.11.17=hcefe29a_0 +- cached-property=1.5.2=hd8ed1ab_1 +- cached_property=1.5.2=pyha770c72_1 +- cairo=1.18.0=ha13f110_0 +- certifi=2023.11.17=pyhd8ed1ab_0 +- cffi=1.16.0=py312hf3c74c0_0 +- charset-normalizer=3.3.2=pyhd8ed1ab_0 +- click=8.1.7=unix_pyh707e725_0 +- colorama=0.4.6=pyhd8ed1ab_0 +- comm=0.2.1=pyhd8ed1ab_0 +- contourpy=1.2.0=py312h8f0b210_0 +- cycler=0.12.1=pyhd8ed1ab_0 +- debugpy=1.8.0=py312h2aa54b4_1 +- decorator=5.1.1=pyhd8ed1ab_0 +- defusedxml=0.7.1=pyhd8ed1ab_0 +- entrypoints=0.4=pyhd8ed1ab_0 +- et_xmlfile=1.1.0=pyhd8ed1ab_0 +- exceptiongroup=1.2.0=pyhd8ed1ab_2 +- executing=2.0.1=pyhd8ed1ab_0 +- expat=2.5.0=hd600fc2_1 +- font-ttf-dejavu-sans-mono=2.37=hab24e00_0 +- font-ttf-inconsolata=3.000=h77eed37_0 +- font-ttf-source-code-pro=2.038=h77eed37_0 +- font-ttf-ubuntu=0.83=h77eed37_1 +- fontconfig=2.14.2=ha9a116f_0 +- fonts-conda-ecosystem=1=0 +- fonts-conda-forge=1=0 +- fonttools=4.47.2=py312hdd3e373_0 +- fqdn=1.5.1=pyhd8ed1ab_0 +- freetype=2.12.1=hf0a5ef3_2 +- fribidi=1.0.10=hb9de7d4_0 +- gdk-pixbuf=2.42.10=h1db8359_4 +- gettext=0.21.1=ha18d298_0 +- giflib=5.2.1=hb4cce97_3 +- graphite2=1.3.13=h7fd3ca4_1001 +- graphviz=9.0.0=h65e8cce_1 +- gtk2=2.24.33=hc82cb13_3 +- gts=0.7.6=he293c15_4 +- h11=0.14.0=pyhd8ed1ab_0 +- h2=4.1.0=pyhd8ed1ab_0 +- harfbuzz=8.3.0=hebeb849_0 +- hpack=4.0.0=pyh9f0ad1d_0 +- httpcore=1.0.2=pyhd8ed1ab_0 +- httpx=0.26.0=pyhd8ed1ab_0 +- hyperframe=6.0.1=pyhd8ed1ab_0 +- icu=73.2=h787c7f5_0 +- idna=3.6=pyhd8ed1ab_0 +- importlib-metadata=7.0.1=pyha770c72_0 +- importlib_metadata=7.0.1=hd8ed1ab_0 +- importlib_resources=6.1.1=pyhd8ed1ab_0 +- ipykernel=6.28.0=pyhd33586a_0 +- ipython=8.20.0=pyh707e725_0 +- ipywidgets=8.1.1=pyhd8ed1ab_0 +- isoduration=20.11.0=pyhd8ed1ab_0 +- jedi=0.19.1=pyhd8ed1ab_0 +- jinja2=3.1.3=pyhd8ed1ab_0 +- json5=0.9.14=pyhd8ed1ab_0 +- jsonpointer=2.4=py312h996f985_3 +- jsonschema=4.20.0=pyhd8ed1ab_0 +- jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 +- jsonschema-with-format-nongpl=4.20.0=pyhd8ed1ab_0 +- jupyter=1.0.0=pyhd8ed1ab_10 +- jupyter-lsp=2.2.1=pyhd8ed1ab_0 +- jupyter_client=8.6.0=pyhd8ed1ab_0 +- jupyter_console=6.6.3=pyhd8ed1ab_0 +- jupyter_core=5.7.1=py312h996f985_0 +- jupyter_events=0.9.0=pyhd8ed1ab_0 +- jupyter_server=2.12.4=pyhd8ed1ab_0 +- jupyter_server_terminals=0.5.1=pyhd8ed1ab_0 +- jupyterlab=4.0.10=pyhd8ed1ab_0 +- jupyterlab_pygments=0.3.0=pyhd8ed1ab_0 +- jupyterlab_server=2.25.2=pyhd8ed1ab_0 +- jupyterlab_widgets=3.0.9=pyhd8ed1ab_0 +- jupytext=1.16.0=pyhd8ed1ab_0 +- kiwisolver=1.4.5=py312h721a97f_1 +- lcms2=2.16=h922389a_0 +- ld_impl_linux-aarch64=2.40=h2d8c526_0 +- lerc=4.0.0=h4de3ea5_0 +- libblas=3.9.0=20_linuxaarch64_openblas +- libbrotlicommon=1.1.0=h31becfc_1 +- libbrotlidec=1.1.0=h31becfc_1 +- libbrotlienc=1.1.0=h31becfc_1 +- libcblas=3.9.0=20_linuxaarch64_openblas +- libdeflate=1.19=h31becfc_0 +- libexpat=2.5.0=hd600fc2_1 +- libffi=3.4.2=h3557bc0_5 +- libgcc-ng=13.2.0=hf8544c7_3 +- libgd=2.3.3=hcd22fd5_9 +- libgfortran-ng=13.2.0=he9431aa_3 +- libgfortran5=13.2.0=h582850c_3 +- libglib=2.78.3=h311d5f7_0 +- libgomp=13.2.0=hf8544c7_3 +- libiconv=1.17=h31becfc_2 +- libjpeg-turbo=3.0.0=h31becfc_1 +- liblapack=3.9.0=20_linuxaarch64_openblas +- libnsl=2.0.1=h31becfc_0 +- libopenblas=0.3.25=pthreads_h5a5ec62_0 +- libpng=1.6.39=hf9034f9_0 +- librsvg=2.56.3=h4341b47_1 +- libsodium=1.0.18=hb9de7d4_1 +- libsqlite=3.44.2=h194ca79_0 +- libstdcxx-ng=13.2.0=h9a76618_3 +- libtiff=4.6.0=h1708d11_2 +- libuuid=2.38.1=hb4cce97_0 +- libwebp=1.3.2=heb2ea1b_1 +- libwebp-base=1.3.2=h31becfc_0 +- libxcb=1.15=h2a766a3_0 +- libxcrypt=4.4.36=h31becfc_1 +- libxml2=2.12.3=h3091e33_0 +- libzlib=1.2.13=h31becfc_5 +- markdown-it-py=3.0.0=pyhd8ed1ab_0 +- markupsafe=2.1.3=py312h9ef2f89_1 +- matplotlib=3.8.2=py312h8025657_0 +- matplotlib-base=3.8.2=py312h132ec79_0 +- matplotlib-inline=0.1.6=pyhd8ed1ab_0 +- mdit-py-plugins=0.4.0=pyhd8ed1ab_0 +- mdurl=0.1.2=pyhd8ed1ab_0 +- mistune=3.0.2=pyhd8ed1ab_0 +- munkres=1.1.4=pyh9f0ad1d_0 +- mypy_extensions=1.0.0=pyha770c72_0 +- nbclient=0.8.0=pyhd8ed1ab_0 +- nbconvert=7.14.1=pyhd8ed1ab_0 +- nbconvert-core=7.14.1=pyhd8ed1ab_0 +- nbconvert-pandoc=7.14.1=pyhd8ed1ab_0 +- nbformat=5.9.2=pyhd8ed1ab_0 +- ncurses=6.4=h0425590_2 +- nest-asyncio=1.5.8=pyhd8ed1ab_0 +- notebook=7.0.6=pyhd8ed1ab_0 +- notebook-shim=0.2.3=pyhd8ed1ab_0 +- numpy=1.26.3=py312h470d778_0 +- openjpeg=2.5.0=h0d9d63b_3 +- openpyxl=3.1.2=py312hdd3e373_1 +- openssl=3.2.0=h31becfc_1 +- overrides=7.4.0=pyhd8ed1ab_0 +- packaging=23.2=pyhd8ed1ab_0 +- pandas=2.1.4=py312hc56aa73_0 +- pandoc=3.1.3=h8af1aa0_0 +- pandocfilters=1.5.0=pyhd8ed1ab_0 +- pango=1.50.14=h11ef544_2 +- parso=0.8.3=pyhd8ed1ab_0 +- pathspec=0.12.1=pyhd8ed1ab_0 +- patsy=0.5.6=pyhd8ed1ab_0 +- pcre2=10.42=hd0f9c67_0 +- pexpect=4.8.0=pyh1a96a4e_2 +- pickleshare=0.7.5=py_1003 +- pillow=10.2.0=py312h1e2a6dd_0 +- pip=23.3.2=pyhd8ed1ab_0 +- pixman=0.43.0=h2f0025b_0 +- pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 +- platformdirs=4.1.0=pyhd8ed1ab_0 +- prometheus_client=0.19.0=pyhd8ed1ab_0 +- prompt-toolkit=3.0.42=pyha770c72_0 +- prompt_toolkit=3.0.42=hd8ed1ab_0 +- psutil=5.9.7=py312hdd3e373_0 +- pthread-stubs=0.4=hb9de7d4_1001 +- ptyprocess=0.7.0=pyhd3deb0d_0 +- pure_eval=0.2.2=pyhd8ed1ab_0 +- pycparser=2.21=pyhd8ed1ab_0 +- pygments=2.17.2=pyhd8ed1ab_0 +- pyparsing=3.1.1=pyhd8ed1ab_0 +- pysocks=1.7.1=pyha2e5f31_6 +- python=3.12.1=h43d1f9e_1_cpython +- python-dateutil=2.8.2=pyhd8ed1ab_0 +- python-fastjsonschema=2.19.1=pyhd8ed1ab_0 +- python-graphviz=0.20.1=pyh22cad53_0 +- python-json-logger=2.0.7=pyhd8ed1ab_0 +- python-tzdata=2023.4=pyhd8ed1ab_0 +- python_abi=3.12=4_cp312 +- pytz=2023.3.post1=pyhd8ed1ab_0 +- pyyaml=6.0.1=py312hdd3e373_1 +- pyzmq=25.1.2=py312h1c32067_0 +- qtconsole-base=5.5.1=pyha770c72_0 +- qtpy=2.4.1=pyhd8ed1ab_0 +- readline=8.2=h8fc344f_1 +- referencing=0.32.1=pyhd8ed1ab_0 +- requests=2.31.0=pyhd8ed1ab_0 +- rfc3339-validator=0.1.4=pyhd8ed1ab_0 +- rfc3986-validator=0.1.1=pyh9f0ad1d_0 +- rich=13.7.0=pyhd8ed1ab_0 +- rpds-py=0.16.2=py312h2a5c9d6_0 +- scipy=1.11.3=py312h470d778_1 +- seaborn=0.13.1=hd8ed1ab_0 +- seaborn-base=0.13.1=pyhd8ed1ab_0 +- send2trash=1.8.2=pyh41d4057_0 +- setuptools=69.0.3=pyhd8ed1ab_0 +- shellingham=1.5.4=pyhd8ed1ab_0 +- six=1.16.0=pyh6c4a22f_0 +- sniffio=1.3.0=pyhd8ed1ab_0 +- soupsieve=2.5=pyhd8ed1ab_1 +- stack_data=0.6.2=pyhd8ed1ab_0 +- statsmodels=0.14.1=py312h3e17d05_0 +- tabulate=0.9.0=pyhd8ed1ab_1 +- terminado=0.18.0=pyh0d859eb_0 +- tinycss2=1.2.1=pyhd8ed1ab_0 +- tk=8.6.13=h194ca79_0 +- toml=0.10.2=pyhd8ed1ab_0 +- tomli=2.0.1=pyhd8ed1ab_0 +- tornado=6.3.3=py312h9ef2f89_1 +- traitlets=5.14.1=pyhd8ed1ab_0 +- typer=0.9.0=pyhd8ed1ab_0 +- types-python-dateutil=2.8.19.20240106=pyhd8ed1ab_0 +- typing-extensions=4.9.0=hd8ed1ab_0 +- typing_extensions=4.9.0=pyha770c72_0 +- typing_utils=0.1.0=pyhd8ed1ab_0 +- tzdata=2023d=h0c530f3_0 +- uri-template=1.3.0=pyhd8ed1ab_0 +- urllib3=2.1.0=pyhd8ed1ab_0 +- wcwidth=0.2.13=pyhd8ed1ab_0 +- webcolors=1.13=pyhd8ed1ab_0 +- webencodings=0.5.1=pyhd8ed1ab_2 +- websocket-client=1.7.0=pyhd8ed1ab_0 +- wheel=0.42.0=pyhd8ed1ab_0 +- widgetsnbextension=4.0.9=pyhd8ed1ab_0 +- xorg-kbproto=1.0.7=h3557bc0_1002 +- xorg-libice=1.1.1=h7935292_0 +- xorg-libsm=1.2.4=h5a01bc2_0 +- xorg-libx11=1.8.7=h055a233_0 +- xorg-libxau=1.0.11=h31becfc_0 +- xorg-libxdmcp=1.1.3=h3557bc0_0 +- xorg-libxext=1.3.4=h2a766a3_2 +- xorg-libxrender=0.9.11=h7935292_0 +- xorg-renderproto=0.11.1=h3557bc0_1002 +- xorg-xextproto=7.3.0=h2a766a3_1003 +- xorg-xproto=7.0.31=h3557bc0_1007 +- xz=5.2.6=h9cdd2b7_0 +- yaml=0.2.5=hf897c2e_2 +- zeromq=4.3.5=h2f0025b_0 +- zipp=3.17.0=pyhd8ed1ab_0 +- zlib=1.2.13=h31becfc_5 +- zstd=1.5.5=h4c53e97_0 + diff --git a/env.yaml.lock b/env.yaml.lock new file mode 100644 index 0000000..3208f38 --- /dev/null +++ b/env.yaml.lock @@ -0,0 +1,61 @@ +name: base +channels: +- conda-forge +dependencies: +- _openmp_mutex=4.5=2_gnu +- anyio=4.2.0=pyhd8ed1ab_0 +- black=23.12.1=py312h996f985_0 +- brotli-python=1.1.0=py312h2aa54b4_1 +- bzip2=1.0.8=h31becfc_5 +- ca-certificates=2023.11.17=hcefe29a_0 +- certifi=2023.11.17=pyhd8ed1ab_0 +- charset-normalizer=3.3.2=pyhd8ed1ab_0 +- click=8.1.7=unix_pyh707e725_0 +- colorama=0.4.6=pyhd8ed1ab_0 +- exceptiongroup=1.2.0=pyhd8ed1ab_2 +- h11=0.14.0=pyhd8ed1ab_0 +- h2=4.1.0=pyhd8ed1ab_0 +- hpack=4.0.0=pyh9f0ad1d_0 +- httpcore=1.0.2=pyhd8ed1ab_0 +- httpx=0.26.0=pyhd8ed1ab_0 +- hyperframe=6.0.1=pyhd8ed1ab_0 +- idna=3.6=pyhd8ed1ab_0 +- ld_impl_linux-aarch64=2.40=h2d8c526_0 +- libexpat=2.5.0=hd600fc2_1 +- libffi=3.4.2=h3557bc0_5 +- libgcc-ng=13.2.0=hf8544c7_3 +- libgomp=13.2.0=hf8544c7_3 +- libnsl=2.0.1=h31becfc_0 +- libsqlite=3.44.2=h194ca79_0 +- libstdcxx-ng=13.2.0=h9a76618_3 +- libuuid=2.38.1=hb4cce97_0 +- libxcrypt=4.4.36=h31becfc_1 +- libzlib=1.2.13=h31becfc_5 +- markdown-it-py=3.0.0=pyhd8ed1ab_0 +- mdurl=0.1.2=pyhd8ed1ab_0 +- mypy_extensions=1.0.0=pyha770c72_0 +- ncurses=6.4=h0425590_2 +- openssl=3.2.0=h31becfc_1 +- packaging=23.2=pyhd8ed1ab_0 +- pathspec=0.12.1=pyhd8ed1ab_0 +- pip=23.3.2=pyhd8ed1ab_0 +- platformdirs=4.1.0=pyhd8ed1ab_0 +- pygments=2.17.2=pyhd8ed1ab_0 +- pysocks=1.7.1=pyha2e5f31_6 +- python=3.12.1=h43d1f9e_1_cpython +- python_abi=3.12=4_cp312 +- readline=8.2=h8fc344f_1 +- requests=2.31.0=pyhd8ed1ab_0 +- rich=13.7.0=pyhd8ed1ab_0 +- setuptools=69.0.3=pyhd8ed1ab_0 +- shellingham=1.5.4=pyhd8ed1ab_0 +- sniffio=1.3.0=pyhd8ed1ab_0 +- tk=8.6.13=h194ca79_0 +- typer=0.9.0=pyhd8ed1ab_0 +- typing-extensions=4.9.0=hd8ed1ab_0 +- typing_extensions=4.9.0=pyha770c72_0 +- tzdata=2023d=h0c530f3_0 +- urllib3=2.1.0=pyhd8ed1ab_0 +- wheel=0.42.0=pyhd8ed1ab_0 +- xz=5.2.6=h9cdd2b7_0 + diff --git a/mini.yaml b/mini.yaml new file mode 100644 index 0000000..db4e84f --- /dev/null +++ b/mini.yaml @@ -0,0 +1,12 @@ +# Using an environment name other than "base" is not recommended! +# Read https://github.com/mamba-org/micromamba-docker#multiple-environments +# if you must use a different environment name. +name: base +channels: + - conda-forge +dependencies: + - pip + - python>=3.9 +# PyPi modules +# - pip: +# - black[jupyter] diff --git a/mini.yaml.lock b/mini.yaml.lock new file mode 100644 index 0000000..d79d391 --- /dev/null +++ b/mini.yaml.lock @@ -0,0 +1,28 @@ +name: base +channels: +- conda-forge +dependencies: +- _openmp_mutex=4.5=2_gnu +- bzip2=1.0.8=h31becfc_5 +- ca-certificates=2023.11.17=hcefe29a_0 +- ld_impl_linux-aarch64=2.40=h2d8c526_0 +- libexpat=2.5.0=hd600fc2_1 +- libffi=3.4.2=h3557bc0_5 +- libgcc-ng=13.2.0=hf8544c7_3 +- libgomp=13.2.0=hf8544c7_3 +- libnsl=2.0.1=h31becfc_0 +- libsqlite=3.44.2=h194ca79_0 +- libuuid=2.38.1=hb4cce97_0 +- libxcrypt=4.4.36=h31becfc_1 +- libzlib=1.2.13=h31becfc_5 +- ncurses=6.4=h0425590_2 +- openssl=3.2.0=h31becfc_1 +- pip=23.3.2=pyhd8ed1ab_0 +- python=3.12.1=h43d1f9e_1_cpython +- readline=8.2=h8fc344f_1 +- setuptools=69.0.3=pyhd8ed1ab_0 +- tk=8.6.13=h194ca79_0 +- tzdata=2023d=h0c530f3_0 +- wheel=0.42.0=pyhd8ed1ab_0 +- xz=5.2.6=h9cdd2b7_0 + diff --git a/notebook.yaml b/notebook.yaml index 22eeff0..2ad5ce0 100644 --- a/notebook.yaml +++ b/notebook.yaml @@ -10,7 +10,16 @@ dependencies: - typer - requests - httpx + - nest-asyncio - black[jupyter] + - jupyter + - ipykernel + - jupytext + - pandas + - numpy + - openpyxl + - tabulate + - beautifulsoup4 # PyPi modules # - pip: # - black[jupyter] diff --git a/notebook.yaml.lock b/notebook.yaml.lock new file mode 100644 index 0000000..be4aaec --- /dev/null +++ b/notebook.yaml.lock @@ -0,0 +1,179 @@ +name: base +channels: +- conda-forge +dependencies: +- _openmp_mutex=4.5=2_gnu +- anyio=4.2.0=pyhd8ed1ab_0 +- argon2-cffi=23.1.0=pyhd8ed1ab_0 +- argon2-cffi-bindings=21.2.0=py312hdd3e373_4 +- arrow=1.3.0=pyhd8ed1ab_0 +- asttokens=2.4.1=pyhd8ed1ab_0 +- async-lru=2.0.4=pyhd8ed1ab_0 +- attrs=23.2.0=pyh71513ae_0 +- babel=2.14.0=pyhd8ed1ab_0 +- beautifulsoup4=4.12.2=pyha770c72_0 +- black=23.12.1=py312h996f985_0 +- bleach=6.1.0=pyhd8ed1ab_0 +- brotli-python=1.1.0=py312h2aa54b4_1 +- bzip2=1.0.8=h31becfc_5 +- ca-certificates=2023.11.17=hcefe29a_0 +- cached-property=1.5.2=hd8ed1ab_1 +- cached_property=1.5.2=pyha770c72_1 +- certifi=2023.11.17=pyhd8ed1ab_0 +- cffi=1.16.0=py312hf3c74c0_0 +- charset-normalizer=3.3.2=pyhd8ed1ab_0 +- click=8.1.7=unix_pyh707e725_0 +- colorama=0.4.6=pyhd8ed1ab_0 +- comm=0.2.1=pyhd8ed1ab_0 +- debugpy=1.8.0=py312h2aa54b4_1 +- decorator=5.1.1=pyhd8ed1ab_0 +- defusedxml=0.7.1=pyhd8ed1ab_0 +- entrypoints=0.4=pyhd8ed1ab_0 +- et_xmlfile=1.1.0=pyhd8ed1ab_0 +- exceptiongroup=1.2.0=pyhd8ed1ab_2 +- executing=2.0.1=pyhd8ed1ab_0 +- fqdn=1.5.1=pyhd8ed1ab_0 +- h11=0.14.0=pyhd8ed1ab_0 +- h2=4.1.0=pyhd8ed1ab_0 +- hpack=4.0.0=pyh9f0ad1d_0 +- httpcore=1.0.2=pyhd8ed1ab_0 +- httpx=0.26.0=pyhd8ed1ab_0 +- hyperframe=6.0.1=pyhd8ed1ab_0 +- idna=3.6=pyhd8ed1ab_0 +- importlib-metadata=7.0.1=pyha770c72_0 +- importlib_metadata=7.0.1=hd8ed1ab_0 +- importlib_resources=6.1.1=pyhd8ed1ab_0 +- ipykernel=6.28.0=pyhd33586a_0 +- ipython=8.20.0=pyh707e725_0 +- ipywidgets=8.1.1=pyhd8ed1ab_0 +- isoduration=20.11.0=pyhd8ed1ab_0 +- jedi=0.19.1=pyhd8ed1ab_0 +- jinja2=3.1.3=pyhd8ed1ab_0 +- json5=0.9.14=pyhd8ed1ab_0 +- jsonpointer=2.4=py312h996f985_3 +- jsonschema=4.20.0=pyhd8ed1ab_0 +- jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 +- jsonschema-with-format-nongpl=4.20.0=pyhd8ed1ab_0 +- jupyter=1.0.0=pyhd8ed1ab_10 +- jupyter-lsp=2.2.1=pyhd8ed1ab_0 +- jupyter_client=8.6.0=pyhd8ed1ab_0 +- jupyter_console=6.6.3=pyhd8ed1ab_0 +- jupyter_core=5.7.1=py312h996f985_0 +- jupyter_events=0.9.0=pyhd8ed1ab_0 +- jupyter_server=2.12.4=pyhd8ed1ab_0 +- jupyter_server_terminals=0.5.1=pyhd8ed1ab_0 +- jupyterlab=4.0.10=pyhd8ed1ab_0 +- jupyterlab_pygments=0.3.0=pyhd8ed1ab_0 +- jupyterlab_server=2.25.2=pyhd8ed1ab_0 +- jupyterlab_widgets=3.0.9=pyhd8ed1ab_0 +- jupytext=1.16.0=pyhd8ed1ab_0 +- ld_impl_linux-aarch64=2.40=h2d8c526_0 +- libblas=3.9.0=20_linuxaarch64_openblas +- libcblas=3.9.0=20_linuxaarch64_openblas +- libexpat=2.5.0=hd600fc2_1 +- libffi=3.4.2=h3557bc0_5 +- libgcc-ng=13.2.0=hf8544c7_3 +- libgfortran-ng=13.2.0=he9431aa_3 +- libgfortran5=13.2.0=h582850c_3 +- libgomp=13.2.0=hf8544c7_3 +- liblapack=3.9.0=20_linuxaarch64_openblas +- libnsl=2.0.1=h31becfc_0 +- libopenblas=0.3.25=pthreads_h5a5ec62_0 +- libsodium=1.0.18=hb9de7d4_1 +- libsqlite=3.44.2=h194ca79_0 +- libstdcxx-ng=13.2.0=h9a76618_3 +- libuuid=2.38.1=hb4cce97_0 +- libxcrypt=4.4.36=h31becfc_1 +- libzlib=1.2.13=h31becfc_5 +- markdown-it-py=3.0.0=pyhd8ed1ab_0 +- markupsafe=2.1.3=py312h9ef2f89_1 +- matplotlib-inline=0.1.6=pyhd8ed1ab_0 +- mdit-py-plugins=0.4.0=pyhd8ed1ab_0 +- mdurl=0.1.2=pyhd8ed1ab_0 +- mistune=3.0.2=pyhd8ed1ab_0 +- mypy_extensions=1.0.0=pyha770c72_0 +- nbclient=0.8.0=pyhd8ed1ab_0 +- nbconvert=7.14.1=pyhd8ed1ab_0 +- nbconvert-core=7.14.1=pyhd8ed1ab_0 +- nbconvert-pandoc=7.14.1=pyhd8ed1ab_0 +- nbformat=5.9.2=pyhd8ed1ab_0 +- ncurses=6.4=h0425590_2 +- nest-asyncio=1.5.8=pyhd8ed1ab_0 +- notebook=7.0.6=pyhd8ed1ab_0 +- notebook-shim=0.2.3=pyhd8ed1ab_0 +- numpy=1.26.3=py312h470d778_0 +- openpyxl=3.1.2=py312hdd3e373_1 +- openssl=3.2.0=h31becfc_1 +- overrides=7.4.0=pyhd8ed1ab_0 +- packaging=23.2=pyhd8ed1ab_0 +- pandas=2.1.4=py312hc56aa73_0 +- pandoc=3.1.3=h8af1aa0_0 +- pandocfilters=1.5.0=pyhd8ed1ab_0 +- parso=0.8.3=pyhd8ed1ab_0 +- pathspec=0.12.1=pyhd8ed1ab_0 +- pexpect=4.8.0=pyh1a96a4e_2 +- pickleshare=0.7.5=py_1003 +- pip=23.3.2=pyhd8ed1ab_0 +- pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 +- platformdirs=4.1.0=pyhd8ed1ab_0 +- prometheus_client=0.19.0=pyhd8ed1ab_0 +- prompt-toolkit=3.0.42=pyha770c72_0 +- prompt_toolkit=3.0.42=hd8ed1ab_0 +- psutil=5.9.7=py312hdd3e373_0 +- ptyprocess=0.7.0=pyhd3deb0d_0 +- pure_eval=0.2.2=pyhd8ed1ab_0 +- pycparser=2.21=pyhd8ed1ab_0 +- pygments=2.17.2=pyhd8ed1ab_0 +- pysocks=1.7.1=pyha2e5f31_6 +- python=3.12.1=h43d1f9e_1_cpython +- python-dateutil=2.8.2=pyhd8ed1ab_0 +- python-fastjsonschema=2.19.1=pyhd8ed1ab_0 +- python-json-logger=2.0.7=pyhd8ed1ab_0 +- python-tzdata=2023.4=pyhd8ed1ab_0 +- python_abi=3.12=4_cp312 +- pytz=2023.3.post1=pyhd8ed1ab_0 +- pyyaml=6.0.1=py312hdd3e373_1 +- pyzmq=25.1.2=py312h1c32067_0 +- qtconsole-base=5.5.1=pyha770c72_0 +- qtpy=2.4.1=pyhd8ed1ab_0 +- readline=8.2=h8fc344f_1 +- referencing=0.32.1=pyhd8ed1ab_0 +- requests=2.31.0=pyhd8ed1ab_0 +- rfc3339-validator=0.1.4=pyhd8ed1ab_0 +- rfc3986-validator=0.1.1=pyh9f0ad1d_0 +- rich=13.7.0=pyhd8ed1ab_0 +- rpds-py=0.16.2=py312h2a5c9d6_0 +- send2trash=1.8.2=pyh41d4057_0 +- setuptools=69.0.3=pyhd8ed1ab_0 +- shellingham=1.5.4=pyhd8ed1ab_0 +- six=1.16.0=pyh6c4a22f_0 +- sniffio=1.3.0=pyhd8ed1ab_0 +- soupsieve=2.5=pyhd8ed1ab_1 +- stack_data=0.6.2=pyhd8ed1ab_0 +- tabulate=0.9.0=pyhd8ed1ab_1 +- terminado=0.18.0=pyh0d859eb_0 +- tinycss2=1.2.1=pyhd8ed1ab_0 +- tk=8.6.13=h194ca79_0 +- toml=0.10.2=pyhd8ed1ab_0 +- tomli=2.0.1=pyhd8ed1ab_0 +- tornado=6.3.3=py312h9ef2f89_1 +- traitlets=5.14.1=pyhd8ed1ab_0 +- typer=0.9.0=pyhd8ed1ab_0 +- types-python-dateutil=2.8.19.20240106=pyhd8ed1ab_0 +- typing-extensions=4.9.0=hd8ed1ab_0 +- typing_extensions=4.9.0=pyha770c72_0 +- typing_utils=0.1.0=pyhd8ed1ab_0 +- tzdata=2023d=h0c530f3_0 +- uri-template=1.3.0=pyhd8ed1ab_0 +- urllib3=2.1.0=pyhd8ed1ab_0 +- wcwidth=0.2.13=pyhd8ed1ab_0 +- webcolors=1.13=pyhd8ed1ab_0 +- webencodings=0.5.1=pyhd8ed1ab_2 +- websocket-client=1.7.0=pyhd8ed1ab_0 +- wheel=0.42.0=pyhd8ed1ab_0 +- widgetsnbextension=4.0.9=pyhd8ed1ab_0 +- xz=5.2.6=h9cdd2b7_0 +- yaml=0.2.5=hf897c2e_2 +- zeromq=4.3.5=h2f0025b_0 +- zipp=3.17.0=pyhd8ed1ab_0 + diff --git a/openai.yaml b/openai.yaml new file mode 100644 index 0000000..3ca4407 --- /dev/null +++ b/openai.yaml @@ -0,0 +1,26 @@ +# Using an environment name other than "base" is not recommended! +# Read https://github.com/mamba-org/micromamba-docker#multiple-environments +# if you must use a different environment name. +name: base +channels: + - conda-forge +dependencies: + - pip + - python>=3.9 + - typer + - requests + - httpx + - nest-asyncio + - black[jupyter] + - jupyter + - ipykernel + - jupytext + - pandas + - numpy + - openpyxl + - tabulate + - openai + # - jupyter_ai +# PyPi modules +# - pip: +# - black[jupyter] diff --git a/openai.yaml.lock b/openai.yaml.lock new file mode 100644 index 0000000..19b701a --- /dev/null +++ b/openai.yaml.lock @@ -0,0 +1,185 @@ +name: base +channels: +- conda-forge +dependencies: +- _openmp_mutex=4.5=2_gnu +- annotated-types=0.6.0=pyhd8ed1ab_0 +- anyio=4.2.0=pyhd8ed1ab_0 +- argon2-cffi=23.1.0=pyhd8ed1ab_0 +- argon2-cffi-bindings=21.2.0=py312hdd3e373_4 +- arrow=1.3.0=pyhd8ed1ab_0 +- asttokens=2.4.1=pyhd8ed1ab_0 +- async-lru=2.0.4=pyhd8ed1ab_0 +- attrs=23.2.0=pyh71513ae_0 +- babel=2.14.0=pyhd8ed1ab_0 +- beautifulsoup4=4.12.2=pyha770c72_0 +- black=23.12.1=py312h996f985_0 +- bleach=6.1.0=pyhd8ed1ab_0 +- brotli-python=1.1.0=py312h2aa54b4_1 +- bzip2=1.0.8=h31becfc_5 +- ca-certificates=2023.11.17=hcefe29a_0 +- cached-property=1.5.2=hd8ed1ab_1 +- cached_property=1.5.2=pyha770c72_1 +- certifi=2023.11.17=pyhd8ed1ab_0 +- cffi=1.16.0=py312hf3c74c0_0 +- charset-normalizer=3.3.2=pyhd8ed1ab_0 +- click=8.1.7=unix_pyh707e725_0 +- colorama=0.4.6=pyhd8ed1ab_0 +- comm=0.2.1=pyhd8ed1ab_0 +- debugpy=1.8.0=py312h2aa54b4_1 +- decorator=5.1.1=pyhd8ed1ab_0 +- defusedxml=0.7.1=pyhd8ed1ab_0 +- distro=1.9.0=pyhd8ed1ab_0 +- entrypoints=0.4=pyhd8ed1ab_0 +- et_xmlfile=1.1.0=pyhd8ed1ab_0 +- exceptiongroup=1.2.0=pyhd8ed1ab_2 +- executing=2.0.1=pyhd8ed1ab_0 +- fqdn=1.5.1=pyhd8ed1ab_0 +- h11=0.14.0=pyhd8ed1ab_0 +- h2=4.1.0=pyhd8ed1ab_0 +- hpack=4.0.0=pyh9f0ad1d_0 +- httpcore=1.0.2=pyhd8ed1ab_0 +- httpx=0.26.0=pyhd8ed1ab_0 +- hyperframe=6.0.1=pyhd8ed1ab_0 +- idna=3.6=pyhd8ed1ab_0 +- importlib-metadata=7.0.1=pyha770c72_0 +- importlib_metadata=7.0.1=hd8ed1ab_0 +- importlib_resources=6.1.1=pyhd8ed1ab_0 +- ipykernel=6.28.0=pyhd33586a_0 +- ipython=8.20.0=pyh707e725_0 +- ipywidgets=8.1.1=pyhd8ed1ab_0 +- isoduration=20.11.0=pyhd8ed1ab_0 +- jedi=0.19.1=pyhd8ed1ab_0 +- jinja2=3.1.3=pyhd8ed1ab_0 +- json5=0.9.14=pyhd8ed1ab_0 +- jsonpointer=2.4=py312h996f985_3 +- jsonschema=4.20.0=pyhd8ed1ab_0 +- jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 +- jsonschema-with-format-nongpl=4.20.0=pyhd8ed1ab_0 +- jupyter=1.0.0=pyhd8ed1ab_10 +- jupyter-lsp=2.2.1=pyhd8ed1ab_0 +- jupyter_client=8.6.0=pyhd8ed1ab_0 +- jupyter_console=6.6.3=pyhd8ed1ab_0 +- jupyter_core=5.7.1=py312h996f985_0 +- jupyter_events=0.9.0=pyhd8ed1ab_0 +- jupyter_server=2.12.4=pyhd8ed1ab_0 +- jupyter_server_terminals=0.5.1=pyhd8ed1ab_0 +- jupyterlab=4.0.10=pyhd8ed1ab_0 +- jupyterlab_pygments=0.3.0=pyhd8ed1ab_0 +- jupyterlab_server=2.25.2=pyhd8ed1ab_0 +- jupyterlab_widgets=3.0.9=pyhd8ed1ab_0 +- jupytext=1.16.0=pyhd8ed1ab_0 +- ld_impl_linux-aarch64=2.40=h2d8c526_0 +- libblas=3.9.0=20_linuxaarch64_openblas +- libcblas=3.9.0=20_linuxaarch64_openblas +- libexpat=2.5.0=hd600fc2_1 +- libffi=3.4.2=h3557bc0_5 +- libgcc-ng=13.2.0=hf8544c7_3 +- libgfortran-ng=13.2.0=he9431aa_3 +- libgfortran5=13.2.0=h582850c_3 +- libgomp=13.2.0=hf8544c7_3 +- liblapack=3.9.0=20_linuxaarch64_openblas +- libnsl=2.0.1=h31becfc_0 +- libopenblas=0.3.25=pthreads_h5a5ec62_0 +- libsodium=1.0.18=hb9de7d4_1 +- libsqlite=3.44.2=h194ca79_0 +- libstdcxx-ng=13.2.0=h9a76618_3 +- libuuid=2.38.1=hb4cce97_0 +- libxcrypt=4.4.36=h31becfc_1 +- libzlib=1.2.13=h31becfc_5 +- markdown-it-py=3.0.0=pyhd8ed1ab_0 +- markupsafe=2.1.3=py312h9ef2f89_1 +- matplotlib-inline=0.1.6=pyhd8ed1ab_0 +- mdit-py-plugins=0.4.0=pyhd8ed1ab_0 +- mdurl=0.1.2=pyhd8ed1ab_0 +- mistune=3.0.2=pyhd8ed1ab_0 +- mypy_extensions=1.0.0=pyha770c72_0 +- nbclient=0.8.0=pyhd8ed1ab_0 +- nbconvert=7.14.1=pyhd8ed1ab_0 +- nbconvert-core=7.14.1=pyhd8ed1ab_0 +- nbconvert-pandoc=7.14.1=pyhd8ed1ab_0 +- nbformat=5.9.2=pyhd8ed1ab_0 +- ncurses=6.4=h0425590_2 +- nest-asyncio=1.5.8=pyhd8ed1ab_0 +- notebook=7.0.6=pyhd8ed1ab_0 +- notebook-shim=0.2.3=pyhd8ed1ab_0 +- numpy=1.26.3=py312h470d778_0 +- openai=1.7.2=pyhd8ed1ab_0 +- openpyxl=3.1.2=py312hdd3e373_1 +- openssl=3.2.0=h31becfc_1 +- overrides=7.4.0=pyhd8ed1ab_0 +- packaging=23.2=pyhd8ed1ab_0 +- pandas=2.1.4=py312hc56aa73_0 +- pandoc=3.1.3=h8af1aa0_0 +- pandocfilters=1.5.0=pyhd8ed1ab_0 +- parso=0.8.3=pyhd8ed1ab_0 +- pathspec=0.12.1=pyhd8ed1ab_0 +- pexpect=4.8.0=pyh1a96a4e_2 +- pickleshare=0.7.5=py_1003 +- pip=23.3.2=pyhd8ed1ab_0 +- pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 +- platformdirs=4.1.0=pyhd8ed1ab_0 +- prometheus_client=0.19.0=pyhd8ed1ab_0 +- prompt-toolkit=3.0.42=pyha770c72_0 +- prompt_toolkit=3.0.42=hd8ed1ab_0 +- psutil=5.9.7=py312hdd3e373_0 +- ptyprocess=0.7.0=pyhd3deb0d_0 +- pure_eval=0.2.2=pyhd8ed1ab_0 +- pycparser=2.21=pyhd8ed1ab_0 +- pydantic=2.5.3=pyhd8ed1ab_0 +- pydantic-core=2.14.6=py312h3abe38b_1 +- pygments=2.17.2=pyhd8ed1ab_0 +- pysocks=1.7.1=pyha2e5f31_6 +- python=3.12.1=h43d1f9e_1_cpython +- python-dateutil=2.8.2=pyhd8ed1ab_0 +- python-fastjsonschema=2.19.1=pyhd8ed1ab_0 +- python-json-logger=2.0.7=pyhd8ed1ab_0 +- python-tzdata=2023.4=pyhd8ed1ab_0 +- python_abi=3.12=4_cp312 +- pytz=2023.3.post1=pyhd8ed1ab_0 +- pyyaml=6.0.1=py312hdd3e373_1 +- pyzmq=25.1.2=py312h1c32067_0 +- qtconsole-base=5.5.1=pyha770c72_0 +- qtpy=2.4.1=pyhd8ed1ab_0 +- readline=8.2=h8fc344f_1 +- referencing=0.32.1=pyhd8ed1ab_0 +- requests=2.31.0=pyhd8ed1ab_0 +- rfc3339-validator=0.1.4=pyhd8ed1ab_0 +- rfc3986-validator=0.1.1=pyh9f0ad1d_0 +- rich=13.7.0=pyhd8ed1ab_0 +- rpds-py=0.16.2=py312h2a5c9d6_0 +- send2trash=1.8.2=pyh41d4057_0 +- setuptools=69.0.3=pyhd8ed1ab_0 +- shellingham=1.5.4=pyhd8ed1ab_0 +- six=1.16.0=pyh6c4a22f_0 +- sniffio=1.3.0=pyhd8ed1ab_0 +- soupsieve=2.5=pyhd8ed1ab_1 +- stack_data=0.6.2=pyhd8ed1ab_0 +- tabulate=0.9.0=pyhd8ed1ab_1 +- terminado=0.18.0=pyh0d859eb_0 +- tinycss2=1.2.1=pyhd8ed1ab_0 +- tk=8.6.13=h194ca79_0 +- toml=0.10.2=pyhd8ed1ab_0 +- tomli=2.0.1=pyhd8ed1ab_0 +- tornado=6.3.3=py312h9ef2f89_1 +- tqdm=4.66.1=pyhd8ed1ab_0 +- traitlets=5.14.1=pyhd8ed1ab_0 +- typer=0.9.0=pyhd8ed1ab_0 +- types-python-dateutil=2.8.19.20240106=pyhd8ed1ab_0 +- typing-extensions=4.9.0=hd8ed1ab_0 +- typing_extensions=4.9.0=pyha770c72_0 +- typing_utils=0.1.0=pyhd8ed1ab_0 +- tzdata=2023d=h0c530f3_0 +- uri-template=1.3.0=pyhd8ed1ab_0 +- urllib3=2.1.0=pyhd8ed1ab_0 +- wcwidth=0.2.13=pyhd8ed1ab_0 +- webcolors=1.13=pyhd8ed1ab_0 +- webencodings=0.5.1=pyhd8ed1ab_2 +- websocket-client=1.7.0=pyhd8ed1ab_0 +- wheel=0.42.0=pyhd8ed1ab_0 +- widgetsnbextension=4.0.9=pyhd8ed1ab_0 +- xz=5.2.6=h9cdd2b7_0 +- yaml=0.2.5=hf897c2e_2 +- zeromq=4.3.5=h2f0025b_0 +- zipp=3.17.0=pyhd8ed1ab_0 + diff --git a/run_notebook.sh b/run_notebook.sh new file mode 100755 index 0000000..2cfbe22 --- /dev/null +++ b/run_notebook.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# Shell script for starting Jupyter Notebook inside Docker container + +# IMAGE_NAME="test_app_dev" +USERNAME=$USER +NOTEBOOK_ID="notebook" +DIGEST="" +NETWORK="--net=bridge" +# Get absolute paths +PWD=$(pwd) +REAL_PWD=$(realpath .) +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +NOTEBOOK_DIR_MOUNT="--mount type=bind,source=$REAL_PWD,target=/usr/app/src" +# Create Jupyter security token so that we have it for opening the browser +TOKEN=$(uuidgen | tr '[:upper:]' '[:lower:]')"-"$(uuidgen | tr '[:upper:]' '[:lower:]') +COMMAND="jupyter notebook --port 8888 --ip=0.0.0.0 --no-browser --notebook-dir=/usr/app/src --IdentityProvider.token=$TOKEN --KernelSpecManager.ensure_native_kernel=False" + +usage () +{ + printf "Starts Jupyter Notebook inside a Docker container\n" + printf 'Usage: %s [OPTIONS] []\n\n' "$0" + printf 'Option(s):\n' + printf ' -i: (i)nteractive mode (start shell instead of Jupyter for debugging)\n' + printf ' --list: List available notebook images\n' + printf ' --help: Show help\n' +} + +if [[ $1 = "--help" ]]; then + usage + exit 0 +fi + +if [[ $1 = "--list" ]]; then + echo Available notebook images: + echo ------------------------- + docker images $USER/$NOTEBOOK_ID + exit 0 +fi + +while getopts ":i" opt; do + case ${opt} in + i) + echo "Interactive mode enabled, starting shell and keeping terminal open (use 'exit' to quit)" + echo Use e.g. $COMMAND + COMMAND="/bin/sh" + ;; + esac +done +# Remove processed options +shift $((OPTIND-1)) +DIGEST=$1 +IMAGE_NAME="${USER}/${NOTEBOOK_ID}${DIGEST:+:$DIGEST}" +echo INFO: Docker image = $IMAGE_NAME +# Internal Jupyter paths: +# config -> /opt/conda/etc/jupyter +# data -> /opt/conda/share/jupyter +# bin -> /opt/conda/bin/jupyter +# https://github.com/jupyter/docker-stacks/blob/main/images/base-notebook/Dockerfile +# https://docs.jupyter.org/en/latest/use/jupyter-directories. +echo "WARNING: Outbound network ENABLED (the notebook and all components can access the entire host network)" +echo "WARNING: Jupyter Notebook will have WRITE-ACCESS to $PWD [$REAL_PWD]" +read -n1 -p "Do you REALLY want to continue (Y/N)?" reply +echo "" +[ "$reply" != "Y" ] && [ "$reply" != "y" ] && echo "Aborting." && exit 1 + +# Open browser +open http://localhost:8888/?token=$TOKEN +docker run -it -p 8888:8888 \ + $NOTEBOOK_DIR_MOUNT \ + $NETWORK \ + --security-opt seccomp=${SCRIPT_DIR}/seccomp-default.json \ + --security-opt=no-new-privileges \ + --cap-drop all \ + --rm \ + $IMAGE_NAME $COMMAND + echo INFO: Shutting down Jupyter Notebook + exit 0 +fi + +# TODO: read-only file system does not seem to work for Jupyter kernels +# --read-only --tmpfs /tmp --tmpfs /home/mambauser/ \