Skip to content
This repository was archived by the owner on Nov 30, 2023. It is now read-only.

Commit f7b92c8

Browse files
Fix installation of common Python packages (#1424)
* Fix package installation * Update comment * Move python to front of PATH * Add PYTHON parameter * Move ML packages to new script * Remove invalid docs * Check for PYTHON * Install packages from argument * Resolve comments * Add tests for new packages * Copy JupyterLab script * Use generic package install script * Add new script to README * Add missing $ * Try to fix smoke test * Revert changes to jupyterlab-debian.sh * Fix directory of Python * Remove busted sudos * Update test.sh Co-authored-by: Josh Spicer <[email protected]>
1 parent ab35cd6 commit f7b92c8

File tree

6 files changed

+179
-5
lines changed

6 files changed

+179
-5
lines changed

containers/codespaces-linux/.devcontainer/base.Dockerfile

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ ENV SHELL=/bin/bash \
3434
JUPYTERLAB_PATH="${HOMEDIR}/.local/bin" \
3535
DOCKER_BUILDKIT=1
3636

37-
ENV PATH="${NVM_DIR}/current/bin:${NPM_GLOBAL}/bin:${ORIGINAL_PATH}:${DOTNET_ROOT}:${DOTNET_ROOT}/tools:${SDKMAN_DIR}/bin:${SDKMAN_DIR}/candidates/gradle/current/bin:${SDKMAN_DIR}/candidates/java/current/bin:/opt/maven/lts:${GOROOT}/bin:${GOPATH}/bin:${PIPX_BIN_DIR}:/opt/conda/condabin:${JAVA_ROOT}/current/bin:${NODE_ROOT}/current/bin:${PHP_ROOT}/current/bin:${PYTHON_ROOT}/current/bin:${RUBY_ROOT}/current/bin:${MAVEN_ROOT}/current/bin:${HUGO_ROOT}/current/bin:${JUPYTERLAB_PATH}:${ORYX_PATHS}"
37+
ENV PATH="${NVM_DIR}/current/bin:${NPM_GLOBAL}/bin:${PYTHON_ROOT}/current/bin:${ORIGINAL_PATH}:${DOTNET_ROOT}:${DOTNET_ROOT}/tools:${SDKMAN_DIR}/bin:${SDKMAN_DIR}/candidates/gradle/current/bin:${SDKMAN_DIR}/candidates/java/current/bin:/opt/maven/lts:${GOROOT}/bin:${GOPATH}/bin:${PIPX_BIN_DIR}:/opt/conda/condabin:${JAVA_ROOT}/current/bin:${NODE_ROOT}/current/bin:${PHP_ROOT}/current/bin:${RUBY_ROOT}/current/bin:${MAVEN_ROOT}/current/bin:${HUGO_ROOT}/current/bin:${JUPYTERLAB_PATH}:${ORYX_PATHS}"
3838

3939
# Install needed utilities and setup non-root user. Use a separate RUN statement to add your own dependencies.
4040
COPY library-scripts/* setup-user.sh first-run-notice.txt /tmp/scripts/
@@ -68,10 +68,21 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
6868
&& mkdir -p /usr/local/etc/vscode-dev-containers/ \
6969
&& mv -f /tmp/scripts/first-run-notice.txt /usr/local/etc/vscode-dev-containers/
7070

71-
# Install Python, PHP, Ruby utilities, and JupyterLab
71+
# Install Python, JupyterLab, common machine learning packages, and Ruby utilities
7272
RUN bash /tmp/scripts/python-debian.sh "none" "/opt/python/latest" "${PIPX_HOME}" "${USERNAME}" "true" \
73-
&& bash /tmp/scripts/jupyterlab-debian.sh \
74-
&& pip install --user numpy pandas scipy matplotlib seaborn scikit-learn tensorflow keras torch requests \
73+
# Install JupyterLab and common machine learning packages
74+
&& PYTHON_BINARY="${PYTHON_ROOT}/current/bin/python" \
75+
&& bash /tmp/scripts/python-package-debian.sh "jupyterlab" "latest" $PYTHON_BINARY \
76+
&& bash /tmp/scripts/python-package-debian.sh "numpy" "latest" $PYTHON_BINARY \
77+
&& bash /tmp/scripts/python-package-debian.sh "pandas" "latest" $PYTHON_BINARY \
78+
&& bash /tmp/scripts/python-package-debian.sh "scipy" "latest" $PYTHON_BINARY \
79+
&& bash /tmp/scripts/python-package-debian.sh "matplotlib" "latest" $PYTHON_BINARY \
80+
&& bash /tmp/scripts/python-package-debian.sh "seaborn" "latest" $PYTHON_BINARY \
81+
&& bash /tmp/scripts/python-package-debian.sh "scikit-learn" "latest" $PYTHON_BINARY \
82+
&& bash /tmp/scripts/python-package-debian.sh "tensorflow" "latest" $PYTHON_BINARY \
83+
&& bash /tmp/scripts/python-package-debian.sh "keras" "latest" $PYTHON_BINARY \
84+
&& bash /tmp/scripts/python-package-debian.sh "torch" "latest" $PYTHON_BINARY \
85+
&& bash /tmp/scripts/python-package-debian.sh "requests" "latest" $PYTHON_BINARY \
7586
# Install rvm, rbenv, any missing base gems
7687
&& chown -R ${USERNAME} /opt/ruby/* \
7788
&& bash /tmp/scripts/ruby-debian.sh "none" "${USERNAME}" "true" "true" \
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
#-------------------------------------------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
5+
#-------------------------------------------------------------------------------------------------------------
6+
#
7+
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/python-package-debian.md
8+
# Maintainer: The VS Code and Codespaces Teams
9+
#
10+
# Syntax: ./python-package-debian.sh
11+
12+
set -e
13+
14+
PACKAGE=${1:-""}
15+
VERSION=${2:-"latest"}
16+
PYTHON=${3:-"python"}
17+
USERNAME=${4-"automatic"}
18+
19+
# If in automatic mode, determine if a user already exists, if not use vscode
20+
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
21+
USERNAME=""
22+
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
23+
for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
24+
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
25+
USERNAME=${CURRENT_USER}
26+
break
27+
fi
28+
done
29+
if [ "${USERNAME}" = "" ]; then
30+
USERNAME=vscode
31+
fi
32+
elif [ "${USERNAME}" = "none" ]; then
33+
USERNAME=root
34+
USER_UID=0
35+
USER_GID=0
36+
fi
37+
38+
# Use sudo to run as non-root user is not already running
39+
sudoUserIf()
40+
{
41+
if [ "$(id -u)" -eq 0 ] && [ "${USERNAME}" != "root" ]; then
42+
sudo -u ${USERNAME} "$@"
43+
else
44+
"$@"
45+
fi
46+
}
47+
48+
# Make sure that Python is installed correctly
49+
if ! ${PYTHON} --version > /dev/null ; then
50+
echo "Python command not found: ${PYTHON}"
51+
exit 1
52+
fi
53+
54+
# pip skips installation when a requirement is already satisfied
55+
if [ ${VERSION} = "latest" ]; then
56+
sudoUserIf ${PYTHON} -m pip install ${PACKAGE} --no-cache-dir
57+
else
58+
sudoUserIf ${PYTHON} -m pip install ${PACKAGE}==${VERSION} --no-cache-dir
59+
fi

containers/codespaces-linux/test-project/test.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ check "dotnet-6-installed-by-oryx" dotnet --info | grep "/opt/dotnet/6\.0\.[0-9]
2020

2121
# Check Python
2222
check "python" python --version
23-
check "pip" pip3 --version
23+
check "python3" python3 --version
24+
check "pip" pip --version
25+
check "pip3" pip3 --version
2426
check "pipx" pipx --version
2527
check "pylint" pylint --version
2628
check "flake8" flake8 --version
@@ -31,6 +33,18 @@ check "pydocstyle" pydocstyle --version
3133
check "bandit" bandit --version
3234
check "virtualenv" virtualenv --version
3335

36+
# # Check Python packages
37+
# check "numpy" python -c 'import numpy'
38+
# check "pandas" python -c 'import pandas'
39+
# check "scipy" python -c 'import scipy'
40+
# check "matplotlib" python -c 'import matplotlib'
41+
# check "seaborn" python -c 'import seaborn'
42+
# check "scikit-learn" python -c 'import sklearn'
43+
# check "tensorflow" python -c 'import tensorflow'
44+
# check "keras" python -c 'import keras'
45+
# check "torch" python -c 'import torch'
46+
# check "requests" python -c 'import requests'
47+
3448
# Check JupyterLab
3549
check "jupyter-lab" jupyter-lab --version
3650

script-library/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Some scripts have special installation instructions (like `desktop-lite-debian.s
3535
| [Node.js Install Script](docs/node.md) | `node-debian.sh` | VS Code and GitHub Codespaces teams|
3636
| [PowerShell Install Script](docs/powershell.md) | `powershell-debian.sh` | VS Code and GitHub Codespaces teams|
3737
| [Python Install Script](docs/python.md) | `python-debian.sh` | VS Code and GitHub Codespaces teams|
38+
| [Python Package Install Script](docs/python-package.md) | `python-package-debian.sh` | VS Code and GitHub Codespaces teams|
3839
| [Ruby Install Script](docs/ruby.md) | `ruby-debian.sh` | VS Code and GitHub Codespaces teams|
3940
| [Rust (rustlang) Install Script](docs/rust.md) | `rust-debian.sh` | VS Code and GitHub Codespaces teams|
4041
| [SSH Server Install Script](docs/sshd.md) | `sshd-debian.sh` | VS Code and GitHub Codespaces teams|
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Python Package Install Script
2+
3+
*Installs a Python package.*
4+
5+
**Script status**: Stable
6+
7+
**OS support**: Debian 9+, Ubuntu 18.04+, and downstream distros.
8+
9+
**Maintainer**: GitHub Codespaces team
10+
11+
## Syntax
12+
13+
```text
14+
./python-package-debian.sh PACKAGE [VERSION] [PYTHON_BINARY] [USERNAME]
15+
```
16+
17+
## Usage
18+
19+
### Script use
20+
21+
1. Add [`python-package-debian.sh`](../python-package-debian.sh) to `.devcontainer/library-scripts`
22+
23+
2. Add the following to your `.devcontainer/Dockerfile`:
24+
25+
```Dockerfile
26+
COPY library-scripts/python-package-debian.sh /tmp/library-scripts/
27+
RUN bash /tmp/library-scripts/python-package-debian.sh PACKAGE
28+
```
29+
30+
That's it!
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
#-------------------------------------------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
5+
#-------------------------------------------------------------------------------------------------------------
6+
#
7+
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/python-package-debian.md
8+
# Maintainer: The VS Code and Codespaces Teams
9+
#
10+
# Syntax: ./python-package-debian.sh
11+
12+
set -e
13+
14+
PACKAGE=${1:-""}
15+
VERSION=${2:-"latest"}
16+
PYTHON=${3:-"python"}
17+
USERNAME=${4-"automatic"}
18+
19+
# If in automatic mode, determine if a user already exists, if not use vscode
20+
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
21+
USERNAME=""
22+
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
23+
for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
24+
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
25+
USERNAME=${CURRENT_USER}
26+
break
27+
fi
28+
done
29+
if [ "${USERNAME}" = "" ]; then
30+
USERNAME=vscode
31+
fi
32+
elif [ "${USERNAME}" = "none" ]; then
33+
USERNAME=root
34+
USER_UID=0
35+
USER_GID=0
36+
fi
37+
38+
# Use sudo to run as non-root user is not already running
39+
sudoUserIf()
40+
{
41+
if [ "$(id -u)" -eq 0 ] && [ "${USERNAME}" != "root" ]; then
42+
sudo -u ${USERNAME} "$@"
43+
else
44+
"$@"
45+
fi
46+
}
47+
48+
# Make sure that Python is installed correctly
49+
if ! ${PYTHON} --version > /dev/null ; then
50+
echo "Python command not found: ${PYTHON}"
51+
exit 1
52+
fi
53+
54+
# pip skips installation when a requirement is already satisfied
55+
if [ ${VERSION} = "latest" ]; then
56+
sudoUserIf ${PYTHON} -m pip install ${PACKAGE} --no-cache-dir
57+
else
58+
sudoUserIf ${PYTHON} -m pip install ${PACKAGE}==${VERSION} --no-cache-dir
59+
fi

0 commit comments

Comments
 (0)