Add a typing-compatible mechanism for ad-hoc attributes on various objects

pytest has several instances where plugins set their own attributes on
objects they receive in hooks, like nodes and config. Since plugins are
detached from these object's definition by design, this causes a problem
for type checking because these attributes are not defined and mypy
complains.

Fix this by giving these objects a "store" which can be used by plugins
in a type-safe manner.

Currently this mechanism is private. We can consider exposing it at a
later point.
This commit is contained in:
Ran Benita
2020-02-21 17:03:46 +02:00
parent f77d606d4e
commit d636fcd557
13 changed files with 261 additions and 46 deletions

View File

@@ -1,7 +1,12 @@
""" submit failure or test session information to a pastebin service. """
import tempfile
from typing import IO
import pytest
from _pytest.store import StoreKey
pastebinfile_key = StoreKey[IO[bytes]]()
def pytest_addoption(parser):
@@ -26,25 +31,26 @@ def pytest_configure(config):
# when using pytest-xdist, for example
if tr is not None:
# pastebin file will be utf-8 encoded binary file
config._pastebinfile = tempfile.TemporaryFile("w+b")
config._store[pastebinfile_key] = tempfile.TemporaryFile("w+b")
oldwrite = tr._tw.write
def tee_write(s, **kwargs):
oldwrite(s, **kwargs)
if isinstance(s, str):
s = s.encode("utf-8")
config._pastebinfile.write(s)
config._store[pastebinfile_key].write(s)
tr._tw.write = tee_write
def pytest_unconfigure(config):
if hasattr(config, "_pastebinfile"):
if pastebinfile_key in config._store:
pastebinfile = config._store[pastebinfile_key]
# get terminal contents and delete file
config._pastebinfile.seek(0)
sessionlog = config._pastebinfile.read()
config._pastebinfile.close()
del config._pastebinfile
pastebinfile.seek(0)
sessionlog = pastebinfile.read()
pastebinfile.close()
del config._store[pastebinfile_key]
# undo our patching in the terminal reporter
tr = config.pluginmanager.getplugin("terminalreporter")
del tr._tw.__dict__["write"]