commit eb9fdec0ab146463603cb39201317bc64eca04df Author: Filip Gralinski Date: Fri Dec 7 21:09:51 2018 +0100 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd4b986 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +Task*Test.xml +*~ +pylint.log diff --git a/blend.sh b/blend.sh new file mode 100755 index 0000000..17ebda6 --- /dev/null +++ b/blend.sh @@ -0,0 +1,29 @@ +#!/bin/zsh + +. ./vars + +cd .. + +STUDENT_DIR=`ls -d ${PREFIX}-s*` + +echo "USING $STUDENT_DIR" + +rm -rf arena +mkdir arena + +cp -R $STUDENT_DIR/* arena/ +ln -s ../$STUDENT_DIR/.git arena/.git + +mkdir -p arena/regexp +#mkdir -p arena/automata + +rm -rf arena/odp arena/$PREFIX + +rm arena/run.sh arena/vars +find arena -regex '.*/Task.*Test\.\(py\|dat\..*\)' -exec rm '{}' ';' + +cp "${PREFIX}/run.sh" arena/run.sh +cp "${PREFIX}/vars" arena/vars +cp "${PREFIX}/overrides.txt" arena/overrides.txt + +find ${PREFIX} -regex '.*/Task.*Test\.\(py\|dat\..*\)' -print | while read T; do cp $T ${T/${PREFIX}/arena}; done diff --git a/intro/Task101.py b/intro/Task101.py new file mode 100644 index 0000000..03ab4ca --- /dev/null +++ b/intro/Task101.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- + +"""Rozwiązanie zadania 101.""" + +def even_elements(inlist): + """Zwraca elementy listy o indeksach parzystych.""" + return [inlist[i] for i in range(len(inlist)) if i % 2 == 0] + +if __name__ == '__main__': + print even_elements([1, 2, 3, 4]) diff --git a/intro/Task101Test.py b/intro/Task101Test.py new file mode 100755 index 0000000..5188444 --- /dev/null +++ b/intro/Task101Test.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 101 + +Napisz funkcję `even_elements` zwracającą listę, która zawiera tylko +elementy z `list` o parzystych indeksach. (Zadanie kontrolne z gotowym +rozwiązaniem!) + +NAME: even_elements +PARAMS: list +RETURN: list +POINTS: 1 +""" + +import unittest +from Task101 import even_elements + +class Task101Test(unittest.TestCase): + """Testy do zadania 101""" + + def test_sequence(self): + """Prosty test.""" + self.assertEqual(even_elements([1, 2, 3, 4, 5, 6]), [1, 3, 5]) + + def test_empty(self): + """Test na pustej liście.""" + self.assertEqual(even_elements([]), []) + + def test_singleton(self): + """Test na liście jednoelementowej.""" + self.assertEqual(even_elements([41]), [41]) + + def test_two_elements(self): + """Test na liście dwuelementowej.""" + self.assertEqual(even_elements([100, 2]), [100]) + + def test_negatives(self): + """Test na liście z ujemnym elementem.""" + self.assertEqual(even_elements([-31, 0, 2]), [-31, 2]) + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task102Test.py b/intro/Task102Test.py new file mode 100755 index 0000000..d493dce --- /dev/null +++ b/intro/Task102Test.py @@ -0,0 +1,30 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 102 + +Napisz funkcję `add_three_numbers` zwracającą sumę trzech liczb całkowitych. + +NAME: add_three_numbers +PARAMS: int, int, int +RETURN: int +POINTS: 3 +""" + +import unittest +from Task102 import add_three_numbers + +class Task102Test(unittest.TestCase): + """Testy do zadania 102""" + + def test_simple(self): + """Prosty test.""" + self.assertEqual(add_three_numbers(2, 5, 7), 14) + + def test_negatives(self): + """Test z liczbami ujemnymi.""" + self.assertEqual(add_three_numbers(-3, -1, 2), -2) + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task103Test.py b/intro/Task103Test.py new file mode 100755 index 0000000..faeabb2 --- /dev/null +++ b/intro/Task103Test.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 103 + +Napisz funkcję `probability` sprawdzającej, czy zadana liczba +reprezentuje prawdopodobieństwo (liczbę z zakresu od 0.0 do 1.0). +Jeśli tak, powinna zostać zwrócona ta liczba, w przeciwnym razie - +liczba 0. + +NAME: probability +PARAMS: double +RETURN: double +POINTS: 2 + +""" + +import unittest +from Task103 import probability + +class Task103Test(unittest.TestCase): + """Testy do zadania 103""" + + def test_simple(self): + """Prosty test.""" + self.assertAlmostEqual(probability(0.62), 0.62) + + def test_negatives(self): + """Test z liczbami ujemnymi.""" + self.assertAlmostEqual(probability(-0.6), 0.0) + self.assertAlmostEqual(probability(-1337), 0.0) + + def test_special_cases(self): + """Test z wartościami specjalnymi.""" + self.assertEqual(probability(0.0), 0.0) + self.assertEqual(probability(1.0), 1.0) + + def test_out_of_range(self): + """Za duże wartości.""" + self.assertEqual(probability(1.001), 0.0) + self.assertEqual(probability(972.12), 0.0) + + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task104Test.py b/intro/Task104Test.py new file mode 100755 index 0000000..2e68f5d --- /dev/null +++ b/intro/Task104Test.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 104 + +Napisz funkcję `sum_from_one_to_n` zwracającą sume kwadratów liczb od 1 do `n`. +Jeśli podany argument jest mniejszy od 1 powinna być zwracana wartość 0. + +NAME: sum_from_one_to_n +PARAMS: int +RETURN: int +POINTS: 3 +""" + +import unittest +from Task104 import sum_from_one_to_n + +class Task104Test(unittest.TestCase): + """Testy do zadania 104""" + + def test_special_cases(self): + """Testy przypadków szczególnych.""" + self.assertEqual(sum_from_one_to_n(-100), 0) + self.assertEqual(sum_from_one_to_n(-1), 0) + self.assertEqual(sum_from_one_to_n(0), 0) + self.assertEqual(sum_from_one_to_n(1), 1) + self.assertEqual(sum_from_one_to_n(2), 5) + + def test_regular(self): + """Testy dla kilku liczb""" + self.assertEqual(sum_from_one_to_n(3), 14) + self.assertEqual(sum_from_one_to_n(4), 30) + + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task105Test.py b/intro/Task105Test.py new file mode 100755 index 0000000..8e45481 --- /dev/null +++ b/intro/Task105Test.py @@ -0,0 +1,50 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 105 + +Napisz funkcję `is_almost_prime(number, limit)` sprawdzającą, czy +podana liczba nie dzieli się przez żadną liczbę z zakresu od 2 do +`limit`. Dla liczb ujemnych powinna zostać zwrócona wartość `True`. + +NAME: is_almost_prime +PARAMS: int, int +RETURN: bool +POINTS: 3 +""" + +import unittest +from Task105 import is_almost_prime + +class Task105Test(unittest.TestCase): + """Testy do zadania 105""" + + def test_simple(self): + """Proste testy""" + self.assertTrue(is_almost_prime(35, 4)) + self.assertFalse(is_almost_prime(35, 5)) + self.assertFalse(is_almost_prime(35, 100)) + self.assertTrue(is_almost_prime(17, 4)) + self.assertTrue(is_almost_prime(17, 16)) + self.assertFalse(is_almost_prime(17, 17)) + self.assertFalse(is_almost_prime(17, 100)) + self.assertFalse(is_almost_prime(16, 2)) + self.assertFalse(is_almost_prime(16, 5)) + self.assertFalse(is_almost_prime(16, 13)) + self.assertFalse(is_almost_prime(16, 101)) + + def test_special_cases(self): + """Testy przypadków szczególnych.""" + self.assertTrue(is_almost_prime(-1, 10)) + self.assertFalse(is_almost_prime(0, 8)) + self.assertTrue(is_almost_prime(1, 6)) + self.assertFalse(is_almost_prime(2, 2)) + + def test_negatives(self): + """Testy dla liczb ujemnych.""" + self.assertTrue(is_almost_prime(-5, 100)) + self.assertTrue(is_almost_prime(-13, 5)) + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task106Test.py b/intro/Task106Test.py new file mode 100755 index 0000000..2faa5ef --- /dev/null +++ b/intro/Task106Test.py @@ -0,0 +1,43 @@ +#!/usr/bin/python2 +# -*- coding: utf-8 -*- + +""" +Zadanie 106 + +Napisz funkcję freq_dic(sequence), która zlicza liczbę wystąpień +elementów dla dowolnego typu sekwencyjnego. Funkcja powinna zwracać +słownik, w którym klucze odpowiadają elementom, a wartości liczbie +elementów. Dla łańcucha "abracadabra" wynikiem jest: + +{"a":5, "b":2, "c":1, "d":1, "r":2} + +NAME: freq_dic +PARAMS: sequence +RETURN: dictionary +POINTS: 4 +""" + +import unittest +from Task106 import freq_dic + +class Task106Test(unittest.TestCase): + """Testy do zadania 106""" + + def test_string(self): + """Test na napisie.""" + self.assertEqual(freq_dic("abracadabra"), {"a": 5, "b": 2, "c": 1, "d": 1, "r": 2}) + + def test_number_list(self): + """Test na liście liczb.""" + self.assertEqual(freq_dic([1, 1, 2, 1, 10, 20, 2]), {1: 3, 2: 2, 10: 1, 20: 1}) + + def test_tuple(self): + """Test na krotce.""" + self.assertEqual(freq_dic((1, 2, 3, 1)), {1: 2, 2: 1, 3: 1}) + + def test_empty(self): + """Test na pustej liście.""" + self.assertEqual(freq_dic([]), { }) + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task107Test.py b/intro/Task107Test.py new file mode 100755 index 0000000..54ebecd --- /dev/null +++ b/intro/Task107Test.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 107 + +Napisz funkcję `list_squared(list)` zwracającą sumę kwadratów +zadanych liczb. Dla listy pustej powinna zostać zwrócona wartość zero. + +NAME: list_squared +PARAMS: list +RETURN: obj +POINTS: 3 +""" + +import unittest +from Task107 import list_squared + +class Task107Test(unittest.TestCase): + """Testy do zadania 107""" + + def test_simple(self): + """Prosty test.""" + self.assertEqual(list_squared([3, 0, -1, 2]), 14), + + def test_empty(self): + """Test na pustej liście.""" + self.assertEqual(list_squared([]), 0), + + def test_singleton(self): + """Test na liście jednoelementowej.""" + self.assertEqual(list_squared([-4]), 16) + + def test_two_elements(self): + """Test na liście dwuelementowej.""" + self.assertEqual(list_squared([100, -100]), 20000) + self.assertEqual(list_squared([2, 10]), 104) + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task108Test.py b/intro/Task108Test.py new file mode 100755 index 0000000..e6ef667 --- /dev/null +++ b/intro/Task108Test.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 108 + +Napisz funkcję `leet_speak`, która podmienia w podanym napisie +niektóre litery na podobnie wyglądające cyfry: 'e' na '3', 'l' na '1', +'o' na '0', 't' na '7'. Np. `leet('leet')` powinno zwrócić '1337'. + +NAME: leet_speak +PARAMS: string +RETURN: string +POINTS: 2 +""" + +import unittest +from Task108 import leet_speak + +class Task108Test(unittest.TestCase): + """Testy do zadania 108.""" + + def test_special_cases(self): + """Przypadki szczególne.""" + self.assertEqual(leet_speak(''), '') + self.assertEqual(leet_speak('x'), 'x') + self.assertEqual(leet_speak('o'), '0') + self.assertEqual(leet_speak('banan'), 'banan') + self.assertEqual(leet_speak('1337'), '1337') + self.assertEqual(leet_speak('admin1'), 'admin1') + + def test_standard_cases(self): + """Standardowe przypadki.""" + self.assertEqual(leet_speak('leet'), '1337') + self.assertEqual(leet_speak('mouse'), 'm0us3') + self.assertEqual(leet_speak('do not want'), 'd0 n07 wan7') + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task109Test.dat.txt b/intro/Task109Test.dat.txt new file mode 100644 index 0000000..89fe8a4 --- /dev/null +++ b/intro/Task109Test.dat.txt @@ -0,0 +1,8 @@ +raz +dwa +YES +cztery +YES +YES +YES +tego YES nie liczyć diff --git a/intro/Task109Test.py b/intro/Task109Test.py new file mode 100755 index 0000000..2481628 --- /dev/null +++ b/intro/Task109Test.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 109 + +Napisz funkcję `count_yes_lines(filename)`, która po podaniu nazwy pliku +tekstowego `filename` zwraca liczbę wierszy w pliku zawierających +(wyłącznie) napis "YES" (i znak końca wiersza). + +NAME: count_yes_lines +PARAMS: string +RETURN: int +POINTS: 3 +""" +import unittest +from Task109 import count_yes_lines + +class Task109Test(unittest.TestCase): + """Testy do zadania 109.""" + + def test_on_self(self): + """Testy na samym sobie.""" + self.failUnlessEqual(count_yes_lines("Task109Test.py"), 0) + + def test_simple(self): + """Testy na prostym pliku.""" + self.failUnlessEqual(count_yes_lines("Task109Test.dat.txt"), 4) + +if __name__ == '__main__': + unittest.main() diff --git a/intro/Task110Test.dat.in.txt b/intro/Task110Test.dat.in.txt new file mode 100644 index 0000000..ce0360c --- /dev/null +++ b/intro/Task110Test.dat.in.txt @@ -0,0 +1,6 @@ +this is a string +Ala ma kota +blablabla + +nic +pies, czyli kot diff --git a/intro/Task110Test.dat.out.txt b/intro/Task110Test.dat.out.txt new file mode 100644 index 0000000..b872e0c --- /dev/null +++ b/intro/Task110Test.dat.out.txt @@ -0,0 +1,6 @@ +4 2 1 6 +3 2 4 +9 + +3 +5 5 3 diff --git a/intro/Task110Test.py b/intro/Task110Test.py new file mode 100755 index 0000000..9f6d34d --- /dev/null +++ b/intro/Task110Test.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Zadanie 110 + +Napisz funkcję `words_to_length(infile, outfile)`, która wczytując +wiersze z pliku `infile` i wypisując je do pliku `outfile`, zamienia +wyrazy na liczbę odpowiadającą długości wyrazu. Np. wiersz `this is a +string` zostanie zamieniony na `4 2 1 6`. Zakładamy, że wyrazy +oddzielone są spacjami (np. dla `pies, czyli kot` powinno wyjść `5 5 +3`). + +NAME: word_to_length +PARAMS: file, file +RETURN: string +POINTS: 5 +""" + +import unittest +from Task110 import word_to_length + +class Task110Test(unittest.TestCase): + """Testy do zadania 110""" + + def test(self): + """Prosty test przez porównanie z oczekiwanym wyjściem.""" + infile = open("Task110Test.dat.in.txt", 'r') + + out1 = open("Task110Test.out.txt", 'w') + word_to_length(infile, out1) + infile.close() + out1.close() + + out1 = open("Task110Test.out.txt", 'r') + out2 = open("Task110Test.dat.out.txt", 'r') + + for line1 in out1: + line2 = out2.readline() + self.assertEqual( line1, line2 ) + + out1.close() + out2.close() + +if __name__ == '__main__': + unittest.main() diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..f3d86e4 --- /dev/null +++ b/run.sh @@ -0,0 +1,273 @@ +#!/bin/zsh + +. ./vars + +PREFIX="$1" +OPTION="$2" +TASKS_DONE=0 +POINTS_AWARDED=0 + +LOGFILE=`pwd`/log.all.txt +echo '' > "$LOGFILE" + +typeset -A POINTS_PER_CLASSES + +if [[ -e /usr/bin/pylint2 ]] +then +PYLINT_EXEC=pylint2 +else +PYLINT_EXEC=pylint +fi + +run_pylint() +{ + T=$1 + DIR=$2 + UNWANTED=$3 + + #pylint --disable=R0904,"$UNWANTED" $T ${T/%Test.py/.py} -f parseable | perl -pne "s{^Task}{${PREFIX}${DIR}/Task}" >> $PYLINT_LOG + $PYLINT_EXEC --disable=R0904,C0111,"$UNWANTED" ${T/%Test.py/.py} -f parseable | perl -pne "s{^Task}{${PREFIX}${DIR}/Task}" >> $PYLINT_LOG + PYLINT_EXIT_CODE=${pipestatus[1]} +} + +run_pylint_single_file() +{ + T=$1 + DIR=$2 + UNWANTED=$3 + + $PYLINT_EXEC --disable=R0904,C0111,"$UNWANTED" $T -f parseable | perl -pne "s{^}{${PREFIX}${DIR}/}" >> $PYLINT_LOG + PYLINT_EXIT_CODE=${pipestatus[1]} +} + +process_test() +{ + SOLUTION=${1/%Test.py/.py} + if [[ -r $SOLUTION ]] + then + echo "RUNNING $1" + + JUST_NUMBER=${1/%Test.py/} + JUST_NUMBER=${JUST_NUMBER/#Task/} + + TASK_KEY="${STUDENT_NUMBER}_${JUST_NUMBER}" + + WAS_OVERRIDDEN=no + + if [[ $OVERRIDDEN_POINTS[$TASK_KEY] != "" ]] + then + echo "from overridden.txt: $OVERRIDDEN_POINTS[$TASK_KEY]" + SUCCESS=yes + WAS_OVERRIDDEN=yes + MSS="READ FROM FILE overridden.txt " + else + XML_FILE=${1/%.py/.xml} + nosetests2 --with-xunit --xunit-file="$XML_FILE" $1 + TESTS_OK=$? + + run_pylint $1 $2 + PYLINT_OK=$PYLINT_EXIT_CODE + + SUCCESS=yes + + if [[ "$TESTS_OK" == "0" ]] + then + MSS="TESTS OK" + else + MSS="TESTS FAILED" + SUCCESS=no + fi + + if [[ "$PYLINT_OK" == "0" ]] + then + MSS="$MSS PYLINT OK" + else + MSS="$MSS PYLINT FAILED" +# SUCCESS=no + fi + + if [[ "$JUST_NUMBER" -gt 205 && "$JUST_NUMBER" -le 219 ]] + then + if [[ `expr $JUST_NUMBER % 15` != `expr $STUDENT_NUMBER % 15` ]] + then + MSS="$MSS ZLA RESZTA Z DZIELENIA!" + SUCCESS=no + fi + fi + + if [[ "$JUST_NUMBER" -gt 305 && "$JUST_NUMBER" -le 329 ]] + then + if [[ `expr $JUST_NUMBER % 25` != `expr $STUDENT_NUMBER % 25` ]] + then + MSS="$MSS ZLA RESZTA Z DZIELENIA!" + SUCCESS=no + fi + fi + + fi + + CLASSES=$SOLUTION[-6] + echo "task belongs to classes $CLASSES" + CLASSES_TIME_LIMIT=$TIME_LIMITS[$CLASSES] + echo "classes time limit is $CLASSES_TIME_LIMIT" + HOME_TIME_LIMIT=$HOME_TIME_LIMITS[$CLASSES] + echo "home time limit is $HOME_TIME_LIMIT" + HOME_POINT_LIMIT=$HOME_POINT_LIMITS[$CLASSES] + echo "home point limit is $HOME_POINT_LIMIT" + + LAST_COMMIT_DATE=`git log -1 --format=%cd --date=iso $SOLUTION` + echo "last commit to solution is $LAST_COMMIT_DATE" + + AT_HOME="no" + TASK_POINTS_FOR_HOME=0 + + if [[ "$WAS_OVERRIDDEN" == "no" && "$CLASSES_TIME_LIMIT" < "$LAST_COMMIT_DATE" ]] + then + if [[ "$HOME_TIME_LIMIT" < "$LAST_COMMIT_DATE" ]] + then + MSS="$MSS TOO LATE" + SUCCESS="no" + echo "solved too late!" + else + MSS="$MSS DONE AT HOME" + + if [[ "$SUCCESS" == "yes" ]] + then + TASK_POINTS_FOR_HOME=1 + + if [[ "$JUST_NUMBER" -gt 205 && "$JUST_NUMBER" -le 219 ]] + then + TASK_POINTS_FOR_HOME=6 + fi + + if [[ "$JUST_NUMBER" -gt 305 && "$JUST_NUMBER" -le 329 ]] + then + TASK_POINTS_FOR_HOME=4 + fi + + HPPC=$HOME_POINTS_PER_CLASSES[$CLASSES] + HPPC=`expr $HPPC + $TASK_POINTS_FOR_HOME` + + HOME_POINT_LIMIT=$HOME_POINT_LIMITS[$CLASSES] + + if [[ $HPPC -gt $HOME_POINT_LIMIT ]] + then + TASK_POINTS_FOR_HOME=`expr $HOME_POINT_LIMIT - $HOME_POINTS_PER_CLASSES[$CLASSES]` + HPPC=$HOME_POINT_LIMIT + MSS="$MSS HOME LIMIT EXCEEDED, AWARDING: $TASK_POINTS_FOR_HOME points" + fi + + MSS="$MSS HOME POINTS: $TASK_POINTS_FOR_HOME" + + HPOINTS_PER_CLASSES[$CLASSES]=$HPPC + fi + + AT_HOME="yes" + echo "solved at home!" + fi + fi + + if [[ "$SUCCESS" == "yes" ]] + then + TASKS_DONE=`expr $TASKS_DONE + 1` + TASK_POINTS=`cat $1 | perl -ne 'print "\$1\n" if /^POINTS:\s*(\d+)/'` + + if [[ "$AT_HOME" == "yes" ]] + then + TASK_POINTS=$TASK_POINTS_FOR_HOME + fi + + if [[ $OVERRIDDEN_POINTS[$TASK_KEY] != "" ]] + then + TASK_POINTS=$OVERRIDDEN_POINTS[$TASK_KEY] + fi + + MSS="$MSS POINTS: $TASK_POINTS" + + PPC=$POINTS_PER_CLASSES[$CLASSES] + PPC=`expr $PPC + $TASK_POINTS` + + POINT_LIMIT=$DEFAULT_POINT_LIMIT + + if [[ $POINT_LIMITS[$CLASSES] != "" ]] + then + POINT_LIMIT=$POINT_LIMITS[$CLASSES] + fi + + if [[ $PPC -gt $POINT_LIMIT ]] + then + TASK_POINTS=`expr $POINT_LIMIT - $POINTS_PER_CLASSES[$CLASSES]` + PPC=$POINT_LIMIT + MSS="$MSS LIMIT EXCEEDED, AWARDING: $TASK_POINTS points" + fi + + echo "$MSS $TASK_POINTS" >> "$LOGFILE" + + POINTS_PER_CLASSES[$CLASSES]=$PPC + + POINTS_AWARDED=`expr $POINTS_AWARDED + $TASK_POINTS` + fi + + SUMMARY="${SUMMARY}\n$1 $MSS" + + else + if [[ "$OPTION" == "fullcheck" ]] + then + # TODO fix duplication problem + run_pylint $1 $2 "F0401,E0602,F0001" + fi + echo "SKIPPING $1" + SUMMARY="${SUMMARY}\n$1 NO SOLUTION" + fi +} + +process_directory() +{ + echo "==============================" + echo "GOING INTO $1" + + pushd $1 + + for T in Task*Test.py + do + process_test $T $1 + done + + popd +} + +read_overrides() +{ + perl -pne 's/\s*\#.*//' < overrides.txt | while read INDEX_NUMBER TASK_CODE POINTS; + do + TASK_KEY="${INDEX_NUMBER}_${TASK_CODE}" + OVERRIDDEN_POINTS[$TASK_KEY]=$POINTS + done +} + +STUDENT_NUMBER=`pwd | perl -ne 'print "$1" if /${PREFIX}-s(\d+)/'` +echo "STUDENT INDEX NUMBER IS: $STUDENT_NUMBER" + +typeset -A OVERRIDDEN_POINTS +read_overrides + +PYLINT_LOG=`pwd`/pylint.log +rm -f "$PYLINT_LOG" + +for D in *(/) +do + process_directory $D +done + +echo "===============================================" +echo "SUMMARY" +echo $SUMMARY + +echo "" +echo "TASKS DONE: $TASKS_DONE" +echo "POINTS: $POINTS_AWARDED" + +echo "points" > result.csv +echo $POINTS_AWARDED >> result.csv + +perl -pne 's{^zaut-2019}{arena/}' -i pylint.log diff --git a/show-solutions.sh b/show-solutions.sh new file mode 100755 index 0000000..2ac357f --- /dev/null +++ b/show-solutions.sh @@ -0,0 +1,20 @@ +#!/bin/zsh + +PREFIX=$1 +TASK=$2 + +for REPO in $PREFIX-s* +do +INDEX=${REPO#$PREFIX-s} + +SOLUTION_FILE="${REPO}/${TASK}.py" + +if [[ -r "$SOLUTION_FILE" ]] +then +echo "========================================" +echo "======== $INDEX ========================" +cat "$SOLUTION_FILE" +echo "" +fi + +done \ No newline at end of file diff --git a/task2eduwiki.py b/task2eduwiki.py new file mode 100755 index 0000000..c46f396 --- /dev/null +++ b/task2eduwiki.py @@ -0,0 +1,116 @@ +#!/usr/bin/python2 +# -*- coding: utf-8 -*- + +import sys +import re + +def process_file(filename): + parsed_file = parse_file(filename) + wikify(parsed_file) + +def parse_file(filename): + task_file = open(filename,'r') + state = 'DOCSTRING_EXPECTED' + parsed_file = {} + parsed_file['filename'] = filename + + for line in task_file: + line = line.rstrip() + if line == '' \ + and state != 'INSIDE_DESCRIPTION' and state != 'INSIDE_TEST': + continue + + if state == 'DOCSTRING_EXPECTED': + if line == '"""': + state = 'HEADER_EXPECTED' + continue + + if state == 'HEADER_EXPECTED': + if re.match(r"Zadanie [A-Z0-9]+", line): + parsed_file['header'] = line + state = 'DESCRIPTION_EXPECTED' + else: + raise_error(state, line) + continue + + if state == 'DESCRIPTION_EXPECTED': + parsed_file['description'] = line + state = 'INSIDE_DESCRIPTION' + continue + + if state == 'INSIDE_DESCRIPTION': + if line == '': + state = 'ATTRS_EXPECTED' + else: + parsed_file['description'] += ' ' + line + continue + + if state == 'ATTRS_EXPECTED': + if line == '"""': + state = 'TEST_EXPECTED' + else: + matched = re.match(r"([A-Z]+):\s*(.*)$", line) + if matched: + parsed_file[matched.group(1).lower()] = matched.group(2) + else: + raise_error(state, line) + continue + + if state == 'TEST_EXPECTED': + if re.match(r"\s+def\s+test", line): + state = 'INSIDE_TEST' + parsed_file['test'] = line + continue + + if state == 'INSIDE_TEST': + if re.match(r"if\s+__name__", line): + state = 'DONE' + else: + parsed_file['test'] += "\n" + line + + if state != 'DONE': + raise BaseException('DONE state expected, was: %s' % state) + + check_parsed_file(parsed_file) + return parsed_file + +def check_parsed_file(parsed_file): + attrs_to_check = ('name', 'points', 'params', 'return', 'filename') + for attr in attrs_to_check: + if not attr in parsed_file: + raise BaseException('no %s attribute' % attr) + +def raise_error(state, line): + raise BaseException("unexpected line in state %s: '%s'" % (state, line)) + +def wikify(parsed_file): + print "==== %(header)s ====" % parsed_file + print "\n({{{%(filename)s}}})\n" % parsed_file + + print get_description_line(parsed_file['description']) + print_attr(parsed_file, "name", "Nazwa funkcji") + print_attr(parsed_file, "params", "Typy parametrów") + print_attr(parsed_file, "return", "Typ zwracany") + print_attr(parsed_file, "points", "Punkty") + print "" + print "Testy:{{{" + print parsed_file['test'] + print "}}}" + print "" + print "" + +def print_attr(parsed_file, attr, pl_label): + print "|| '''%s''' || `%s` ||" % (pl_label, parsed_file[attr]) + +def get_description_line(description): + formatting = "|| ''' Zadanie''' ||<80%%> %s ||" + return formatting % process_description(description) + +def process_description(description): + description = re.sub(r"((?:\d+|n)\^(?:\d+|n))", r"\1^", description) + return description + +if __name__ == '__main__': + if len(sys.argv) != 2: + raise BaseException('expected just one argument!') + process_file(sys.argv[1]) diff --git a/tasks2eduwiki.sh b/tasks2eduwiki.sh new file mode 100755 index 0000000..ccd187a --- /dev/null +++ b/tasks2eduwiki.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for X in $1/Task${2}??Test.py +do +./task2eduwiki.py $X +done diff --git a/vars b/vars new file mode 100644 index 0000000..a7e7bd0 --- /dev/null +++ b/vars @@ -0,0 +1,23 @@ +PREFIX=zaut-2019 + +DEFAULT_POINT_LIMIT=15 +POINT_LIMIT=15 + +typeset -A TIME_LIMITS +set -A TIME_LIMITS \ + "1" "2018-12-09 14:30:00 +0100" \ + "2" "2019-01-12 12:00:00 +0100" \ + "3" "2019-01-12 13:30:00 +0100" + +typeset -A HOME_TIME_LIMITS +set -A HOME_TIME_LIMITS \ + "1" "2019-01-12 12:00:00 +0100" \ + "2" "2019-02-05 23:59:59 +0100" \ + "3" "2019-02-05 23:59:00 +0100" + + +typeset -A HOME_POINT_LIMITS +set -A HOME_POINT_LIMITS \ + "1" "5" \ + "2" "0" \ + "3" "0"