Skip to content

Commit c9a6de8

Browse files
committed
Add check-requirements.sh script and GitHub workflow
1 parent b853df4 commit c9a6de8

10 files changed

+180
-9
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Python check requirements.txt
2+
3+
on:
4+
push:
5+
paths:
6+
- 'check-requirements.sh'
7+
- 'convert*.py'
8+
- 'requirements*.txt'
9+
pull_request:
10+
paths:
11+
- 'check-requirements.sh'
12+
- 'convert*.py'
13+
- 'requirements*.txt'
14+
15+
jobs:
16+
python-check-requirements:
17+
runs-on: ubuntu-latest
18+
name: check-requirements
19+
steps:
20+
- name: Install shellcheck
21+
run: |
22+
sudo apt-get update
23+
sudo apt-get install shellcheck
24+
- name: Check out source repository
25+
uses: actions/checkout@v3
26+
- name: Set up Python environment
27+
uses: actions/setup-python@v4
28+
with:
29+
python-version: "3.11"
30+
- name: Run check-requirements.sh script
31+
run: bash check-requirements.sh

check-requirements.sh

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/bin/bash
2+
#
3+
# check-requirements.sh checks all requirements files for each top-level
4+
# convert*.py script.
5+
#
6+
# WARNING: This is quite IO intensive, because a fresh venv is set up for every
7+
# python script.
8+
#
9+
# requires:
10+
# * bash >= 3.2.57
11+
# * shellcheck
12+
#
13+
# For each script, it creates a fresh venv, `pip install -r` the
14+
# requirements, and finally executes the python script with no arguments to
15+
# check for a `ModuleNotFoundError`.
16+
#
17+
18+
log() {
19+
local level="$1"; shift
20+
local format="$1"; shift
21+
# shellcheck disable=SC2059
22+
>&2 printf "$level: $format\n" "$@"
23+
}
24+
25+
info() {
26+
log 'INFO' "$@"
27+
}
28+
29+
fatal() {
30+
log 'FATAL' "$@"
31+
exit 1
32+
}
33+
34+
cleanup() {
35+
if [[ -n ${workdir+x} && -d $workdir && -w $workdir ]]; then
36+
info "Removing $workdir"
37+
(
38+
count=0
39+
rm -rfv "$workdir" | while read -r; do
40+
if (( count++ > 750 )); then
41+
printf '.'
42+
count=0
43+
fi
44+
done
45+
printf '\n'
46+
)&
47+
wait $!
48+
info "Removed '$workdir'"
49+
fi
50+
}
51+
52+
abort() {
53+
cleanup
54+
exit 1
55+
}
56+
57+
trap abort SIGINT SIGTERM SIGQUIT SIGABRT
58+
trap cleanup EXIT
59+
60+
set -eu -o pipefail
61+
this="$(realpath "$0")"
62+
readonly this
63+
cd "$(dirname "$this")"
64+
65+
shellcheck "$this"
66+
67+
workdir=
68+
if [[ -n ${1+x} ]]; then
69+
arg_dir="$(realpath "$1")"
70+
if [[ ! ( -d $arg_dir && -w $arg_dir ) ]]; then
71+
fatal "$arg_dir is not a valid directory"
72+
fi
73+
workdir="$(mktemp -d "$arg_dir/check-requirements.XXXX")"
74+
else
75+
workdir="$(mktemp -d "/tmp/check-requirements.XXXX")"
76+
fi
77+
readonly workdir
78+
79+
info "Working directory: $workdir"
80+
81+
assert_arg_count() {
82+
local argcount="$1"; shift
83+
if (( $# != argcount )); then
84+
fatal "${FUNCNAME[1]}: incorrect number of args"
85+
fi
86+
}
87+
88+
check_requirements() {
89+
assert_arg_count 2 "$@"
90+
local venv="$1"
91+
local reqs="$2"
92+
93+
info "$reqs: beginning check"
94+
(
95+
# shellcheck source=/dev/null
96+
source "$venv/bin/activate"
97+
pip --disable-pip-version-check install -q -r "$reqs"
98+
)
99+
info "$reqs: OK"
100+
}
101+
102+
check_convert_script() {
103+
assert_arg_count 1 "$@"
104+
local py="$1"
105+
local pyname="${py%.py}"
106+
107+
info "$py: beginning check"
108+
109+
local reqs="requirements-$pyname.txt"
110+
local venv="$workdir/$pyname-venv"
111+
python3 -m venv "$venv"
112+
113+
check_requirements "$venv" "$reqs"
114+
set +e
115+
(
116+
# shellcheck source=/dev/null
117+
source "$venv/bin/activate"
118+
py_err="$workdir/$pyname.out"
119+
python "$py" 2> "$py_err"
120+
>&2 cat "$py_err"
121+
grep -e 'ModuleNotFoundError' "$py_err"
122+
)
123+
set -e
124+
# shellcheck disable=SC2181
125+
(( $? )) && fatal "$py: some imports not declared in $reqs"
126+
info "$py: imports OK"
127+
}
128+
129+
# Check requirements.txt
130+
all_venv="$workdir/all-venv"
131+
python3 -m venv "$all_venv"
132+
check_requirements "$all_venv" 'requirements.txt'
133+
134+
check_convert_script 'convert.py'
135+
for py in convert-*.py; do
136+
check_convert_script "$py"
137+
done
138+
139+
info "Done! No issues found."

convert-lora-to-ggml_requirements.txt

Lines changed: 0 additions & 2 deletions
This file was deleted.

convert-persimmon-to-gguf_requirements.txt

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
-r convert_requirements.txt
1+
-r requirements-convert.txt
22
torch==2.1.1
33
transformers==4.35.2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-r requirements-convert.txt

requirements-convert-lora-to-ggml.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-r requirements-convert.txt
2+
torch==2.1.1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-r requirements-convert.txt
2+
torch==2.1.1
File renamed without changes.

requirements.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# Package versions must stay compatible across all top-level python scripts.
55
#
66

7-
-r convert_requirements.txt
7+
-r requirements-convert.txt
88

9-
-r convert-hf-to-gguf_requirements.txt
10-
-r convert-lora-to-ggml_requirements.txt
11-
-r convert-persimmon-to-gguf_requirements.txt
9+
-r requirements-convert-hf-to-gguf.txt
10+
-r requirements-convert-lora-to-ggml.txt
11+
-r requirements-convert-persimmon-to-gguf.txt

0 commit comments

Comments
 (0)