1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
import functools
import os
import platform
import sys
import unittest
from io import StringIO
from build_swift import cache_utils
from build_swift.versions import Version
__all__ = [
'quiet_output',
'redirect_stderr',
'redirect_stdout',
'requires_attr',
'requires_module',
'requires_platform',
'requires_python',
]
# -----------------------------------------------------------------------------
# Constants
_PYTHON_VERSION = Version(platform.python_version())
# -----------------------------------------------------------------------------
# Helpers
def _can_import(fullname):
try:
__import__(fullname)
return True
except ImportError:
return False
# -----------------------------------------------------------------------------
class quiet_output(object):
"""Context manager and decorator used to quiet both sys.stderr and
sys.stdout by redirecting them to os.devnull.
"""
__slots__ = ('_devnull', '_old_stderr', '_old_stdout')
def __enter__(self):
self._devnull = open(os.devnull, 'w')
self._old_stderr = sys.stderr
self._old_stdout = sys.stdout
sys.stderr = self._devnull
sys.stdout = self._devnull
def __exit__(self, exc_type, exc_value, traceback):
sys.stderr = self._old_stderr
sys.stdout = self._old_stdout
self._devnull.close()
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
with self:
return func(*args, **kwargs)
return wrapper
class redirect_stderr(object):
"""Context manager used to substitute sys.stderr with a different file-like
object.
"""
__slots__ = ('_stream', '_old_stderr')
def __init__(self, stream=None):
self._stream = stream or StringIO()
def __enter__(self):
self._old_stderr, sys.stderr = sys.stderr, self._stream
return self._stream
def __exit__(self, exc_type, exc_value, traceback):
sys.stderr = self._old_stderr
class redirect_stdout():
"""Context manager used to substitute sys.stdout with a different file-like
object.
"""
__slots__ = ('_stream', '_old_stdout')
def __init__(self, stream=None):
self._stream = stream or StringIO()
def __enter__(self):
self._old_stdout, sys.stderr = sys.stderr, self._stream
return self._stream
def __exit__(self, exc_type, exc_value, traceback):
sys.stderr = self._old_stdout
@cache_utils.cache
def requires_attr(obj, attr):
"""Decorator used to skip tests if an object does not have the required
attribute.
"""
try:
getattr(obj, attr)
return lambda func: func
except AttributeError:
return unittest.skip('Required attribute "{}" not found on {}'.format(
attr, obj))
@cache_utils.cache
def requires_module(fullname):
"""Decorator used to skip tests if a module is not imported.
"""
if _can_import(fullname):
return lambda func: func
return unittest.skip('Unable to import "{}"'.format(fullname))
@cache_utils.cache
def requires_platform(name):
"""Decorator used to skip tests if not running on the given platform.
"""
if name == platform.system():
return lambda func: func
return unittest.skip(
'Required platform "{}" does not match system'.format(name))
@cache_utils.cache
def requires_python(version):
"""Decorator used to skip tests if the running Python version is not
greater or equal to the required version.
"""
if isinstance(version, str):
version = Version(version)
if _PYTHON_VERSION >= version:
return lambda func: func
return unittest.skip(
'Requires Python version {} or greater'.format(version))
|