Commit 9b8820e43d7c164f7cef3372224d6b9d6975ecef
1 parent
a7d6b9e1
Exists in
dev
move run_script to questions.py
it was only used there.
Showing
2 changed files
with
86 additions
and
44 deletions
Show diff stats
aprendizations/questions.py
@@ -11,11 +11,11 @@ import logging | @@ -11,11 +11,11 @@ import logging | ||
11 | from os import path | 11 | from os import path |
12 | import random | 12 | import random |
13 | import re | 13 | import re |
14 | -from typing import Any, Dict, NewType | 14 | +from typing import Any, Dict, List, NewType |
15 | import uuid | 15 | import uuid |
16 | 16 | ||
17 | -# this project | ||
18 | -from aprendizations.tools import run_script | 17 | +# third party libraries |
18 | +import yaml | ||
19 | 19 | ||
20 | # setup logger for this module | 20 | # setup logger for this module |
21 | logger = logging.getLogger(__name__) | 21 | logger = logging.getLogger(__name__) |
@@ -33,8 +33,9 @@ class QuestionException(Exception): | @@ -33,8 +33,9 @@ class QuestionException(Exception): | ||
33 | # ============================================================================ | 33 | # ============================================================================ |
34 | class Question(dict): | 34 | class Question(dict): |
35 | ''' | 35 | ''' |
36 | - Classes derived from this base class are meant to instantiate questions | ||
37 | - for each student. | 36 | + Base class for all question types |
37 | + | ||
38 | + Classes derived from this base class can instantiate questions. | ||
38 | Instances can shuffle options or automatically generate questions. | 39 | Instances can shuffle options or automatically generate questions. |
39 | ''' | 40 | ''' |
40 | 41 | ||
@@ -695,3 +696,44 @@ class QFactory(): | @@ -695,3 +696,44 @@ class QFactory(): | ||
695 | question = question_from(qdict) # returns a Question instance | 696 | question = question_from(qdict) # returns a Question instance |
696 | question.gen() | 697 | question.gen() |
697 | return question | 698 | return question |
699 | + | ||
700 | +# ----------------------------------------------------------------------------- | ||
701 | +async def run_script(script: str, | ||
702 | + args: List[str], | ||
703 | + stdin: str = '', | ||
704 | + timeout: int = 5) -> Any: | ||
705 | + | ||
706 | + # normalize args | ||
707 | + script = path.expanduser(script) | ||
708 | + input_bytes = stdin.encode('utf-8') | ||
709 | + args = [str(a) for a in args] | ||
710 | + | ||
711 | + try: | ||
712 | + p = await asyncio.create_subprocess_exec( | ||
713 | + script, *args, | ||
714 | + stdin=asyncio.subprocess.PIPE, | ||
715 | + stdout=asyncio.subprocess.PIPE, | ||
716 | + stderr=asyncio.subprocess.DEVNULL, | ||
717 | + ) | ||
718 | + except FileNotFoundError: | ||
719 | + logger.error(f'Can not execute script "{script}": not found.') | ||
720 | + except PermissionError: | ||
721 | + logger.error(f'Can not execute script "{script}": wrong permissions.') | ||
722 | + except OSError: | ||
723 | + logger.error(f'Can not execute script "{script}": unknown reason.') | ||
724 | + else: | ||
725 | + try: | ||
726 | + stdout, _ = await asyncio.wait_for(p.communicate(input_bytes), timeout) | ||
727 | + except asyncio.TimeoutError: | ||
728 | + logger.warning(f'Timeout {timeout}s exceeded running "{script}".') | ||
729 | + return | ||
730 | + | ||
731 | + if p.returncode != 0: | ||
732 | + logger.error(f'Return code {p.returncode} running "{script}".') | ||
733 | + else: | ||
734 | + try: | ||
735 | + output = yaml.safe_load(stdout.decode('utf-8', 'ignore')) | ||
736 | + except yaml.YAMLError: | ||
737 | + logger.error(f'Error parsing yaml output of "{script}"') | ||
738 | + else: | ||
739 | + return output |
aprendizations/tools.py
@@ -212,42 +212,42 @@ def load_yaml(filename: str, default: Any = None) -> Any: | @@ -212,42 +212,42 @@ def load_yaml(filename: str, default: Any = None) -> Any: | ||
212 | # ---------------------------------------------------------------------------- | 212 | # ---------------------------------------------------------------------------- |
213 | # Same as above, but asynchronous | 213 | # Same as above, but asynchronous |
214 | # ---------------------------------------------------------------------------- | 214 | # ---------------------------------------------------------------------------- |
215 | -async def run_script(script: str, | ||
216 | - args: List[str] = [], | ||
217 | - stdin: str = '', | ||
218 | - timeout: int = 2) -> Any: | ||
219 | - | ||
220 | - # normalize args | ||
221 | - script = path.expanduser(script) | ||
222 | - input_bytes = stdin.encode('utf-8') | ||
223 | - args = [str(a) for a in args] | ||
224 | - | ||
225 | - try: | ||
226 | - p = await asyncio.create_subprocess_exec( | ||
227 | - script, *args, | ||
228 | - stdin=asyncio.subprocess.PIPE, | ||
229 | - stdout=asyncio.subprocess.PIPE, | ||
230 | - stderr=asyncio.subprocess.DEVNULL, | ||
231 | - ) | ||
232 | - except FileNotFoundError: | ||
233 | - logger.error(f'Can not execute script "{script}": not found.') | ||
234 | - except PermissionError: | ||
235 | - logger.error(f'Can not execute script "{script}": wrong permissions.') | ||
236 | - except OSError: | ||
237 | - logger.error(f'Can not execute script "{script}": unknown reason.') | ||
238 | - else: | ||
239 | - try: | ||
240 | - stdout, _ = await asyncio.wait_for(p.communicate(input_bytes), timeout) | ||
241 | - except asyncio.TimeoutError: | ||
242 | - logger.warning(f'Timeout {timeout}s exceeded running "{script}".') | ||
243 | - return | ||
244 | - | ||
245 | - if p.returncode != 0: | ||
246 | - logger.error(f'Return code {p.returncode} running "{script}".') | ||
247 | - else: | ||
248 | - try: | ||
249 | - output = yaml.safe_load(stdout.decode('utf-8', 'ignore')) | ||
250 | - except Exception: | ||
251 | - logger.error(f'Error parsing yaml output of "{script}"') | ||
252 | - else: | ||
253 | - return output | 215 | +# async def run_script(script: str, |
216 | +# args: List[str] = [], | ||
217 | +# stdin: str = '', | ||
218 | +# timeout: int = 5) -> Any: | ||
219 | +# | ||
220 | +# # normalize args | ||
221 | +# script = path.expanduser(script) | ||
222 | +# input_bytes = stdin.encode('utf-8') | ||
223 | +# args = [str(a) for a in args] | ||
224 | +# | ||
225 | +# try: | ||
226 | +# p = await asyncio.create_subprocess_exec( | ||
227 | +# script, *args, | ||
228 | +# stdin=asyncio.subprocess.PIPE, | ||
229 | +# stdout=asyncio.subprocess.PIPE, | ||
230 | +# stderr=asyncio.subprocess.DEVNULL, | ||
231 | +# ) | ||
232 | +# except FileNotFoundError: | ||
233 | +# logger.error(f'Can not execute script "{script}": not found.') | ||
234 | +# except PermissionError: | ||
235 | +# logger.error(f'Can not execute script "{script}": wrong permissions.') | ||
236 | +# except OSError: | ||
237 | +# logger.error(f'Can not execute script "{script}": unknown reason.') | ||
238 | +# else: | ||
239 | +# try: | ||
240 | +# stdout, _ = await asyncio.wait_for(p.communicate(input_bytes), timeout) | ||
241 | +# except asyncio.TimeoutError: | ||
242 | +# logger.warning(f'Timeout {timeout}s exceeded running "{script}".') | ||
243 | +# return | ||
244 | +# | ||
245 | +# if p.returncode != 0: | ||
246 | +# logger.error(f'Return code {p.returncode} running "{script}".') | ||
247 | +# else: | ||
248 | +# try: | ||
249 | +# output = yaml.safe_load(stdout.decode('utf-8', 'ignore')) | ||
250 | +# except Exception: | ||
251 | +# logger.error(f'Error parsing yaml output of "{script}"') | ||
252 | +# else: | ||
253 | +# return output |