Some error handling/reporting fixes.
[pygobject.git] / tests / helper.py
blobc4308fee2ad847073d7412af676a568220a36c53
1 import contextlib
2 import unittest
3 import inspect
4 import warnings
5 import functools
6 import sys
7 from collections import namedtuple
9 import gi
10 from gi import PyGIDeprecationWarning
11 from gi.repository import GLib
13 from compathelper import callable, StringIO
16 ExceptionInfo = namedtuple("ExceptionInfo", ["type", "value", "traceback"])
17 """The type used for storing exceptions used by capture_exceptions()"""
20 @contextlib.contextmanager
21 def capture_exceptions():
22 """Installs a temporary sys.excepthook which records all exceptions
23 instead of printing them.
24 """
26 exceptions = []
28 def custom_excepthook(*args):
29 exceptions.append(ExceptionInfo(*args))
31 old_hook = sys.excepthook
32 sys.excepthook = custom_excepthook
33 try:
34 yield exceptions
35 finally:
36 sys.excepthook = old_hook
39 def ignore_gi_deprecation_warnings(func_or_class):
40 """A unittest class and function decorator which makes them ignore
41 PyGIDeprecationWarning.
42 """
44 if inspect.isclass(func_or_class):
45 assert issubclass(func_or_class, unittest.TestCase)
46 cls = func_or_class
47 for name, value in cls.__dict__.items():
48 if callable(value) and name.startswith("test_"):
49 new_value = ignore_gi_deprecation_warnings(value)
50 setattr(cls, name, new_value)
51 return cls
52 else:
53 func = func_or_class
55 @functools.wraps(func)
56 def wrapper(*args, **kwargs):
57 with capture_gi_deprecation_warnings():
58 return func(*args, **kwargs)
60 return wrapper
63 @contextlib.contextmanager
64 def capture_gi_deprecation_warnings():
65 """Temporarily suppress PyGIDeprecationWarning output and record them"""
67 with warnings.catch_warnings(record=True) as warn:
68 warnings.simplefilter('always', category=PyGIDeprecationWarning)
69 yield warn
72 @contextlib.contextmanager
73 def capture_glib_warnings(allow_warnings=False, allow_criticals=False):
74 """Temporarily suppress glib warning output and record them.
76 The test suite is run with G_DEBUG="fatal-warnings fatal-criticals"
77 by default. Setting allow_warnings and allow_criticals will temporarily
78 allow warnings or criticals without terminating the test run.
79 """
81 old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags(0))
83 new_mask = old_mask
84 if allow_warnings:
85 new_mask &= ~GLib.LogLevelFlags.LEVEL_WARNING
86 if allow_criticals:
87 new_mask &= ~GLib.LogLevelFlags.LEVEL_CRITICAL
89 GLib.log_set_always_fatal(GLib.LogLevelFlags(new_mask))
91 GLibWarning = gi._gi._gobject.Warning
92 try:
93 with warnings.catch_warnings(record=True) as warn:
94 warnings.filterwarnings('always', category=GLibWarning)
95 yield warn
96 finally:
97 GLib.log_set_always_fatal(old_mask)
100 @contextlib.contextmanager
101 def capture_glib_deprecation_warnings():
102 """Temporarily suppress glib deprecation warning output and record them"""
104 GLibWarning = gi._gi._gobject.Warning
105 with warnings.catch_warnings(record=True) as warn:
106 warnings.filterwarnings(
107 'always', category=GLibWarning,
108 message=".+ is deprecated and shouldn't be used anymore\. "
109 "It will be removed in a future version\.")
110 yield warn
113 @contextlib.contextmanager
114 def capture_output():
116 with capture_output as (stdout, stderr):
117 some_action()
118 print(stdout.getvalue(), stderr.getvalue())
121 err = StringIO()
122 out = StringIO()
123 old_err = sys.stderr
124 old_out = sys.stdout
125 sys.stderr = err
126 sys.stdout = out
128 try:
129 yield (out, err)
130 finally:
131 sys.stderr = old_err
132 sys.stdout = old_out