diff --git a/.github/workflows/python-check-requirements.yml b/.github/workflows/python-check-requirements.yml new file mode 100644 index 000000000..c7929a20c --- /dev/null +++ b/.github/workflows/python-check-requirements.yml @@ -0,0 +1,31 @@ +name: Python check requirements.txt + +on: + push: + paths: + - 'check-requirements.sh' + - 'convert*.py' + - 'requirements*.txt' + pull_request: + paths: + - 'check-requirements.sh' + - 'convert*.py' + - 'requirements*.txt' + +jobs: + python-check-requirements: + runs-on: ubuntu-latest + name: check-requirements + steps: + - name: Install shellcheck + run: | + sudo apt-get update + sudo apt-get install shellcheck + - name: Check out source repository + uses: actions/checkout@v3 + - name: Set up Python environment + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Run check-requirements.sh script + run: bash check-requirements.sh diff --git a/check-requirements.sh b/check-requirements.sh new file mode 100755 index 000000000..881b8f190 --- /dev/null +++ b/check-requirements.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# +# check-requirements.sh checks all requirements files for each top-level +# convert*.py script. +# +# WARNING: This is quite IO intensive, because a fresh venv is set up for every +# python script. +# +# requires: +# * bash >= 3.2.57 +# * shellcheck +# +# For each script, it creates a fresh venv, `pip install -r` the +# requirements, and finally executes the python script with no arguments to +# check for a `ModuleNotFoundError`. +# + +log() { + local level="$1"; shift + local format="$1"; shift + # shellcheck disable=SC2059 + >&2 printf "$level: $format\n" "$@" +} + +info() { + log 'INFO' "$@" +} + +fatal() { + log 'FATAL' "$@" + exit 1 +} + +cleanup() { + if [[ -n ${workdir+x} && -d $workdir && -w $workdir ]]; then + info "Removing $workdir" + ( + count=0 + rm -rfv "$workdir" | while read -r; do + if (( count++ > 750 )); then + printf '.' + count=0 + fi + done + printf '\n' + )& + wait $! + info "Removed '$workdir'" + fi +} + +abort() { + cleanup + exit 1 +} + +trap abort SIGINT SIGTERM SIGQUIT SIGABRT +trap cleanup EXIT + +set -eu -o pipefail +this="$(realpath "$0")" +readonly this +cd "$(dirname "$this")" + +shellcheck "$this" + +workdir= +if [[ -n ${1+x} ]]; then + arg_dir="$(realpath "$1")" + if [[ ! ( -d $arg_dir && -w $arg_dir ) ]]; then + fatal "$arg_dir is not a valid directory" + fi + workdir="$(mktemp -d "$arg_dir/check-requirements.XXXX")" +else + workdir="$(mktemp -d "/tmp/check-requirements.XXXX")" +fi +readonly workdir + +info "Working directory: $workdir" + +assert_arg_count() { + local argcount="$1"; shift + if (( $# != argcount )); then + fatal "${FUNCNAME[1]}: incorrect number of args" + fi +} + +check_requirements() { + assert_arg_count 2 "$@" + local venv="$1" + local reqs="$2" + + info "$reqs: beginning check" + ( + # shellcheck source=/dev/null + source "$venv/bin/activate" + pip --disable-pip-version-check install -q -r "$reqs" + ) + info "$reqs: OK" +} + +check_convert_script() { + assert_arg_count 1 "$@" + local py="$1" + local pyname="${py%.py}" + + info "$py: beginning check" + + local reqs="requirements-$pyname.txt" + local venv="$workdir/$pyname-venv" + python3 -m venv "$venv" + + check_requirements "$venv" "$reqs" + set +e + ( + # shellcheck source=/dev/null + source "$venv/bin/activate" + py_err="$workdir/$pyname.out" + python "$py" 2> "$py_err" + >&2 cat "$py_err" + grep -e 'ModuleNotFoundError' "$py_err" + ) + set -e + # shellcheck disable=SC2181 + (( $? )) && fatal "$py: some imports not declared in $reqs" + info "$py: imports OK" +} + +# Check requirements.txt +all_venv="$workdir/all-venv" +python3 -m venv "$all_venv" +check_requirements "$all_venv" 'requirements.txt' + +check_convert_script 'convert.py' +for py in convert-*.py; do + check_convert_script "$py" +done + +info "Done! No issues found." diff --git a/convert-lora-to-ggml_requirements.txt b/convert-lora-to-ggml_requirements.txt deleted file mode 100644 index f9481c128..000000000 --- a/convert-lora-to-ggml_requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ --r convert_requirements.txt -torch==2.1.1 diff --git a/convert-persimmon-to-gguf_requirements.txt b/convert-persimmon-to-gguf_requirements.txt deleted file mode 100644 index f9481c128..000000000 --- a/convert-persimmon-to-gguf_requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ --r convert_requirements.txt -torch==2.1.1 diff --git a/convert-hf-to-gguf_requirements.txt b/requirements-convert-hf-to-gguf.txt similarity index 54% rename from convert-hf-to-gguf_requirements.txt rename to requirements-convert-hf-to-gguf.txt index d295025c9..4d00b1966 100644 --- a/convert-hf-to-gguf_requirements.txt +++ b/requirements-convert-hf-to-gguf.txt @@ -1,3 +1,3 @@ --r convert_requirements.txt +-r requirements-convert.txt torch==2.1.1 transformers==4.35.2 diff --git a/requirements-convert-llama-ggml-to-gguf.txt b/requirements-convert-llama-ggml-to-gguf.txt new file mode 100644 index 000000000..8a5377762 --- /dev/null +++ b/requirements-convert-llama-ggml-to-gguf.txt @@ -0,0 +1 @@ +-r requirements-convert.txt diff --git a/requirements-convert-lora-to-ggml.txt b/requirements-convert-lora-to-ggml.txt new file mode 100644 index 000000000..30827c896 --- /dev/null +++ b/requirements-convert-lora-to-ggml.txt @@ -0,0 +1,2 @@ +-r requirements-convert.txt +torch==2.1.1 diff --git a/requirements-convert-persimmon-to-gguf.txt b/requirements-convert-persimmon-to-gguf.txt new file mode 100644 index 000000000..30827c896 --- /dev/null +++ b/requirements-convert-persimmon-to-gguf.txt @@ -0,0 +1,2 @@ +-r requirements-convert.txt +torch==2.1.1 diff --git a/convert_requirements.txt b/requirements-convert.txt similarity index 100% rename from convert_requirements.txt rename to requirements-convert.txt diff --git a/requirements.txt b/requirements.txt index c946b5e4c..da4f3f9a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,8 +4,8 @@ # Package versions must stay compatible across all top-level python scripts. # --r convert_requirements.txt +-r requirements-convert.txt --r convert-hf-to-gguf_requirements.txt --r convert-lora-to-ggml_requirements.txt --r convert-persimmon-to-gguf_requirements.txt +-r requirements-convert-hf-to-gguf.txt +-r requirements-convert-lora-to-ggml.txt +-r requirements-convert-persimmon-to-gguf.txt