Merge branch 'master' into features
This commit is contained in:
@@ -69,10 +69,22 @@ class Cache(object):
|
||||
like e. g. lists of dictionaries.
|
||||
"""
|
||||
path = self._getvaluepath(key)
|
||||
path.dirpath().ensure_dir()
|
||||
with path.open("w") as f:
|
||||
self.trace("cache-write %s: %r" % (key, value,))
|
||||
json.dump(value, f, indent=2, sort_keys=True)
|
||||
try:
|
||||
path.dirpath().ensure_dir()
|
||||
except (py.error.EEXIST, py.error.EACCES):
|
||||
self.config.warn(
|
||||
code='I9', message='could not create cache path %s' % (path,)
|
||||
)
|
||||
return
|
||||
try:
|
||||
f = path.open('w')
|
||||
except py.error.ENOTDIR:
|
||||
self.config.warn(
|
||||
code='I9', message='cache could not write path %s' % (path,))
|
||||
else:
|
||||
with f:
|
||||
self.trace("cache-write %s: %r" % (key, value,))
|
||||
json.dump(value, f, indent=2, sort_keys=True)
|
||||
|
||||
|
||||
class LFPlugin:
|
||||
@@ -174,8 +186,20 @@ def pytest_configure(config):
|
||||
|
||||
@pytest.fixture
|
||||
def cache(request):
|
||||
"""
|
||||
Return a cache object that can persist state between testing sessions.
|
||||
|
||||
cache.get(key, default)
|
||||
cache.set(key, value)
|
||||
|
||||
Keys must be strings not containing a "/" separator. Add a unique identifier
|
||||
(such as plugin/app name) to avoid clashes with other cache users.
|
||||
|
||||
Values can be any object handled by the json stdlib module.
|
||||
"""
|
||||
return request.config.cache
|
||||
|
||||
|
||||
def pytest_report_header(config):
|
||||
if config.option.verbose:
|
||||
relpath = py.path.local().bestrelpath(config.cache._cachedir)
|
||||
|
||||
@@ -32,6 +32,9 @@ exc_clear = getattr(sys, 'exc_clear', lambda: None)
|
||||
# The type of re.compile objects is not exposed in Python.
|
||||
REGEX_TYPE = type(re.compile(''))
|
||||
|
||||
_PY3 = sys.version_info > (3, 0)
|
||||
_PY2 = not _PY3
|
||||
|
||||
|
||||
if hasattr(inspect, 'signature'):
|
||||
def _format_args(func):
|
||||
@@ -912,7 +915,7 @@ class Metafunc(FuncargnamesCompatAttr):
|
||||
|
||||
:arg argvalues: The list of argvalues determines how often a
|
||||
test is invoked with different argument values. If only one
|
||||
argname was specified argvalues is a list of simple values. If N
|
||||
argname was specified argvalues is a list of values. If N
|
||||
argnames were specified, argvalues must be a list of N-tuples,
|
||||
where each tuple-element specifies a value for its respective
|
||||
argname.
|
||||
@@ -1037,6 +1040,35 @@ class Metafunc(FuncargnamesCompatAttr):
|
||||
self._calls.append(cs)
|
||||
|
||||
|
||||
if _PY3:
|
||||
def _escape_bytes(val):
|
||||
"""
|
||||
If val is pure ascii, returns it as a str(), otherwise escapes
|
||||
into a sequence of escaped bytes:
|
||||
b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
|
||||
|
||||
note:
|
||||
the obvious "v.decode('unicode-escape')" will return
|
||||
valid utf-8 unicode if it finds them in the string, but we
|
||||
want to return escaped bytes for any byte, even if they match
|
||||
a utf-8 string.
|
||||
"""
|
||||
# source: http://goo.gl/bGsnwC
|
||||
import codecs
|
||||
encoded_bytes, _ = codecs.escape_encode(val)
|
||||
return encoded_bytes.decode('ascii')
|
||||
else:
|
||||
def _escape_bytes(val):
|
||||
"""
|
||||
In py2 bytes and str are the same, so return it unchanged if it
|
||||
is a full ascii string, otherwise escape it into its binary form.
|
||||
"""
|
||||
try:
|
||||
return val.encode('ascii')
|
||||
except UnicodeDecodeError:
|
||||
return val.encode('string-escape')
|
||||
|
||||
|
||||
def _idval(val, argname, idx, idfn):
|
||||
if idfn:
|
||||
try:
|
||||
@@ -1046,7 +1078,9 @@ def _idval(val, argname, idx, idfn):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if isinstance(val, (float, int, str, bool, NoneType)):
|
||||
if isinstance(val, bytes):
|
||||
return _escape_bytes(val)
|
||||
elif isinstance(val, (float, int, str, bool, NoneType)):
|
||||
return str(val)
|
||||
elif isinstance(val, REGEX_TYPE):
|
||||
return val.pattern
|
||||
@@ -1054,6 +1088,14 @@ def _idval(val, argname, idx, idfn):
|
||||
return str(val)
|
||||
elif isclass(val) and hasattr(val, '__name__'):
|
||||
return val.__name__
|
||||
elif _PY2 and isinstance(val, unicode):
|
||||
# special case for python 2: if a unicode string is
|
||||
# convertible to ascii, return it as an str() object instead
|
||||
try:
|
||||
return str(val)
|
||||
except UnicodeDecodeError:
|
||||
# fallthrough
|
||||
pass
|
||||
return str(argname)+str(idx)
|
||||
|
||||
def _idvalset(idx, valset, argnames, idfn):
|
||||
|
||||
@@ -22,7 +22,7 @@ def pytest_addoption(parser):
|
||||
group._addoption('-r',
|
||||
action="store", dest="reportchars", default=None, metavar="chars",
|
||||
help="show extra test summary info as specified by chars (f)ailed, "
|
||||
"(E)error, (s)skipped, (x)failed, (X)passed (w)warnings (a)all.")
|
||||
"(E)error, (s)skipped, (x)failed, (X)passed (w)pytest-warnings (a)all.")
|
||||
group._addoption('-l', '--showlocals',
|
||||
action="store_true", dest="showlocals", default=False,
|
||||
help="show locals in tracebacks (disabled by default).")
|
||||
|
||||
Reference in New Issue
Block a user