PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/_pytest/python.py

https://bitbucket.org/pjenvey/pypy-mq
Python | 1967 lines | 1842 code | 65 blank | 60 comment | 126 complexity | f64f23535fd1193f384c96a13811b7e1 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. """ Python test discovery, setup and run of test functions. """
  2. import py
  3. import inspect
  4. import sys
  5. import pytest
  6. from _pytest.mark import MarkDecorator
  7. from py._code.code import TerminalRepr
  8. import _pytest
  9. cutdir = py.path.local(_pytest.__file__).dirpath()
  10. NoneType = type(None)
  11. NOTSET = object()
  12. callable = py.builtin.callable
  13. def getfslineno(obj):
  14. # xxx let decorators etc specify a sane ordering
  15. while hasattr(obj, "__wrapped__"):
  16. obj = obj.__wrapped__
  17. if hasattr(obj, 'place_as'):
  18. obj = obj.place_as
  19. fslineno = py.code.getfslineno(obj)
  20. assert isinstance(fslineno[1], int), obj
  21. return fslineno
  22. def getimfunc(func):
  23. try:
  24. return func.__func__
  25. except AttributeError:
  26. try:
  27. return func.im_func
  28. except AttributeError:
  29. return func
  30. class FixtureFunctionMarker:
  31. def __init__(self, scope, params,
  32. autouse=False, yieldctx=False, ids=None):
  33. self.scope = scope
  34. self.params = params
  35. self.autouse = autouse
  36. self.yieldctx = yieldctx
  37. self.ids = ids
  38. def __call__(self, function):
  39. if inspect.isclass(function):
  40. raise ValueError(
  41. "class fixtures not supported (may be in the future)")
  42. function._pytestfixturefunction = self
  43. return function
  44. def fixture(scope="function", params=None, autouse=False, ids=None):
  45. """ (return a) decorator to mark a fixture factory function.
  46. This decorator can be used (with or or without parameters) to define
  47. a fixture function. The name of the fixture function can later be
  48. referenced to cause its invocation ahead of running tests: test
  49. modules or classes can use the pytest.mark.usefixtures(fixturename)
  50. marker. Test functions can directly use fixture names as input
  51. arguments in which case the fixture instance returned from the fixture
  52. function will be injected.
  53. :arg scope: the scope for which this fixture is shared, one of
  54. "function" (default), "class", "module", "session".
  55. :arg params: an optional list of parameters which will cause multiple
  56. invocations of the fixture function and all of the tests
  57. using it.
  58. :arg autouse: if True, the fixture func is activated for all tests that
  59. can see it. If False (the default) then an explicit
  60. reference is needed to activate the fixture.
  61. :arg ids: list of string ids each corresponding to the params
  62. so that they are part of the test id. If no ids are provided
  63. they will be generated automatically from the params.
  64. """
  65. if callable(scope) and params is None and autouse == False:
  66. # direct decoration
  67. return FixtureFunctionMarker(
  68. "function", params, autouse)(scope)
  69. if params is not None and not isinstance(params, (list, tuple)):
  70. params = list(params)
  71. return FixtureFunctionMarker(scope, params, autouse, ids=ids)
  72. def yield_fixture(scope="function", params=None, autouse=False, ids=None):
  73. """ (return a) decorator to mark a yield-fixture factory function
  74. (EXPERIMENTAL).
  75. This takes the same arguments as :py:func:`pytest.fixture` but
  76. expects a fixture function to use a ``yield`` instead of a ``return``
  77. statement to provide a fixture. See
  78. http://pytest.org/en/latest/yieldfixture.html for more info.
  79. """
  80. if callable(scope) and params is None and autouse == False:
  81. # direct decoration
  82. return FixtureFunctionMarker(
  83. "function", params, autouse, yieldctx=True)(scope)
  84. else:
  85. return FixtureFunctionMarker(scope, params, autouse,
  86. yieldctx=True, ids=ids)
  87. defaultfuncargprefixmarker = fixture()
  88. def pyobj_property(name):
  89. def get(self):
  90. node = self.getparent(getattr(pytest, name))
  91. if node is not None:
  92. return node.obj
  93. doc = "python %s object this node was collected from (can be None)." % (
  94. name.lower(),)
  95. return property(get, None, None, doc)
  96. def pytest_addoption(parser):
  97. group = parser.getgroup("general")
  98. group.addoption('--fixtures', '--funcargs',
  99. action="store_true", dest="showfixtures", default=False,
  100. help="show available fixtures, sorted by plugin appearance")
  101. parser.addini("usefixtures", type="args", default=[],
  102. help="list of default fixtures to be used with this project")
  103. parser.addini("python_files", type="args",
  104. default=('test_*.py', '*_test.py'),
  105. help="glob-style file patterns for Python test module discovery")
  106. parser.addini("python_classes", type="args", default=("Test",),
  107. help="prefixes for Python test class discovery")
  108. parser.addini("python_functions", type="args", default=("test",),
  109. help="prefixes for Python test function and method discovery")
  110. def pytest_cmdline_main(config):
  111. if config.option.showfixtures:
  112. showfixtures(config)
  113. return 0
  114. def pytest_generate_tests(metafunc):
  115. try:
  116. markers = metafunc.function.parametrize
  117. except AttributeError:
  118. return
  119. for marker in markers:
  120. metafunc.parametrize(*marker.args, **marker.kwargs)
  121. def pytest_configure(config):
  122. config.addinivalue_line("markers",
  123. "parametrize(argnames, argvalues): call a test function multiple "
  124. "times passing in different arguments in turn. argvalues generally "
  125. "needs to be a list of values if argnames specifies only one name "
  126. "or a list of tuples of values if argnames specifies multiple names. "
  127. "Example: @parametrize('arg1', [1,2]) would lead to two calls of the "
  128. "decorated test function, one with arg1=1 and another with arg1=2."
  129. "see http://pytest.org/latest/parametrize.html for more info and "
  130. "examples."
  131. )
  132. config.addinivalue_line("markers",
  133. "usefixtures(fixturename1, fixturename2, ...): mark tests as needing "
  134. "all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures "
  135. )
  136. def pytest_sessionstart(session):
  137. session._fixturemanager = FixtureManager(session)
  138. @pytest.mark.trylast
  139. def pytest_namespace():
  140. raises.Exception = pytest.fail.Exception
  141. return {
  142. 'fixture': fixture,
  143. 'yield_fixture': yield_fixture,
  144. 'raises' : raises,
  145. 'collect': {
  146. 'Module': Module, 'Class': Class, 'Instance': Instance,
  147. 'Function': Function, 'Generator': Generator,
  148. '_fillfuncargs': fillfixtures}
  149. }
  150. @fixture(scope="session")
  151. def pytestconfig(request):
  152. """ the pytest config object with access to command line opts."""
  153. return request.config
  154. def pytest_pyfunc_call(__multicall__, pyfuncitem):
  155. if not __multicall__.execute():
  156. testfunction = pyfuncitem.obj
  157. if pyfuncitem._isyieldedfunction():
  158. testfunction(*pyfuncitem._args)
  159. else:
  160. funcargs = pyfuncitem.funcargs
  161. testargs = {}
  162. for arg in pyfuncitem._fixtureinfo.argnames:
  163. testargs[arg] = funcargs[arg]
  164. testfunction(**testargs)
  165. def pytest_collect_file(path, parent):
  166. ext = path.ext
  167. if ext == ".py":
  168. if not parent.session.isinitpath(path):
  169. for pat in parent.config.getini('python_files'):
  170. if path.fnmatch(pat):
  171. break
  172. else:
  173. return
  174. ihook = parent.session.gethookproxy(path)
  175. return ihook.pytest_pycollect_makemodule(path=path, parent=parent)
  176. def pytest_pycollect_makemodule(path, parent):
  177. return Module(path, parent)
  178. def pytest_pycollect_makeitem(__multicall__, collector, name, obj):
  179. res = __multicall__.execute()
  180. if res is not None:
  181. return res
  182. if inspect.isclass(obj):
  183. #if hasattr(collector.obj, 'unittest'):
  184. # return # we assume it's a mixin class for a TestCase derived one
  185. if collector.classnamefilter(name):
  186. Class = collector._getcustomclass("Class")
  187. return Class(name, parent=collector)
  188. elif collector.funcnamefilter(name) and hasattr(obj, '__call__') and \
  189. getfixturemarker(obj) is None:
  190. if is_generator(obj):
  191. return Generator(name, parent=collector)
  192. else:
  193. return list(collector._genfunctions(name, obj))
  194. def is_generator(func):
  195. try:
  196. return py.code.getrawcode(func).co_flags & 32 # generator function
  197. except AttributeError: # builtin functions have no bytecode
  198. # assume them to not be generators
  199. return False
  200. class PyobjContext(object):
  201. module = pyobj_property("Module")
  202. cls = pyobj_property("Class")
  203. instance = pyobj_property("Instance")
  204. class PyobjMixin(PyobjContext):
  205. def obj():
  206. def fget(self):
  207. try:
  208. return self._obj
  209. except AttributeError:
  210. self._obj = obj = self._getobj()
  211. return obj
  212. def fset(self, value):
  213. self._obj = value
  214. return property(fget, fset, None, "underlying python object")
  215. obj = obj()
  216. def _getobj(self):
  217. return getattr(self.parent.obj, self.name)
  218. def getmodpath(self, stopatmodule=True, includemodule=False):
  219. """ return python path relative to the containing module. """
  220. chain = self.listchain()
  221. chain.reverse()
  222. parts = []
  223. for node in chain:
  224. if isinstance(node, Instance):
  225. continue
  226. name = node.name
  227. if isinstance(node, Module):
  228. assert name.endswith(".py")
  229. name = name[:-3]
  230. if stopatmodule:
  231. if includemodule:
  232. parts.append(name)
  233. break
  234. parts.append(name)
  235. parts.reverse()
  236. s = ".".join(parts)
  237. return s.replace(".[", "[")
  238. def _getfslineno(self):
  239. return getfslineno(self.obj)
  240. def reportinfo(self):
  241. # XXX caching?
  242. obj = self.obj
  243. if hasattr(obj, 'compat_co_firstlineno'):
  244. # nose compatibility
  245. fspath = sys.modules[obj.__module__].__file__
  246. if fspath.endswith(".pyc"):
  247. fspath = fspath[:-1]
  248. lineno = obj.compat_co_firstlineno
  249. else:
  250. fspath, lineno = getfslineno(obj)
  251. modpath = self.getmodpath()
  252. assert isinstance(lineno, int)
  253. return fspath, lineno, modpath
  254. class PyCollector(PyobjMixin, pytest.Collector):
  255. def funcnamefilter(self, name):
  256. for prefix in self.config.getini("python_functions"):
  257. if name.startswith(prefix):
  258. return True
  259. def classnamefilter(self, name):
  260. for prefix in self.config.getini("python_classes"):
  261. if name.startswith(prefix):
  262. return True
  263. def collect(self):
  264. # NB. we avoid random getattrs and peek in the __dict__ instead
  265. # (XXX originally introduced from a PyPy need, still true?)
  266. dicts = [getattr(self.obj, '__dict__', {})]
  267. for basecls in inspect.getmro(self.obj.__class__):
  268. dicts.append(basecls.__dict__)
  269. seen = {}
  270. l = []
  271. for dic in dicts:
  272. for name, obj in dic.items():
  273. if name in seen:
  274. continue
  275. seen[name] = True
  276. res = self.makeitem(name, obj)
  277. if res is None:
  278. continue
  279. if not isinstance(res, list):
  280. res = [res]
  281. l.extend(res)
  282. l.sort(key=lambda item: item.reportinfo()[:2])
  283. return l
  284. def makeitem(self, name, obj):
  285. #assert self.ihook.fspath == self.fspath, self
  286. return self.ihook.pytest_pycollect_makeitem(
  287. collector=self, name=name, obj=obj)
  288. def _genfunctions(self, name, funcobj):
  289. module = self.getparent(Module).obj
  290. clscol = self.getparent(Class)
  291. cls = clscol and clscol.obj or None
  292. transfer_markers(funcobj, cls, module)
  293. fm = self.session._fixturemanager
  294. fixtureinfo = fm.getfixtureinfo(self, funcobj, cls)
  295. metafunc = Metafunc(funcobj, fixtureinfo, self.config,
  296. cls=cls, module=module)
  297. gentesthook = self.config.hook.pytest_generate_tests
  298. extra = [module]
  299. if cls is not None:
  300. extra.append(cls())
  301. plugins = self.getplugins() + extra
  302. gentesthook.pcall(plugins, metafunc=metafunc)
  303. Function = self._getcustomclass("Function")
  304. if not metafunc._calls:
  305. yield Function(name, parent=self)
  306. else:
  307. # add funcargs() as fixturedefs to fixtureinfo.arg2fixturedefs
  308. add_funcarg_pseudo_fixture_def(self, metafunc, fm)
  309. for callspec in metafunc._calls:
  310. subname = "%s[%s]" %(name, callspec.id)
  311. yield Function(name=subname, parent=self,
  312. callspec=callspec, callobj=funcobj,
  313. keywords={callspec.id:True})
  314. def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
  315. # this function will transform all collected calls to a functions
  316. # if they use direct funcargs (i.e. direct parametrization)
  317. # because we want later test execution to be able to rely on
  318. # an existing FixtureDef structure for all arguments.
  319. # XXX we can probably avoid this algorithm if we modify CallSpec2
  320. # to directly care for creating the fixturedefs within its methods.
  321. if not metafunc._calls[0].funcargs:
  322. return # this function call does not have direct parametrization
  323. # collect funcargs of all callspecs into a list of values
  324. arg2params = {}
  325. arg2scope = {}
  326. for callspec in metafunc._calls:
  327. for argname, argvalue in callspec.funcargs.items():
  328. assert argname not in callspec.params
  329. callspec.params[argname] = argvalue
  330. arg2params_list = arg2params.setdefault(argname, [])
  331. callspec.indices[argname] = len(arg2params_list)
  332. arg2params_list.append(argvalue)
  333. if argname not in arg2scope:
  334. scopenum = callspec._arg2scopenum.get(argname,
  335. scopenum_function)
  336. arg2scope[argname] = scopes[scopenum]
  337. callspec.funcargs.clear()
  338. # register artificial FixtureDef's so that later at test execution
  339. # time we can rely on a proper FixtureDef to exist for fixture setup.
  340. arg2fixturedefs = metafunc._arg2fixturedefs
  341. for argname, valuelist in arg2params.items():
  342. # if we have a scope that is higher than function we need
  343. # to make sure we only ever create an according fixturedef on
  344. # a per-scope basis. We thus store and cache the fixturedef on the
  345. # node related to the scope.
  346. scope = arg2scope[argname]
  347. node = None
  348. if scope != "function":
  349. node = get_scope_node(collector, scope)
  350. if node is None:
  351. assert scope == "class" and isinstance(collector, Module)
  352. # use module-level collector for class-scope (for now)
  353. node = collector
  354. if node and argname in node._name2pseudofixturedef:
  355. arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
  356. else:
  357. fixturedef = FixtureDef(fixturemanager, '', argname,
  358. get_direct_param_fixture_func,
  359. arg2scope[argname],
  360. valuelist, False, False)
  361. arg2fixturedefs[argname] = [fixturedef]
  362. if node is not None:
  363. node._name2pseudofixturedef[argname] = fixturedef
  364. def get_direct_param_fixture_func(request):
  365. return request.param
  366. class FuncFixtureInfo:
  367. def __init__(self, argnames, names_closure, name2fixturedefs):
  368. self.argnames = argnames
  369. self.names_closure = names_closure
  370. self.name2fixturedefs = name2fixturedefs
  371. def transfer_markers(funcobj, cls, mod):
  372. # XXX this should rather be code in the mark plugin or the mark
  373. # plugin should merge with the python plugin.
  374. for holder in (cls, mod):
  375. try:
  376. pytestmark = holder.pytestmark
  377. except AttributeError:
  378. continue
  379. if isinstance(pytestmark, list):
  380. for mark in pytestmark:
  381. mark(funcobj)
  382. else:
  383. pytestmark(funcobj)
  384. class Module(pytest.File, PyCollector):
  385. """ Collector for test classes and functions. """
  386. def _getobj(self):
  387. return self._memoizedcall('_obj', self._importtestmodule)
  388. def collect(self):
  389. self.session._fixturemanager.parsefactories(self)
  390. return super(Module, self).collect()
  391. def _importtestmodule(self):
  392. # we assume we are only called once per module
  393. try:
  394. mod = self.fspath.pyimport(ensuresyspath=True)
  395. except SyntaxError:
  396. excinfo = py.code.ExceptionInfo()
  397. raise self.CollectError(excinfo.getrepr(style="short"))
  398. except self.fspath.ImportMismatchError:
  399. e = sys.exc_info()[1]
  400. raise self.CollectError(
  401. "import file mismatch:\n"
  402. "imported module %r has this __file__ attribute:\n"
  403. " %s\n"
  404. "which is not the same as the test file we want to collect:\n"
  405. " %s\n"
  406. "HINT: remove __pycache__ / .pyc files and/or use a "
  407. "unique basename for your test file modules"
  408. % e.args
  409. )
  410. #print "imported test module", mod
  411. self.config.pluginmanager.consider_module(mod)
  412. return mod
  413. def setup(self):
  414. setup_module = xunitsetup(self.obj, "setUpModule")
  415. if setup_module is None:
  416. setup_module = xunitsetup(self.obj, "setup_module")
  417. if setup_module is not None:
  418. #XXX: nose compat hack, move to nose plugin
  419. # if it takes a positional arg, its probably a pytest style one
  420. # so we pass the current module object
  421. if inspect.getargspec(setup_module)[0]:
  422. setup_module(self.obj)
  423. else:
  424. setup_module()
  425. fin = getattr(self.obj, 'tearDownModule', None)
  426. if fin is None:
  427. fin = getattr(self.obj, 'teardown_module', None)
  428. if fin is not None:
  429. #XXX: nose compat hack, move to nose plugin
  430. # if it takes a positional arg, it's probably a pytest style one
  431. # so we pass the current module object
  432. if inspect.getargspec(fin)[0]:
  433. finalizer = lambda: fin(self.obj)
  434. else:
  435. finalizer = fin
  436. self.addfinalizer(finalizer)
  437. class Class(PyCollector):
  438. """ Collector for test methods. """
  439. def collect(self):
  440. if hasinit(self.obj):
  441. # XXX used to be skip(), but silently skipping classes
  442. # XXX just because they have been written long ago is
  443. # XXX imho a very, very, very bad idea
  444. pytest.fail("class %s.%s with __init__ won't get collected" % (
  445. self.obj.__module__,
  446. self.obj.__name__,
  447. ))
  448. return [self._getcustomclass("Instance")(name="()", parent=self)]
  449. def setup(self):
  450. setup_class = xunitsetup(self.obj, 'setup_class')
  451. if setup_class is not None:
  452. setup_class = getattr(setup_class, 'im_func', setup_class)
  453. setup_class = getattr(setup_class, '__func__', setup_class)
  454. setup_class(self.obj)
  455. fin_class = getattr(self.obj, 'teardown_class', None)
  456. if fin_class is not None:
  457. fin_class = getattr(fin_class, 'im_func', fin_class)
  458. fin_class = getattr(fin_class, '__func__', fin_class)
  459. self.addfinalizer(lambda: fin_class(self.obj))
  460. class Instance(PyCollector):
  461. def _getobj(self):
  462. obj = self.parent.obj()
  463. return obj
  464. def collect(self):
  465. self.session._fixturemanager.parsefactories(self)
  466. return super(Instance, self).collect()
  467. def newinstance(self):
  468. self.obj = self._getobj()
  469. return self.obj
  470. class FunctionMixin(PyobjMixin):
  471. """ mixin for the code common to Function and Generator.
  472. """
  473. def setup(self):
  474. """ perform setup for this test function. """
  475. if hasattr(self, '_preservedparent'):
  476. obj = self._preservedparent
  477. elif isinstance(self.parent, Instance):
  478. obj = self.parent.newinstance()
  479. self.obj = self._getobj()
  480. else:
  481. obj = self.parent.obj
  482. if inspect.ismethod(self.obj):
  483. setup_name = 'setup_method'
  484. teardown_name = 'teardown_method'
  485. else:
  486. setup_name = 'setup_function'
  487. teardown_name = 'teardown_function'
  488. setup_func_or_method = xunitsetup(obj, setup_name)
  489. if setup_func_or_method is not None:
  490. setup_func_or_method(self.obj)
  491. fin = getattr(obj, teardown_name, None)
  492. if fin is not None:
  493. self.addfinalizer(lambda: fin(self.obj))
  494. def _prunetraceback(self, excinfo):
  495. if hasattr(self, '_obj') and not self.config.option.fulltrace:
  496. code = py.code.Code(self.obj)
  497. path, firstlineno = code.path, code.firstlineno
  498. traceback = excinfo.traceback
  499. ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
  500. if ntraceback == traceback:
  501. ntraceback = ntraceback.cut(path=path)
  502. if ntraceback == traceback:
  503. ntraceback = ntraceback.cut(excludepath=cutdir)
  504. excinfo.traceback = ntraceback.filter()
  505. def _repr_failure_py(self, excinfo, style="long"):
  506. if excinfo.errisinstance(pytest.fail.Exception):
  507. if not excinfo.value.pytrace:
  508. return str(excinfo.value)
  509. return super(FunctionMixin, self)._repr_failure_py(excinfo,
  510. style=style)
  511. def repr_failure(self, excinfo, outerr=None):
  512. assert outerr is None, "XXX outerr usage is deprecated"
  513. return self._repr_failure_py(excinfo,
  514. style=self.config.option.tbstyle)
  515. class Generator(FunctionMixin, PyCollector):
  516. def collect(self):
  517. # test generators are seen as collectors but they also
  518. # invoke setup/teardown on popular request
  519. # (induced by the common "test_*" naming shared with normal tests)
  520. self.session._setupstate.prepare(self)
  521. # see FunctionMixin.setup and test_setupstate_is_preserved_134
  522. self._preservedparent = self.parent.obj
  523. l = []
  524. seen = {}
  525. for i, x in enumerate(self.obj()):
  526. name, call, args = self.getcallargs(x)
  527. if not callable(call):
  528. raise TypeError("%r yielded non callable test %r" %(self.obj, call,))
  529. if name is None:
  530. name = "[%d]" % i
  531. else:
  532. name = "['%s']" % name
  533. if name in seen:
  534. raise ValueError("%r generated tests with non-unique name %r" %(self, name))
  535. seen[name] = True
  536. l.append(self.Function(name, self, args=args, callobj=call))
  537. return l
  538. def getcallargs(self, obj):
  539. if not isinstance(obj, (tuple, list)):
  540. obj = (obj,)
  541. # explict naming
  542. if isinstance(obj[0], py.builtin._basestring):
  543. name = obj[0]
  544. obj = obj[1:]
  545. else:
  546. name = None
  547. call, args = obj[0], obj[1:]
  548. return name, call, args
  549. def hasinit(obj):
  550. init = getattr(obj, '__init__', None)
  551. if init:
  552. if init != object.__init__:
  553. return True
  554. def fillfixtures(function):
  555. """ fill missing funcargs for a test function. """
  556. try:
  557. request = function._request
  558. except AttributeError:
  559. # XXX this special code path is only expected to execute
  560. # with the oejskit plugin. It uses classes with funcargs
  561. # and we thus have to work a bit to allow this.
  562. fm = function.session._fixturemanager
  563. fi = fm.getfixtureinfo(function.parent, function.obj, None)
  564. function._fixtureinfo = fi
  565. request = function._request = FixtureRequest(function)
  566. request._fillfixtures()
  567. # prune out funcargs for jstests
  568. newfuncargs = {}
  569. for name in fi.argnames:
  570. newfuncargs[name] = function.funcargs[name]
  571. function.funcargs = newfuncargs
  572. else:
  573. request._fillfixtures()
  574. _notexists = object()
  575. class CallSpec2(object):
  576. def __init__(self, metafunc):
  577. self.metafunc = metafunc
  578. self.funcargs = {}
  579. self._idlist = []
  580. self.params = {}
  581. self._globalid = _notexists
  582. self._globalid_args = set()
  583. self._globalparam = _notexists
  584. self._arg2scopenum = {} # used for sorting parametrized resources
  585. self.keywords = {}
  586. self.indices = {}
  587. def copy(self, metafunc):
  588. cs = CallSpec2(self.metafunc)
  589. cs.funcargs.update(self.funcargs)
  590. cs.params.update(self.params)
  591. cs.keywords.update(self.keywords)
  592. cs.indices.update(self.indices)
  593. cs._arg2scopenum.update(self._arg2scopenum)
  594. cs._idlist = list(self._idlist)
  595. cs._globalid = self._globalid
  596. cs._globalid_args = self._globalid_args
  597. cs._globalparam = self._globalparam
  598. return cs
  599. def _checkargnotcontained(self, arg):
  600. if arg in self.params or arg in self.funcargs:
  601. raise ValueError("duplicate %r" %(arg,))
  602. def getparam(self, name):
  603. try:
  604. return self.params[name]
  605. except KeyError:
  606. if self._globalparam is _notexists:
  607. raise ValueError(name)
  608. return self._globalparam
  609. @property
  610. def id(self):
  611. return "-".join(map(str, filter(None, self._idlist)))
  612. def setmulti(self, valtype, argnames, valset, id, keywords, scopenum,
  613. param_index):
  614. for arg,val in zip(argnames, valset):
  615. self._checkargnotcontained(arg)
  616. getattr(self, valtype)[arg] = val
  617. self.indices[arg] = param_index
  618. self._arg2scopenum[arg] = scopenum
  619. if val is _notexists:
  620. self._emptyparamspecified = True
  621. self._idlist.append(id)
  622. self.keywords.update(keywords)
  623. def setall(self, funcargs, id, param):
  624. for x in funcargs:
  625. self._checkargnotcontained(x)
  626. self.funcargs.update(funcargs)
  627. if id is not _notexists:
  628. self._idlist.append(id)
  629. if param is not _notexists:
  630. assert self._globalparam is _notexists
  631. self._globalparam = param
  632. for arg in funcargs:
  633. self._arg2scopenum[arg] = scopenum_function
  634. class FuncargnamesCompatAttr:
  635. """ helper class so that Metafunc, Function and FixtureRequest
  636. don't need to each define the "funcargnames" compatibility attribute.
  637. """
  638. @property
  639. def funcargnames(self):
  640. """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
  641. return self.fixturenames
  642. class Metafunc(FuncargnamesCompatAttr):
  643. def __init__(self, function, fixtureinfo, config, cls=None, module=None):
  644. self.config = config
  645. self.module = module
  646. self.function = function
  647. self.fixturenames = fixtureinfo.names_closure
  648. self._arg2fixturedefs = fixtureinfo.name2fixturedefs
  649. self.cls = cls
  650. self.module = module
  651. self._calls = []
  652. self._ids = py.builtin.set()
  653. def parametrize(self, argnames, argvalues, indirect=False, ids=None,
  654. scope=None):
  655. """ Add new invocations to the underlying test function using the list
  656. of argvalues for the given argnames. Parametrization is performed
  657. during the collection phase. If you need to setup expensive resources
  658. see about setting indirect=True to do it rather at test setup time.
  659. :arg argnames: a comma-separated string denoting one or more argument
  660. names, or a list/tuple of argument strings.
  661. :arg argvalues: The list of argvalues determines how often a
  662. test is invoked with different argument values. If only one
  663. argname was specified argvalues is a list of simple values. If N
  664. argnames were specified, argvalues must be a list of N-tuples,
  665. where each tuple-element specifies a value for its respective
  666. argname.
  667. :arg indirect: if True each argvalue corresponding to an argname will
  668. be passed as request.param to its respective argname fixture
  669. function so that it can perform more expensive setups during the
  670. setup phase of a test rather than at collection time.
  671. :arg ids: list of string ids each corresponding to the argvalues so
  672. that they are part of the test id. If no ids are provided they will
  673. be generated automatically from the argvalues.
  674. :arg scope: if specified it denotes the scope of the parameters.
  675. The scope is used for grouping tests by parameter instances.
  676. It will also override any fixture-function defined scope, allowing
  677. to set a dynamic scope using test context or configuration.
  678. """
  679. # individual parametrized argument sets can be wrapped in a series
  680. # of markers in which case we unwrap the values and apply the mark
  681. # at Function init
  682. newkeywords = {}
  683. unwrapped_argvalues = []
  684. for i, argval in enumerate(argvalues):
  685. while isinstance(argval, MarkDecorator):
  686. newmark = MarkDecorator(argval.markname,
  687. argval.args[:-1], argval.kwargs)
  688. newmarks = newkeywords.setdefault(i, {})
  689. newmarks[newmark.markname] = newmark
  690. argval = argval.args[-1]
  691. unwrapped_argvalues.append(argval)
  692. argvalues = unwrapped_argvalues
  693. if not isinstance(argnames, (tuple, list)):
  694. argnames = [x.strip() for x in argnames.split(",") if x.strip()]
  695. if len(argnames) == 1:
  696. argvalues = [(val,) for val in argvalues]
  697. if not argvalues:
  698. argvalues = [(_notexists,) * len(argnames)]
  699. if scope is None:
  700. scope = "function"
  701. scopenum = scopes.index(scope)
  702. if not indirect:
  703. #XXX should we also check for the opposite case?
  704. for arg in argnames:
  705. if arg not in self.fixturenames:
  706. raise ValueError("%r uses no fixture %r" %(
  707. self.function, arg))
  708. valtype = indirect and "params" or "funcargs"
  709. if ids and len(ids) != len(argvalues):
  710. raise ValueError('%d tests specified with %d ids' %(
  711. len(argvalues), len(ids)))
  712. if not ids:
  713. ids = idmaker(argnames, argvalues)
  714. newcalls = []
  715. for callspec in self._calls or [CallSpec2(self)]:
  716. for param_index, valset in enumerate(argvalues):
  717. assert len(valset) == len(argnames)
  718. newcallspec = callspec.copy(self)
  719. newcallspec.setmulti(valtype, argnames, valset, ids[param_index],
  720. newkeywords.get(param_index, {}), scopenum,
  721. param_index)
  722. newcalls.append(newcallspec)
  723. self._calls = newcalls
  724. def addcall(self, funcargs=None, id=_notexists, param=_notexists):
  725. """ (deprecated, use parametrize) Add a new call to the underlying
  726. test function during the collection phase of a test run. Note that
  727. request.addcall() is called during the test collection phase prior and
  728. independently to actual test execution. You should only use addcall()
  729. if you need to specify multiple arguments of a test function.
  730. :arg funcargs: argument keyword dictionary used when invoking
  731. the test function.
  732. :arg id: used for reporting and identification purposes. If you
  733. don't supply an `id` an automatic unique id will be generated.
  734. :arg param: a parameter which will be exposed to a later fixture function
  735. invocation through the ``request.param`` attribute.
  736. """
  737. assert funcargs is None or isinstance(funcargs, dict)
  738. if funcargs is not None:
  739. for name in funcargs:
  740. if name not in self.fixturenames:
  741. pytest.fail("funcarg %r not used in this function." % name)
  742. else:
  743. funcargs = {}
  744. if id is None:
  745. raise ValueError("id=None not allowed")
  746. if id is _notexists:
  747. id = len(self._calls)
  748. id = str(id)
  749. if id in self._ids:
  750. raise ValueError("duplicate id %r" % id)
  751. self._ids.add(id)
  752. cs = CallSpec2(self)
  753. cs.setall(funcargs, id, param)
  754. self._calls.append(cs)
  755. def idmaker(argnames, argvalues):
  756. idlist = []
  757. for valindex, valset in enumerate(argvalues):
  758. this_id = []
  759. for nameindex, val in enumerate(valset):
  760. if not isinstance(val, (float, int, str, bool, NoneType)):
  761. this_id.append(str(argnames[nameindex])+str(valindex))
  762. else:
  763. this_id.append(str(val))
  764. idlist.append("-".join(this_id))
  765. return idlist
  766. def showfixtures(config):
  767. from _pytest.main import wrap_session
  768. return wrap_session(config, _showfixtures_main)
  769. def _showfixtures_main(config, session):
  770. session.perform_collect()
  771. curdir = py.path.local()
  772. if session.items:
  773. nodeid = session.items[0].nodeid
  774. else:
  775. part = session._initialparts[0]
  776. nodeid = "::".join(map(str, [curdir.bestrelpath(part[0])] + part[1:]))
  777. nodeid.replace(session.fspath.sep, "/")
  778. tw = py.io.TerminalWriter()
  779. verbose = config.getvalue("verbose")
  780. fm = session._fixturemanager
  781. available = []
  782. for argname in fm._arg2fixturedefs:
  783. fixturedefs = fm.getfixturedefs(argname, nodeid)
  784. assert fixturedefs is not None
  785. if not fixturedefs:
  786. continue
  787. fixturedef = fixturedefs[-1]
  788. loc = getlocation(fixturedef.func, curdir)
  789. available.append((len(fixturedef.baseid),
  790. fixturedef.func.__module__,
  791. curdir.bestrelpath(loc),
  792. fixturedef.argname, fixturedef))
  793. available.sort()
  794. currentmodule = None
  795. for baseid, module, bestrel, argname, fixturedef in available:
  796. if currentmodule != module:
  797. if not module.startswith("_pytest."):
  798. tw.line()
  799. tw.sep("-", "fixtures defined from %s" %(module,))
  800. currentmodule = module
  801. if verbose <= 0 and argname[0] == "_":
  802. continue
  803. if verbose > 0:
  804. funcargspec = "%s -- %s" %(argname, bestrel,)
  805. else:
  806. funcargspec = argname
  807. tw.line(funcargspec, green=True)
  808. loc = getlocation(fixturedef.func, curdir)
  809. doc = fixturedef.func.__doc__ or ""
  810. if doc:
  811. for line in doc.split("\n"):
  812. tw.line(" " + line.strip())
  813. else:
  814. tw.line(" %s: no docstring available" %(loc,),
  815. red=True)
  816. def getlocation(function, curdir):
  817. import inspect
  818. fn = py.path.local(inspect.getfile(function))
  819. lineno = py.builtin._getcode(function).co_firstlineno
  820. if fn.relto(curdir):
  821. fn = fn.relto(curdir)
  822. return "%s:%d" %(fn, lineno+1)
  823. # builtin pytest.raises helper
  824. def raises(ExpectedException, *args, **kwargs):
  825. """ assert that a code block/function call raises @ExpectedException
  826. and raise a failure exception otherwise.
  827. This helper produces a ``py.code.ExceptionInfo()`` object.
  828. If using Python 2.5 or above, you may use this function as a
  829. context manager::
  830. >>> with raises(ZeroDivisionError):
  831. ... 1/0
  832. Or you can specify a callable by passing a to-be-called lambda::
  833. >>> raises(ZeroDivisionError, lambda: 1/0)
  834. <ExceptionInfo ...>
  835. or you can specify an arbitrary callable with arguments::
  836. >>> def f(x): return 1/x
  837. ...
  838. >>> raises(ZeroDivisionError, f, 0)
  839. <ExceptionInfo ...>
  840. >>> raises(ZeroDivisionError, f, x=0)
  841. <ExceptionInfo ...>
  842. A third possibility is to use a string to be executed::
  843. >>> raises(ZeroDivisionError, "f(0)")
  844. <ExceptionInfo ...>
  845. Performance note:
  846. -----------------
  847. Similar to caught exception objects in Python, explicitly clearing local
  848. references to returned ``py.code.ExceptionInfo`` objects can help the Python
  849. interpreter speed up its garbage collection.
  850. Clearing those references breaks a reference cycle (``ExceptionInfo`` -->
  851. caught exception --> frame stack raising the exception --> current frame
  852. stack --> local variables --> ``ExceptionInfo``) which makes Python keep all
  853. objects referenced from that cycle (including all local variables in the
  854. current frame) alive until the next cyclic garbage collection run. See the
  855. official Python ``try`` statement documentation for more detailed
  856. information.
  857. """
  858. __tracebackhide__ = True
  859. if ExpectedException is AssertionError:
  860. # we want to catch a AssertionError
  861. # replace our subclass with the builtin one
  862. # see https://bitbucket.org/hpk42/pytest/issue/176/pytestraises
  863. from _pytest.assertion.util import BuiltinAssertionError as ExpectedException
  864. if not args:
  865. return RaisesContext(ExpectedException)
  866. elif isinstance(args[0], str):
  867. code, = args
  868. assert isinstance(code, str)
  869. frame = sys._getframe(1)
  870. loc = frame.f_locals.copy()
  871. loc.update(kwargs)
  872. #print "raises frame scope: %r" % frame.f_locals
  873. try:
  874. code = py.code.Source(code).compile()
  875. py.builtin.exec_(code, frame.f_globals, loc)
  876. # XXX didn'T mean f_globals == f_locals something special?
  877. # this is destroyed here ...
  878. except ExpectedException:
  879. return py.code.ExceptionInfo()
  880. else:
  881. func = args[0]
  882. try:
  883. func(*args[1:], **kwargs)
  884. except ExpectedException:
  885. return py.code.ExceptionInfo()
  886. pytest.fail("DID NOT RAISE")
  887. class RaisesContext(object):
  888. def __init__(self, ExpectedException):
  889. self.ExpectedException = ExpectedException
  890. self.excinfo = None
  891. def __enter__(self):
  892. self.excinfo = object.__new__(py.code.ExceptionInfo)
  893. return self.excinfo
  894. def __exit__(self, *tp):
  895. __tracebackhide__ = True
  896. if tp[0] is None:
  897. pytest.fail("DID NOT RAISE")
  898. self.excinfo.__init__(tp)
  899. return issubclass(self.excinfo.type, self.ExpectedException)
  900. #
  901. # the basic pytest Function item
  902. #
  903. class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr):
  904. """ a Function Item is responsible for setting up and executing a
  905. Python test function.
  906. """
  907. _genid = None
  908. def __init__(self, name, parent, args=None, config=None,
  909. callspec=None, callobj=NOTSET, keywords=None, session=None):
  910. super(Function, self).__init__(name, parent, config=config,
  911. session=session)
  912. self._args = args
  913. if callobj is not NOTSET:
  914. self.obj = callobj
  915. for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
  916. self.keywords[name] = val
  917. if callspec:
  918. for name, val in callspec.keywords.items():
  919. self.keywords[name] = val
  920. if keywords:
  921. for name, val in keywords.items():
  922. self.keywords[name] = val
  923. isyield = self._isyieldedfunction()
  924. self._fixtureinfo = fi = self.session._fixturemanager.getfixtureinfo(
  925. self.parent, self.obj, self.cls, funcargs=not isyield)
  926. self.fixturenames = fi.names_closure
  927. if callspec is not None:
  928. self.callspec = callspec
  929. self._initrequest()
  930. def _initrequest(self):
  931. self.funcargs = {}
  932. if self._isyieldedfunction():
  933. assert not hasattr(self, "callspec"), (
  934. "yielded functions (deprecated) cannot have funcargs")
  935. else:
  936. if hasattr(self, "callspec"):
  937. callspec = self.callspec
  938. assert not callspec.funcargs
  939. self._genid = callspec.id
  940. if hasattr(callspec, "param"):
  941. self.param = callspec.param
  942. self._request = FixtureRequest(self)
  943. @property
  944. def function(self):
  945. "underlying python 'function' object"
  946. return getattr(self.obj, 'im_func', self.obj)
  947. def _getobj(self):
  948. name = self.name
  949. i = name.find("[") # parametrization
  950. if i != -1:
  951. name = name[:i]
  952. return getattr(self.parent.obj, name)
  953. @property
  954. def _pyfuncitem(self):
  955. "(compatonly) for code expecting pytest-2.2 style request objects"
  956. return self
  957. def _isyieldedfunction(self):
  958. return getattr(self, "_args", None) is not None
  959. def runtest(self):
  960. """ execute the underlying test function. """
  961. self.ihook.pytest_pyfunc_call(pyfuncitem=self)
  962. def setup(self):
  963. # check if parametrization happend with an empty list
  964. try:
  965. self.callspec._emptyparamspecified
  966. except AttributeError:
  967. pass
  968. else:
  969. fs, lineno = self._getfslineno()
  970. pytest.skip("got empty parameter set, function %s at %s:%d" %(
  971. self.function.__name__, fs, lineno))
  972. super(Function, self).setup()
  973. fillfixtures(self)
  974. scope2props = dict(session=())
  975. scope2props["module"] = ("fspath", "module")
  976. scope2props["class"] = scope2props["module"] + ("cls",)
  977. scope2props["instance"] = scope2props["class"] + ("instance", )
  978. scope2props["function"] = scope2props["instance"] + ("function", "keywords")
  979. def scopeproperty(name=None, doc=None):
  980. def decoratescope(func):
  981. scopename = name or func.__name__
  982. def provide(self):
  983. if func.__name__ in scope2props[self.scope]:
  984. return func(self)
  985. raise AttributeError("%s not available in %s-scoped context" % (
  986. scopename, self.scope))
  987. return property(provide, None, None, func.__doc__)
  988. return decoratescope
  989. class FixtureRequest(FuncargnamesCompatAttr):
  990. """ A request for a fixture from a test or fixture function.
  991. A request object gives access to the requesting test context
  992. and has an optional ``param`` attribute in case
  993. the fixture is parametrized indirectly.
  994. """
  995. def __init__(self, pyfuncitem):
  996. self._pyfuncitem = pyfuncitem
  997. #: fixture for which this request is being performed
  998. self.fixturename = None
  999. #: Scope string, one of "function", "cls", "module", "session"
  1000. self.scope = "function"
  1001. self._funcargs = {}
  1002. self._fixturedefs = {}
  1003. fixtureinfo = pyfuncitem._fixtureinfo
  1004. self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
  1005. self._arg2index = {}
  1006. self.fixturenames = fixtureinfo.names_closure
  1007. self._fixturemanager = pyfuncitem.session._fixturemanager
  1008. @property
  1009. def node(self):
  1010. """ underlying collection node (depends on current request scope)"""
  1011. return self._getscopeitem(self.scope)
  1012. def _getnextfixturedef(self, argname):
  1013. fixturedefs = self._arg2fixturedefs.get(argname, None)
  1014. if fixturedefs is None:
  1015. # we arrive here because of a a dynamic call to
  1016. # getfuncargvalue(argname) usage which was naturally
  1017. # not known at parsing/collection time
  1018. fixturedefs = self._fixturemanager.getfixturedefs(
  1019. argname, self._pyfuncitem.parent.nodeid)
  1020. self._arg2fixturedefs[argname] = fixturedefs
  1021. # fixturedefs list is immutable so we maintain a decreasing index
  1022. index = self._arg2index.get(argname, 0) - 1
  1023. if fixturedefs is None or (-index > len(fixturedefs)):
  1024. raise FixtureLookupError(argname, self)
  1025. self._arg2index[argname] = index
  1026. return fixturedefs[index]
  1027. @property
  1028. def config(self):
  1029. """ the pytest config object associated with this request. """
  1030. return self._pyfuncitem.config
  1031. @scopeproperty()
  1032. def function(self):
  1033. """ test function object if the request has a per-function scope. """
  1034. return self._pyfuncitem.obj
  1035. @scopeproperty("class")
  1036. def cls(self):
  1037. """ class (can be None) where the test function was collected. """
  1038. clscol = self._pyfuncitem.getparent(pytest.Class)
  1039. if clscol:
  1040. return clscol.obj
  1041. @property
  1042. def instance(self):
  1043. """ instance (can be None) on which test function was collected. """
  1044. # unittest support hack, see _pytest.unittest.TestCaseFunction
  1045. try:
  1046. return self._pyfuncitem._testcase
  1047. except AttributeError:
  1048. function = getattr(self, "function", None)
  1049. if function is not None:
  1050. return py.builtin._getimself(function)
  1051. @scopeproperty()
  1052. def module(self):
  1053. """ python module object where the test function was collected. """
  1054. return self._pyfuncitem.getparent(pytest.Module).obj
  1055. @scopeproperty()
  1056. def fspath(self):
  1057. """ the file system path of the test module which collected this test. """
  1058. return self._pyfuncitem.fspath
  1059. @property
  1060. def keywords(self):
  1061. """ keywords/markers dictionary for the underlying node. """
  1062. return self.node.keywords
  1063. @property
  1064. def session(self):
  1065. """ pytest session object. """
  1066. return self._pyfuncitem.session
  1067. def addfinalizer(self, finalizer):
  1068. """add finalizer/teardown function to be called after the
  1069. last test within the requesting test context finished
  1070. execution. """
  1071. # XXX usually this method is shadowed by fixturedef specific ones
  1072. self._addfinalizer(finalizer, scope=self.scope)
  1073. def _addfinalizer(self, finalizer, scope):
  1074. colitem = self._getscopeitem(scope)
  1075. self._pyfuncitem.session._setupstate.addfinalizer(
  1076. finalizer=finalizer, colitem=colitem)
  1077. def applymarker(self, marker):
  1078. """ Apply a marker to a single test function invocation.
  1079. This method is useful if you don't want to have a keyword/marker
  1080. on all function invocations.
  1081. :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object
  1082. created by a call to ``pytest.mark.NAME(...)``.
  1083. """
  1084. try:
  1085. self.node.keywords[marker.markname] = marker
  1086. except AttributeError:
  1087. raise ValueError(marker)
  1088. def raiseerror(self, msg):
  1089. """ raise a FixtureLookupError with the given message. """
  1090. raise self._fixturemanager.FixtureLookupError(None, self, msg)
  1091. def _fillfixtures(self):
  1092. item = self._pyfuncitem
  1093. fixturenames = getattr(item, "fixturenames", self.fixturenames)
  1094. for argname in fixturenames:
  1095. if argname not in item.funcargs:
  1096. item.funcargs[argname] = self.getfuncargvalue(argname)
  1097. def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
  1098. """ (deprecated) Return a testing resource managed by ``setup`` &
  1099. ``teardown`` calls. ``scope`` and ``extrakey`` determine when the
  1100. ``teardown`` function will be called so that subsequent calls to
  1101. ``setup`` would recreate the resource. With pytest-2.3 you often
  1102. do not need ``cached_setup()`` as you can directly declare a scope
  1103. on a fixture function and register a finalizer through
  1104. ``request.addfinalizer()``.
  1105. :arg teardown: function receiving a previously setup resource.
  1106. :arg setup: a no-argument function creating a resource.
  1107. :arg scope: a string value out of ``function``, ``class``, ``module``
  1108. or ``session`` indicating the caching lifecycle of the resource.
  1109. :arg extrakey: added to internal caching key of (funcargname, scope).
  1110. """
  1111. if not hasattr(self.config, '_setupcache'):
  1112. self.config._setupcache = {} # XXX weakref?
  1113. cachekey = (self.fixturename, self._getscopeitem(scope), extrakey)
  1114. cache = self.config._setupcache
  1115. try:
  1116. val = cache[cachekey]
  1117. except KeyError:
  1118. __tracebackhide__ = True
  1119. if scopemismatch(self.scope, scope):
  1120. raise ScopeMismatchError("You tried to access a %r scoped "
  1121. "resource with a %r scoped request object" %(
  1122. (scope, self.scope)))
  1123. __tracebackhide__ = False
  1124. val = setup()
  1125. cache[cachekey] = val
  1126. if teardown is not None:
  1127. def finalizer():
  1128. del cache[cachekey]
  1129. teardown(val)
  1130. self._addfinalizer(finalizer, scope=scope)
  1131. return val
  1132. def getfuncargvalue(self, argname):
  1133. """ Dynamically retrieve a named fixture function argument.
  1134. As of pytest-2.3, it is easier and usually better to access other
  1135. fixture values by stating it as an input argument in the fixture
  1136. function. If you only can decide about using another fixture at test
  1137. setup time, you may

Large files files are truncated, but you can click here to view the full file