From: W. Trevor King Date: Sat, 23 Mar 2013 13:03:28 +0000 (-0400) Subject: util: Support Python 3.2 by ignoring timeouts passed to invoke() X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=af248ffb3c0f4de2010dca5b425fce42d03db766;p=quizzer.git util: Support Python 3.2 by ignoring timeouts passed to invoke() If you're not asking ScriptQuestions, you don't care about this feature, and it's good to be able to relax the Python 3.3 requirement. --- diff --git a/README b/README index 04df170..67e057c 100644 --- a/README +++ b/README @@ -71,7 +71,7 @@ The unanswered question (“What is your name?”) wasn't asked because the user successfully answered the question that depended on it (“What is your quest?”). -Quizzer requires Python ≥ 3.3. If Pygments is installed, the command +Quizzer requires Python ≥ 3.2. If Pygments is installed, the command line prompt will be colored. Types of questions: @@ -90,6 +90,7 @@ Types of questions: temporary directories, and we judge success by comparing the output of the teardown phase (and optionally the output of the answer phase). You can optionally set a timeout to catch answers that - hang. There is no sandboxing (other than working in a scratch - directory), so it's not a good idea to serve questions like this on - a public interface (stick to ``cli``). + hang, although this requires Python ≥ 3.3. There is no sandboxing + (other than working in a scratch directory), so it's not a good idea + to serve questions like this on a public interface (stick to + ``cli``). diff --git a/pq.py b/pq.py index 5594572..9a64cbb 100755 --- a/pq.py +++ b/pq.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.3 +#!/usr/bin/env python # # Copyright (C) 2013 W. Trevor King # diff --git a/quizzer/util.py b/quizzer/util.py index 6b6f1a1..688ad03 100644 --- a/quizzer/util.py +++ b/quizzer/util.py @@ -17,11 +17,15 @@ import logging as _logging import os.path as _os_path import subprocess as _subprocess +import sys as _sys import tempfile as _tempfile from . import error as _error +LOG = _logging.getLogger(__name__) + + def invoke(args, stdin=None, stdout=_subprocess.PIPE, stderr=_subprocess.PIPE, universal_newlines=False, timeout=None, expect=None, **kwargs): if stdin: @@ -34,16 +38,22 @@ def invoke(args, stdin=None, stdout=_subprocess.PIPE, stderr=_subprocess.PIPE, universal_newlines=universal_newlines, **kwargs) except FileNotFoundError as e: raise _error.CommandError(arguments=args, stdin=stdin) from e - try: - stdout,stderr = p.communicate(input=stdin, timeout=timeout) - except _subprocess.TimeoutExpired as e: - p.kill() - stdout,stderr = p.communicate() - status = p.wait() - raise _error.CommandError( - msg='timeout ({}s) expired'.format(timeout), - arguments=args, stdin=stdin, stdout=stdout, stderr=stderr, - status=status) from e + if _sys.version_info >= (3, 3): # Python >= 3.3 + try: + stdout,stderr = p.communicate(input=stdin, timeout=timeout) + except _subprocess.TimeoutExpired as e: + p.kill() + stdout,stderr = p.communicate() + status = p.wait() + raise _error.CommandError( + msg='timeout ({}s) expired'.format(timeout), + arguments=args, stdin=stdin, stdout=stdout, stderr=stderr, + status=status) from e + else: # Python <= 3.2 don't support communicate(..., timeout) + if timeout is not None: + LOG.warning('Python version {} does not support timeouts'.format( + _sys.version.split()[0])) + stdout,stderr = p.communicate(input=stdin) status = p.wait() if expect and status not in expect: raise _error.CommandError( diff --git a/setup.py b/setup.py index 1d8c426..18d318c 100644 --- a/setup.py +++ b/setup.py @@ -43,6 +43,7 @@ _setup( 'Operating System :: OS Independent', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Topic :: Education', 'Topic :: Education :: Computer Aided Instruction (CAI)',