probably the last major internal cleanup action: rename collection to

session which now is the root collection node.  This means that
session, collection and config objects have a more defined
relationship (previously there was no way to get from a collection
node or even from a runtest hook to the session object which
was strange).
This commit is contained in:
holger krekel 2010-11-07 10:19:58 +01:00
parent 722e20c7d6
commit 6461295ab4
29 changed files with 163 additions and 143 deletions

View File

@ -21,7 +21,7 @@ assertion fails you will see the value of ``x``::
$ py.test test_assert1.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_assert1.py
test_assert1.py F
@ -35,7 +35,7 @@ assertion fails you will see the value of ``x``::
E + where 3 = f()
test_assert1.py:5: AssertionError
========================= 1 failed in 0.02 seconds =========================
========================= 1 failed in 0.05 seconds =========================
Reporting details about the failing assertion is achieved by re-evaluating
the assert expression and recording intermediate values.
@ -101,7 +101,7 @@ if you run this module::
$ py.test test_assert2.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_assert2.py
test_assert2.py F

View File

@ -44,7 +44,7 @@ then you can just invoke ``py.test`` without command line options::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
test path 1: /tmp/doc-exec-400
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: /tmp/doc-exec-519
============================= in 0.00 seconds =============================

View File

@ -27,10 +27,10 @@ Let's run our little function::
F
================================= FAILURES =================================
______________________________ test_something ______________________________
def test_something():
> checkconfig(42)
E Failed: not configured: 42
test_checkconfig.py:8: Failed
1 failed in 0.02 seconds

View File

@ -36,12 +36,12 @@ and when running it will see a skipped "slow" test::
$ py.test test_module.py -rs # "-rs" means report on the little 's'
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_module.py
test_module.py .s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-435/conftest.py:9: need --runslow option to run
SKIP [1] /tmp/doc-exec-557/conftest.py:9: need --runslow option to run
=================== 1 passed, 1 skipped in 0.02 seconds ====================
@ -49,7 +49,7 @@ Or run it including the ``slow`` marked test::
$ py.test test_module.py --runslow
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_module.py
test_module.py ..

View File

@ -49,7 +49,7 @@ You can now run the test::
$ py.test test_sample.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_sample.py
test_sample.py F
@ -57,7 +57,7 @@ You can now run the test::
================================= FAILURES =================================
_______________________________ test_answer ________________________________
mysetup = <conftest.MySetup instance at 0x1cf6b90>
mysetup = <conftest.MySetup instance at 0x1ca5cf8>
def test_answer(mysetup):
app = mysetup.myapp()
@ -122,14 +122,14 @@ Running it yields::
$ py.test test_ssh.py -rs
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_ssh.py
test_ssh.py s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-438/conftest.py:22: specify ssh host with --ssh
SKIP [1] /tmp/doc-exec-560/conftest.py:22: specify ssh host with --ssh
======================== 1 skipped in 0.02 seconds =========================
======================== 1 skipped in 0.03 seconds =========================
If you specify a command line option like ``py.test --ssh=python.org`` the test will execute as expected.

View File

@ -27,17 +27,19 @@ now execute the test specification::
nonpython $ py.test test_simple.yml
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_simple.yml
test_simple.yml .F
================================= FAILURES =================================
______________________________ usecase: hello ______________________________
usecase execution failed
spec failed: 'some': 'other'
no further details known at this point.
==================== 1 failed, 1 passed in 0.42 seconds ====================
========================= short test summary info ==========================
FAIL test_simple.yml::hello
==================== 1 failed, 1 passed in 0.43 seconds ====================
You get one dot for the passing ``sub1: sub1`` check and one failure.
Obviously in the above ``conftest.py`` you'll want to implement a more
@ -56,24 +58,25 @@ reporting in ``verbose`` mode::
nonpython $ py.test -v
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19 -- /home/hpk/venv/0/bin/python
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22 -- /home/hpk/venv/0/bin/python
test path 1: /home/hpk/p/pytest/doc/example/nonpython
test_simple.yml <- test_simple.yml:1: usecase: ok PASSED
test_simple.yml <- test_simple.yml:1: usecase: hello FAILED
================================= FAILURES =================================
______________________________ usecase: hello ______________________________
usecase execution failed
spec failed: 'some': 'other'
no further details known at this point.
========================= short test summary info ==========================
FAIL test_simple.yml::hello
==================== 1 failed, 1 passed in 0.07 seconds ====================
While developing your custom test collection and execution it's also
interesting to just look at the collection tree::
nonpython $ py.test --collectonly
<Collection 'nonpython'>
<YamlFile 'test_simple.yml'>
<YamlItem 'ok'>
<YamlItem 'hello'>

View File

@ -31,7 +31,6 @@ finding out what is collected
You can always peek at the collection tree without running tests like this::
. $ py.test --collectonly collectonly.py
<Collection 'example'>
<Module 'collectonly.py'>
<Function 'test_function'>
<Class 'TestClass'>

View File

@ -130,7 +130,7 @@ let's run the full monty::
E assert 4 < 4
test_compute.py:3: AssertionError
1 failed, 4 passed in 0.02 seconds
1 failed, 4 passed in 0.03 seconds
As expected when running the full range of ``param1`` values
we'll get an error on the last one.

View File

@ -12,11 +12,11 @@ On naming, nosetests, licensing and magic XXX
Why a ``py.test`` instead of a ``pytest`` command?
++++++++++++++++++++++++++++++++++++++++++++++++++
Some historic, some practical reasons: ``py.test`` used to be part of
Some historic, some practical reasons: ``py.test`` used to be part of
the ``py`` package which provided several developer utitilities,
all starting with ``py.<TAB>``, providing nice TAB-completion. If
you install ``pip install pycmd`` you get these tools from a separate
package. These days the command line tool could be ``pytest``
package. These days the command line tool could be ``pytest``
but then many people have gotten used to the old name and there
also is another tool with this same which would lead to some clashes.
@ -37,11 +37,11 @@ What's this "magic" with py.test?
Around 2007 (version ``0.8``) some several people claimed that py.test
was using too much "magic". It has been refactored a lot. It is today
probably one of the smallest, most universally runnable and most
customizable testing frameworks for Python. It remains true
that ``py.test`` uses metaprogramming techniques, i.e. it views
test code similar to how compilers view programs, using a
somewhat abstract internal model.
probably one of the smallest, most universally runnable and most
customizable testing frameworks for Python. It remains true
that ``py.test`` uses metaprogramming techniques, i.e. it views
test code similar to how compilers view programs, using a
somewhat abstract internal model.
It's also true that the no-boilerplate testing is implemented by making
use of the Python assert statement through "re-interpretation":
@ -64,7 +64,7 @@ function arguments, parametrized tests and setup
Is using funcarg- versus xUnit setup a style question?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
For simple applications and for people experienced with nose_ or
For simple applications and for people experienced with nose_ or
unittest-style test setup using `xUnit style setup`_
feels natural. For larger test suites, parametrized testing
or setup of complex test resources using funcargs_ is recommended.

View File

@ -34,7 +34,7 @@ Running the test looks like this::
$ py.test test_simplefactory.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_simplefactory.py
test_simplefactory.py F
@ -136,7 +136,7 @@ Running this::
$ py.test test_example.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_example.py
test_example.py .........F
@ -158,7 +158,6 @@ the test collection phase which is separate from the actual test running.
Let's just look at what is collected::
$ py.test --collectonly test_example.py
<Collection 'doc-exec-403'>
<Module 'test_example.py'>
<Function 'test_func[0]'>
<Function 'test_func[1]'>
@ -175,7 +174,7 @@ If you want to select only the run with the value ``7`` you could do::
$ py.test -v -k 7 test_example.py # or -k test_func[7]
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19 -- /home/hpk/venv/0/bin/python
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22 -- /home/hpk/venv/0/bin/python
test path 1: test_example.py
test_example.py <- test_example.py:6: test_func[7] PASSED

View File

@ -14,7 +14,7 @@ Installation options::
To check your installation has installed the correct version::
$ py.test --version
This is py.test version 2.0.0.dev19, imported from /home/hpk/p/pytest/pytest
This is py.test version 2.0.0.dev22, imported from /home/hpk/p/pytest/pytest
If you get an error checkout :ref:`installation issues`.
@ -34,8 +34,8 @@ That's it. You can execute the test function now::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
test path 1: /tmp/doc-exec-404
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: /tmp/doc-exec-523
test_sample.py F
@ -121,7 +121,7 @@ run the module by passing its filename::
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass instance at 0x2c2c560>
self = <test_class.TestClass instance at 0x254f6c8>
def test_two(self):
x = "hello"
@ -129,7 +129,7 @@ run the module by passing its filename::
E assert hasattr('hello', 'check')
test_class.py:8: AssertionError
1 failed, 1 passed in 0.02 seconds
1 failed, 1 passed in 0.03 seconds
The first test passed, the second failed. Again we can easily see
the intermediate values used in the assertion, helping us to
@ -157,7 +157,7 @@ before performing the test function call. Let's just run it::
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________
tmpdir = local('/tmp/pytest-240/test_needsfiles0')
tmpdir = local('/tmp/pytest-446/test_needsfiles0')
def test_needsfiles(tmpdir):
print tmpdir
@ -166,8 +166,8 @@ before performing the test function call. Let's just run it::
test_tmpdir.py:3: AssertionError
----------------------------- Captured stdout ------------------------------
/tmp/pytest-240/test_needsfiles0
1 failed in 0.04 seconds
/tmp/pytest-446/test_needsfiles0
1 failed in 0.07 seconds
Before the test runs, a unique-per-test-invocation temporary directory
was created. More info at :ref:`tmpdir handling`.

View File

@ -88,20 +88,20 @@ You can use the ``-k`` command line option to select tests::
$ py.test -k webtest # running with the above defined examples yields
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
test path 1: /tmp/doc-exec-407
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: /tmp/doc-exec-527
test_mark.py ..
test_mark_classlevel.py ..
========================= 4 passed in 0.01 seconds =========================
========================= 4 passed in 0.02 seconds =========================
And you can also run all tests except the ones that match the keyword::
$ py.test -k-webtest
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
test path 1: /tmp/doc-exec-407
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: /tmp/doc-exec-527
===================== 4 tests deselected by '-webtest' =====================
======================= 4 deselected in 0.01 seconds =======================
@ -110,8 +110,8 @@ Or to only select the class::
$ py.test -kTestClass
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
test path 1: /tmp/doc-exec-407
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: /tmp/doc-exec-527
test_mark_classlevel.py ..

View File

@ -39,8 +39,8 @@ will be undone.
.. background check:
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
test path 1: /tmp/doc-exec-408
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: /tmp/doc-exec-528
============================= in 0.00 seconds =============================

View File

@ -16,7 +16,7 @@ conftest.py: local per-directory plugins
--------------------------------------------------------------
local ``conftest.py`` plugins contain directory-specific hook
implementations. Collection and test running activities will
implementations. Session and test running activities will
invoke all hooks defined in "higher up" ``conftest.py`` files.
Example: Assume the following layout and content of files::
@ -268,7 +268,7 @@ you can use the following hook:
reporting hooks
------------------------------
Collection related reporting hooks:
Session related reporting hooks:
.. autofunction: pytest_collectstart
.. autofunction: pytest_itemcollected

View File

@ -28,7 +28,7 @@ Running this would result in a passed test except for the last
$ py.test test_tmpdir.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_tmpdir.py
test_tmpdir.py F
@ -36,7 +36,7 @@ Running this would result in a passed test except for the last
================================= FAILURES =================================
_____________________________ test_create_file _____________________________
tmpdir = local('/tmp/pytest-243/test_create_file0')
tmpdir = local('/tmp/pytest-447/test_create_file0')
def test_create_file(tmpdir):
p = tmpdir.mkdir("sub").join("hello.txt")
@ -47,7 +47,7 @@ Running this would result in a passed test except for the last
E assert 0
test_tmpdir.py:7: AssertionError
========================= 1 failed in 0.04 seconds =========================
========================= 1 failed in 0.15 seconds =========================
.. _`base temporary directory`:

View File

@ -24,7 +24,7 @@ Running it yields::
$ py.test test_unittest.py
=========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev19
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev22
test path 1: test_unittest.py
test_unittest.py F
@ -56,7 +56,7 @@ Running it yields::
/usr/lib/python2.6/unittest.py:350: AssertionError
----------------------------- Captured stdout ------------------------------
hello
========================= 1 failed in 0.02 seconds =========================
========================= 1 failed in 0.12 seconds =========================
.. _`unittest.py style`: http://docs.python.org/library/unittest.html

View File

@ -175,5 +175,4 @@ Running it will exit quickly::
$ python myinvoke.py
ERROR: hi from our plugin
.. include:: links.inc

View File

@ -5,7 +5,7 @@ see http://pytest.org for documentation and details
(c) Holger Krekel and others, 2004-2010
"""
__version__ = '2.0.0.dev22'
__version__ = '2.0.0.dev23'
__all__ = ['config', 'cmdline']

View File

@ -38,7 +38,8 @@ def pytest_unconfigure(config):
""" called before test process is exited. """
def pytest_runtestloop(session):
""" called for performing the main runtest loop (after collection. """
""" called for performing the main runtest loop
(after collection finished). """
pytest_runtestloop.firstresult = True
# -------------------------------------------------------------------------
@ -49,11 +50,11 @@ def pytest_collection(session):
""" perform the collection protocol for the given session. """
pytest_collection.firstresult = True
def pytest_collection_modifyitems(config, items):
def pytest_collection_modifyitems(session, config, items):
""" called after collection has been performed, may filter or re-order
the items in-place."""
def pytest_collection_finish(collection):
def pytest_collection_finish(session):
""" called after collection has been performed and modified. """
def pytest_ignore_collect(path, config):
@ -64,8 +65,7 @@ def pytest_ignore_collect(path, config):
pytest_ignore_collect.firstresult = True
def pytest_collect_directory(path, parent):
""" return collection Node or None for the given path. Any new node
needs to have the specified ``parent`` as a parent."""
""" called before traversing a directory for collection files. """
pytest_collect_directory.firstresult = True
def pytest_collect_file(path, parent):

View File

@ -6,7 +6,7 @@ import re
import inspect
import time
from fnmatch import fnmatch
from pytest.plugin.session import Collection
from pytest.plugin.session import Session
from py.builtin import print_
from pytest.main import HookRelay
@ -273,34 +273,34 @@ class TmpTestdir:
p.ensure("__init__.py")
return p
Collection = Collection
Session = Session
def getnode(self, config, arg):
collection = Collection(config)
session = Session(config)
assert '::' not in str(arg)
p = py.path.local(arg)
x = collection.fspath.bestrelpath(p)
return collection.perform_collect([x], genitems=False)[0]
x = session.fspath.bestrelpath(p)
return session.perform_collect([x], genitems=False)[0]
def getpathnode(self, path):
config = self.parseconfig(path)
collection = Collection(config)
x = collection.fspath.bestrelpath(path)
return collection.perform_collect([x], genitems=False)[0]
session = Session(config)
x = session.fspath.bestrelpath(path)
return session.perform_collect([x], genitems=False)[0]
def genitems(self, colitems):
collection = colitems[0].collection
session = colitems[0].session
result = []
for colitem in colitems:
result.extend(collection.genitems(colitem))
result.extend(session.genitems(colitem))
return result
def inline_genitems(self, *args):
#config = self.parseconfig(*args)
config = self.parseconfigure(*args)
rec = self.getreportrecorder(config)
collection = Collection(config)
collection.perform_collect()
return collection.items, rec
session = Session(config)
session.perform_collect()
return session.items, rec
def runitem(self, source):
# used from runner functional tests

View File

@ -47,7 +47,7 @@ def pytest_collect_file(path, parent):
ext = path.ext
pb = path.purebasename
if ext == ".py" and (pb.startswith("test_") or pb.endswith("_test") or
parent.collection.isinitpath(path)):
parent.session.isinitpath(path)):
return parent.ihook.pytest_pycollect_makemodule(
path=path, parent=parent)
@ -393,9 +393,9 @@ class Function(FunctionMixin, pytest.collect.Item):
"""
_genid = None
def __init__(self, name, parent=None, args=None, config=None,
callspec=None, callobj=_dummy, keywords=None, collection=None):
callspec=None, callobj=_dummy, keywords=None, session=None):
super(Function, self).__init__(name, parent,
config=config, collection=collection)
config=config, session=session)
self._args = args
if self._isyieldedfunction():
assert not callspec, (
@ -711,13 +711,13 @@ class FuncargRequest:
raise self.LookupError(msg)
def showfuncargs(config):
from pytest.plugin.session import Collection
collection = Collection(config)
collection.perform_collect()
if collection.items:
plugins = getplugins(collection.items[0])
from pytest.plugin.session import Session
session = Session(config)
session.perform_collect()
if session.items:
plugins = getplugins(session.items[0])
else:
plugins = getplugins(collection)
plugins = getplugins(session)
curdir = py.path.local()
tw = py.io.TerminalWriter()
verbose = config.getvalue("verbose")

View File

@ -1,4 +1,4 @@
""" core implementation of testing process: init, collection, runtest loop. """
""" core implementation of testing process: init, session, runtest loop. """
import py
import pytest
@ -54,7 +54,7 @@ def pytest_configure(config):
config.option.maxfail = 1
def pytest_cmdline_main(config):
""" default command line protocol for initialization, collection,
""" default command line protocol for initialization, session,
running tests and reporting. """
session = Session(config)
session.exitstatus = EXIT_OK
@ -83,20 +83,17 @@ def pytest_cmdline_main(config):
return session.exitstatus
def pytest_collection(session):
collection = session.collection
assert not hasattr(collection, 'items')
collection.perform_collect()
session.perform_collect()
hook = session.config.hook
items = collection.items
hook.pytest_collection_modifyitems(config=session.config, items=items)
hook.pytest_collection_finish(collection=collection)
hook.pytest_collection_modifyitems(session=session,
config=session.config, items=session.items)
hook.pytest_collection_finish(session=session)
return True
def pytest_runtestloop(session):
if session.config.option.collectonly:
return True
for item in session.collection.items:
for item in session.session.items:
item.config.hook.pytest_runtest_protocol(item=item)
if session.shouldstop:
raise session.Interrupted(session.shouldstop)
@ -121,7 +118,7 @@ class Session(object):
self.config.pluginmanager.register(self, name="session", prepend=True)
self._testsfailed = 0
self.shouldstop = False
self.collection = Collection(config) # XXX move elswehre
self.session = Session(config) # XXX move elswehre
def pytest_collectstart(self):
if self.shouldstop:
@ -154,7 +151,7 @@ def compatproperty(name):
def fget(self):
#print "retrieving %r property from %s" %(name, self.fspath)
py.log._apiwarn("2.0", "use py.test.collect.%s for "
"Collection classes" % name)
"Session classes" % name)
return getattr(pytest.collect, name)
return property(fget)
@ -162,7 +159,7 @@ class Node(object):
""" base class for all Nodes in the collection tree.
Collector subclasses have children, Items are terminal nodes."""
def __init__(self, name, parent=None, config=None, collection=None):
def __init__(self, name, parent=None, config=None, session=None):
#: a unique name with the scope of the parent
self.name = name
@ -173,11 +170,11 @@ class Node(object):
self.config = config or parent.config
#: the collection this node is part of
self.collection = collection or parent.collection
self.session = session or parent.session
#: filesystem path where this node was collected from
self.fspath = getattr(parent, 'fspath', None)
self.ihook = self.collection.gethookproxy(self.fspath)
self.ihook = self.session.gethookproxy(self.fspath)
self.keywords = {self.name: True}
Module = compatproperty("Module")
@ -312,16 +309,16 @@ class Collector(Node):
excinfo.traceback = ntraceback.filter()
class FSCollector(Collector):
def __init__(self, fspath, parent=None, config=None, collection=None):
def __init__(self, fspath, parent=None, config=None, session=None):
fspath = py.path.local(fspath) # xxx only for test_resultlog.py?
name = parent and fspath.relto(parent.fspath) or fspath.basename
super(FSCollector, self).__init__(name, parent, config, collection)
super(FSCollector, self).__init__(name, parent, config, session)
self.fspath = fspath
def _makeid(self):
if self == self.collection:
if self == self.session:
return "."
relpath = self.collection.fspath.bestrelpath(self.fspath)
relpath = self.session.fspath.bestrelpath(self.fspath)
if os.sep != "/":
relpath = relpath.replace(os.sep, "/")
return relpath
@ -346,13 +343,33 @@ class Item(Node):
self._location = location
return location
class Collection(FSCollector):
class Session(FSCollector):
class Interrupted(KeyboardInterrupt):
""" signals an interrupted test run. """
__module__ = 'builtins' # for py3
def __init__(self, config):
super(Collection, self).__init__(py.path.local(), parent=None,
config=config, collection=self)
super(Session, self).__init__(py.path.local(), parent=None,
config=config, session=self)
self.config.pluginmanager.register(self, name="session", prepend=True)
self._testsfailed = 0
self.shouldstop = False
self.trace = config.trace.root.get("collection")
self._norecursepatterns = config.getini("norecursedirs")
def pytest_collectstart(self):
if self.shouldstop:
raise self.Interrupted(self.shouldstop)
def pytest_runtest_logreport(self, report):
if report.failed and 'xfail' not in getattr(report, 'keywords', []):
self._testsfailed += 1
maxfail = self.config.getvalue("maxfail")
if maxfail and self._testsfailed >= maxfail:
self.shouldstop = "stopping after %d failures" % (
self._testsfailed)
pytest_collectreport = pytest_runtest_logreport
def isinitpath(self, path):
return path in self._initialpaths
@ -509,3 +526,4 @@ class Collection(FSCollector):
yield x
node.ihook.pytest_collectreport(report=rep)
Session = Session

View File

@ -376,8 +376,9 @@ class CollectonlyReporter:
self._tw.line("INTERNALERROR> " + line)
def pytest_collectstart(self, collector):
self.outindent(collector)
self.indent += self.INDENT
if collector.session != collector:
self.outindent(collector)
self.indent += self.INDENT
def pytest_itemcollected(self, item):
self.outindent(item)

View File

@ -22,7 +22,7 @@ def main():
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
version='2.0.0.dev22',
version='2.0.0.dev23',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

View File

@ -205,15 +205,15 @@ class TestFunction:
def test_function_equality(self, testdir, tmpdir):
config = testdir.reparseconfig()
collection = testdir.Collection(config)
session = testdir.Session(config)
f1 = py.test.collect.Function(name="name", config=config,
args=(1,), callobj=isinstance, collection=collection)
args=(1,), callobj=isinstance, session=session)
f2 = py.test.collect.Function(name="name",config=config,
args=(1,), callobj=py.builtin.callable, collection=collection)
args=(1,), callobj=py.builtin.callable, session=session)
assert not f1 == f2
assert f1 != f2
f3 = py.test.collect.Function(name="name", config=config,
args=(1,2), callobj=py.builtin.callable, collection=collection)
args=(1,2), callobj=py.builtin.callable, session=session)
assert not f3 == f2
assert f3 != f2
@ -221,7 +221,7 @@ class TestFunction:
assert f3 != f1
f1_b = py.test.collect.Function(name="name", config=config,
args=(1,), callobj=isinstance, collection=collection)
args=(1,), callobj=isinstance, session=session)
assert f1 == f1_b
assert not f1 != f1_b
@ -235,11 +235,11 @@ class TestFunction:
param = 1
funcargs = {}
id = "world"
collection = testdir.Collection(config)
session = testdir.Session(config)
f5 = py.test.collect.Function(name="name", config=config,
callspec=callspec1, callobj=isinstance, collection=collection)
callspec=callspec1, callobj=isinstance, session=session)
f5b = py.test.collect.Function(name="name", config=config,
callspec=callspec2, callobj=isinstance, collection=collection)
callspec=callspec2, callobj=isinstance, session=session)
assert f5 != f5b
assert not (f5 == f5b)
@ -396,7 +396,7 @@ def test_generate_tests_only_done_in_subdir(testdir):
def test_modulecol_roundtrip(testdir):
modcol = testdir.getmodulecol("pass", withinit=True)
trail = modcol.nodeid
newcol = modcol.collection.perform_collect([trail], genitems=0)[0]
newcol = modcol.session.perform_collect([trail], genitems=0)[0]
assert modcol.name == newcol.name

View File

@ -5,10 +5,10 @@ from pytest.plugin.resultlog import generic_path, ResultLog, \
from pytest.plugin.session import Node, Item, FSCollector
def test_generic_path(testdir):
from pytest.plugin.session import Collection
from pytest.plugin.session import Session
config = testdir.parseconfig()
collection = Collection(config)
p1 = Node('a', config=config, collection=collection)
session = Session(config)
p1 = Node('a', config=config, session=session)
#assert p1.fspath is None
p2 = Node('B', parent=p1)
p3 = Node('()', parent = p2)
@ -17,7 +17,7 @@ def test_generic_path(testdir):
res = generic_path(item)
assert res == 'a.B().c'
p0 = FSCollector('proj/test', config=config, collection=collection)
p0 = FSCollector('proj/test', config=config, session=session)
p1 = FSCollector('proj/test/a', parent=p0)
p2 = Node('B', parent=p1)
p3 = Node('()', parent = p2)

View File

@ -244,7 +244,7 @@ class TestExecutionForked(BaseFunctionalTests):
assert rep.failed
assert rep.when == "???"
class TestCollectionReports:
class TestSessionReports:
def test_collect_result(self, testdir):
col = testdir.getmodulecol("""
def test_func1():

View File

@ -516,7 +516,7 @@ def test_traceconfig(testdir, monkeypatch):
def test_debug(testdir, monkeypatch):
result = testdir.runpytest("--debug")
result.stderr.fnmatch_lines([
"*registered*session*",
"*pytest_sessionstart*session*",
])
assert result.ret == 0

View File

@ -1,6 +1,6 @@
import py
from pytest.plugin.session import Collection
from pytest.plugin.session import Session
class TestCollector:
def test_collect_versus_item(self):
@ -86,7 +86,7 @@ class TestCollector:
node = testdir.getpathnode(hello)
assert isinstance(node, py.test.collect.File)
assert node.name == "hello.xxx"
nodes = node.collection.perform_collect([node.nodeid], genitems=False)
nodes = node.session.perform_collect([node.nodeid], genitems=False)
assert len(nodes) == 1
assert isinstance(nodes[0], py.test.collect.File)
@ -292,7 +292,7 @@ class TestCustomConftests:
"*test_x*"
])
class TestCollection:
class TestSession:
def test_parsearg(self, testdir):
p = testdir.makepyfile("def test_func(): pass")
subdir = testdir.mkdir("sub")
@ -302,7 +302,7 @@ class TestCollection:
testdir.chdir()
subdir.chdir()
config = testdir.parseconfig(p.basename)
rcol = Collection(config=config)
rcol = Session(config=config)
assert rcol.fspath == subdir
parts = rcol._parsearg(p.basename)
@ -318,7 +318,7 @@ class TestCollection:
id = "::".join([p.basename, "test_func"])
config = testdir.parseconfig(id)
topdir = testdir.tmpdir
rcol = Collection(config)
rcol = Session(config)
assert topdir == rcol.fspath
rootid = rcol.nodeid
#root2 = rcol.perform_collect([rcol.nodeid], genitems=False)[0]
@ -333,7 +333,7 @@ class TestCollection:
id = "::".join([p.basename, "test_func"])
config = testdir.parseconfig(id)
topdir = testdir.tmpdir
rcol = Collection(config)
rcol = Session(config)
assert topdir == rcol.fspath
hookrec = testdir.getreportrecorder(config)
rcol.perform_collect()
@ -367,7 +367,7 @@ class TestCollection:
normid,
]:
config = testdir.parseconfig(id)
rcol = Collection(config=config)
rcol = Session(config=config)
rcol.perform_collect()
items = rcol.items
assert len(items) == 1
@ -392,7 +392,7 @@ class TestCollection:
id = p.basename
config = testdir.parseconfig(id)
rcol = Collection(config)
rcol = Session(config)
hookrec = testdir.getreportrecorder(config)
rcol.perform_collect()
items = rcol.items
@ -400,7 +400,7 @@ class TestCollection:
assert len(items) == 2
hookrec.hookrecorder.contains([
("pytest_collectstart",
"collector.fspath == collector.collection.fspath"),
"collector.fspath == collector.session.fspath"),
("pytest_collectstart",
"collector.__class__.__name__ == 'SpecialFile'"),
("pytest_collectstart",
@ -417,7 +417,7 @@ class TestCollection:
test_aaa = aaa.join("test_aaa.py")
p.move(test_aaa)
config = testdir.parseconfig()
rcol = Collection(config)
rcol = Session(config)
hookrec = testdir.getreportrecorder(config)
rcol.perform_collect()
items = rcol.items
@ -441,7 +441,7 @@ class TestCollection:
id = "."
config = testdir.parseconfig(id)
rcol = Collection(config)
rcol = Session(config)
hookrec = testdir.getreportrecorder(config)
rcol.perform_collect()
items = rcol.items
@ -459,12 +459,13 @@ class TestCollection:
def test_serialization_byid(self, testdir):
p = testdir.makepyfile("def test_func(): pass")
config = testdir.parseconfig()
rcol = Collection(config)
rcol = Session(config)
rcol.perform_collect()
items = rcol.items
assert len(items) == 1
item, = items
newcol = Collection(config)
rcol.config.pluginmanager.unregister(name="session")
newcol = Session(config)
item2, = newcol.perform_collect([item.nodeid], genitems=False)
assert item2.name == item.name
assert item2.fspath == item.fspath