diff --git a/_pytest/doctest.py b/_pytest/doctest.py index 05699ca4c..c8417c521 100644 --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -64,12 +64,16 @@ class DoctestItem(pytest.Item): class DoctestTextfile(DoctestItem, pytest.File): def runtest(self): - failed, tot = py.std.doctest.testfile( + doctest = py.std.doctest + failed, tot = doctest.testfile( str(self.fspath), module_relative=False, + optionflags=doctest.ELLIPSIS, raise_on_error=True, verbose=0) class DoctestModule(DoctestItem, pytest.File): def runtest(self): + doctest = py.std.doctest module = self.fspath.pyimport() - failed, tot = py.std.doctest.testmod( - module, raise_on_error=True, verbose=0) + failed, tot = doctest.testmod( + module, raise_on_error=True, verbose=0, + optionflags=doctest.ELLIPSIS) diff --git a/_pytest/nose.py b/_pytest/nose.py index af07ae8f8..2f90a93f8 100644 --- a/_pytest/nose.py +++ b/_pytest/nose.py @@ -1,4 +1,4 @@ -"""run test suites written for nose. """ +""" run test suites written for nose. """ import pytest, py import inspect diff --git a/_pytest/python.py b/_pytest/python.py index 8ea3676f9..d347aab9e 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -762,19 +762,28 @@ def raises(ExpectedException, *args, **kwargs): If using Python 2.5 or above, you may use this function as a context manager:: - >>> with raises(ZeroDivisionError): - ... 1/0 + >>> with raises(ZeroDivisionError): + ... 1/0 - Or you can one of two forms: + Or you can specify a callable by passing a to-be-called lambda:: - if args[0] is callable: raise AssertionError if calling it with - the remaining arguments does not raise the expected exception. - if args[0] is a string: raise AssertionError if executing the - the string in the calling scope does not raise expected exception. - examples: - >>> x = 5 - >>> raises(TypeError, lambda x: x + 'hello', x=x) - >>> raises(TypeError, "x + 'hello'") + >>> raises(ZeroDivisionError, lambda: 1/0) + + + or you can specify an arbitrary callable with arguments:: + + >>> def f(x): return 1/x + ... + >>> raises(ZeroDivisionError, f, 0) + + >>> raises(ZeroDivisionError, f, x=0) + + + A third possibility is to use a string which which will + be executed:: + + >>> raises(ZeroDivisionError, "f(0)") + """ __tracebackhide__ = True diff --git a/_pytest/recwarn.py b/_pytest/recwarn.py index 41cf48c51..e2fb2b17e 100644 --- a/_pytest/recwarn.py +++ b/_pytest/recwarn.py @@ -24,8 +24,8 @@ def pytest_namespace(): return {'deprecated_call': deprecated_call} def deprecated_call(func, *args, **kwargs): - """ assert that calling func(*args, **kwargs) - triggers a DeprecationWarning. + """ assert that calling ``func(*args, **kwargs)`` + triggers a DeprecationWarning. """ warningmodule = py.std.warnings l = [] diff --git a/_pytest/session.py b/_pytest/session.py index 8c2da87e7..1fdfd72b2 100644 --- a/_pytest/session.py +++ b/_pytest/session.py @@ -408,7 +408,8 @@ class Session(FSCollector): path = names.pop(0) if path.check(dir=1): assert not names, "invalid arg %r" %(arg,) - for path in path.visit(rec=self._recurse, bf=True, sort=True): + for path in path.visit(fil=lambda x: x.check(file=1), + rec=self._recurse, bf=True, sort=True): for x in self._collectfile(path): yield x else: @@ -424,12 +425,13 @@ class Session(FSCollector): return ihook.pytest_collect_file(path=path, parent=self) def _recurse(self, path): - ihook = self.gethookproxy(path) + ihook = self.gethookproxy(path.dirpath()) if ihook.pytest_ignore_collect(path=path, config=self.config): return for pat in self._norecursepatterns: if path.check(fnmatch=pat): return False + ihook = self.gethookproxy(path) ihook.pytest_collect_directory(path=path, parent=self) return True diff --git a/doc/announce/release-2.0.0.txt b/doc/announce/release-2.0.0.txt index 0d6cb0371..d6ff3206a 100644 --- a/doc/announce/release-2.0.0.txt +++ b/doc/announce/release-2.0.0.txt @@ -87,6 +87,7 @@ and "pytest.raises" used as the recommended default way. - py.test.config is now only available if you are in a test run. - the following (mostly already deprecated) functionality was removed: + - removed support for Module/Class/... collection node definitions in conftest.py files. They will cause nothing special. - removed support for calling the pre-1.0 collection API of "run()" and "join" diff --git a/doc/apiref.txt b/doc/apiref.txt index 4392eb8f3..1a88adbd3 100644 --- a/doc/apiref.txt +++ b/doc/apiref.txt @@ -15,6 +15,7 @@ py.test reference documentation xunit_setup.txt capture.txt monkeypatch.txt + xdist.txt tmpdir.txt skipping.txt mark.txt diff --git a/doc/builtin.txt b/doc/builtin.txt index 63db8dd5c..ef8387fbf 100644 --- a/doc/builtin.txt +++ b/doc/builtin.txt @@ -1,8 +1,10 @@ +.. _`pytest helpers`: + pytest builtin helpers ================================================ -builtin pytest.* helpers +builtin pytest.* functions and helping objects ----------------------------------------------------- You can always use an interactive Python prompt and type:: diff --git a/doc/example/nonpython/__init__.py b/doc/example/nonpython/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/doc/example/x.txt b/doc/example/x.txt deleted file mode 100644 index df63880f5..000000000 --- a/doc/example/x.txt +++ /dev/null @@ -1,123 +0,0 @@ -Looping on the failing test set ------------------------------------------ - -``py.test --looponfailing`` (implemented through the external -`pytest-xdist`_ plugin) allows to run a test suite, -memorize all failures and then loop over the failing set -of tests until they all pass. It will re-start running -the tests when it detects file changes in your project. - -select tests by keyword / test name search ------------------------------------------------------ - -.. _`selection by keyword`: - -You can selectively run tests by specifiying a keyword -on the command line. Examples:: - - py.test -k test_simple - py.test -k "-test_simple" - -will run all tests matching (or not matching) the -"test_simple" keyword. Note that you need to quote -the keyword if "-" is recognized as an indicator -for a commandline option. Lastly, you may use:: - - py.test. -k "test_simple:" - -which will run all tests after the expression has *matched once*, i.e. -all tests that are seen after a test that matches the "test_simple" -keyword. - -By default, all filename parts and -class/function names of a test function are put into the set -of keywords for a given test. You can specify additional -kewords like this: - -.. sourcecode:: python - - @py.test.mark.webtest - def test_send_http(): - ... - -and then use those keywords to select tests. See the `pytest_keyword`_ -plugin for more information. - -.. _`pytest_keyword`: plugin/mark.html -skip or expect-to-fail a test -------------------------------------------- - -py.test has a dedicated `skipping plugin`_ that allows to define - -* define "skip" outcomes indicating a platform or a - dependency mismatch. - -* "xfail" outcomes indicating an "expected failure" either with - with or without running a test. - -* skip and xfail outcomes can be applied at module, class or method - level or even only for certain argument sets of a parametrized function. - -.. _`skipping plugin`: plugin/skipping.html -.. _`funcargs mechanism`: funcargs.html -.. _`doctest.py`: http://docs.python.org/library/doctest.html -.. _`xUnit style setup`: xunit_setup.html -.. _`pytest_nose`: plugin/nose.html - - -no-boilerplate testing ----------------------------------- - -.. _`autocollect`: - -automatic Python test discovery -+++++++++++++++++++++++++++++++++++ - -By default, all python modules with a ``test_*.py`` -filename are inspected for finding tests: - -* functions with a name beginning with ``test_`` -* classes with a leading ``Test`` name and ``test`` prefixed methods. -* ``unittest.TestCase`` subclasses - -parametrizing test functions and functional testing -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -py.test offers the unique `funcargs mechanism`_ for setting up -and passing project-specific objects to Python test functions. -Test Parametrization happens by triggering a call to the same test -function with different argument values. For doing fixtures -using the funcarg mechanism makes your test and setup code -more efficient and more readable. This is especially true -for functional tests which might depend on command line -options and a setup that needs to be shared across -a whole test run. - -per-test capturing of output, including subprocesses -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -By default, ``py.test`` captures all writes to stdout/stderr. -Output from ``print`` statements as well as from subprocesses -is captured_. When a test fails, the associated captured outputs are shown. -This allows you to put debugging print statements in your code without -being overwhelmed by all the output that might be generated by tests -that do not fail. - -.. _captured: plugin/capture.html - - -information-rich tracebacks, PDB introspection -+++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -.. _`example tracebacks`: http://paste.pocoo.org/show/134814/ - -A lot of care is taken to present useful failure information -and in particular nice and concise Python tracebacks. This -is especially useful if you need to regularly look at failures -from nightly runs, i.e. are detached from the actual test -running session. Here are `example tracebacks`_ for a number of failing -test functions. You can modify traceback printing styles through the -command line. Using the `--pdb`` option you can automatically activate -a PDB `Python debugger`_ when a test fails. - - diff --git a/doc/features.txt b/doc/features.txt index 518022a33..632ced88a 100644 --- a/doc/features.txt +++ b/doc/features.txt @@ -5,12 +5,12 @@ no-boilerplate testing with Python ---------------------------------- - automatic, fully customizable Python test discovery -- allows fully :pep:`8` compliant coding style - write simple test functions and freely group tests - ``assert`` statement for your assertions - powerful parametrization of test functions -- rely on powerful traceback and assertion reporting +- rely on helpful traceback and failing assertion reporting - use ``print`` or ``pdb`` debugging on failures +- enables fully :pep:`8` compliant coding style extensive plugin and customization system ------------------------------------------------------ @@ -25,11 +25,9 @@ extensive plugin and customization system mature command line testing tool -------------------------------------- -- powerful :ref:`usage` possibilities +- powerful :ref:`usage` possibilities, well sorted command line options - used in many projects, ranging from 10 to 10K tests -- simple well sorted command line options -- runs on Unix, Windows from Python 2.4 up to Python 3.1 and 3.2 -- is itself tested extensively on a CI server +- tested on Unix and Windows from Python 2.4 up to Python 3.1 and 3.2 - keyword/testname based selection of tests integrates well with CI systems @@ -41,7 +39,6 @@ integrates well with CI systems .. _`tox`: http://codespeak.net/tox - supports common testing practises and methods ----------------------------------------------------------- diff --git a/doc/getting-started.txt b/doc/getting-started.txt index d8302dbfe..eca8ed385 100644 --- a/doc/getting-started.txt +++ b/doc/getting-started.txt @@ -36,17 +36,17 @@ That's it. You can execute the test function now:: =========================== test session starts ============================ platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev30 test path 1: /tmp/doc-exec-70 - + test_sample.py F - + ================================= FAILURES ================================= _______________________________ test_answer ________________________________ - + def test_answer(): > assert func(3) == 5 E assert 4 == 5 E + where 4 = func(3) - + test_sample.py:5: AssertionError ========================= 1 failed in 0.02 seconds ========================= @@ -120,14 +120,14 @@ run the module by passing its filename:: .F ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ - + self = - + def test_two(self): x = "hello" > assert hasattr(x, 'check') E assert hasattr('hello', 'check') - + test_class.py:8: AssertionError 1 failed, 1 passed in 0.02 seconds @@ -156,14 +156,14 @@ before performing the test function call. Let's just run it:: F ================================= FAILURES ================================= _____________________________ test_needsfiles ______________________________ - + tmpdir = local('/tmp/pytest-122/test_needsfiles0') - + def test_needsfiles(tmpdir): print tmpdir > assert 0 E assert 0 - + test_tmpdir.py:3: AssertionError ----------------------------- Captured stdout ------------------------------ /tmp/pytest-122/test_needsfiles0 @@ -194,29 +194,20 @@ Known Installation issues easy_install or pip not found? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Consult `distribute docs `_ to install the ``easy_install`` -tool on your machine. You may also use the original but somewhat older -`setuptools`_ project although we generally recommend to use -``distribute`` because it contains more bug fixes and also works for -Python3. - -For Python2 you can also consult pip_ for the popular ``pip`` tool. - -However, If you want to install on Python3 you need to use Distribute_ which -provides the ``easy_install`` utility. - +Consult `distribute docs`_ to install the ``easy_install`` +tool on your machine. You may also use the older +`setuptools`_ project but it lacks bug fixes and does not +work on Python3. If you use Python2 you may also install pip_. py.test not found on Windows despite installation? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. _`Python for Windows`: http://www.imladris.com/Scripts/PythonForWindows.html - - **Windows**: If "easy_install" or "py.test" are not found - please see here for preparing your environment for running - command line tools: `Python for Windows`_. You may alternatively - use an `ActivePython install`_ which makes command line tools - automatically available under Windows. + you need to add the Python script path to your ``PATH``, see here: + `Python for Windows`_. You may alternatively use an `ActivePython install`_ + which does this for you automatically. .. _`ActivePython install`: http://www.activestate.com/activepython/downloads diff --git a/doc/index.txt b/doc/index.txt index 4790aceaa..544bf8309 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -5,8 +5,8 @@ py.test: no-boilerplate testing with Python .. note:: version 2.0 introduces ``pytest`` as the main Python import name - but for compatibility reasons you can continue to use ``py.test`` - in your test code. + but for compatibility reasons you can continue to use ``import py`` + and ``py.test.XYZ`` to access :ref:`pytest helpers` in your test code. Welcome to ``py.test`` documentation: @@ -25,6 +25,7 @@ Welcome to ``py.test`` documentation: :hidden: changelog.txt + example/attic Indices and tables ================== diff --git a/doc/links.inc b/doc/links.inc index a2b5fbf89..d519cbc7a 100644 --- a/doc/links.inc +++ b/doc/links.inc @@ -12,6 +12,7 @@ .. _`setuptools`: http://pypi.python.org/pypi/setuptools .. _`easy_install`: +.. _`distribute docs`: .. _`distribute`: http://pypi.python.org/pypi/distribute .. _`pip`: http://pypi.python.org/pypi/pip .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv diff --git a/doc/nose.txt b/doc/nose.txt index 8d785f5fa..5e3352817 100644 --- a/doc/nose.txt +++ b/doc/nose.txt @@ -4,7 +4,6 @@ Running test written for nose .. include:: links.inc py.test has basic support for running tests written for nose_. -This is implemented in :pymod:`_pytest.nose`. Usage ------------- @@ -13,8 +12,8 @@ type:: py.test # instead of 'nosetests' -and you should be able to run your nose style tests and at the same -make full use of py.test's capabilities. +and you should be able to run your nose style tests and +make use of py.test's capabilities. Supported nose Idioms ---------------------- @@ -25,18 +24,12 @@ Supported nose Idioms * yield-based tests and their setup * general usage of nose utilities -Unsupported idioms / issues +Unsupported idioms / known issues ---------------------------------- - nose-style doctests are not collected and executed correctly, - also fixtures don't work. + also doctest fixtures don't work. - no nose-configuration is recognized -If you find other issues or have suggestions please run:: - py.test --pastebin=all - -and send the resulting URL to a py.test contact channel, -at best to the mailing list. -""" diff --git a/doc/plugins.txt b/doc/plugins.txt index 4308fad20..ccca1271c 100644 --- a/doc/plugins.txt +++ b/doc/plugins.txt @@ -52,7 +52,6 @@ earlier than further away ones. under a package scope or to never import anything from a conftest.py file. -.. _`installing plugins`: .. _`external plugins`: Installing External Plugins / Searching @@ -85,12 +84,11 @@ you can copy from: * around 20 `builtin plugins`_ which comprise py.test's own functionality * around 10 `external plugins`_ providing additional features -All of these plugins are using the documented `well specified hooks`_ -to implement their wide-ranging functionality. +All of these plugins implement the documented `well specified hooks`_ +to extend and add functionality. .. _`setuptools entry points`: - Making your plugin installable by others ----------------------------------------------- diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 352c0ec99..dab0654a2 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -39,7 +39,7 @@ class TestGeneralUsage: def test_1(pytestconfig): pytestconfig.getbasetemp().ensure("hello") """) - result = testdir.runpytest(p, '--basetemp=%s' %mytemp) + result = testdir.runpytest(p, '--basetemp=%s' % mytemp) assert result.ret == 0 assert mytemp.join('hello').check() @@ -239,7 +239,7 @@ class TestInvocationVariants: def test_pydoc(self, testdir): for name in ('py.test', 'pytest'): - result = testdir.runpython_c("import %s;help(%s)" % (name,name)) + result = testdir.runpython_c("import %s;help(%s)" % (name, name)) assert result.ret == 0 s = result.stdout.str() assert 'MarkGenerator' in s @@ -325,7 +325,7 @@ class TestInvocationVariants: class MyPlugin: def pytest_addoption(self, parser): parser.addoption("--myopt") - + pytest.main(["-h"], plugins=[MyPlugin()]) out, err = capsys.readouterr() assert "--myopt" in out @@ -358,7 +358,6 @@ class TestInvocationVariants: "ERROR*file*or*package*not*found*", ]) - @pytest.mark.xfail(reason="decide: feature or bug") def test_noclass_discovery_if_not_testcase(self, testdir): testpath = testdir.makepyfile(""" diff --git a/testing/test_collection.py b/testing/test_collection.py index 425edd887..b5b15d466 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -204,12 +204,12 @@ class TestCustomConftests: return path.basename.startswith("x") or \ path.basename == "test_one.py" """) - testdir.mkdir("xy123").ensure("test_hello.py").write( - "syntax error" - ) + sub = testdir.mkdir("xy123") + sub.ensure("test_hello.py").write("syntax error") + sub.join("conftest.py").write("syntax error") testdir.makepyfile("def test_hello(): pass") testdir.makepyfile(test_one="syntax error") - result = testdir.runpytest() + result = testdir.runpytest("--fulltrace") assert result.ret == 0 result.stdout.fnmatch_lines(["*1 passed*"]) diff --git a/testing/test_mark.py b/testing/test_mark.py index b924a2237..e8f747dc4 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -2,6 +2,10 @@ import py, pytest from _pytest.mark import MarkGenerator as Mark class TestMark: + def test_pytest_exists_in_namespace_all(self): + assert 'mark' in py.test.__all__ + assert 'mark' in pytest.__all__ + def test_pytest_mark_notcallable(self): mark = Mark() pytest.raises((AttributeError, TypeError), "mark()") diff --git a/tox.ini b/tox.ini index 164bd6065..264233beb 100644 --- a/tox.ini +++ b/tox.ini @@ -24,6 +24,12 @@ commands= py.test -n3 -rfsxX \ --junitxml={envlogdir}/junit-{envname}.xml [] +[testenv:doctest] +changedir=. +commands=py.test --doctest-modules _pytest +deps= + + [testenv:doc] basepython=python changedir=doc @@ -57,6 +63,6 @@ commands= [pytest] minversion=2.0 plugins=pytester -addopts= -rxf --pyargs +addopts= -rxf --pyargs --doctest-modules rsyncdirs=tox.ini pytest.py _pytest testing