1"""Support code for distutils test cases."""
2import os
3import shutil
4import tempfile
5from copy import deepcopy
6import warnings
7
8from distutils import log
9from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
10from distutils.core import Distribution
11
12def capture_warnings(func):
13    def _capture_warnings(*args, **kw):
14        with warnings.catch_warnings():
15            warnings.simplefilter("ignore")
16            return func(*args, **kw)
17    return _capture_warnings
18
19class LoggingSilencer(object):
20
21    def setUp(self):
22        super(LoggingSilencer, self).setUp()
23        self.threshold = log.set_threshold(log.FATAL)
24        # catching warnings
25        # when log will be replaced by logging
26        # we won't need such monkey-patch anymore
27        self._old_log = log.Log._log
28        log.Log._log = self._log
29        self.logs = []
30
31    def tearDown(self):
32        log.set_threshold(self.threshold)
33        log.Log._log = self._old_log
34        super(LoggingSilencer, self).tearDown()
35
36    def _log(self, level, msg, args):
37        if level not in (DEBUG, INFO, WARN, ERROR, FATAL):
38            raise ValueError('%s wrong log level' % str(level))
39        self.logs.append((level, msg, args))
40
41    def get_logs(self, *levels):
42        def _format(msg, args):
43            if len(args) == 0:
44                return msg
45            return msg % args
46        return [_format(msg, args) for level, msg, args
47                in self.logs if level in levels]
48
49    def clear_logs(self):
50        self.logs = []
51
52class TempdirManager(object):
53    """Mix-in class that handles temporary directories for test cases.
54
55    This is intended to be used with unittest.TestCase.
56    """
57
58    def setUp(self):
59        super(TempdirManager, self).setUp()
60        self.tempdirs = []
61
62    def tearDown(self):
63        super(TempdirManager, self).tearDown()
64        while self.tempdirs:
65            d = self.tempdirs.pop()
66            shutil.rmtree(d, os.name in ('nt', 'cygwin'))
67
68    def mkdtemp(self):
69        """Create a temporary directory that will be cleaned up.
70
71        Returns the path of the directory.
72        """
73        d = tempfile.mkdtemp()
74        self.tempdirs.append(d)
75        return d
76
77    def write_file(self, path, content='xxx'):
78        """Writes a file in the given path.
79
80
81        path can be a string or a sequence.
82        """
83        if isinstance(path, (list, tuple)):
84            path = os.path.join(*path)
85        f = open(path, 'w')
86        try:
87            f.write(content)
88        finally:
89            f.close()
90
91    def create_dist(self, pkg_name='foo', **kw):
92        """Will generate a test environment.
93
94        This function creates:
95         - a Distribution instance using keywords
96         - a temporary directory with a package structure
97
98        It returns the package directory and the distribution
99        instance.
100        """
101        tmp_dir = self.mkdtemp()
102        pkg_dir = os.path.join(tmp_dir, pkg_name)
103        os.mkdir(pkg_dir)
104        dist = Distribution(attrs=kw)
105
106        return pkg_dir, dist
107
108class DummyCommand:
109    """Class to store options for retrieval via set_undefined_options()."""
110
111    def __init__(self, **kwargs):
112        for kw, val in kwargs.items():
113            setattr(self, kw, val)
114
115    def ensure_finalized(self):
116        pass
117
118class EnvironGuard(object):
119
120    def setUp(self):
121        super(EnvironGuard, self).setUp()
122        self.old_environ = deepcopy(os.environ)
123
124    def tearDown(self):
125        for key, value in self.old_environ.items():
126            if os.environ.get(key) != value:
127                os.environ[key] = value
128
129        for key in os.environ.keys():
130            if key not in self.old_environ:
131                del os.environ[key]
132
133        super(EnvironGuard, self).tearDown()
134