11#! /bin/bash
22
3- # Copyright 2020 MONAI Consortium
3+ # Copyright (c) MONAI Consortium
44# Licensed under the Apache License, Version 2.0 (the "License");
55# you may not use this file except in compliance with the License.
66# You may obtain a copy of the License at
@@ -100,13 +100,16 @@ then
100100fi
101101
102102doChecks=true
103+ doCopyright=false
103104doRun=true
104105autofix=false
105106failfast=false
106107pattern=" "
107108
108109kernelspec=" python3"
109110
111+ PY_EXE=${MONAI_PY_EXE:- $(which python)}
112+
110113function print_usage {
111114 echo " runner.sh [--no-run] [--no-checks] [--autofix] [-f/--failfast] [-p/--pattern <find pattern>] [-h/--help]"
112115 echo " [-v/--version]"
@@ -118,18 +121,19 @@ function print_usage {
118121 echo " --no-run : don't run notebooks"
119122 echo " --no-checks : don't run code checks"
120123 echo " --autofix : autofix where possible"
124+ echo " --copyright : check whether every source code and notebook has a copyright header"
121125 echo " -f, --failfast : stop on first error"
122126 echo " -p, --pattern : pattern of files to be run (added to \` find . -type f -name *.ipynb -and ! -wholename *.ipynb_checkpoints*\` )"
123127 echo " -h, --help : show this help message and exit"
124- echo " -t, --test : shortcut to run a single notebook using pattern ` -and -wholename` "
128+ echo " -t, --test : shortcut to run a single notebook using pattern ` -and -wholename` "
125129 echo " -v, --version : show MONAI and system version information and exit"
126130 echo " "
127131 echo " Examples:"
128132 echo " ./runner.sh # run full tests (${green} recommended before making pull requests${noColor} )."
129133 echo " ./runner.sh --no-run # don't run the notebooks."
130134 echo " ./runner.sh --no-checks # don't run code checks."
131- echo " ./runner.sh -t 2d_classification/mednist_tutorial.ipynb"
132- echo " # test if notebook mednist_tutorial.ipynb runs properly in test."
135+ echo " ./runner.sh -t 2d_classification/mednist_tutorial.ipynb"
136+ echo " # test if notebook mednist_tutorial.ipynb runs properly in test."
133137 echo " ./runner.sh --pattern \" -and \( -name '*read*' -or -name '*load*' \) -and ! -wholename '*acceleration*'\" "
134138 echo " # check filenames containing \" read\" or \" load\" , but not if the"
135139 echo " whole path contains \" deepgrow\" ."
@@ -138,6 +142,7 @@ function print_usage {
138142 echo " ${separator} For bug reports, questions, and discussions, please file an issue at:"
139143 echo " https://github.com/Project-MONAI/MONAI/issues/new/choose"
140144 echo " "
145+ echo " To choose an alternative python executable, set the environmental variable, \" MONAI_PY_EXE\" ."
141146}
142147
143148function print_style_fail_msg() {
162167 --autofix)
163168 autofix=true
164169 ;;
170+ --copyright)
171+ doCopyright=true
172+ ;;
165173 -f|--failfast)
166174 failfast=true
167175 ;;
178186 print_usage
179187 exit 0
180188 ;;
181- -t|--test)
182- pattern+=" -and -wholename ./$2 "
183- echo $pattern
184- shift
185- ;;
189+ -t|--test)
190+ pattern+=" -and -wholename ./$2 "
191+ echo $pattern
192+ shift
193+ ;;
186194 -v|--version)
187195 print_version
188196 exit 1
@@ -229,6 +237,58 @@ if [ $doChecks = true ]; then
229237 fi
230238fi
231239
240+ function verify_notebook_has_key_in_cell() {
241+ fname=$1
242+ key=$2
243+ cell=$3
244+ celltype=$4
245+ ${PY_EXE} - << END
246+ import nbformat
247+ import re
248+
249+ with open("$fname ", "r") as f:
250+ contents = nbformat.reads(f.read(), as_version=4)
251+ cell = contents.cells[int("$cell ")]
252+ result = "true" if cell.cell_type == "$celltype " and re.search("$key ", cell.source) else "false"
253+ print(result)
254+ END
255+ }
256+
257+ if [ $doCopyright = true ]
258+ then
259+ check_installed nbformat
260+ # check copyright headers
261+ copyright_bad=0
262+ copyright_all=0
263+ license=" http://www.apache.org/licenses/LICENSE-2.0"
264+ while read -r fname; do
265+ copyright_all=$(( copyright_all + 1 ))
266+ if ! grep " $license " " $fname " > /dev/null; then
267+ print_error_msg " Missing the license header in file: $fname "
268+ copyright_bad=$(( copyright_bad + 1 ))
269+ fi
270+ done <<< " $(find " $( pwd) " -type f \
271+ -and -name " * .py" -or -name " * .sh" -or -name " * .cpp" -or -name " * .cu" -or -name " * .h" )"
272+
273+ while read -r fname; do
274+ copyright_all=$(( copyright_all + 1 ))
275+ if [[ $( verify_notebook_has_key_in_cell " $fname " " $license " 0 " markdown" ) != true ]]; then
276+ print_error_msg " Missing the license header the first markdown cell of file: $fname "
277+ copyright_bad=$(( copyright_bad + 1 ))
278+ fi
279+ done <<< " $(find " $( pwd) " -type f -name " * .ipynb" -and ! -wholename " * .ipynb_checkpoints* " )"
280+
281+ if [[ ${copyright_bad} -eq 0 ]];
282+ then
283+ echo " ${green} Source code copyright headers checked ($copyright_all ).${noColor} "
284+ else
285+ echo " Please add the licensing header to the file ($copyright_bad of $copyright_all files)."
286+ echo " See also: https://github.com/Project-MONAI/tutorials/blob/main/CONTRIBUTING.md#add-license"
287+ echo " "
288+ exit 1
289+ fi
290+ fi
291+
232292
233293base_path=" $( cd " $( dirname " $0 " ) " > /dev/null 2>&1 ; pwd -P ) "
234294cd " ${base_path} "
@@ -246,14 +306,13 @@ function replace_text {
246306 [ ! -z " $after " ] && echo After: && echo " $after "
247307}
248308
249- # Get notebooks (pattern is "-and -name '*' -and ! -wholename '*federated_learning*'"
250- # unless user specifies otherwise)
309+ # Get notebooks (pattern is an empty string unless the user specifies otherwise)
251310files=($( echo $pattern | xargs find . -type f -name " *.ipynb" -and ! -wholename " *.ipynb_checkpoints*" ) )
252311if [[ $files == " " ]]; then
253312 print_error_msg " No files match pattern"
254313 exit 0
255314fi
256- echo " Files to be tested:"
315+ echo " Notebook files to be tested:"
257316for i in " ${files[@]} " ; do echo $i ; done
258317
259318# Keep track of number of passed tests. Use a trap to print results on exit
0 commit comments