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:
parent
722e20c7d6
commit
6461295ab4
|
@ -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
|
||||
|
|
|
@ -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 =============================
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ..
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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'>
|
||||
|
|
|
@ -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'>
|
||||
|
|
|
@ -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.
|
||||
|
|
16
doc/faq.txt
16
doc/faq.txt
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`.
|
||||
|
|
14
doc/mark.txt
14
doc/mark.txt
|
@ -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 ..
|
||||
|
||||
|
|
|
@ -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 =============================
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -175,5 +175,4 @@ Running it will exit quickly::
|
|||
$ python myinvoke.py
|
||||
ERROR: hi from our plugin
|
||||
|
||||
|
||||
.. include:: links.inc
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
2
setup.py
2
setup.py
|
@ -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'],
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue