util: Support Python 3.2 by ignoring timeouts passed to invoke()
authorW. Trevor King <wking@tremily.us>
Sat, 23 Mar 2013 13:03:28 +0000 (09:03 -0400)
committerW. Trevor King <wking@tremily.us>
Sat, 23 Mar 2013 13:08:03 +0000 (09:08 -0400)
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.

README
pq.py
quizzer/util.py
setup.py

diff --git a/README b/README
index 04df1700bea31a155250df91669154563e9f917a..67e057ce6c1945d35c613b30f34c3fee887a82cc 100644 (file)
--- 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 5594572082685057e72a59eaa19bb4e6be0e8c66..9a64cbb93b107ae4c323ef9879113c8067aceb4e 100755 (executable)
--- 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 <wking@tremily.us>
 #
index 6b6f1a1b3c9acde7ea39432816ec1a866b8cd23d..688ad0394a7077ac1de894711a2b96e0de21baca 100644 (file)
 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(
index 1d8c4262f459e37c90380b0073c6c8f0df230ac7..18d318c3e1ffe289c295384bb53c873f49832335 100644 (file)
--- 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)',