[Reproducible-commits] [reprotest] 01/01: Move contextlib monkey-patch to its own file

Ceridwen ceridwen-guest at moszumanska.debian.org
Mon Jul 18 13:58:41 UTC 2016


This is an automated email from the git hooks/post-receive script.

ceridwen-guest pushed a commit to branch virtualization
in repository reprotest.

commit dda03c695d05310aec449e609899863b2c9e3b21
Author: Ceridwen <ceridwenv at gmail.com>
Date:   Mon Jul 18 09:58:15 2016 -0400

    Move contextlib monkey-patch to its own file
---
 reprotest/__init__.py    | 98 ++++++++----------------------------------------
 reprotest/_contextlib.py | 68 +++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 82 deletions(-)

diff --git a/reprotest/__init__.py b/reprotest/__init__.py
index c172fec..7ff387b 100644
--- a/reprotest/__init__.py
+++ b/reprotest/__init__.py
@@ -4,7 +4,6 @@
 import argparse
 import collections
 import configparser
-import contextlib
 import logging
 import os
 import pathlib
@@ -18,85 +17,20 @@ import pkg_resources
 
 from reprotest.lib import adtlog
 from reprotest.lib import adt_testbed
+from reprotest import _contextlib
 from reprotest import _shell_ast
 
 
 adtlog.verbosity = 2
 
 
-# Monkey-patch contextlib.ExitStack
-
-# Patch from: https://bugs.python.org/file41216/Issue25786.patch
-
-# https://bugs.python.org/issue25782
-
-# https://bugs.python.org/issue25786
-
-# This code is from the standard library contextlib
-
-def monkey_patch_exit_stack():
-    def __exit__(self, *exc_details):
-        received_exc = exc_details[0] is not None
-
-        # We manipulate the exception state so it behaves as though
-        # we were actually nesting multiple with statements
-        frame_exc = sys.exc_info()[1]
-        def _fix_exception_context(new_exc, old_exc):
-            # Context may not be correct, so find the end of the chain
-            if new_exc is old_exc:
-                return
-            while 1:
-                exc_context = new_exc.__context__
-                if exc_context is old_exc:
-                    # Context is already set correctly (see issue 20317)
-                    return
-                if exc_context is None or exc_context is frame_exc:
-                    break
-                new_exc = exc_context
-            # Change the end of the chain to point to the exception
-            # we expect it to reference
-            new_exc.__context__ = old_exc
-
-        # Callbacks are invoked in LIFO order to match the behaviour of
-        # nested context managers
-        suppressed_exc = False
-        pending_raise = False
-        while self._exit_callbacks:
-            cb = self._exit_callbacks.pop()
-            try:
-                if cb(*exc_details):
-                    suppressed_exc = True
-                    pending_raise = False
-                    exc_details = (None, None, None)
-            except:
-                new_exc_details = sys.exc_info()
-                # simulate the stack of exceptions by setting the context
-                _fix_exception_context(new_exc_details[1], exc_details[1])
-                pending_raise = True
-                exc_details = new_exc_details
-        if pending_raise:
-            try:
-                # bare "raise exc_details[1]" replaces our carefully
-                # set-up context
-                fixed_ctx = exc_details[1].__context__
-                raise exc_details[1]
-            except BaseException:
-                exc_details[1].__context__ = fixed_ctx
-                raise
-        return received_exc and suppressed_exc
-
-    contextlib.ExitStack.__exit__ = __exit__
-
-monkey_patch_exit_stack()
-
-
 # chroot is the only form of OS virtualization that's available on
 # most POSIX OSes.  Linux containers (lxc) and namespaces are specific
 # to Linux.  Some versions of BSD have jails (MacOS X?).  There are a
 # variety of other options including Docker etc that use different
 # approaches.
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def start_testbed(args, temp_dir):
     '''This is a simple wrapper around adt_testbed that automates the
     initialization and cleanup.'''
@@ -127,22 +61,22 @@ def add(mapping, key, value):
 
 
 # TODO: relies on a pbuilder-specific command to parallelize
-# @contextlib.contextmanager
+# @_contextlib.contextmanager
 # def cpu(env, tree, testbed):
 #     yield script, env, tree
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def captures_environment(script, env, tree, testbed):
     new_env = add(env.experiment, 'CAPTURE_ENVIRONMENT',
                   'i_capture_the_environment')
     yield script, Pair(env.control, new_env), tree
 
 # TODO: this requires superuser privileges.
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def domain_host(script, env, tree, testbed):
     yield script, env, tree
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def fileordering(script, env, tree, testbed):
     new_tree = os.path.dirname(os.path.dirname(tree.control)) + '/disorderfs/'
     testbed.execute(['mkdir', '-p', new_tree])
@@ -156,11 +90,11 @@ def fileordering(script, env, tree, testbed):
         # subprocess.check_call(['fusermount', '-u', str(disorderfs)])
         testbed.execute(['fusermount', '-u', new_tree])
 
-# @contextlib.contextmanager
+# @_contextlib.contextmanager
 # def fileordering(script, env, tree, testbed):
 #     yield script, env, tree
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def home(script, env, tree, testbed):
     control = add(env.control, 'HOME', '/nonexistent/first-build')
     experiment = add(env.experiment, 'HOME', '/nonexistent/second-build')
@@ -171,7 +105,7 @@ def home(script, env, tree, testbed):
 # FreeBSD changes uname with environment variables.  Wikipedia has a
 # reference to a setname command on another Unix variant:
 # https://en.wikipedia.org/wiki/Uname
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def kernel(script, env, tree, testbed):
     setarch = _shell_ast.SimpleCommand(
         '', 'linux64', _shell_ast.CmdSuffix(
@@ -192,7 +126,7 @@ def kernel(script, env, tree, testbed):
 
 # TODO: what exact locales and how to many test is probably a mailing
 # list question.
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def locales(script, env, tree, testbed):
     # env1['LANG'] = 'C'
     new_env = add(add(env.experiment, 'LANG', 'fr_CH.UTF-8'),
@@ -208,7 +142,7 @@ def locales(script, env, tree, testbed):
 #     # command2 = ['unshare', '--uts'] + command2
 #     yield script, env, tree
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def path(script, env, tree, testbed):
     new_env = add(env.experiment, 'PATH', env.control['PATH'] +
                   '/i_capture_the_path')
@@ -216,11 +150,11 @@ def path(script, env, tree, testbed):
 
 # This doesn't require superuser privileges, but the chsh command
 # affects all user shells, which would be bad.
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def shell(script, env, tree, testbed):
     yield script, env, tree
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def timezone(script, env, tree, testbed):
     # These time zones are theoretically in the POSIX time zone format
     # (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08),
@@ -229,7 +163,7 @@ def timezone(script, env, tree, testbed):
     experiment = add(env.experiment, 'TZ', 'GMT-14')
     yield script, Pair(control, experiment), tree
 
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def umask(script, env, tree, testbed):
     umask = _shell_ast.SimpleCommand('', 'umask', _shell_ast.CmdSuffix(['0002']))
     new_script = (_shell_ast.List([_shell_ast.Term(umask, ';')])
@@ -237,7 +171,7 @@ def umask(script, env, tree, testbed):
     yield Pair(script.control, new_script), env, tree
 
 # TODO: This requires superuser privileges.
- at contextlib.contextmanager
+ at _contextlib.contextmanager
 def user_group(script, env, tree, testbed):
     yield script, env, tree
 
@@ -289,7 +223,7 @@ def check(build_command, artifact_name, virtual_server_args, source_root,
         # print(pathlib.Path.cwd())
         # print(source_root)
         try:
-            with contextlib.ExitStack() as stack:
+            with _contextlib.ExitStack() as stack:
                 for variation in variations:
                     # print('START')
                     # print(variation)
diff --git a/reprotest/_contextlib.py b/reprotest/_contextlib.py
new file mode 100644
index 0000000..82dd6ba
--- /dev/null
+++ b/reprotest/_contextlib.py
@@ -0,0 +1,68 @@
+# Licensed under the GPL: https://www.gnu.org/licenses/gpl-3.0.en.html
+# For details: reprotest/debian/copyright
+'''This files monkey-patches contextlib.ExitStack to work around
+CPython bugs, https://bugs.python.org/issue25782 and
+https://bugs.python.org/issue25786.  Assigning an exception
+__context__ to itself causes CPython to hang.  This is scheduled to be
+fixed in 3.5.3.  This code is from the standard library contextlib,
+patched with https://bugs.python.org/file41216/Issue25786.patch.
+
+'''
+
+from contextlib import *
+
+import sys
+
+def _new_exit():
+    def __exit__(self, *exc_details):
+        received_exc = exc_details[0] is not None
+
+        # We manipulate the exception state so it behaves as though
+        # we were actually nesting multiple with statements
+        frame_exc = sys.exc_info()[1]
+        def _fix_exception_context(new_exc, old_exc):
+            # Context may not be correct, so find the end of the chain
+            if new_exc is old_exc:
+                return
+            while 1:
+                exc_context = new_exc.__context__
+                if exc_context is old_exc:
+                    # Context is already set correctly (see issue 20317)
+                    return
+                if exc_context is None or exc_context is frame_exc:
+                    break
+                new_exc = exc_context
+            # Change the end of the chain to point to the exception
+            # we expect it to reference
+            new_exc.__context__ = old_exc
+
+        # Callbacks are invoked in LIFO order to match the behaviour of
+        # nested context managers
+        suppressed_exc = False
+        pending_raise = False
+        while self._exit_callbacks:
+            cb = self._exit_callbacks.pop()
+            try:
+                if cb(*exc_details):
+                    suppressed_exc = True
+                    pending_raise = False
+                    exc_details = (None, None, None)
+            except:
+                new_exc_details = sys.exc_info()
+                # simulate the stack of exceptions by setting the context
+                _fix_exception_context(new_exc_details[1], exc_details[1])
+                pending_raise = True
+                exc_details = new_exc_details
+        if pending_raise:
+            try:
+                # bare "raise exc_details[1]" replaces our carefully
+                # set-up context
+                fixed_ctx = exc_details[1].__context__
+                raise exc_details[1]
+            except BaseException:
+                exc_details[1].__context__ = fixed_ctx
+                raise
+        return received_exc and suppressed_exc
+    return __exit__
+
+ExitStack.__exit__ = _new_exit()

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/reprotest.git



More information about the Reproducible-commits mailing list