Skip to content

Commit 76d608b

Browse files
authored
fix: snapshot decorator for pytest fixtures (#1743)
In using snapshot decorator with pytest tests with fixtures, a TypeError error is raised. This is due to a known limitation of functools.wraps with Python 2.7 and pytest: pytest-dev/pytest#2782. This fix uses wrapt.decorator instead. * fix snapshot decorator for pytest fixtures * flush before starting snapshot
1 parent 730b6e9 commit 76d608b

File tree

1 file changed

+49
-48
lines changed

1 file changed

+49
-48
lines changed

tests/__init__.py

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import contextlib
2-
import functools
32
import inspect
43
import os
54
import sys
65
from contextlib import contextmanager
76

87
import pytest
8+
from ddtrace.vendor import wrapt
99

1010
import ddtrace
1111
from ddtrace import Tracer, Span
@@ -815,54 +815,55 @@ def snapshot(ignores=None, tracer=ddtrace.tracer):
815815
"""
816816
ignores = ignores or []
817817

818-
def dec(f):
819-
@functools.wraps(f)
820-
def wrapper(*args, **kwargs):
821-
if len(args) > 1:
822-
self = args[0]
823-
clsname = self.__class__.__name__
824-
else:
825-
clsname = ""
818+
@wrapt.decorator
819+
def wrapper(wrapped, instance, args, kwargs):
820+
if len(args) > 1:
821+
self = args[0]
822+
clsname = self.__class__.__name__
823+
else:
824+
clsname = ""
826825

827-
module = inspect.getmodule(f)
826+
module = inspect.getmodule(wrapped)
828827

829-
# Use the fully qualified function name as a unique test token to
830-
# identify the snapshot.
831-
token = "{}{}{}.{}".format(module.__name__, "." if clsname else "", clsname, f.__name__)
828+
# Use the fully qualified function name as a unique test token to
829+
# identify the snapshot.
830+
token = "{}{}{}.{}".format(module.__name__, "." if clsname else "", clsname, wrapped.__name__)
832831

833-
conn = httplib.HTTPConnection(tracer.writer.api.hostname, tracer.writer.api.port)
832+
conn = httplib.HTTPConnection(tracer.writer.api.hostname, tracer.writer.api.port)
833+
try:
834+
# clear queue in case traces have been generated before test case is
835+
# itself run
836+
tracer.writer.flush_queue()
837+
838+
# Signal the start of this test case to the test agent.
834839
try:
835-
# Signal the start of this test case to the test agent.
836-
try:
837-
conn.request("GET", "/test/start?token=%s" % token)
838-
except Exception as e:
839-
pytest.fail("Could not connect to test agent: %s" % str(e), pytrace=False)
840-
841-
r = conn.getresponse()
842-
if r.status != 200:
843-
# The test agent returns nice error messages we can forward to the user.
844-
raise SnapshotFailed(r.read().decode())
845-
846-
# Run the test.
847-
ret = f(*args, **kwargs)
848-
849-
# Flush out any remnant traces.
850-
tracer.writer.flush_queue()
851-
852-
# Query for the results of the test.
853-
conn = httplib.HTTPConnection(tracer.writer.api.hostname, tracer.writer.api.port)
854-
conn.request("GET", "/test/snapshot?ignores=%s&token=%s" % (",".join(ignores), token))
855-
r = conn.getresponse()
856-
if r.status != 200:
857-
raise SnapshotFailed(r.read().decode())
858-
return ret
859-
except SnapshotFailed as e:
860-
# Fail the test if a failure has occurred and print out the
861-
# message we got from the test agent.
862-
pytest.fail(str(e), pytrace=False)
863-
finally:
864-
conn.close()
865-
866-
return wrapper
867-
868-
return dec
840+
conn.request("GET", "/test/start?token=%s" % token)
841+
except Exception as e:
842+
pytest.fail("Could not connect to test agent: %s" % str(e), pytrace=False)
843+
844+
r = conn.getresponse()
845+
if r.status != 200:
846+
# The test agent returns nice error messages we can forward to the user.
847+
raise SnapshotFailed(r.read().decode())
848+
849+
# Run the test.
850+
ret = wrapped(*args, **kwargs)
851+
852+
# Flush out any remnant traces.
853+
tracer.writer.flush_queue()
854+
855+
# Query for the results of the test.
856+
conn = httplib.HTTPConnection(tracer.writer.api.hostname, tracer.writer.api.port)
857+
conn.request("GET", "/test/snapshot?ignores=%s&token=%s" % (",".join(ignores), token))
858+
response = conn.getresponse()
859+
if response.status != 200:
860+
raise SnapshotFailed(response.read().decode())
861+
return ret
862+
except SnapshotFailed as e:
863+
# Fail the test if a failure has occurred and print out the
864+
# message we got from the test agent.
865+
pytest.fail(str(e), pytrace=False)
866+
finally:
867+
conn.close()
868+
869+
return wrapper

0 commit comments

Comments
 (0)