Merge remote-tracking branch 'upstream/features' into invocation-scoped-fixtures
This commit is contained in:
commit
fb4da00a32
|
@ -0,0 +1,203 @@
|
|||
"""
|
||||
python version compatibility code
|
||||
"""
|
||||
import sys
|
||||
import inspect
|
||||
import types
|
||||
import re
|
||||
import functools
|
||||
|
||||
import py
|
||||
|
||||
import _pytest
|
||||
|
||||
|
||||
|
||||
try:
|
||||
import enum
|
||||
except ImportError: # pragma: no cover
|
||||
# Only available in Python 3.4+ or as a backport
|
||||
enum = None
|
||||
|
||||
_PY3 = sys.version_info > (3, 0)
|
||||
_PY2 = not _PY3
|
||||
|
||||
|
||||
NoneType = type(None)
|
||||
NOTSET = object()
|
||||
|
||||
if hasattr(inspect, 'signature'):
|
||||
def _format_args(func):
|
||||
return str(inspect.signature(func))
|
||||
else:
|
||||
def _format_args(func):
|
||||
return inspect.formatargspec(*inspect.getargspec(func))
|
||||
|
||||
isfunction = inspect.isfunction
|
||||
isclass = inspect.isclass
|
||||
# used to work around a python2 exception info leak
|
||||
exc_clear = getattr(sys, 'exc_clear', lambda: None)
|
||||
# The type of re.compile objects is not exposed in Python.
|
||||
REGEX_TYPE = type(re.compile(''))
|
||||
|
||||
|
||||
def is_generator(func):
|
||||
try:
|
||||
return _pytest._code.getrawcode(func).co_flags & 32 # generator function
|
||||
except AttributeError: # builtin functions have no bytecode
|
||||
# assume them to not be generators
|
||||
return False
|
||||
|
||||
|
||||
def getlocation(function, curdir):
|
||||
import inspect
|
||||
fn = py.path.local(inspect.getfile(function))
|
||||
lineno = py.builtin._getcode(function).co_firstlineno
|
||||
if fn.relto(curdir):
|
||||
fn = fn.relto(curdir)
|
||||
return "%s:%d" %(fn, lineno+1)
|
||||
|
||||
|
||||
def num_mock_patch_args(function):
|
||||
""" return number of arguments used up by mock arguments (if any) """
|
||||
patchings = getattr(function, "patchings", None)
|
||||
if not patchings:
|
||||
return 0
|
||||
mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None))
|
||||
if mock is not None:
|
||||
return len([p for p in patchings
|
||||
if not p.attribute_name and p.new is mock.DEFAULT])
|
||||
return len(patchings)
|
||||
|
||||
|
||||
def getfuncargnames(function, startindex=None):
|
||||
# XXX merge with main.py's varnames
|
||||
#assert not isclass(function)
|
||||
realfunction = function
|
||||
while hasattr(realfunction, "__wrapped__"):
|
||||
realfunction = realfunction.__wrapped__
|
||||
if startindex is None:
|
||||
startindex = inspect.ismethod(function) and 1 or 0
|
||||
if realfunction != function:
|
||||
startindex += num_mock_patch_args(function)
|
||||
function = realfunction
|
||||
if isinstance(function, functools.partial):
|
||||
argnames = inspect.getargs(_pytest._code.getrawcode(function.func))[0]
|
||||
partial = function
|
||||
argnames = argnames[len(partial.args):]
|
||||
if partial.keywords:
|
||||
for kw in partial.keywords:
|
||||
argnames.remove(kw)
|
||||
else:
|
||||
argnames = inspect.getargs(_pytest._code.getrawcode(function))[0]
|
||||
defaults = getattr(function, 'func_defaults',
|
||||
getattr(function, '__defaults__', None)) or ()
|
||||
numdefaults = len(defaults)
|
||||
if numdefaults:
|
||||
return tuple(argnames[startindex:-numdefaults])
|
||||
return tuple(argnames[startindex:])
|
||||
|
||||
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
def isclass(object):
|
||||
""" Return true if the object is a class. Overrides inspect.isclass for
|
||||
python 2.6 because it will return True for objects which always return
|
||||
something on __getattr__ calls (see #1035).
|
||||
Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc
|
||||
"""
|
||||
return isinstance(object, (type, types.ClassType))
|
||||
|
||||
|
||||
if _PY3:
|
||||
import codecs
|
||||
|
||||
STRING_TYPES = bytes, str
|
||||
|
||||
def _escape_strings(val):
|
||||
"""If val is pure ascii, returns it as a str(). Otherwise, escapes
|
||||
bytes objects into a sequence of escaped bytes:
|
||||
|
||||
b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
|
||||
|
||||
and escapes unicode objects into a sequence of escaped unicode
|
||||
ids, e.g.:
|
||||
|
||||
'4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944'
|
||||
|
||||
note:
|
||||
the obvious "v.decode('unicode-escape')" will return
|
||||
valid utf-8 unicode if it finds them in bytes, but we
|
||||
want to return escaped bytes for any byte, even if they match
|
||||
a utf-8 string.
|
||||
|
||||
"""
|
||||
if isinstance(val, bytes):
|
||||
if val:
|
||||
# source: http://goo.gl/bGsnwC
|
||||
encoded_bytes, _ = codecs.escape_encode(val)
|
||||
return encoded_bytes.decode('ascii')
|
||||
else:
|
||||
# empty bytes crashes codecs.escape_encode (#1087)
|
||||
return ''
|
||||
else:
|
||||
return val.encode('unicode_escape').decode('ascii')
|
||||
else:
|
||||
STRING_TYPES = bytes, str, unicode
|
||||
|
||||
def _escape_strings(val):
|
||||
"""In py2 bytes and str are the same type, so return if it's a bytes
|
||||
object, return it unchanged if it is a full ascii string,
|
||||
otherwise escape it into its binary form.
|
||||
|
||||
If it's a unicode string, change the unicode characters into
|
||||
unicode escapes.
|
||||
|
||||
"""
|
||||
if isinstance(val, bytes):
|
||||
try:
|
||||
return val.encode('ascii')
|
||||
except UnicodeDecodeError:
|
||||
return val.encode('string-escape')
|
||||
else:
|
||||
return val.encode('unicode-escape')
|
||||
|
||||
|
||||
def get_real_func(obj):
|
||||
""" gets the real function object of the (possibly) wrapped object by
|
||||
functools.wraps or functools.partial.
|
||||
"""
|
||||
while hasattr(obj, "__wrapped__"):
|
||||
obj = obj.__wrapped__
|
||||
if isinstance(obj, functools.partial):
|
||||
obj = obj.func
|
||||
return obj
|
||||
|
||||
def getfslineno(obj):
|
||||
# xxx let decorators etc specify a sane ordering
|
||||
obj = get_real_func(obj)
|
||||
if hasattr(obj, 'place_as'):
|
||||
obj = obj.place_as
|
||||
fslineno = _pytest._code.getfslineno(obj)
|
||||
assert isinstance(fslineno[1], int), obj
|
||||
return fslineno
|
||||
|
||||
def getimfunc(func):
|
||||
try:
|
||||
return func.__func__
|
||||
except AttributeError:
|
||||
try:
|
||||
return func.im_func
|
||||
except AttributeError:
|
||||
return func
|
||||
|
||||
def safe_getattr(object, name, default):
|
||||
""" Like getattr but return default upon any Exception.
|
||||
|
||||
Attribute access can potentially fail for 'evil' Python objects.
|
||||
See issue214
|
||||
"""
|
||||
try:
|
||||
return getattr(object, name, default)
|
||||
except Exception:
|
||||
return default
|
|
@ -63,7 +63,7 @@ class UsageError(Exception):
|
|||
_preinit = []
|
||||
|
||||
default_plugins = (
|
||||
"mark main terminal runner python debugging unittest capture skipping "
|
||||
"mark main terminal runner python fixtures debugging unittest capture skipping "
|
||||
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion "
|
||||
"junitxml resultlog doctest cacheprovider freeze_support "
|
||||
"setuponly setupplan").split()
|
||||
|
|
|
@ -5,7 +5,7 @@ import traceback
|
|||
|
||||
import pytest
|
||||
from _pytest._code.code import TerminalRepr, ReprFileLocation, ExceptionInfo
|
||||
from _pytest.python import FixtureRequest
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
1321
_pytest/python.py
1321
_pytest/python.py
File diff suppressed because it is too large
Load Diff
|
@ -334,7 +334,7 @@ class TestFunction:
|
|||
reprec.assertoutcome()
|
||||
|
||||
def test_function_equality(self, testdir, tmpdir):
|
||||
from _pytest.python import FixtureManager
|
||||
from _pytest.fixtures import FixtureManager
|
||||
config = testdir.parseconfigure()
|
||||
session = testdir.Session(config)
|
||||
session._fixturemanager = FixtureManager(session)
|
||||
|
|
|
@ -3,31 +3,30 @@ from textwrap import dedent
|
|||
import _pytest._code
|
||||
import pytest
|
||||
import sys
|
||||
from _pytest import python as funcargs
|
||||
from _pytest.pytester import get_public_names
|
||||
from _pytest.python import FixtureLookupError
|
||||
|
||||
from _pytest.fixtures import FixtureLookupError
|
||||
from _pytest import fixtures
|
||||
|
||||
def test_getfuncargnames():
|
||||
def f(): pass
|
||||
assert not funcargs.getfuncargnames(f)
|
||||
assert not fixtures.getfuncargnames(f)
|
||||
def g(arg): pass
|
||||
assert funcargs.getfuncargnames(g) == ('arg',)
|
||||
assert fixtures.getfuncargnames(g) == ('arg',)
|
||||
def h(arg1, arg2="hello"): pass
|
||||
assert funcargs.getfuncargnames(h) == ('arg1',)
|
||||
assert fixtures.getfuncargnames(h) == ('arg1',)
|
||||
def h(arg1, arg2, arg3="hello"): pass
|
||||
assert funcargs.getfuncargnames(h) == ('arg1', 'arg2')
|
||||
assert fixtures.getfuncargnames(h) == ('arg1', 'arg2')
|
||||
class A:
|
||||
def f(self, arg1, arg2="hello"):
|
||||
pass
|
||||
assert funcargs.getfuncargnames(A().f) == ('arg1',)
|
||||
assert fixtures.getfuncargnames(A().f) == ('arg1',)
|
||||
if sys.version_info < (3,0):
|
||||
assert funcargs.getfuncargnames(A.f) == ('arg1',)
|
||||
assert fixtures.getfuncargnames(A.f) == ('arg1',)
|
||||
|
||||
class TestFillFixtures:
|
||||
def test_fillfuncargs_exposed(self):
|
||||
# used by oejskit, kept for compatibility
|
||||
assert pytest._fillfuncargs == funcargs.fillfixtures
|
||||
assert pytest._fillfuncargs == fixtures.fillfixtures
|
||||
|
||||
def test_funcarg_lookupfails(self, testdir):
|
||||
testdir.makepyfile("""
|
||||
|
@ -54,7 +53,7 @@ class TestFillFixtures:
|
|||
def test_func(some, other):
|
||||
pass
|
||||
""")
|
||||
funcargs.fillfixtures(item)
|
||||
fixtures.fillfixtures(item)
|
||||
del item.funcargs["request"]
|
||||
assert len(get_public_names(item.funcargs)) == 2
|
||||
assert item.funcargs['some'] == "test_func"
|
||||
|
@ -400,7 +399,7 @@ class TestRequestBasic:
|
|||
def pytest_funcarg__something(request): pass
|
||||
def test_func(something): pass
|
||||
""")
|
||||
req = funcargs.FixtureRequest(item)
|
||||
req = fixtures.FixtureRequest(item)
|
||||
assert req.function == item.obj
|
||||
assert req.keywords == item.keywords
|
||||
assert hasattr(req.module, 'test_func')
|
||||
|
@ -431,7 +430,7 @@ class TestRequestBasic:
|
|||
""")
|
||||
item1, = testdir.genitems([modcol])
|
||||
assert item1.name == "test_method"
|
||||
arg2fixturedefs = funcargs.FixtureRequest(item1)._arg2fixturedefs
|
||||
arg2fixturedefs = fixtures.FixtureRequest(item1)._arg2fixturedefs
|
||||
assert len(arg2fixturedefs) == 1
|
||||
assert arg2fixturedefs[0].__name__ == "pytest_funcarg__something"
|
||||
|
||||
|
@ -558,7 +557,7 @@ class TestRequestBasic:
|
|||
def test_request_getmodulepath(self, testdir):
|
||||
modcol = testdir.getmodulecol("def test_somefunc(): pass")
|
||||
item, = testdir.genitems([modcol])
|
||||
req = funcargs.FixtureRequest(item)
|
||||
req = fixtures.FixtureRequest(item)
|
||||
assert req.fspath == modcol.fspath
|
||||
|
||||
def test_request_fixturenames(self, testdir):
|
||||
|
@ -687,7 +686,7 @@ class TestRequestMarking:
|
|||
def test_func2(self, something):
|
||||
pass
|
||||
""")
|
||||
req1 = funcargs.FixtureRequest(item1)
|
||||
req1 = fixtures.FixtureRequest(item1)
|
||||
assert 'xfail' not in item1.keywords
|
||||
req1.applymarker(pytest.mark.xfail)
|
||||
assert 'xfail' in item1.keywords
|
||||
|
@ -769,7 +768,7 @@ class TestRequestCachedSetup:
|
|||
|
||||
def test_request_cachedsetup_extrakey(self, testdir):
|
||||
item1 = testdir.getitem("def test_func(): pass")
|
||||
req1 = funcargs.FixtureRequest(item1)
|
||||
req1 = fixtures.FixtureRequest(item1)
|
||||
l = ["hello", "world"]
|
||||
def setup():
|
||||
return l.pop()
|
||||
|
@ -784,7 +783,7 @@ class TestRequestCachedSetup:
|
|||
|
||||
def test_request_cachedsetup_cache_deletion(self, testdir):
|
||||
item1 = testdir.getitem("def test_func(): pass")
|
||||
req1 = funcargs.FixtureRequest(item1)
|
||||
req1 = fixtures.FixtureRequest(item1)
|
||||
l = []
|
||||
def setup():
|
||||
l.append("setup")
|
||||
|
|
|
@ -73,7 +73,7 @@ def test_wrapped_getfslineno():
|
|||
|
||||
class TestMockDecoration:
|
||||
def test_wrapped_getfuncargnames(self):
|
||||
from _pytest.python import getfuncargnames
|
||||
from _pytest.compat import getfuncargnames
|
||||
def wrap(f):
|
||||
def func():
|
||||
pass
|
||||
|
@ -86,7 +86,7 @@ class TestMockDecoration:
|
|||
assert l == ("x",)
|
||||
|
||||
def test_wrapped_getfuncargnames_patching(self):
|
||||
from _pytest.python import getfuncargnames
|
||||
from _pytest.compat import getfuncargnames
|
||||
def wrap(f):
|
||||
def func():
|
||||
pass
|
||||
|
@ -234,7 +234,7 @@ class TestReRunTests:
|
|||
""")
|
||||
|
||||
def test_pytestconfig_is_session_scoped():
|
||||
from _pytest.python import pytestconfig
|
||||
from _pytest.fixtures import pytestconfig
|
||||
assert pytestconfig._pytestfixturefunction.scope == "session"
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import sys
|
|||
import _pytest._code
|
||||
import py
|
||||
import pytest
|
||||
from _pytest import python as funcargs
|
||||
from _pytest import python, fixtures
|
||||
|
||||
import hypothesis
|
||||
from hypothesis import strategies
|
||||
|
@ -22,9 +22,9 @@ class TestMetafunc:
|
|||
name2fixturedefs = None
|
||||
def __init__(self, names):
|
||||
self.names_closure = names
|
||||
names = funcargs.getfuncargnames(func)
|
||||
names = fixtures.getfuncargnames(func)
|
||||
fixtureinfo = FixtureInfo(names)
|
||||
return funcargs.Metafunc(func, fixtureinfo, None)
|
||||
return python.Metafunc(func, fixtureinfo, None)
|
||||
|
||||
def test_no_funcargs(self, testdir):
|
||||
def function(): pass
|
||||
|
@ -558,16 +558,16 @@ class TestMetafunc:
|
|||
|
||||
def test_format_args(self):
|
||||
def function1(): pass
|
||||
assert funcargs._format_args(function1) == '()'
|
||||
assert fixtures._format_args(function1) == '()'
|
||||
|
||||
def function2(arg1): pass
|
||||
assert funcargs._format_args(function2) == "(arg1)"
|
||||
assert fixtures._format_args(function2) == "(arg1)"
|
||||
|
||||
def function3(arg1, arg2="qwe"): pass
|
||||
assert funcargs._format_args(function3) == "(arg1, arg2='qwe')"
|
||||
assert fixtures._format_args(function3) == "(arg1, arg2='qwe')"
|
||||
|
||||
def function4(arg1, *args, **kwargs): pass
|
||||
assert funcargs._format_args(function4) == "(arg1, *args, **kwargs)"
|
||||
assert fixtures._format_args(function4) == "(arg1, *args, **kwargs)"
|
||||
|
||||
|
||||
class TestMetafuncFunctional:
|
||||
|
|
Loading…
Reference in New Issue