Commit 34b58efe7ddde7d3dd1aec1b98410e6ec5c100dc

Authored by Miguel Barao
1 parent 9bace4f6
Exists in master and in 1 other branch dev

- replaced key 'stdin' by 'arg' in questions of type generator

- updated manual and demo
@@ -7,7 +7,6 @@ @@ -7,7 +7,6 @@
7 - parece que é preciso criar à mão a pasta para as respostas (ans/...) depois apercebo-me que os caminhos no teste dizem respeito à directoria donde o teste é corrido... as respostas deveriam guardadas no directório dado. 7 - parece que é preciso criar à mão a pasta para as respostas (ans/...) depois apercebo-me que os caminhos no teste dizem respeito à directoria donde o teste é corrido... as respostas deveriam guardadas no directório dado.
8 - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao. 8 - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao.
9 - testar regex na definicao das perguntas. como se faz rawstring em yaml? singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w. 9 - testar regex na definicao das perguntas. como se faz rawstring em yaml? singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w.
10 -- testar envio de parametros para stdin para perguntas tipo generator.  
11 10
12 # TODO 11 # TODO
13 12
@@ -26,6 +25,7 @@ @@ -26,6 +25,7 @@
26 25
27 # FIXED 26 # FIXED
28 27
  28 +- testar envio de parametros para stdin para perguntas tipo generator.
29 - mathjax e jquery no login 29 - mathjax e jquery no login
30 - mostrar erro quando nao consegue importar questions files 30 - mostrar erro quando nao consegue importar questions files
31 - pacotes exactos usados para instalar. 31 - pacotes exactos usados para instalar.
@@ -2,29 +2,29 @@ @@ -2,29 +2,29 @@
2 2
3 ### Requirements and instalation 3 ### Requirements and instalation
4 4
5 -Install:  
6 -  
7 -- python3.4  
8 -- cherrypy3  
9 -- mako  
10 -- yaml  
11 -- markdown 5 +Install python 3.4 and the following packages from pip:
12 6
  7 +- CherryPy (3.7.0)
  8 +- Mako (1.0.1)
  9 +- Markdown (2.6.2)
  10 +- PyYAML (3.11)
13 11
14 Before using the program you need to 12 Before using the program you need to
15 13
16 1. Create the students database 14 1. Create the students database
17 1. Create questions 15 1. Create questions
18 1. Create a test 16 1. Create a test
19 -1. Configure the server (the default may be enough) 17 +1. Configure the server (the default should be enough)
20 18
21 ### Create students database 19 ### Create students database
22 20
23 We need a sqlite3 database to store students, passwords, test results, and questions results, etc. 21 We need a sqlite3 database to store students, passwords, test results, and questions results, etc.
24 22
25 -The database can be initialized from a list of students in CSV format using the script 23 +The database can be initialized from a list of students in CSV format by running in the terminal
26 24
27 - $ ./initdb_from_csv.py list_of_students.csv 25 +```sh
  26 +./initdb_from_csv.py list_of_students.csv
  27 +```
28 28
29 This script will create a new sqlite3 database with the correct tables and insert the students with empty passwords. 29 This script will create a new sqlite3 database with the correct tables and insert the students with empty passwords.
30 It also adds a special user number 0. This is the administrator user (Professor). 30 It also adds a special user number 0. This is the administrator user (Professor).
@@ -36,24 +36,26 @@ The passwords will be defined on the first login. @@ -36,24 +36,26 @@ The passwords will be defined on the first login.
36 Questions are defined in `yaml` files and can reside anywhere in the filesystem. 36 Questions are defined in `yaml` files and can reside anywhere in the filesystem.
37 Each file contains a list of questions, where each question is a dictionary. Example 37 Each file contains a list of questions, where each question is a dictionary. Example
38 38
39 - -  
40 - ref: question-1  
41 - type: radio  
42 - text: Select the correct option  
43 - options:  
44 - - correct  
45 - - wrong  
46 -  
47 - -  
48 - ref: question-2  
49 - type: checkbox  
50 - text: Which ones are correct?  
51 - options:  
52 - - correct  
53 - - correct  
54 - - wrong  
55 - correct: [1, 1, -1]  
56 - hint: There are two correct answers! 39 +```yaml
  40 +-
  41 + ref: question-1
  42 + type: radio
  43 + text: Select the correct option
  44 + options:
  45 + - correct
  46 + - wrong
  47 +
  48 +-
  49 + ref: question-2
  50 + type: checkbox
  51 + text: Which ones are correct?
  52 + options:
  53 + - correct
  54 + - correct
  55 + - wrong
  56 + correct: [1, 1, -1]
  57 + hint: There are two correct answers!
  58 +```
57 59
58 There are several kinds of questions: 60 There are several kinds of questions:
59 61
@@ -72,84 +74,90 @@ Detailed information on each question type is described later on. @@ -72,84 +74,90 @@ Detailed information on each question type is described later on.
72 74
73 A test is a file in `yaml` format that can reside anywhere on the filesystem. It has the following structure: 75 A test is a file in `yaml` format that can reside anywhere on the filesystem. It has the following structure:
74 76
75 - ref: this-is-a-key  
76 - title: Titulo do teste  
77 - database: db/mystudents.db  
78 -  
79 - # Will save the entire test of each student in JSON format.  
80 - # If tests are to be saved, we must specify the directory.  
81 - # The directory is created if it doesn't exist already.  
82 - # The name of the JSON files will include the student number, test  
83 - # reference key, date and time.  
84 - save_answers: True  
85 - answers_dir: ans/asc1_test4  
86 -  
87 - # Some questions can contain hints, embedded videos, etc  
88 - show_hints: True  
89 -  
90 - # Each question has some number of points. Show them normalized to 0-20.  
91 - show_points: True  
92 -  
93 - # In train mode, the correction of the test is shown and the test can  
94 - # be repeated  
95 - practice_mode: True  
96 -  
97 - # Show the data structures obtained from the test and the questions  
98 - debug: False  
99 -  
100 - # Show the file and ref field of each question  
101 - show_ref: True  
102 -  
103 - # -------------------------------------------------------------------------  
104 - # This are the questions database to be imported.  
105 - files:  
106 - - questions/file1.yaml  
107 - - questions/file2.yaml  
108 - - questions/file3.yaml  
109 - # -------------------------------------------------------------------------  
110 - # This is the actual test configuration. Selection of questions and points  
111 - # It'a defined as a list of questions. Each question can be a single  
112 - # question key or a list of keys from which one is chosen at random.  
113 - # Each question has a default value of 1.0 point, but it can be overridden.  
114 - # The points defined here do not need to be normalized (it's automatic).  
115 - questions:  
116 - - ref:  
117 - - first-question-1 # randomly choose one from these 3 questions  
118 - - first-question-2  
119 - - first-question-3  
120 - points: 0.5  
121 -  
122 - - ref: second-question # one question, 1.0 point (unnormalized)  
123 -  
124 - - third-question # "ref:" not needed in simple cases 77 +```yaml
  78 +ref: this-is-a-key
  79 +title: Titulo do teste
  80 +database: db/mystudents.db
  81 +
  82 +# Will save the entire test of each student in JSON format.
  83 +# If tests are to be saved, we must specify the directory.
  84 +# The directory is created if it doesn't exist already.
  85 +# The name of the JSON files will include the student number, test
  86 +# reference key, date and time.
  87 +save_answers: True
  88 +answers_dir: ans/asc1_test4
  89 +
  90 +# Some questions can contain hints, embedded videos, etc
  91 +show_hints: True
  92 +
  93 +# Each question has some number of points. Show them normalized to 0-20.
  94 +show_points: True
  95 +
  96 +# In train mode, the correction of the test is shown and the test can
  97 +# be repeated
  98 +practice_mode: True
  99 +
  100 +# Show the data structures obtained from the test and the questions
  101 +debug: False
  102 +
  103 +# Show the file and ref field of each question
  104 +show_ref: True
  105 +
  106 +# -------------------------------------------------------------------------
  107 +# This are the questions database to be imported.
  108 +files:
  109 + - questions/file1.yaml
  110 + - questions/file2.yaml
  111 + - questions/file3.yaml
  112 +# -------------------------------------------------------------------------
  113 +# This is the actual test configuration. Selection of questions and points
  114 +# It'a defined as a list of questions. Each question can be a single
  115 +# question key or a list of keys from which one is chosen at random.
  116 +# Each question has a default value of 1.0 point, but it can be overridden.
  117 +# The points defined here do not need to be normalized (it's automatic).
  118 +questions:
  119 + - ref:
  120 + - first-question-1 # randomly choose one from these 3 questions
  121 + - first-question-2
  122 + - first-question-3
  123 + points: 0.5
  124 +
  125 + - ref: second-question # one question, 1.0 point (unnormalized)
  126 +
  127 + - third-question # "ref:" not needed in simple cases
125 128
126 This following one is wrong: 129 This following one is wrong:
127 130
128 - - wrong-question # missing "ref:" key  
129 - points: 2 131 + - wrong-question # missing "ref:" key
  132 + points: 2
  133 +```
130 134
131 Some of the options have default values if they are omitted. The defaults are the following: 135 Some of the options have default values if they are omitted. The defaults are the following:
132 136
133 - ref: filename.yaml  
134 - title: ''  
135 - save_answers: False  
136 - show_hints: False  
137 - show_points: False  
138 - practice_mode: False  
139 - show_ref: False  
140 - debug: False  
141 - points: 1.0  
142 - 137 +```yaml
  138 +ref: filename.yaml
  139 +title: ''
  140 +save_answers: False
  141 +show_hints: False
  142 +show_points: False
  143 +practice_mode: False
  144 +show_ref: False
  145 +debug: False
  146 +points: 1.0
  147 +```
143 ### Running an existing test 148 ### Running an existing test
144 149
145 A test is a file in `yaml` format. Just run `serve.py` with the test to run as argument: 150 A test is a file in `yaml` format. Just run `serve.py` with the test to run as argument:
146 151
147 - $ ./serve.py tests_dir/mytest.yaml 152 +```sh
  153 +$ ./serve.py tests_dir/mytest.yaml
  154 +```
148 155
149 Some defaults can be overriden with command line options. Example 156 Some defaults can be overriden with command line options. Example
150 157
151 - $ ./serve.py mytest.yaml --debug --show_points --show_hints --practice_mode --save_answers  
152 - 158 +```sh
  159 +$ ./serve.py mytest.yaml --debug --show_points --show_hints --practice_mode --save_answers
  160 +```
153 To terminate the test just do `^C` on the keyboard. 161 To terminate the test just do `^C` on the keyboard.
154 162
155 ## Questions 163 ## Questions
@@ -160,29 +168,31 @@ Every question should have a `ref` and a `type`. The other keys depend on the ty @@ -160,29 +168,31 @@ Every question should have a `ref` and a `type`. The other keys depend on the ty
160 168
161 Not a real question. Just text to be shown without expecting an answer. 169 Not a real question. Just text to be shown without expecting an answer.
162 170
163 - -  
164 - ref: some-key  
165 - type: information  
166 - text: Tomorrow will rain.  
167 - 171 +```yaml
  172 +-
  173 + ref: some-key
  174 + type: information
  175 + text: Tomorrow will rain.
  176 +```
168 Correcting an information will always be considered correct, but the grade will be zero because it has 0.0 points by default. 177 Correcting an information will always be considered correct, but the grade will be zero because it has 0.0 points by default.
169 178
170 ### Radio 179 ### Radio
171 180
172 Only one option is correct. 181 Only one option is correct.
173 182
174 - -  
175 - ref: some-key  
176 - type: radio  
177 - text: The horse is white. # optional (default: '')  
178 - options:  
179 - - The horse is white  
180 - - The horse is not black  
181 - - The horse is black  
182 - correct: 0 # optional (default: 0). Index is 0-based.  
183 - shuffle: True # optional (default: True)  
184 - discount: True # optional (default: True)  
185 - 183 +```yaml
  184 +-
  185 + ref: some-key
  186 + type: radio
  187 + text: The horse is white. # optional (default: '')
  188 + options:
  189 + - The horse is white
  190 + - The horse is not black
  191 + - The horse is black
  192 + correct: 0 # optional (default: 0). Index is 0-based.
  193 + shuffle: True # optional (default: True)
  194 + discount: True # optional (default: True)
  195 +```
186 The `correct` value can also be defined as a list of degrees of correctness between 0 (wrong) and 1 (correct), e.g. if answering "the horse is not black" should be considered half-right, then we should use `correct: [1, 0.5, 0]`. 196 The `correct` value can also be defined as a list of degrees of correctness between 0 (wrong) and 1 (correct), e.g. if answering "the horse is not black" should be considered half-right, then we should use `correct: [1, 0.5, 0]`.
187 197
188 Wrong answers discount by default. If there are half-right answers, the discount values are calculated automatically. `discount: False` disables the discount calculation and the values are the ones defined in `correct`. 198 Wrong answers discount by default. If there are half-right answers, the discount values are calculated automatically. `discount: False` disables the discount calculation and the values are the ones defined in `correct`.
@@ -191,20 +201,22 @@ Wrong answers discount by default. If there are half-right answers, the discount @@ -191,20 +201,22 @@ Wrong answers discount by default. If there are half-right answers, the discount
191 201
192 There can be several options correct. Each option is like answering an independent question. 202 There can be several options correct. Each option is like answering an independent question.
193 203
194 - -  
195 - ref: some-key  
196 - type: checkbox  
197 - text: The horse is white. # optional (default: '')  
198 - options:  
199 - - The horse is white  
200 - - The horse is not black  
201 - - The horse is black  
202 - correct: [1,1,-1] # optional (default: [0,0,0]).  
203 - shuffle: True # optional (default: True)  
204 - discount: True # optional (default: True)  
205 - 204 +```yaml
  205 +-
  206 + ref: some-key
  207 + type: checkbox
  208 + text: The horse is white. # optional (default: '')
  209 + options:
  210 + - The horse is white
  211 + - The horse is not black
  212 + - The horse is black
  213 + correct: [1,1,-1] # optional (default: [0,0,0]).
  214 + shuffle: True # optional (default: True)
  215 + discount: True # optional (default: True)
  216 +```
206 Wrong answers discount by default. The discount values are calculated automatically and are simply the symmetric of the correct value. 217 Wrong answers discount by default. The discount values are calculated automatically and are simply the symmetric of the correct value.
207 E.g. consider `correct: [1, 0.5, -1]`, then 218 E.g. consider `correct: [1, 0.5, -1]`, then
  219 +
208 - if the first option is marked the value is 1, otherwise if it's unmarked the value is -1. 220 - if the first option is marked the value is 1, otherwise if it's unmarked the value is -1.
209 - if the second option is marked the value is 0.5, otherwise if it's unmarked the value is -0.5. 221 - if the second option is marked the value is 0.5, otherwise if it's unmarked the value is -0.5.
210 - if the third option is marked the value is -1, otherwise if it's unmarked the value is 1. (the student shouldn't have marked this one) 222 - if the third option is marked the value is -1, otherwise if it's unmarked the value is 1. (the student shouldn't have marked this one)
@@ -216,26 +228,29 @@ E.g. consider `correct: [1, 0.5, -1]`, then @@ -216,26 +228,29 @@ E.g. consider `correct: [1, 0.5, -1]`, then
216 The answer is a line of text. 228 The answer is a line of text.
217 The server will check if the answer exactly matches the correct one. 229 The server will check if the answer exactly matches the correct one.
218 230
219 - -  
220 - ref: some-key  
221 - type: text  
222 - text: What's your favorite color? # optional (default: '')  
223 - correct: white  
224 - 231 +```yaml
  232 +-
  233 + ref: some-key
  234 + type: text
  235 + text: What's your favorite color? # optional (default: '')
  236 + correct: white
  237 +```
225 alternatively, we can give a list of acceptable answers 238 alternatively, we can give a list of acceptable answers
226 -  
227 - correct: ['white', 'blue', 'red']  
228 - 239 +```yaml
  240 + correct: ['white', 'blue', 'red']
  241 +```
229 ### Regular expression 242 ### Regular expression
230 243
231 The answer is a line of text. 244 The answer is a line of text.
232 The server will check if the answer matches a regular expression. 245 The server will check if the answer matches a regular expression.
233 246
234 - -  
235 - ref: some-key  
236 - type: text_regex  
237 - text: What's your favorite color? # optional (default: '')  
238 - correct: '[Ww]hite' 247 +```yaml
  248 +-
  249 + ref: some-key
  250 + type: text_regex
  251 + text: What's your favorite color? # optional (default: '')
  252 + correct: '[Ww]hite'
  253 +```
239 254
240 Careful: yaml does not support raw text. Some characters have to be escaped. 255 Careful: yaml does not support raw text. Some characters have to be escaped.
241 256
@@ -245,23 +260,27 @@ The answer is given in a textarea. The text (usually code) is sent to an externa @@ -245,23 +260,27 @@ The answer is given in a textarea. The text (usually code) is sent to an externa
245 The external program should accept input from stdin, and print to stdout a single number in the interval 0.0 to 1.0 indicating the level of correctness. 260 The external program should accept input from stdin, and print to stdout a single number in the interval 0.0 to 1.0 indicating the level of correctness.
246 The server will try to convert the printed message to a float, a failure will give 0.0. 261 The server will try to convert the printed message to a float, a failure will give 0.0.
247 262
248 - -  
249 - ref: some-key  
250 - type: textarea  
251 - text: write an expression to add x and y. # optional (default: '')  
252 - correct: path/to/myscript 263 +```yaml
  264 +-
  265 + ref: some-key
  266 + type: textarea
  267 + text: write an expression to add x and y. # optional (default: '')
  268 + correct: path/to/myscript
  269 +```
253 270
254 An example of a script in python that validades an answer is 271 An example of a script in python that validades an answer is
255 272
256 - #!/usr/bin/env python3.4 273 +```python
  274 +#!/usr/bin/env python3.4
257 275
258 - import sys  
259 - s = sys.stdin.read()  
260 - if s == 'Alibaba':  
261 - print(1.0)  
262 - else:  
263 - print(0.0)  
264 - exit(0) 276 +import sys
  277 +s = sys.stdin.read()
  278 +if s == 'Alibaba':
  279 + print(1.0)
  280 +else:
  281 + print(0.0)
  282 +exit(0)
  283 +```
265 284
266 but any script language or executable program can be used for this purpose. 285 but any script language or executable program can be used for this purpose.
267 286
@@ -270,25 +289,38 @@ but any script language or executable program can be used for this purpose. @@ -270,25 +289,38 @@ but any script language or executable program can be used for this purpose.
270 289
271 A generator question will run an external program that is expected to print a question in yaml format to stdout. After running the generator, the question can be any of the other types (but not another generator!). 290 A generator question will run an external program that is expected to print a question in yaml format to stdout. After running the generator, the question can be any of the other types (but not another generator!).
272 291
273 - -  
274 - ref: some-key  
275 - type: generator  
276 - script: path/to/generator_script 292 +```yaml
  293 +-
  294 + ref: some-key
  295 + type: generator
  296 + script: path/to/generator_script
  297 + # arg: "optional string passed on to stdin of the script"
  298 +```
277 299
278 An example of a question generator is the following 300 An example of a question generator is the following
279 301
280 - #!/usr/bin/env python3.4  
281 - from random import randint  
282 -  
283 - x = randint(10,20)  
284 - y = randint(10,20)  
285 - s = '''  
286 - ref: addition  
287 - type: text  
288 - text: How much is {0} plus {1}?  
289 - correct: {2}  
290 - '''.format(x, y, x + y)  
291 - print(s) 302 +```python
  303 +#!/usr/bin/env python3.4
  304 +from random import randint
  305 +import sys
  306 +
  307 +# read arguments from stdin and convert to integers
  308 +arg = sys.stdin.read()
  309 +a,b = (int(n) for n in arg.split(','))
  310 +
  311 +# generate question
  312 +x = randint(a, b)
  313 +y = randint(a, b)
  314 +s = '''
  315 +ref: addition
  316 +type: text
  317 +text: How much is {0} plus {1}?
  318 +correct: {2}
  319 +'''.format(x, y, x + y)
  320 +
  321 +# send question to stdout
  322 +print(s)
  323 +```
292 324
293 ## Writing good looking questions 325 ## Writing good looking questions
294 326
@@ -296,13 +328,16 @@ The text of the questions (and options in radio and checkbox type questios) is p @@ -296,13 +328,16 @@ The text of the questions (and options in radio and checkbox type questios) is p
296 328
297 A good way to define multiple lines of text in the questions is to use the bar |. Yaml will use all the text that is indented to the right of that column. Example 329 A good way to define multiple lines of text in the questions is to use the bar |. Yaml will use all the text that is indented to the right of that column. Example
298 330
299 - text: |  
300 - Text is parsed as __markdown__. We can include equations $\sqrt{\pi}$ like in LaTeX  
301 - and pretty code in several languages 331 +```yaml
  332 + text: |
  333 + Text is parsed as __markdown__. We can include equations $\sqrt{\pi}$ like in LaTeX
  334 + and pretty code in several languages
  335 +
  336 + ```.C
  337 + int main(){
  338 + return 0;
  339 + }
  340 + ```
  341 + # this line stops the text because it is not indented
  342 +```
302 343
303 - ```.C  
304 - int main(){  
305 - return 0;  
306 - }  
307 - ```  
308 - # this line does stops the text because it is not indented  
demo/generate-question.py
1 #!/usr/bin/env python3.4 1 #!/usr/bin/env python3.4
2 2
3 from random import randint 3 from random import randint
  4 +import sys
4 5
  6 +arg = sys.stdin.read() # read arguments
  7 +
  8 +a,b = (int(n) for n in arg.split(','))
5 9
6 q = ''' 10 q = '''
7 type: checkbox 11 type: checkbox
8 -text: Indique quais das seguintes adições resultam em overflow quando se considera a adição de números com sinal (complemento para 2) em registos de 8 bits. 12 +text: |
  13 + Indique quais das seguintes adições resultam em overflow quando se considera a adição de números com sinal (complemento para 2) em registos de 8 bits.
  14 +
  15 + Os números foram gerados aleatoriamente no intervalo de {0} a {1}.
9 options: 16 options:
10 -''' 17 +'''.format(a,b)
11 18
12 correct = [] 19 correct = []
13 for i in range(5): 20 for i in range(5):
14 - x = randint(11,120)  
15 - y = randint(11,120) 21 + x = randint(a, b)
  22 + y = randint(a, b)
16 q += '- "`{} + {}`"\n'.format(x, y) 23 q += '- "`{} + {}`"\n'.format(x, y)
17 correct.append(1 if x + y > 127 else -1) 24 correct.append(1 if x + y > 127 else -1)
18 25
demo/questions.yaml
@@ -51,6 +51,7 @@ @@ -51,6 +51,7 @@
51 ref: question-whatever 51 ref: question-whatever
52 type: generator 52 type: generator
53 script: demo/generate-question.py 53 script: demo/generate-question.py
  54 + arg: "11,120"
54 # the script should print a question in yaml format like the ones above. 55 # the script should print a question in yaml format like the ones above.
55 # Print only the dictionary, not the list (hiffen). 56 # Print only the dictionary, not the list (hiffen).
56 # --------------------------------------------------------------------------- 57 # ---------------------------------------------------------------------------
@@ -114,7 +114,7 @@ def question_generator(q): @@ -114,7 +114,7 @@ def question_generator(q):
114 '''Run an external script that will generate a question in yaml format. 114 '''Run an external script that will generate a question in yaml format.
115 This function will return the yaml converted back to a dict.''' 115 This function will return the yaml converted back to a dict.'''
116 116
117 - q['stdin'] = q.get('stdin', '') 117 + q['arg'] = q.get('arg', '') # send this string to stdin
118 118
119 try: 119 try:
120 p = subprocess.Popen([q['script']], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) 120 p = subprocess.Popen([q['script']], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
@@ -122,7 +122,7 @@ def question_generator(q): @@ -122,7 +122,7 @@ def question_generator(q):
122 print(' * Script "{0}" defined in question "{1}" of file "{2}" could not be found'.format(q['script'], q['ref'], q['filename'])) 122 print(' * Script "{0}" defined in question "{1}" of file "{2}" could not be found'.format(q['script'], q['ref'], q['filename']))
123 123
124 try: 124 try:
125 - qyaml = p.communicate(input=q['stdin'].encode('utf-8'), timeout=5)[0].decode('utf-8') 125 + qyaml = p.communicate(input=q['arg'].encode('utf-8'), timeout=5)[0].decode('utf-8')
126 except subprocess.TimeoutExpired: 126 except subprocess.TimeoutExpired:
127 p.kill() 127 p.kill()
128 128