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 167 168 169 170 171 172 173 174 175 176 177 178
|
import os
import sys
import signal
import subprocess
import atexit
import warnings
import pytest
import contextlib
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_call(item):
"""A pytest hook which takes over sys.excepthook and raises any uncaught
exception (with PyGObject this happesn often when we get called from C,
like any signal handler, vfuncs tc).
"""
exceptions = []
def on_hook(type_, value, tback):
exceptions.append((type_, value, tback))
orig_excepthook = sys.excepthook
sys.excepthook = on_hook
try:
outcome = yield
finally:
sys.excepthook = orig_excepthook
if exceptions:
tp, value, tb = exceptions[0]
outcome.force_exception(tp(value).with_traceback(tb))
def set_dll_search_path():
# Python 3.8 no longer searches for DLLs in PATH, so we have to add
# everything in PATH manually. Note that unlike PATH add_dll_directory
# has no defined order, so if there are two cairo DLLs in PATH we
# might get a random one.
if os.name != "nt" or not hasattr(os, "add_dll_directory"):
return
for p in os.environ.get("PATH", "").split(os.pathsep):
with contextlib.suppress(OSError):
os.add_dll_directory(p)
def os_environ_prepend(envvar, path):
current = os.environ.get(envvar)
os.environ[envvar] = os.path.pathsep.join([path, current] if current else [path])
def init_test_environ():
set_dll_search_path()
def dbus_launch_session():
if os.name == "nt" or sys.platform == "darwin":
return (-1, "")
try:
out = subprocess.check_output(
[
"dbus-daemon",
"--session",
"--fork",
"--print-address=1",
"--print-pid=1",
]
)
except (subprocess.CalledProcessError, OSError):
return (-1, "")
else:
out = out.decode("utf-8")
addr, pid = out.splitlines()
return int(pid), addr
pid, addr = dbus_launch_session()
if pid >= 0:
os.environ["DBUS_SESSION_BUS_ADDRESS"] = addr
atexit.register(os.kill, pid, signal.SIGKILL)
else:
os.environ["DBUS_SESSION_BUS_ADDRESS"] = "."
# force untranslated messages, as we check for them in some tests
os.environ["LC_MESSAGES"] = "C"
os.environ["G_DEBUG"] = "fatal-warnings fatal-criticals"
if sys.platform == "darwin" or os.name == "nt":
# gtk 3.22 has warnings and ciriticals on OS X, ignore for now.
# On Windows glib will create an error dialog which will block tests
# so it's never a good idea there to make things fatal.
os.environ["G_DEBUG"] = ""
# First add test directory, since we have a gi package there
tests_srcdir = os.path.abspath(os.path.dirname(__file__))
srcdir = os.path.dirname(tests_srcdir)
sys.path.insert(0, tests_srcdir)
sys.path.insert(0, srcdir)
import gi
gi_builddir = os.path.dirname(gi._gi.__file__)
builddir = os.path.dirname(gi_builddir)
tests_builddir = os.path.join(builddir, "tests")
sys.path.insert(0, tests_builddir)
sys.path.insert(0, builddir)
# make Gio able to find our gschemas.compiled in tests/. This needs to be set
# before importing Gio. Support a separate build tree, so look in build dir
# first.
os.environ["GSETTINGS_BACKEND"] = "memory"
os.environ["GSETTINGS_SCHEMA_DIR"] = tests_builddir
os.environ["G_FILENAME_ENCODING"] = "UTF-8"
# Avoid accessibility dbus warnings
os.environ["NO_AT_BRIDGE"] = "1"
# A workaround for https://gitlab.gnome.org/GNOME/glib/-/issues/2251
# The gtk4 a11y stack calls get_dbus_object_path() on the default app
os.environ["GTK_A11Y"] = "none"
# Force the default theme so broken themes don't affect the tests
os.environ["GTK_THEME"] = "Adwaita"
gi_gir_path = os.path.join(
builddir, "subprojects", "glib", "girepository", "introspection"
)
if os.path.exists(gi_gir_path):
os_environ_prepend("GI_TYPELIB_PATH", gi_gir_path)
gi.require_version("GIRepository", "3.0")
repo = gi.Repository.get_default()
gi_tests_path = os.path.join(builddir, "subprojects", "gobject-introspection-tests")
repo.prepend_library_path(gi_tests_path)
repo.prepend_search_path(gi_tests_path)
def try_require_version(namespace, version):
try:
gi.require_version(namespace, version)
except ValueError:
# prevent tests from running with the wrong version
sys.modules["gi.repository." + namespace] = None
# Optional
try_require_version("Gtk", os.environ.get("TEST_GTK_VERSION", "3.0"))
try_require_version("Gdk", os.environ.get("TEST_GTK_VERSION", "3.0"))
try_require_version("GdkPixbuf", "2.0")
try_require_version("Pango", "1.0")
try_require_version("PangoCairo", "1.0")
try_require_version("Atk", "1.0")
# Required
gi.require_versions(
{
"GIMarshallingTests": "1.0",
"Regress": "1.0",
"GLib": "2.0",
"Gio": "2.0",
"GObject": "2.0",
}
)
# It's disabled for stable releases by default, this makes sure it's
# always on for the tests.
warnings.simplefilter("default", gi.PyGIDeprecationWarning)
# Otherwise we crash on the first gtk use when e.g. DISPLAY isn't set
try:
from gi.repository import Gtk
except ImportError:
pass
else:
res = Gtk.init_check() if Gtk._version == "4.0" else Gtk.init_check([])[0]
if not res:
raise RuntimeError("Gtk available, but Gtk.init_check() failed")
init_test_environ()
|